tar 1.33 symlinks : Cannot change mode to...

Ken Brown kbrown@cornell.edu
Tue Jan 12 16:55:10 GMT 2021


On 1/11/2021 6:50 PM, Ken Brown via Cygwin wrote:
> On 1/11/2021 2:57 PM, Morgan King via Cygwin wrote:
>> Hello,
>>
>> I am experiencing the same issue with tar and I am able to reproduce it 
>> following the steps at:
>> https://lists.gnu.org/archive/html/bug-tar/2011-08/msg00006.html
>>
>> This issue only appears to occur when using 32-bit Cygwin, I am unable to 
>> reproduce it using 64-bit Cygwin.
> 
> I can confirm this.  Running the tar command under gdb shows a problem at 
> gnu/fchmodat.c:94:
> 
> 94            if (S_ISLNK (st.st_mode))
> 
> Here st is a stat structure for directory/1, so S_ISLNK() should be true.  It is 
> indeed true on 64-bit Cygwin but not on 32-bit Cygwin.  Someone needs to look 
> more closely and find out why this happened.  I'll try to do it tomorrow if no 
> one beats me to it.

This appears to be a bug in fstat in 32-bit Cygwin.  Here's what I'm seeing in 
gdb, using an unoptimized build of cygwin1.dll.  There is a call to fstatat in 
the tar source file gnu/fchmodat.c:87.  This ultimately leads to a call to 
fstat, whose definition in syscalls.cc is the following in the 32-bit case:

extern "C" int
fstat (int fd, struct stat *buf)
{
   struct stat buf64;
   int ret = fstat64 (fd, &buf64);
   if (!ret)
     stat64_to_stat32 (&buf64, (struct __stat32 *) buf);
   return ret;
}

After the call to fstat64, buf64 looks like this:

(gdb) p/o buf64
$20 = {st_dev = 016465473173, st_ino = 01240000000006533716,
   st_mode = 0120777, st_nlink = 01, st_uid = 0601751, st_gid = 0601001,
   st_rdev = 0, st_size = 01, st_atim = {tv_sec = 013777346014,
     tv_nsec = 03415154434}, st_mtim = {tv_sec = 013777334323, tv_nsec = 0},
   st_ctim = {tv_sec = 013777346014, tv_nsec = 03421004710},
   st_blksize = 0200000, st_blocks = 0, st_birthtim = {tv_sec = 013777346014,
     tv_nsec = 03415154434}}

After the call to stat64_to_stat32, buf looks like this:

(gdb) p/o *buf
$22 = {st_dev = 026106753173, st_ino = 017510000040000120777, st_mode = 01001,
   st_nlink = 01, st_uid = 013777346014, st_gid = 03415154434,
   st_rdev = 013777334323, st_size = 0161040234413777346014, st_atim = {
     tv_sec = 0200000, tv_nsec = 0}, st_mtim = {tv_sec = 01, tv_nsec = 0},
   st_ctim = {tv_sec = 06533716, tv_nsec = 025000000}, st_blksize = 0,
   st_blocks = 0, st_birthtim = {tv_sec = 0, tv_nsec = 03}}

Note that many of the values have been corrupted or shifted.  (A few are 
expected to change.)  I think the problem is the cast in the call

   stat64_to_stat32 (&buf64, (struct __stat32 *) buf);

I don't see how that could be expected to work, since several members of struct 
__stat32 have different sizes than the corresponding members of struct stat.  I 
wonder if it worked by accident in the past, but the problem is just showing up 
with newer gcc because of changes in how it pads the two structs?

Corinna, can you shed some light on this?

Ken


More information about the Cygwin mailing list