Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2008-375
$eventId
ID of event: wwdc2008
$eventContentId
ID of session without event part: 375
$eventShortId
Shortened ID of event: wwdc08
$year
Year of session: 2008
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2008] [Session 375] Using Files...

WWDC08 • Session 375

Using Filesystem APIs Efficiently

Essentials • 59:20

Learn about new file system APIs and how they can be used to access the file system efficiently. Find out how new techniques for accessing file properties and enumerating directories can make your code cleaner and faster.

Speakers: Chris Linn, Keith Stattenfield

Unlisted on Apple Developer site

Downloads from Apple

SD Video (724.8 MB)

Transcript

This transcript was generated using Whisper, it may have transcription errors.

Good afternoon, everyone. My name's Christopher Linn, and I work on the core services team at Apple, which means we work on a whole constellation of pieces of technology down at the core services, application services layer. And today we wanted to talk about the file system APIs at the framework levels, and let you know what we're doing in Snow Leopard to improve efficiency and how you can take advantage of it. So here's our agenda. I wanted to give a quick overview of the current state of the APIs for accessing the file system. And that's to set the stage for giving you an idea what the limitations are and what we're looking at improving. And then we'll go into a fair amount of detail about the solutions that we want to present in Snow Leopard for certain parts of accessing the file system. We're not talking about things like reading and writing, opening files right now or mounting volumes, but the areas we're concentrating on today are getting info out of the file system, info about specific files, enumerating directories, and we're also going to touch on creating long-lived persistent references to files, tracking files. Okay. So these are the kinds of things that we hope you'll be able to take away. What are the problems that both internally at Apple and you guys are facing in writing your applications, the kinds of performance problems you're facing? How and improved APIs help solve these problems. how will these new APIs affect your application in Snow Leopard, even without adopting, and how you can take advantage of them in your own code.

So here's the overview. We've got a long history in the operating system. We've had a lot of different pieces coming together over the years with companies coming together and many different layers of the system. So what we've got right now are pretty much three different ways to get at the file system. We've got the CoreOS or POSIX APIs. And sitting on top of that, we have the Carbon File Manager and Cocoa APIs, primarily NS File Manager. And these APIs all give mostly overlapping access to the file system. And so right away, you can probably guess at some of the problems that this presents. The redundancy is sort of heavy in the system.

There's different ways to do the same thing. There's complexity associated with all these different APIs. and it gives rise to some kinds of inefficiency that I'll go into here. So first of all, complexity. As I mentioned, there's a lot of different ways, different APIs for getting at some of the same information. So, And these APIs use different data types to identify files. So, for example, we have in POSIX APIs primarily we have C strings representing paths to identify a file. At the Cocoa layer, we mostly are looking at, again, NS file manager, we use paths, but as NSStrings.

The Carbon File Manager uses FSRaps, which those of you who aren't too familiar with them, they're 80 byte opaque data. And so they're path independent, regardless of the path to the file, they're always 80 bytes in size and you have no idea what's inside them. But it's just a different way to refer to a file.

And then we also have APIs that are URL-based that only accept file URLs. And, of course, file URLs are ultimately just another form of a path. But those APIs don't accept a string as a path. You have to have an NSURL or a CFURL object passed to them. And so the APIs wrapped around these data types are sort of mutually exclusive. For example, with a C string, you would be using to get some basic information about a file, you'd be calling lstat or stat. The equivalent call in the Carbon File Manager is fs-catalog-info.

NS File Manager uses attributes, the method attributes of item at path and takes an NSString path. So while there's many different ways to do similar stuff, none of these APIs is actually complete. And so you often are faced with the requirement of switching to a different data type in order to get at some piece of information you need that you can't get from NS File Manager or you can't get from POSIX or you can't get from the Carbon File Manager. And so this switching around requires conversion. So in your application, if you're primarily path-based and you're able to get at, given a path, You're able to get it, say, the name or the file size from the APIs that you have available for paths. And then you need to get some other information, say, the localized name or the display name, as Launch Services calls it, or you want to get the icon. on, well, you either need to convert to an FS ref yourself by calling FS path make ref, or you might be using some of the convenience functions in Cocoa that give you access to this information.

But the fact is that under the covers, Cocoa is often doing a conversion to an FS ref in order to call through to the Carbon file manager. And vice versa, sometimes you find yourself holding on to an FS ref and you need a path, and so you call FS ref path to do another data type conversion. There's a lot of problems with this. First of all, it's just not any fun. It feels like a waste of time. You're going along and you scratch your head and you think darn, I need to do this data type conversion here and it adds to my code and it's just unpleasant or yucky to have to do this in your application.

