bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: mv trailing slash warning


From: Eric Blake
Subject: Re: mv trailing slash warning
Date: Wed, 28 Sep 2005 22:14:54 +0000

> > On a related note, why don't rm and rmdir have a --strip-trailing-slashes
> > option?
> 
> Because as far as I know, there is no need.
> Do you know of a system where `rmdir symlink/'
> removes only the referent of the symlink?

Yes, cygwin (but again, that goes back to the rmdir(2) bug
in cygwin that I have just reported to the cygwin maintainers):

$ mkdir a
$ ln -s a b
$ rmdir b/
$ ls -F a b
ls: a: No such file or directory
b@

Whereas on sane systems (for example, Solaris 8):

$ mkdir a
$ ln -s a b
$ rmdir b/
rmdir: directory "b/": Path component not a directory
$ rmdir b/.
rmdir: directory "b/.": Can't remove current directory or ..

By Paul's argument, both uses should have failed with
EINVAL, since POSIX requires resolving "symlink/" as
"symlink/.", and requires rmdir("symlink/." to fail with
EINVAL.  Solaris 8 returned ENOTDIR in the first case, so
it appears they stripped the trailing slash (and their error
message leaves something to be desired in accuracy in
the second case).  But at least it reliably failed instead
of removing a.  I don't have access to other systems to
see what other behaviors might exist.

> > Is it worth patching coreutils rm and rmdir to work around buggy
> > systems that don't follow this POSIX restriction on rmdir()?  (Meanwhile,
> > I will try to get cygwin fixed.)  Should we update the coreutils testsuite?
> 
> It depends a whole lot on how invasive or complicated the patch is.
> Ideally, it wouldn't change anything in src/*.c at all.

If cygwin doesn't get patched, it sounds like a gnulib module
to replace rmdir() is all that would be needed.  Something like
this untested snippet (it would need to be cleaned up for
corner cases like "", "/", ".", but you get the picture):

int
rpl_rmdir(const char* name)
{
  int len = strlen (name);
  if (name[len - 1] == '/'
      || (name[len - 1] == '.'
          && (name[len - 2] == '/'
              || (name[len - 2] == '.' && name[len - 3] == '/'))))
    {
      errno = EINVAL;
      return -1;
    }
  return rmdir (name);
}

--
Eric Blake






reply via email to

[Prev in Thread] Current Thread [Next in Thread]