rentzsch.com: tales from the red shed

PATH_MAX Blackholing

Mac OS X

Matt Gough's carbon-dev posting did a great job unearthing my previously repressed *nix trama: PATH_MAX.

For those of you who don't know, *nix guys think it's a really good idea to represent file system entities as, of all things, strings. This is especially shocking, because *nix is written in C, and C's handling of strings is extremely deficient.

With foresight and extra effort, you can easily deal with C's string inadequacy. Or, in the grand *nix tradition, you can cop out, write poor-quality code, and then blame the user when Things Go Wrong ("It's your fault! You shouldn't have run out of swap!").

One quick indicator of such shoddy code is the presence of PATH_MAX, a constant #define'd to 1024 on Mac OS X. Programmers use PATH_MAX when they need to store a path and don't want to hassle with dynamic memory or variable length storage issues. (In my personal Neighborhood of Make-Believe, PATH_MAX is obliterated, and all code that subsequently breaks is thrown away.)

Mac OS X uses PATH_MAX in its BSD layer. Unfortunately the NeXT guys were also *nix guys, which means they also think path strings are the bee's knees. Thus Cocoa's file system entity representation is, sigh, NSString. Cocoa does an excellent job of re-exporting the BSD-level brokenness, as we'll see in a minute.

Perhaps you can see the trouble brewing. At the very bottom is the file system code, which is robust and well-structured. Then a sloppy layer of path strings is slathered on top of that. Then we build our programs on top of that sloppy layer. It's as if you're building a house on a granite foundation, but before you start you lay down a six-foot thick blanket of tofu. Kind of defeats the purpose.

Well, you don't have to use the tofu file system APIs. You can use Carbon's granite FSRef-based APIs, which offers high-fidelity file system entity routines. They're not path-based, and thus don't suffer from the inherent flaws of path strings.

But! Hilarity ensues when you mix the competent FSRef APIs and the tofu path APIs: it's possible to "blackhole" a file.

"Blackholing" is a term I made up. It's possible -- easy, actually -- to construct a set of nested folders that will accept files placed into it, but won't let them out again.

The recipe:

  • In the Finder, create five folders, each with a 255-character name.
  • Place them inside each other, like a Russian doll.
  • Place your victim file into the deepest folder.

If you don't feel like doing this yourself, I wrote a small AppleScript applet that does this for you.

Your victim file is now mostly inaccessible:

  • In the Finder, you cannot drag it out of the folder, or anywhere else.
  • It's nonobvious how to use the Terminal to access the file.
  • Cocoa apps won't allow you to open the file (the "Open" button dims).
  • Carbon apps like BBEdit and Script Editor will attempt to open it but will crash inside Navigation Services.
  • Tellingly, Classic apps will be able to open the file without incident.

Probably the best way to rescue the file trapped in the blackhole folder's event horizon is careful use of AppleScript or coding directly to the Carbon APIs.

You can file a bug against this if you want, but it will probably will be closed as duplicate and ignored. This bug is a design choice from 10.0, and I don't see Apple fixing it anytime soon. About the best we can hope for is that they patch up the Finder to allow dragging the file out again. But you already know my lack of optimism regarding the Finder.

Update: Turns out you can navigate to the blackhole folder in zsh (cd ~/Desktop/aaaa*/bbbb*/cccc*/dddd*/eeee*) and tcsh (cd ~/Desktop/aaaa*/bbbb*/cccc*;cd dddd*/eeee*). That's great news, that means the PATH_MAX brokenness isn't in the BSD layer, it's "just" in sh, bash, Core Founation and/or Cocoa. While I doubt sh or bash will be fixed, it's quite possible that Apple would fix Cocoa. Radar 4262085. Credit to Peter da Silva for pointing this out.

Tuesday, September 13, 2005
12:00 AM