It to. But worse than that, it also triggers IOs. Whenever you're converting between a path and an FSRef or vice versa, we have to actually look on disk to generate the internals of an FSRef or to turn it back into a path because what's in an FSRef is a persistent file ID and a device identifier.

And so usually, you know, it's pretty quick because it's usually be cached in the kernel. But you can get into situations where if you do have to go out over the network when you're talking to a file server, you've got network latency problems that can slow you up or worse, the network could actually be disconnected or have a hiccup and you might hang for a long time. So this can really interfere with your application.

In addition to the expense of doing path to ref and ref to path, those kind of conversions, we've spent a lot of time over the past several years looking at how our own frameworks use the file system. And we see that there is a lot of what I call bursts of redundant access to a file over a short period of time.

So say you're opening up a document and there's a lot of information the application needs to do very quickly. Some of it you're not even really aware of because the frameworks are doing it. We're, of course, getting an icon and getting the localized name or display name of the file. And this requires calls down into several frameworks. And those frameworks will often either be FSRef based or path based. And as you go down from, say, your application into NS document. NS document may call down into launch services, which may then go down into the Carbon file manager or into core foundation. And we end up with each layer doing redundant access and sometimes even doing data type conversions back and forth. And what you end up with is a lot more trips into the kernel, into the core file system layer to get the same information over and over again. And rather than continuing to trip over my tongue trying to explain all that, I wanted to do a quick demo of just what we're talking about. So if I can have the laptop here.

Okay. So I wanted to show an example of what I was just talking about, opening up a document. And I wanted to use a very low-level debugging tool or analysis tool called FS usage, which can show all access to the file system by the entire system or in this case just from in one application. So we're going to be opening up an image in preview. And I wanna launch preview first so that we're not seeing anything related to launch activity. We're just looking at the IO from opening up a document.

So I'm gonna start up fsusage. This command just says I wanna look only at file system access, it can also look at network access. And I wanna look at just preview. So now we're ready to go, and I'm gonna go ahead and open up the document. Now as I mentioned, there's a lot of things happening here before I open this. We're sending an Apple event to the application, it receives the Apple event, and there's an alias in it.

So it has to resolve the alias, it has to compute the localized name of the document, it has to get the icon of it so it can show it in the title bar. It has to add it to the application recents menu, it has to add it to the system's global recents menu. We tell Spotlight that the document was opened. So there's a lot of, oh, and at some point we read the file and actually display the contents. Let me go ahead and open it.

So that was pretty quick. But let's look back at what happened. Okay, that's too slow. Let me go back. So there's over 600 lines of output here. just to give you an idea of what we're looking at. We've got Carbon File Manager calls occurring in here that you see, such as Get Volume Info. We have Get Catalog Info, which ultimately boils down to something called Get Adder List against the document here.

And getAddrList is the Core OS API, or essentially POSIX API, for getting any arbitrary list of attributes. So we can get anything we want, including the finder info, finder flags, any attributes we want to get, we can get through getAddrList. But you don't really want to be using this API. It's a very hard API to use because it packs a bunch, in order to get the information out, you have to unpack a buffer, you have to ask for just the right attributes for the file system you're accessing. So it's very difficult to use. But that's what the Carbon File Manager is using. You'll also see FS make path and FS ref make path. And elsewhere in here, there's FS path make ref. So, you know, you get an idea of the volume of it here. We're not just accessing the document.

there's access to some framework code and also preview resources, nib files and strings files. And some of the path to ref conversions are happening on those resource files as well. So to summarize, I went and analyzed this myself and found out that just looking at the document I.O., we're doing, in this example, we do four times we convert the FSRef to a path for this document. Ten times we convert the path back to an FSRef. 25 times we're calling getAtterList, seven times we're calling stat or lstat.

And we're opening the file and closing it again four times. all to open it. So now it happens pretty fast. So it doesn't -- it might not seem like something to really get all that worried about. But it can be -- it's a lot more apparent when you're on, say, a network file server that this can slow you up. But also, we know that it is preventing us from really being zippy. That there's -- it must be easier than just doing the same work over and over again in a very short period of time. So that gives you an idea of the problem we're trying to solve here.

