New rename(2) function

Corinna Vinschen corinna-cygwin@cygwin.com
Thu Aug 9 12:03:00 GMT 2007


On Aug  7 06:54, Eric Blake wrote:
> According to Corinna Vinschen on 7/31/2007 9:57 AM:
> > It's rather tricky to explain how it tries to behave, but I do my best
> > below.  If you (or others) think there's a thinko in the plan, or you
> > find corner cases which behave strange or unexpected (that's probably
> > what's called a "bug"), I would like to discuss it here on
> > cygwin-developers.
> 
> Just for closure (since I originally these two corner cases via gmane on
> the main list), the rename function is still non-compliant in these two
> examples:
> 
> $ mkdir -p b/c a/b
> $ mv b a

Much simpler:

  $ mkdir a b
  $ mv -T a b
  mv: cannot move `d1' to `d2': Permission denied

Sigh.  Why does NT claim to be POSIX compliant if it does not allow
POSIX semantics?  Here's the problem:

Even if the ReplaceIfExists member in the FILE_RENAME_INFORMATION
structure is set to TRUE, the rename operation fails if 
- the target has the R/O DOS attribute set, or
- the target is an existing directory, or
- the target is a currently executing file.

It doesn't matter if the target dir is empty, it fails always.  My test
for a non-empty directory was rather useless.

That's really annoying.  So I have to go ahead and create a special case
so that the target dir is removed before the actual rename operation.
But the whole thing is still not POSIX compliant then, because of the
following requirement,

"If the link named by the new argument exists, it shall be removed and
 old renamed to new. In this case, a link named new shall remain visible
 to other processes throughout the renaming operation and refer either to
 the file referred to by new or old before the operation began."

which is impossible to implement with the given NT behaviour.  Grr.

> currently fails, but should overwrite empty a/b with populated ./b,
> resulting in a/b/c.
> 
> $ mkdir d
> $ ln -s e f
> $ mv d f/
> 
> currently succeeds, but should fail with ENOTDIR, because f/ does not
> resolve to an existing directory.

This looks like a problem in path_conv.  I tried this in /tmp, and
path_conv::check ("f/", PC_SYM_NOFOLLOW) creates a path_conv structure
with fileattr == -1, error == 0, path = "C:\\cygwin\\tmp\\e".  The 
path is the resolved path of the original symlink and there's no hint
in the path_conv which identifies it as dangling symlink.

Chris, shouldn't path_conv return the same structure as if the incoming
path name was "f", without trailing slash, given that PC_SYM_NOFOLLOW
is set?

> Also, the check for link count >= 2 might also be optimized to skip
> directories (whose link count is always > 1, but since directories can't
> be hard-linked, it is not worth looking up their id).

The link count for directories is always 1 on FAT and NTFS.  But, yes,
I will add a test for directories, too.


Thanks,
Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat



More information about the Cygwin-developers mailing list