adding file to an existing archive change the mode of the archive file
aqueos opened this issue · 1 comments
Describe the Bug
on certain machines adding a file to a zip archive change the mode of the file, on my case from 644 to 600.
I was unable to track down anything at the OS level and i find it very hard to read the source as an admin and not a developer.
I have done several test and all the one using libzip show the same behavior.
Expected Behavior
the new archive should have the same mode than the source archive before adding the file to the zip
Observed Behavior
created an archive
added a file to it
the new archive has its mode changed to 0600
To Reproduce
using this code in php (see later for a perl one) that use libzip:
$zip = new ZipArchive;
$zip->open('aqtest.zip');
$zip->addFile('aqtestzip.php');
$zip->close();
i launch
chmod 617 aqtest.zip;
ls -la aqtest.zip;
strace -F -s 500 -v php aqtestzip.php;
ls -la aqtest.zip;
[~]: chmod 617 aqtest.zip; ls -la aqtest.zip;php aqtestzip.php ; ls -la aqtest.zip;
-rw---xrwx 1 root root 11906 Aug 3 12:03 aqtest.zip
-rw------- 1 root root 12315 Aug 3 12:03 aqtest.zip
The starting zip file is 617 (just used this mode for test purpose the real mode is 640), i add a file in it, the resulting mode file is 600. We can see the issue is the temporary archive created that has the wrong mode in some case. i tried on this machine on xfs, btrfs and tmpfs partition. Only the tmpfs works as espected.
on a btrfs or xfs filesystem:
/dev/sda5 / btrfs rw,relatime,idmapped,compress=zstd:3,ssd,discard=async,space_cache=v2,user_subvol_rm_allowed,subvolid=259,subvol=/containers/guest01 0 0
/dev/md126 /mnt/DATABASE xfs rw,noatime,attr2,inode64,logbufs=8,logbsize=32k,sunit=1024,swidth=2048,prjquota 0 0
btrfs => openat(AT_FDCWD, "/root/aqtest.zip.8WZFcH", O_RDWR|O_CREAT|O_EXCL, 0600) = 5
xfs => openat(AT_FDCWD, "/var/lib/mysql/aqtest.zip.yJkvuu", O_RDWR|O_CREAT|O_EXCL, 0600) = 5
on /dev/shm:
tmpfs /dev/shm tmpfs rw,nosuid,nodev,uid=1065536,gid=1065536,inode64 0 0
tmpfs => openat(AT_FDCWD, "/dev/shm/aqtest.zip.dai3z8", O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC, 0100644) = 5
i tried to search the libzip code and the php zip code but i cannot find anywhere why it does this but i am very bad at reading C code.
i confirmed also in perl:
use warnings;
use strict;
use Archive::Zip qw( :ERROR_CODES );
my $zip = Archive::Zip->new();
$zip->read('./test.zip') == AZ_OK or die "read error\n";
$zip->addFile('aqzip.pl');
$zip->overwrite() == AZ_OK or die "write error\n";
[~]: chmod 617 test.zip ; ls -la test.zip ;perl aqzip.pl;ls -la test.zip ;
-rw---xrwx 1 root root 959 août 3 10:31 test.zip
-rw------- 1 root root 1213 août 3 10:32 test.zip
command line tool that do not use libzip do not have the issue
[~]: chmod 617 test.zip ; ls -la test.zip ;zip test.zip aqzip.pl;ls -la test.zip ;
-rw---xrwx 1 root root 705 août 3 10:56 test.zip
adding: aqzip.pl (deflated 32%)
-rw---xrwx 1 root root 1011 août 3 10:56 test.zip
libzip Version
1.7.3
Operating System
debian 11 and unbuntu 22.04
Test Files
tried with random file to create a zip its not specific to the starting archive file.
Additional context
on some machine it works as espected and on some others it change the mode of the archive.
I was unable to find anywhere in the code where it take the actual mode to recreate the archive with the same one.
I cannot track where it set the temporary file mode. All i can say is that the numerous stats lstat etc.. that the strace show all return the correct mode for the file:
[00007fd074895986] lstat("/root/aqtest.zip", {st_dev=makedev(0, 0x3d), st_ino=5196676, st_mode=S_IFREG|0617, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=32, st_size=12315, st_atime=1690987066 /* 2023-08-02T16:37:46.083227887+0200 */, st_atime_nsec=83227887, st_mtime=1690986414 /* 2023-08-02T16:26:54.787299747+0200 */, st_mtime_nsec=787299747, st_ctime=1691056475 /* 2023-08-03T11:54:35.382224336+0200 */, st_ctime_nsec=382224336}) = 0
[00007fd0748958e6] stat("/root/aqtest.zip", {st_dev=makedev(0, 0x3d), st_ino=5196676, st_mode=S_IFREG|0617, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=32, st_size=12315, st_atime=1690987066 /* 2023-08-02T16:37:46.083227887+0200 */, st_atime_nsec=83227887, st_mtime=1690986414 /* 2023-08-02T16:26:54.787299747+0200 */, st_mtime_nsec=787299747, st_ctime=1691056475 /* 2023-08-03T11:54:35.382224336+0200 */, st_ctime_nsec=382224336}) = 0
[00007fd0748958e6] stat("/root/aqtest.zip", {st_dev=makedev(0, 0x3d), st_ino=5196676, st_mode=S_IFREG|0617, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=32, st_size=12315, st_atime=1690987066 /* 2023-08-02T16:37:46.083227887+0200 */, st_atime_nsec=83227887, st_mtime=1690986414 /* 2023-08-02T16:26:54.787299747+0200 */, st_mtime_nsec=787299747, st_ctime=1691056475 /* 2023-08-03T11:54:35.382224336+0200 */, st_ctime_nsec=382224336}) = 0
[00007fd074896127] openat(AT_FDCWD, "/root/aqtest.zip", O_RDONLY|O_CLOEXEC) = 4
....
[00007fd074896127] openat(AT_FDCWD, "/root/aqtest.zip.e9gpp4", O_RDWR|O_CREAT|O_EXCL, 0600) = 5
but in the end it create the file in 600 mode.
best regards,
Ghislain.
The mode of the original file is applied to the new file in create_temp_file()
in zip_source_file_stdio_named.c.
Since you also have this problem with Perl's Archive::Zip
, which doesn't use libzip, and you're only experiencing this on some machines, I think your problem is somewhere else. Try using chmod directly and see if that works as expected.
Also libzip version 1.7.3 is quite old. If you think this is a problem with libzip, please try to reproduce it with the current version.