So we thought about this a long time and we've come up with some solutions. We wanna simplify and provide a clear direction for everyone, both internally at Apple and app developers like yourselves, a preferred file system API that we can optimize for and is designed to work well with all different kinds of file systems.

And in order to do that, we need to unify all of our APIs around a particular file type or file identifier. Some of the things we can do to make this API more efficient are make sure that we're caching at a high level, as I say, in the application process so we have at least short-term caching of values that are being computed over and over again, avoid the kind of object reallocation that happens in bursts right now. And we are also looking at directory enumeration and making that as efficient as possible so that when you hit a directory with 10,000 items in it in particular, and we definitely have a bunch of customers out there like that with those kinds of configurations, that you can be assured you're as efficient as possible at enumerating those directory contents. Thank you.

And then finally, we want to eat our own dog food on this and design these APIs for use in our own frameworks so that we can get benefits from these APIs right in Snow Leopard even before we get wide application adoption. So it kind of started with, well, what are we really going to base all these APIs on?

What's the best choice here? Because we do have several choices. We have existing APIs, as I mentioned, that are using paths. We have FS refs. We have some APIs that are URL-based. Or we could do something new. And, you know, something new is kind of a neat idea, a new object type, because it could be completely pristine and do everything just exactly the way we wanted to. But the effect on our APIs would be pretty bad, because we would have to have a completely new API set, and it would be unfamiliar to everybody.

And so looking back at paths and FSRefs and URLs, well, paths kind of are what they are. They give us one way to identify a file. FSRefs, likewise, they're purely ID-based. FSRefs are not objects. It's one of the problems we've had over the years is that FSRefs are just stack-based largely, and we have no idea when they come and go, and so that makes it difficult for us to do any kind of cache management or cache policy to know when an FSRef is no longer going to be in use. So considering all these different pros and cons, let's look at URLs. There are a bunch of advantages to focusing our API on the URL data type.

First of all, I mentioned that creating a whole new data type would explode our APIs. URLs are nice because we actually have quite a few APIs that are already using file URLs. So these are the frameworks or technologies that... that, sorry, I'm getting distracted because they're counting down my timer at about one minute every five seconds right now. Um.

I'm going to talk really fast. These technologies are using URLs for file system access right now. So they have APIs that accept only file URLs. And AppKit has a whole bunch in, say, for NSDocument and even Pasteboard, using Pasteboard. What else? Core Foundation uses them heavily in the CFBundle API. Launch Services has always supported URLs, both FHIR URLs and arbitrary other URLs. So you can see there's actually a wide adoption of URLs already, but we don't really have any core API that gives us access to directory contents and file properties via URLs.

There are some other things that are attractive about URLs. We already have NSURL and CFURL as toll-free bridged objects. So you can cast back and forth between C and Objective-C all you want without any sort of conversion cost. Because URLs are objects in the sense that we know when they come and go, it allows us to do some smart cache management. We know when you're no longer gonna be referencing the file through a particular URL object. And on top of all that, there's a general URL syntax that's very flexible, right? So you can imagine wanting to access domains, resource domains other than the file system, but even within the file system domain, URLs give us a lot of flexibility for how we identify files, and I'll talk about that in a few minutes.

So as you have guessed, we're picked the URL as the new preferred file identifier on Mac OS X at the foundation layer and core foundation and above. So we're introducing new APIs in Snow Leopard in both foundation and core foundation that largely mirror each other so that it's convenient for Objective-C and C developers or for lower level programs that need just C access. And it consists of new methods on NSURL and some new methods in NSFileManager, particularly for directory enumeration. And in core foundation, we have a new CFURL methods for accessing file properties and a new type CFURL enumerator for enumerating directories as well as the volume list.

So what does the API look like? Well, in the URL language that we're using, everything's a resource. That's what URL, that's what the R in URL stands for. So everything's a resource, and so resources have properties which are identified by keys, and every property key can be turned into a value for that property. And so it's a pretty familiar sort of API model on our platform. And we have more than three properties, but these are three examples. NSURL name key, NSURL modification date key, NSURL file size key. So these are string constants in the API that you would pass in if you wanted to get the value of one of these properties.

We have both getters and setters for properties. Many of the properties are read-only, but anything that you would expect to be settable, as long as you have access to the file, is settable. And we also support temporary properties, which is something whose use will become a little more obvious later in the talk. But it's basically a way for you to say, in memory only set a property value of your own design and be able to get back at that property value through the same URL instance later on.

