This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: untarring symlinks with ../ fails randomly


(Re-posting yet again, didn't get through yesterday or today (?), this time
from a different account.)


Corinna,

Debugging with gdb shows that "tar" is prepared for the possibility that
symbolic links don't work and that hard links will have to be used instead.
So, when it encounters a symbolic link, it creates a zero-length file with mode
0 as a placeholder, and it records the inode number of the new file.  That way
it can wait until all the regular files have been created, and then replace the
placeholder by a symbolic link, or if that doesn't work, by a hard link to the
existing file.  However, a tar file can contain multiple entries corresponding
to the same file name or path, so it may happen that the placeholder is no
longer present at the end, having been replaced by another file.  Hence, it
will only replace the placeholder if the inode number and the creation time are
unchanged.  But, under cygwin, the creation time may change gratuitously after
the creation of the file, at random!  Hence the placeholder is sometimes left
in place.  My system is Windows 7.

Here is a C program (simple test case) that illustrates it.


#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>

int main () {
     static struct stat s;
     int i;
     char * fn [12] = {
	  "tmpdir/a","tmpdir/b","tmpdir/c","tmpdir/d","tmpdir/e","tmpdir/f",
	  "tmpdir/g","tmpdir/h","tmpdir/i","tmpdir/j","tmpdir/k","tmpdir/l"
     };
     struct timespec ctime[12];
     mkdir("tmpdir",0755);
     for (i=0; i<12; i++) {
	  int fd = open(fn[i],O_EXCL|O_CREAT|O_WRONLY,0);
	  fstat(fd,&s);
	  ctime[i] = s.st_ctim;
	  close(fd);
	  }
     sleep(1);
     for (i=0; i<12; i++) {
	  struct timespec ctime2;
	  stat(fn[i],&s);
	  ctime2 = s.st_ctim;
	  if (ctime[i].tv_nsec != ctime2.tv_nsec) 
	       printf("ctime changed: file %s, %lu.%09lu -> %lu.%09lu\n", 
		      fn[i],
		      ctime[i].tv_sec, ctime[i].tv_nsec, 
		      ctime2.tv_sec, ctime2.tv_nsec);
	  }
     return 0;
     }


Here is some sample output from the program.


$ rm -rf tmpdir && gcc -Wall p.c && ./a.exe
ctime changed: file tmpdir/c, 1303742293.177618900 -> 1303742293.178619000
ctime changed: file tmpdir/f, 1303742293.178619000 -> 1303742293.179619000
ctime changed: file tmpdir/h, 1303742293.179619000 -> 1303742293.180619100
ctime changed: file tmpdir/k, 1303742293.180619100 -> 1303742293.181619100




--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]