Friday, August 2, 2024

The Switch From File Paths to URLs

Quinn:

I don’t think we ever documented this officially, but to understand this choice you have to look at the history of macOS. Traditional Mac OS did not use paths a lot. Rather, files were identified by an FSSpec, which contains a volume identifier, a directory ID, and a name. The directory ID was an HFS [Plus] catalogue node ID (CNID), which is kinda like an inode number.

Additionally, starting with System 7 it was possible to track a file with a volume identifier and the file ID, that is, the CNID of the file itself.

This was quite tricky to support on a Unix-y platform like Mac OS X. At the lowest levels of the system you needed the ability to manipulate files based on CNIDs rather than paths. For an explanation of how this was done, see QA1113 The “/.vol” directory and “volfs” (note, however, that volfs is no longer a thing and the same functionality is now implemented in a very different way).

[…]

So far, so much obscure backward compatibility. However, since we made the decision to use file URLs we’ve exploited that to significant advantage[…]

Via Matt Gallagher:

There’s a lesson about attaching data (like security attributes) to an opaque interface (like NSURL). Because my mental model of NSURL is as plain RFC-3986 storage, these attributes are easy to lose and the security behaviours are easy to forget, when moving data around an app (I wish we received a bookmark type that made this explicit).

Jim Luther:

The original proposal was not to use a NS/CFString object encapsulating the path or a NS/CFURL object, and instead use a new object type to identify a file’s location, to cache properties, etc. That idea was vetoed in early API reviews because there were already API that took file locations as paths or URLs. We were told to pick path or URL. We chose URL objects over string objects.

I still think a new object type would have been cleaner and better in the long run. 🤷‍♂️

[…]

FSRefs were not objects so they didn’t fit into the Cocoa (or CoreFoundation)API memory model. They were also a fixed size glob of memory so expanding their functionality was very difficult. One of the things I did in my last year at Apple was to make the old Carbon File Manager work well with APFS and its 64-bit inode numbers. That meant making shoehorning 64-bit file and folder ids into FSRefs and translating them to 32-bit ids for the old File Manager API. Fun hacking 😀

Previously:

1 Comment RSS · Twitter · Mastodon


Interesting. In the early days of that switch, I never liked the URL as an abstraction of a path, because it basically just added extra bytes to a path and was just as fragile. Even worse, it had dismal performance in hashing containers due to collisions; I think this may have eventually been fixed. I always thought there was some grand idea of instantiating NSDocuments and so forth from any URL scheme, but in practice I never wanted to hand it a remote URL.

In BibDesk, we eventually ended up following the lead of Chris Hanson's BDAlias and making a class that represented a file. Internally (back when I was involved) it used an FSRef, but could give back Alias, path, URL, or -fileSystemRepresentation to hand off to Cocoa. We serialized aliases to disk, in the days before the more cumbersome (IMNSHO) bookmark stuff was added to NSURL. This was pretty lightweight, and we had good performance for the most part, at least in the days of spinning disks.

Leave a Comment