So I wanted to just show you a whole list just to help emphasize how much we're supporting. We've got over 40 properties available, and I think there will definitely be a few more before we ship Snow Leopard. But... We've got the core set that you might expect, the name, some Booleans like is it a file, is it a directory, is volume, is package, that is, is it a packaged directory, is it immutable, is it hidden, does it have a hidden extension, all the dates, creation date, modification date, and so on.

What's the parent directory? You get that back, of course, as a URL. What's the volume URL that it's on? These are the kinds of core properties you can get for any file system resource. And then there's other higher-level ones that you don't have to go to a higher-level framework to get. We do that for you. We have a model of providers from higher-level frameworks. But through one API, you can get things like the type identifier, that is the uniform type identifier that symbolically describes the resource type. Likewise, you can get the localized type description or the kind string. You can get the label information and the label color. That's the finder label. You can even get the icon. You can get both the effective icon, which is the one that the finder is displaying, or if you want to know whether the item has a custom icon, you can ask for the custom icon key. Okay.

And that's available either if you request it through the core foundation API, you get it back as a CG image, the core graphics image. If you request it through the foundation NSURL API, you get it back as an NS image, assuming you have AppKit linked into your process.

And then the last set on the bottom right is a whole slew of properties for getting at volume capabilities. So we're continuing and pushing even harder on our design point of not assuming too much. If you need to know what volume format you're on in order to know whether a certain capability exists, don't assume that the volume format capabilities are going to remain constant forever.

You're much better off asking, instead of asking for the format and inferring information from the format code, ask the volume for its capabilities. So these properties tell you, does the volume support persistent file IDs? Does it support symlinks? Does it support journaling? Does it support some esoteric things like zero runs in files? Does it have case-sensitive names? These are all properties you can get through, values you can get through this API.

Now, about enumerating directories. We have enumerators that now return URLs instead of paths. And in order to design them or in order to use them most efficiently, we want to be able to, under the covers, get things in bulk from the kernel. And so we can do that most efficiently if we know up front which properties you're going to be accessing against the URLs you're going to be getting back. So that's called prefetching, and that's a feature of the enumerators that you can give us optionally an array of property keys want prefetched up front. And as the enumerator runs, under the covers, it's getting all the values for those properties in the most efficient way possible and caching them in the application process so that when you ask later, ask for those properties from the URLs that you get back from the enumerator, we don't do any additional I/O to give you those property values. These enumerators also support deep enumeration for those of you that need that.

In core foundation, I mentioned that's done with a new type called CFURL enumerator. And what we've done in foundation is we already -- NS file manager already has the NS directory enumerator type that returns paths. And we're just making a new factory method for that that gives you an NS directory enumerator which returns URLs, NSURLs instead.

Now, what about FSRefs? I mentioned that URLs are path-based. And there are some things that FSRefs do that are pretty useful. The main thing is that since FSRefs are path independent, and remember, you track your file by file ID, they're much smaller. It doesn't matter how long the path is. But also, the file ID doesn't change when the path may change. So, if the user moves a document around or renames it, a path reference to that file becomes invalid and is useless. But NFS ref remains valid and can track that file around on disk. In addition, the 80-byte size means that it scales really well for a few clients who need to hold on to a lot of FSRefs like the finder.

So, we realized that we can do the same thing by being clever with our URLs. And so, we're introducing today something called file reference URLs, which you can think of as a file URL that behaves just like an FSRef. And in a lot of ways, it's even better because it's smaller than 80 bytes.

But better than that, because it's a URL, we don't need two separate APIs in order to work with either path references or path URLs or reference URLs. We can have a single API that can handle either form of the URL, but you get the semantics that you want depending on your needs. Let me show you a little bit about what those look like.

So imagine I have my presentation on disk, and a traditional file URL would look a little bit like this, just a path into my home directory that identifies the file. File reference URL looks a little different. It has something at the beginning that says.file, and that's simply a reserved name in our file system that tells us at the root of the file system This URL, it's not a valid path, by the way. This is only valid in the URL space, but we prevent it from conflicting in the file system. And it tells us that in the URL, the next item in the next element of the path in the URL is an ID, a device and a file ID pair. But you don't need to worry about this. I just wanted to explain what you see when you look at the URL string, because the URL string is what identifies the resource, but we have the flexibility to interpret file URLs on our platform the way that works for us. And so this is not a format, though, that you ever have to worry about. In fact, please don't try to construct this yourself or parse this string and make sense of it. we provide very convenient APIs that do everything you need to produce a file reference URL. So how does that work? Well, first of all, we have a lot of APIs that are URL-based already, and... And those people expect to continue returning path-based file URLs, so we'll continue to do that. Your app's not gonna see any file reference URLs unless you ask for them.

