On Wed, Sep 30, 2009 at 11:24:38AM -0400, Christopher Faylor wrote: >On Wed, Sep 30, 2009 at 06:07:29AM -0600, Eric Blake wrote: >>-----BEGIN PGP SIGNED MESSAGE----- >>Hash: SHA1 >> >>My testing on rename found another corner case: we rejected >>rename("dir","a/./") but accepted rename("dir","a/.//"). OK to commit? >> >>For reference, the test I am writing for hammering rename() and renameat() >>corner cases is currently visible here; it will be part of the next >>coreutils release, among other places. It currently stands at 400+ lines, >>and exposes bugs in NetBSD, Solaris 10, mingw, and cygwin 1.5, but passes >>on cygwin 1.7 (after this patch) and on Linux: >>http://repo.or.cz/w/gnulib/ericb.git?a=blob;f=tests/test-rename.h >> >>2009-09-30 Eric Blake <e...@byu.net> >> >> * path.cc (has_dot_last_component): Detect "a/.//". > >No, I don't think so. I don't think this function is right. It >shouldn't be doing a strrchr(dir, '//). And the formatting is off >slightly. > >Is this function supposed to detect just "." or "*/."?
Assuming the answer is yes, then how about the below? I added a bunch of comments but the function is still fairly small. I've attached the function as-is since I basically rewrote it. cgf bool has_dot_last_component (const char *dir, bool test_dot_dot) { /* SUSv3: . and .. are not allowed as last components in various system calls. Don't test for backslash path separator since that's a Win32 path following Win32 rules. */ const char *last_comp = strrchr (dir, '\0'); if (last_comp == dir) return false; /* Empty string. Probably shouldn't happen here? */ /* Detect run of trailing slashes */ while (last_comp > dir && *--last_comp == '/') continue; /* Detect just a run of slashes or a path that does not end with a slash. */ if (*last_comp != '.') return false; /* We know we have a trailing dot here. Check that it really is a standalone "." path component by checking that it is at the beginning of the string or is preceded by a "/" */ if (last_comp == dir || *--last_comp == '/') return true; /* If we're not checking for '..' we're done. Ditto if we're now pointing to a non-dot. */ if (!test_dot_dot || *last_comp != '.') return false; /* either not testing for .. or this was not '..' */ /* Repeat previous test for standalone or path component. */ return last_comp == dir || last_comp[-1] == '/'; }