views:

58

answers:

4

I'd seen some ancient code that simplifed Unix paths for comparison by doing something like the following pseudocode:

  • strip off the last path component to get a directory only part: /foo/bar -> /foo
  • getcwd and remember original path
  • chdir /foo
  • getcwd and remember to return to caller
  • chdir old original path

Is there a standard Unix system function that does all this without the thread unsafe current directory manipulation?

A mutex could make that code sequence less thread unsafe, but isn't really ideal (you'd have to know that all other code using getcwd or other functions dependent on the process cwd including system and vendor code protects with this same mutex).

A: 

Oh dear, doing the action you mention couldn't possibly be thread safe, because it actually chdir's, which is going to confuse any other threads. I'll have to look up the string-manipulation portion of what you want, but it can't possibly also strip softlinks or do anything else that requires asking the operating system for file information without being a little thread-unsafe.

Related posts:

Try this to convert relative file paths, then compare them as strings:

#include<stdio.h>
#include<dirent.h>
#include<fcntl.h>
#include<sys/param.h>
int main( int argc, char **argv )
{
  char buffer[MAXPATHLEN+1];
  if( argc <= 1 ) return 0;
  DIR*d = opendir( argv[1] );
  if( !d ) return 0;
  int dfd = dirfd(d);
  if( !dfd ) return 0;
  int result = fcntl( dfd, F_GETPATH, buffer );
  if( result == -1 ) return 0;
  fprintf( stdout, "path='%s'\n", buffer );
  return 0;
}
eruciform
I know it is not thread safe. If such a function exists I'm sure it would have to be a system call that can do the lookup in a more direct sane way.
Peeter Joot
looks like someone else posted a shortcut for this, but i suspect it does this under the hood :-)
eruciform
+2  A: 

Try realpath() or canonicalize_file_name()

If your system supports it (and it probably does), I suggest calling realpath(pathname, NULL); this will malloc the buffer for the canonicalized filename and pass it back as the return value. You'd have to be sure to free() the pointer. The alternative, passing in an output buffer, runs the risk of buffer overruns.

canonicalize_file_name() is a Gnu extension that is equivalent to realpath(pathname, NULL).

Dan Breslau
Note that passing in an output buffer only runs the risk of buffer overruns on systems where `PATH_MAX` is either too large to `malloc()` or completely unbounded.
caf
A: 

There is no "canonical" path in a Unix directory. It may be possible for a file/directory to have multiple hard links/mount points.

The closest thing to the identity of a file/directory is its inode.

Lie Ryan
+2  A: 

What about realpath(3)?

Since it returns its result in a buffer you supply, thread-safety should not be an issue.

David Gelhar
cool, didn't know about this library function
eruciform
I once knew about realpath() and had forgotten it. The reason that it is not useful (and thus not memorable) is that it too is also not threadsafe on some platforms (basically using the busted chdir'ing mechanism described).
Peeter Joot
Hmm. I do see a call to that function now in our code. Maybe it is now thread safe on all the platforms we care about (this was definitely not the case a few years ago, but I don't remember the specifics).
Peeter Joot