However, our frameworks will be supporting them so that you can start using them anytime you want in Snow Leopard. And it's mostly transparent because what most people do currently with URLs is when you need to get at the underlying file, you ask for its path, or you call CFURL, get file system representation, which gives you back the CPath. And that will all continue to work with file reference URLs. If you call these APIs, you'll get back the standard file system path, not an ID-based path.

But if you use them to say, if you use a file reference URL to get property values, then we don't have to do any conversion. The path to ref conversion or any of that stuff, we can talk directly to the Core OS to get properties from the file ID that's encoded in the reference URL. you One important difference about reference URLs is that they're not persistent.

You don't want to save them to disk and expect them to work later on. Like FSRefs, they're valid for the boot life, or the mount lifetime of the volume that you're working with. So if your system is rebooted, whatever file reference URL you may have been holding onto, it's no longer valid. However, they are good globally, so you can send them between processes, no problem.

All right, so that's a quick overview of the APIs. I wanted to run through a few code examples. just to give you a feel for what it looks like. If I want to get values, property values, this is a method called name and icon for URL. It returns a dictionary with just the localized name and the icon of the file that's passed in, the file URL that's passed in. So in order to do that, we create an array containing the keys that we want, the localized name key and the effective icon key.

I spaced this out vertically because if I put it all in line with creating the array on the fly, it would be hard to see. But we create the array, and then we simply call on the URL itself, we call resource values for keys, we pass in the keys array, and then optionally we can get back an error if we want. The way the API works in this case is it returns a dictionary. The resource values for keys returns a dictionary. Or if an error occurs, it returns nil. And then you can check the optional output error.

If I want to set a property, say I want, in this example, I want to set the modification date on a file. This method example is called touch URL. It's like the touch command line. It simply calls set resource value, and you pass in the value, in this case, NSDateDate, which is the current time and date. For key, and the key is NSURLContentModificationDateKey. And again, you get back an optional error. This method returns a Boolean for success or failure. If it returns false, then you've got an error result.

If you want to create a file reference URL, and the case where you might want to use this is any time you want to make sure you're tracking a document by its ID so that if you're holding onto it in memory for a long time, the path might change, then it's a good idea to hold onto a file reference URL. So in this example, the set document method is given an arbitrary file URL, and you know you want to assign it to your instance variable, but you don't know what kind of file URL you are given. It may be a file reference URL or maybe a path-based URL. Well, you can simply call on the URL, you call the file reference URL method and if necessary, it converts it into a reference URL and returns it. And then we simply hold on to that in the instance A real quick example of directory enumeration, say we want to enumerate the directory and we know that right after we finish the enumeration, we're going to be drawing the icons and the display name or localized name of each item in the directory. And so what we do is we make an array with the property keys that we want to prefetch, so the localized name and the effective icon key. And then continuing, we ask NSFileManager for an enumerator that is URL-based. So that method is enumerator at URL, and you pass in the directory URL that you want to enumerate. This is the parallel to enumerator at path, which is an existing method in NSFileManager. So enumerator at URL, including properties for keys, we pass in our key array, And there's some options that I won't go into, but it includes things like deep enumeration. And then there's an error handler, which is actually a block, a callback in the form of a block that allows you to handle errors and either continue or not continue. Once you have an enumerator, you can go through it any way in any of the traditional ways. In this case, We call for URL in enumerator using the fast enumeration protocol. And we just go through each item one at a time. We get back the URLs in the directory and add them to our object view here. pretty simple. Although it's one at a time access at the API level, we're doing bulk access when enumerating the directory talking to the core file system.

