bug-tar
[Top][All Lists]
Advanced

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

[Bug-tar] GNU tar 1.28: tests 161 163 fail on !Linux


From: Christian Weisgerber
Subject: [Bug-tar] GNU tar 1.28: tests 161 163 fail on !Linux
Date: Tue, 5 Aug 2014 22:07:20 +0200
User-agent: Mutt/1.5.23 (2014-03-12)

On both FreeBSD and OpenBSD, these tests in GNU tar 1.28 fail:

 161: remfiles08a.at:28  remove-files deleting two subdirs in -c/non-incr. mode
      create remove-files remfiles08 remfiles08a
 163: remfiles08c.at:28  remove-files deleting two subdirs in -r mode
      create append remove-files remfiles08 remfiles08c

According to an earlier message to bug-tar, they also fail on Solaris.

I've looked at test #161 and it does this:

  mkdir foo
  mkdir bar
  echo foo/foo_file > foo/foo_file
  echo bar/bar_file > bar/bar_file
  decho A
  tar -cvf foo.tar --remove-files -C foo . -C ../bar .
  decho B
  find .

The failing result is that ./bar still exists.

A system call trace reveals this:

  ...
  9370 gtar     CALL  unlinkat(0x4,0x801453100,0)
  9370 gtar     NAMI  "foo_file"
  9370 gtar     RET   unlinkat 0
  9370 gtar     CALL  unlinkat(AT_FDCWD,0x801451060,0x800)
  9370 gtar     NAMI  "foo"
  9370 gtar     RET   unlinkat 0
  9370 gtar     CALL  unlinkat(0x5,0x801453110,0)
  9370 gtar     NAMI  "bar_file"
  9370 gtar     RET   unlinkat 0
  9370 gtar     CALL  unlinkat(0x4,0x801451068,0x800)
  9370 gtar     NAMI  "../bar"
  9370 gtar     RET   unlinkat -1 errno 2 No such file or directory
  ...

The problem is that "foo" is deleted and then the attempt fails to
delete a path relative to a filedescriptor referring to "foo".

The test program below reproduces this: The final unlinkat() fails
on FreeBSD/OpenBSD but succeeds on Linux.

(err.h may not be available everywhere.)
-----------------------------
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
        int fd;

        if (mkdir("foo", 0777) == -1)
                err(1, "can't create foo");
        if (mkdir("bar", 0777) == -1)
                err(1, "can't create bar");

        if ((fd = open("foo", O_RDONLY)) == -1)
                err(1, "can't open foo");
        if (unlinkat(AT_FDCWD, "foo", AT_REMOVEDIR) == -1)
                err(1, "can't remove foo");
        if (unlinkat(fd, "../bar", AT_REMOVEDIR) == -1)
                err(1, "can't remove ../bar");

        return 0;
}
-----------------------------

The BSD behavior appears to be in line with POSIX.  unlinkat() with
AT_REMOVEDIR is equivalent to rmdir(), whose specification says:

  If one or more processes have the directory open when the last
  link is removed, the dot and dot-dot entries, if present, shall
  be removed before rmdir() returns and no new entries may be created
  in the directory, but the directory shall not be removed until
  all references to the directory are closed.

Without "..", the path resolution of the subsequent unlinkat() call
should--or at least can--fail.

-- 
Christian "naddy" Weisgerber                          address@hidden



reply via email to

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