This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

another instance of .. issues


CVS coreutils has recently provided emulation of the *at()
functions available in Solaris and recent glibc for other
platforms without them.  The *at functions are nice because
you can recurse through directories without changing
the current working directory, which adds a measure
of thread-safety previously not possible when using
[f]chdir (since the current working directory is per-process,
not per-thread).  For example,

dir = open("/tmp", O_RDONLY);
fd = openat(dir, "foo", O_RDONLY);

opens /tmp/foo, even though "foo" was a relative
pathname, without regards to getcwd().  Coreutils
emulates this on cygwin (and on Linux with older
glibc) by this slick trick:
openat(int dirfd, const char *name, int flags, ...) {
  char *buf /* alloca'd properly... */;
  int mode /* grabbed from va_arg properly ... */;
  sprintf(buf, "/proc/self/fd/%d/%s", dirfd, name);
  return open(buf, flags, mode);
}

Now for the problem.  Start with 'mkdir -p foo/bar', then
'touch foo/bar/file', and finally do 'rm -Rf foo'.  Since coreutils
now uses openat() and friends for directory traversal, the
recursive operation eventually gets file desriptor 3 open on
"foo", calls openat(3, "bar") which the emulation resolves to
open("/proc/self/fd/3/bar") to set the virtual directory
to foo/bar, then calls close(3) to avoid having too many open
file descriptors.  From there, rm empties foo/bar, then desires
to return back up the hierarchy to remove bar.  But it does so
by calling openat(4, ".."), which translates to
open("/proc/self/fd/4/..").  Since cygwin is improperly treating
this as open("/proc/self/fd") rather than dereferencing the
symlink and (re-)opening "foo", it triggers a sanity check in
rm complaining that the inode of foo has changed during
traversal, aborting the recursive operation:

$ rm --version | head -n1
rm (GNU coreutils) 6.0-cvs
$ mkdir -p foo/bar
$ touch foo/bar/file
$ rm -Rf foo
rm: FATAL: directory `foo' changed dev/ino
$ ls -R foo
foo:
bar

foo/bar:
$

I know that http://cygwin.com/acronyms/#PTC, and that this
won't be fixed for 1.5.20, but it is yet another datapoint
where blindly treating .. logically in cygwin path resolution
is violating POSIX requirements and thus breaking
assumptions being made by coreutils.  I will be able to
patch coreutils to work around this issue (coreutils does
have non-threadsafe fallback code that calls 'cwd=open(".");
fchdir(dirfd); open(name); fchdir(cwd); close(cwd)', triggered
on older Linux where /proc/self doesn't exist; my patch would
be to use this non-threadsafe fallback unconditionally on cygwin),
but it would be nice to have .. semantics working the same as in
Linux without having to hack the openat emulation fallback code,
and/or have openat() implemented directly in cygwin so that the
openat emulation of open("/proc/self/fd/4/..") is avoided (not to
mention more efficient by avoiding several other syscalls during
the emulation).

-- 
Eric Blake

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]