Before I finish my section, I wanted to mention and just show real quick some sample code that's available. If I can switch to this machine and get rid of that. The sample is called URL Git Info. It doesn't do a whole lot yet, but we're going to be adding to it as we fill in more of the API. It does this nice sort of simplified version of the Finder Info Window where it gives us a bunch of information, basically fetching property values from using the API. So this is a volume. It starts out with showing the root, but it gives us the volume name. It tells us the localized description, the type identifier is public.volume, and a bunch of other things, the date, the parent directory URL is null, but the volume URL is basically slash itself. And this app just lets you drag in anything. You can drag a file in and it shows you all of the same information. Of course, this is a package. the keynotes documents or packages. So this size in this case is zero 'cause it's really a directory. Or even if you drag in a file, an alias, you can see a couple of things. First of all, this is the music folder's custom icon, where we get that back from the API. And it's even badged. It has the little alias badge on it. And this is all through one API. So as I said, we'll be adding to that. I was going to open up the project, but I think I'll skip that so that we can stay on schedule. OK, slides, please.

So what's the status of the API on the DVD that you got on Monday? Right now we have fetching property values is supported both for NSURL and CFURL, so you can get property values. You can also use file reference URLs, so that the methods that convert back and forth between reference URLs and path URLs work properly. And coming soon in upcoming seeds, we'll have setting property values supported and directory enumeration.

So just recapping some of the benefits here, this is really designed for, to provide the future foundation going forward for framework level access to the file system. It improves efficiency by avoiding all those costly data type conversions. It simplifies our APIs by preferring one data type going forward that works for all different usage models of the file system. And as you adopt the APIs, we hope you'll find them much more convenient. You'll be able to simplify your code and really get every bit of efficiency you can by moving this -- adopting this model up right all the way into your application.

Now, what else? What else haven't we covered? Well, I mentioned up at the top persistent file references. And URLs, in addition to file reference URLs being not that great for Holt and for tracking a file over the long term because your system might get rebooted, even file path URLs aren't that great because file paths change over time. And so we've reached that point in our show where Keith is going to explain all about persistent file references.

Am I on? Okay. As Chris said, I'm going to talk about persistent file references. And as he said, everything you've heard about so far is designed to give you really efficient and fast access to cache properties of files and stuff in memory. However, sometimes that isn't what you need. Sometimes you have to store away what file in particular you're going to need to use later, or keep track of it so that you can come back to it the next time the user opens your document. And URLs aren't the best for that. As Chris said, URLs are either path-based or file ID-based. And file IDs aren't valid terribly long. And paths are usually valid for a while, but there are times paths aren't sufficient.

And the reason is for files on your local hard drive, usually the path is the same. But if users have a USB drive or they put stuff on a file Sometimes even the path to a file can change over time. Or for file servers, the file server volume might not be mounted. And so when you go to use it later, that path is no longer correct. So, What do you do? If you're an old school Carbon person, you're saying, hey, aliases are the answer. And Alias Manager has solved most of those problems for the last 15 years or so. Aliases, you create them with an FSRef. It gives you back something called an alias handle. Later, you get that alias handle back to the Alias Manager and say, hey, what file did this use to point to? And it gives you back an FSRef if it can find the file it thinks the alias was originally made to. Now, there are a lot of alias manager calls. There are more every year because we need to add more stuff, and the API has evolved over time. There also are things that you know in the Finder. You can say make alias under the file menu, and that makes a little file on your hard drive that, you know, when you double-click on it or when a user picks it in an open or save panel, It kind of follows what the alias was made to, and it acts a lot like symbolic links, but kind of at a higher level, with a lot of the benefits we just talked about, finding and mounting file servers or disk images or USB keys. Thank you.

Now, that said, aliases aren't perfect. They use FSRefs and they use alias handles, which are both kind of older types, and we've explained why we're not that, you know, why FSRefs aren't doing it for us as well as they used to. Alias handles also, handles are kind of deprecated in the API. They're not necessary anymore, certainly the way they used to be. Aliases also have a limited set of information in them you can get back without resolving. You can ask an alias what the name of its file was and maybe what kind of volume it was on, but you can't ask it for much beyond that. And as I said before, there are a lot of calls in the alias manager because the API has had to evolve over time.

And so just staring at the header file, it's difficult to know what function to call and what to pass in at some points. The set of rules for how we resolve an alias has changed over time because it's needed to. Paths are a lot more important in Mac OS than they used to be. When aliases were first created, the only kind of file server that existed was an AFP file server. And now we have the Internet and we have USB drives. And so the rules for how they work have changed and that's caused problems. And lastly, aliases don't mesh very well with everything you've heard about so far.

So we're introducing a new type called bookmarks. And we were going to put up bookmarks in huge letters and do that flashy thing Steve does when it's new. But I didn't know how to do the flashy thing in Keynote. And then Chris Parker gave away our name earlier. So it's not a surprise anymore.

