X-Spam-Check-By: sourceware.org From: ericblake AT comcast DOT net (Eric Blake) To: Cygwin List Subject: another instance of .. issues Date: Wed, 22 Feb 2006 16:00:34 +0000 Message-Id: <022220061600.18471.43FC8AA2000A6AE70000482722073007930A050E040D0C079D0A@comcast.net> Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com 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/