Re: A mystery with NSFileManager
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.