That's it. Bookmarks, I mean, you've heard the name before. You know, in web browsers, you have bookmarks. And logically, a bookmark is kind of a saved URL, something you can come back to later. And they're the same thing in FSEfficiency. If you have a file colon URL, you can make a bookmark from it.

And then later, you can say, hey, give me back that original URL. And it'll do what it can to get you back a pointer to the file that you originally had it from. Bookmarks use standard foundation and core foundation types like NSStrings and NSNumbers, just like everything else in the FS efficiency APIs. So they mesh well with the rest of the system. Bookmarks can also store resource properties in the same way that we said URLs all have resource properties. Bookmarks all have resource properties, and they map directly onto the resource properties that from the original file it was a URL from. And in Snow Leopard bookmarks, we expect you're going to use them for file scheme URLs. You can make a bookmark from any URL you have in memory. And if you have an HTTP URL and you say, hey, give me a bookmark to this, I'll give you a bookmark. And if you give me the bookmark later, I'll give you back an HTTP URL. But there won't be much in it besides the string of the URL.

Here's what you do to create a bookmark. As we said, you have, for example, a URL in Foundation. You'd say bookmark data with options, and you'd pass in a bunch of zeros and nulls to get pretty much the default behavior. And it will give you back an NSData item. And then you can squirrel that away in whatever place you wanna use it, in your document or just in memory.

At core foundation, we have pretty much the same function, the same functionality, CFURL create bookmark data. And then sometime in the future, you're going to have one of these bookmarks, and you're going to say, hey, I want a URL back. So you're going to give that to NSURL, URL by resolving bookmark data, and you'll give it that data object that was earlier created. And again, you pass in a bunch of nulls, and you get pretty much default behavior, and it will give you back a URL. If you pass in an error, and if something goes wrong, like we can't find the file, or that volume doesn't seem to exist, we'll return it. If you don't pass an error and you get null back, either the file doesn't exist or bookmark was corrupt or something.

Now, this process is called resolution. If you're familiar with the alias manager, it's, you know, the same idea. Internally, we'll go through a whole bunch of rules to try to find the file that you made the bookmark to. If the file was on a file server, we may tell the user, hey, you need to give us a password so we can mount this file server. If it was on a USB key, we may ask the user to insert that USB key back into the computer or mount a disk image for a file that was on a disk image. And that's all code that you don't have to write. We'll do the right thing.

Earlier I said there were properties in bookmarks, just like URLs have resource properties. Bookmarks have the same properties that you can get from an NSURL that use the same namespace. And they have information in NSStrings or NSNumbers. So once you've learned how to get a property from the file system through the FS efficiency APIs on a URL, you know how to get the same property out of a bookmark. It's the same key. It's pretty much exactly the same code. This includes any temporary properties that you add. If you want to create a bookmark and kind of squirrel away some information of your own in it, you can create a URL, add a temporary property to that URL with your information, then ask to create a bookmark and ask it to include the value for that property in the bookmark, and it'll create a bookmark with that. Later, you can ask the bookmark what was the value of this key that you guys set as your temporary key value and it'll return it to you. Now, I wrote it that has to be one of the standard types that the system knows about, like an NSString or an NSNumber or an NSData. And this information is retrieved without needing access to the original item. We don't touch the file system to return properties from bookmarks, because the bookmark has pretty much encoded everything into that NSData object that I showed you.

So here's an example of how you'd create a bookmark with a set of properties. In this particular case, I'm saying, I'd like you to make a bookmark from this URL, which is that URL up front. In the bookmark, I'd like you to include the name of the file, the display name of the file, how big the file is, and what the effective icon is for it, which will be the icon that would show, for example, in the finder for the file.

And when that comes back, you'll have a bookmark. Later, you can ask that bookmark data object for any of those values, and it'll give it to you, even if the user has unmounted the disk, even if you save this out and write it back into memory later, even on a different computer if you send this across the network to somewhere else.

Now that said, if you want to ask a bookmark for a property, at some time in the future, you need to ensure that you ask to have the bookmark created with that property. We are trying not to include any default types in bookmarks. We want you to tell us what you need so that we don't have to guess and we don't have to make things bigger or slower or less efficient than they would otherwise be.

