• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: A mystery with NSFileManager
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: A mystery with NSFileManager


  • Subject: Re: A mystery with NSFileManager
  • From: Chris Kane <email@hidden>
  • Date: Sat, 23 Feb 2002 17:30:52 -0800

On Saturday, February 23, 2002, at 04:08 PM, email@hidden wrote:
In other words, the -fileExistsAtPath:isDirectory: call returns success, but the isDirectory flag is set to NO -- it claims /tmp is not a directory. Now, there's nothing wrong with /tmp on my machine; it's sitting right there, it conatins some spam files I've made over the past days, I have rwx access to it.

lrwxrwxr-t 1 root wheel 11 Feb 23 17:09 tmp -> private/tmp

It's a symbolic link.

Oh. Um... hmm. Well, I don't really understand this (why the trailing slash matters, mostly), but... thanks to all who replied. Sounds like I want to use -stringByResolvingSymlinksInPath before I start trying to use the path. Thanks for the help!

The trailing slash passes down to the POSIX calls, which treat the path then as "/tmp/.". In essence, the trailling slash causes the symlink to be traversed. Command-line utilities will also behave differently sometimes if there is a trailing slash vs. not. It's a kernel filesystem feature.

-stringByResolvingSymlinksInPath on @"/tmp" gives me @"/tmp". It is documented as doing this, to wit: "If the name of the receiving path begins with /private, the stringByResolvingSymlinksInPath method strips off the /private designator, provided the result is the name of an existing file." This seems a bit odd, though, because it means that symbolic links to things like /tmp are not resolved.

Historical hiding of /private/ from NextStep/OpenStep days, when possible. Had something to do with "in case you saved the string as, say, a user default" and something to do with automounting via /Net (whereas accessing a file via /private/Net/... wouldn't trigger the automounting or somesuch thing).

-fileExistsAtPath:isDirectory: says "The method traverses final symbolic links." So it should not be fazed by /tmp being a link. However, I suspect it's being bitten by this "feature" of -stringByResolvingSymlinksInPath, and is returning the wrong value for isDirectory as a result.

This is true, but incompletely specific, as the documentation often is (which, is often a good thing from Apple's standpoint, because very specific implementation details can change from release to release).

The last symlink is traversed, UNLESS the sticky bit is also indicated in the stat info. (Why? read on.)


Here's where the mystery starts, and so we'll go on a little hunt. I think symlinks ALWAYS have the sticky bit set. The current code dates back to October 1997 and hasn't changed since then. The comments in this code fragment are telling:

// don't chase the link for this magic case -- we might be /Net/foo
// which is a symlink to /private/Net/foo which is not yet mounted...
if ((fileInfo->st_mode & S_IFMT) == S_IFLNK && (fileInfo->st_mode & S_ISVTX) == S_ISVTX) return YES;
// chase the link; too bad if it is a slink to /Net/foo
if ((fileInfo->st_mode & S_IFMT) == S_IFLNK && stat(fschars, fileInfo) < 0) return NO;

There's some references to that automounting business I was remembering above. Automount mount points were indicated with the sticky bit on the mount directory. The code doesn't want to cause the automounting of the volume just for this query (or this query would be much more expensive, itself and to the system), which will happen if the stat() (or other operations) is done. The code before Oct 1997 became the code above when it was factored out into a separate internal function to reduce copy-paste copies of it elsewhere. Let's see....

Well, the code before that wasn't much better. The comments above actually come verbatim from that code, and were just moved. In the symlink case, and if the sticky bit was set, the old code would always report that YES, the destination file was a directory without going through the last symlink. In the non-sticky/non-symlink case, the code worked the same as the current code. But isDir==YES would obviously not be correct either, since symlinks can be to files. The old code predates OPENSTEP 4.0 by at least a year.

So the only remaining question is, have symlinks always had the sticky bit set in the NeXT>Apple OS? Not in OPENSTEP 4.0 at least, and also NOT (currently) inside NFS-mounted volumes, nor UFS-volumes. It seems to be an HFS+ filesystem behavior!

If symlinks on HFS+ didn't have the sticky bit set, the current code would work fine, as would the old code. And as the current code works on UFS or NFS. Stating the filesystem to see what type it is would make this method more expensive, but might be required to get the documented behavior. Or we could ditch the automounting "niceness". File a bug.


Fascinating....

Chris Kane
Cocoa Frameworks, Apple
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.

References: 
 >Re: A mystery with NSFileManager (From: email@hidden)

  • Prev by Date: Re: Frameworks inside applications
  • Next by Date: Re: Cocoa objects in pthreads
  • Previous by thread: Re: A mystery with NSFileManager
  • Next by thread: Re: A mystery with NSFileManager
  • Index(es):
    • Date
    • Thread