Here's how you'd get those same properties back from that bookmark. You would call NSURL's resource value for keys. Earlier you saw Chris was calling URL resource values for keys. Here you have a bookmark. You're saying, please return resource values for keys for this bookmark data. You've given me the bookmark data, and you've said, I'd like the file name, localized name, and file size back. And that's going to give you back a dictionary, and you can then just ask the dictionary for each of those keys in it. And again, all these values are returned without accessing the file system, without touching the original item on disk. So one thing that means is, those values might now be wrong, because they were essentially cached at the point in time, you know, they were frozen in the bookmark at the point in time you created it.

However, if what you want to know is, here's a file the user might want to locate. What's its icon? Well, you've got an icon to show. You don't have to worry about hoping that the file system's available, that it doesn't take too long to spin up the disk.

Earlier I mentioned alias files as something that exists in the Alias Manager. We have the same idea with bookmarks. We expect to have a bookmark file format. which from the point of view of the user, probably will look exactly like an alias file, which will store all of the information that, you know, I've been talking about being in bookmarks, supporting functionality very similar to the alias manager. And we think, we expect to have an API to let you create bookmark files on disk so that you can do it in the same way that we in the Finder do it.

You're probably going to find you may need to work with existing aliases and alias files in order to begin converting your code over to use this FS efficiency stuff. And there's public API for all of this. If you have an alias or an alias record or an alias handle in your application, well, first you're going to resolve that into an FS ref using the, you know, one of the tried true alias manager routines like FS resolve alias with mount flags. That'll give you back an FS ref and then you can create a URL from that FS ref by going through CFURL create with FS ref. If you then needed to convert that into a bookmark, you would do what I just showed you. You would say, bookmark with, you would ask the URL for its bookmark data.

What's the state of bookmarks in the developer preview you have? Most of the APIs are there. You can create a bookmark given a URL. You can give it a bookmark, resolve it back into a file URL of some kind. And you can ask bookmarks for their resource properties. There are some limitations so far. We're not done, cuz if we were done, we'd ship it.

So right now bookmarks only resolve to their items by path. We don't have the, you know, the user has renamed the file, let's go out and find it behavior working yet. We don't have support for automatically mounting file systems or asking the user to put disks in. And we don't have support for every property type in a bookmark. We currently can't put icons in bookmarks. There are a couple other things that haven't been fully tested and vetted yet. And we don't have any of the bookmark file APIs I just talked about present yet. We hope to have them in one of the next upcoming seeds. Thank you.

So I'll kind of wrap up by saying why you should use these. Bookmarks let you leverage the rest of your adoption of NSURL and CFURL. As I said, they use the same namespace of keys, so once you've learned how to do something in the URL space, you know how to make aliases from it. And they're also extensible in ways that aliases didn't used to be. You can ask to have your own information encoded in them, and we can continue to grow them over time. So with that, I'll ask Chris to come back up.

Thank you, Keith. So just to recap everything from the last hour. Thank you. We've gone over a bunch of new foundational APIs for getting at the file system, getting information out of the file system. We love URLs. Everything is URL-oriented now. So we have APIs for getting and setting properties from file objects. And under the covers, they're cached to improve performance. We have efficient directory enumeration with prefetching of properties. And we have the whole bookmark model and API that Keith just went over providing very efficient resolution and the kind of extensibility that people have been asking for from aliases for a number of years.

So of course, the message is we want everyone to use URLs. We're really happy with the kind of capability that this is going to give us to simplify our own APIs, use our own APIs internally to, in our own frameworks, improve Snow Leopard performance even in applications that aren't using these APIs just by changing the way our frameworks work. And we invite you all to just take a look at these APIs, see if it helps you simplify your code, and give us feedback because we're not totally done yet and we still have time to make any changes that you think are necessary, which is a good way to say bug Derek. He's a good, Deric Horn is our evangelist, and you can send him feedback.

Related sessions, I didn't go in, we didn't really have time to mention the additional higher level APIs that are going to be specifically taking advantage of this stuff. But Chris Parker's session this morning on what's new in Cocoa actually covered some of this as well as additional APIs going into NS File Manager for copying files, moving files, things like that. So if you can catch those slides, you can see all those APIs reviewed.

They're also in the release notes for Foundation. This afternoon, I'm sorry, tomorrow is performance in document-centric Cocoa apps where Mark Pettorelli is going to be talking about NSDocument. And one of the things that NSDocument is doing in Snow Leopard is using these APIs to improve performance. We also have the file system lab coming up this afternoon. In fact, right after this session, I'll be going downstairs. Keith will be downstairs in the lab to answer any more questions.