[PATCH 2/2] git-archive --format=zip: add symlink support
From: Rene Scharfe <hidden>
Date: 2016-06-15 22:42:42
Subsystem:
the rest · Maintainer:
Linus Torvalds
Add symlink support to ZIP file creation, and a few tests. This implementation sets the "version made by" field (creator_version) to Unix for symlinks, only; regular files and directories are still marked as originating from FAT/VFAT/NTFS. Also set "external file attributes" (attr2) to 0 for regular files and 16 for directories (FAT attribute), and to the file mode for symlinks. We could always set the creator_version to Unix and include the mode, but then Info-ZIP unzip would set the mode of the extracted files to *exactly* the value stored in attr2. The FAT trick makes it apply the umask instead. Note: FAT has no executable bit, so this information is not stored in the ZIP file. Signed-off-by: Rene Scharfe <redacted> --- I tested this change only using Info-ZIP unzip 5.52 on Linux. I wonder what PKZIP or WinZIP would do with symlink entries. All calls of git-tar-tree in the test script should be converted to git-archive --format=tar, then the script can be renamed to t5000-archive.sh. Later. archive-zip.c | 13 +++++++++---- t/t5000-tar-tree.sh | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/archive-zip.c b/archive-zip.c
index ae74623..d8317f8 100644
--- a/archive-zip.c
+++ b/archive-zip.c@@ -145,6 +145,7 @@ static int write_zip_entry(const unsigne { struct zip_local_header header; struct zip_dir_header dirent; + unsigned long attr2; unsigned long compressed_size; unsigned long uncompressed_size; unsigned long crc;
@@ -172,12 +173,16 @@ static int write_zip_entry(const unsigne if (S_ISDIR(mode)) { method = 0; + attr2 = 16; result = READ_TREE_RECURSIVE; out = NULL; uncompressed_size = 0; compressed_size = 0; - } else if (S_ISREG(mode)) { - method = zlib_compression_level == 0 ? 0 : 8; + } else if (S_ISREG(mode) || S_ISLNK(mode)) { + method = 0; + attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) : 0; + if (S_ISREG(mode) && zlib_compression_level != 0) + method = 8; result = 0; buffer = read_sha1_file(sha1, type, &size); if (!buffer)
@@ -213,7 +218,7 @@ static int write_zip_entry(const unsigne } copy_le32(dirent.magic, 0x02014b50); - copy_le16(dirent.creator_version, 0); + copy_le16(dirent.creator_version, S_ISLNK(mode) ? 0x0317 : 0); copy_le16(dirent.version, 10); copy_le16(dirent.flags, 0); copy_le16(dirent.compression_method, method);
@@ -227,7 +232,7 @@ static int write_zip_entry(const unsigne copy_le16(dirent.comment_length, 0); copy_le16(dirent.disk, 0); copy_le16(dirent.attr1, 0); - copy_le32(dirent.attr2, 0); + copy_le32(dirent.attr2, attr2); copy_le32(dirent.offset, zip_offset); memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header)); zip_dir_offset += sizeof(struct zip_dir_header);
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 278eb66..cf08e92 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh@@ -26,6 +26,7 @@ commit id embedding: . ./test-lib.sh TAR=${TAR:-tar} +UNZIP=${UNZIP:-unzip} test_expect_success \ 'populate workdir' \
@@ -95,4 +96,38 @@ test_expect_success \ 'validate file contents with prefix' \ 'diff -r a c/prefix/a' +test_expect_success \ + 'git-archive --format=zip' \ + 'git-archive --format=zip HEAD >d.zip' + +test_expect_success \ + 'extract ZIP archive' \ + '(mkdir d && cd d && $UNZIP ../d.zip)' + +test_expect_success \ + 'validate filenames' \ + '(cd d/a && find .) | sort >d.lst && + diff a.lst d.lst' + +test_expect_success \ + 'validate file contents' \ + 'diff -r a d/a' + +test_expect_success \ + 'git-archive --format=zip with prefix' \ + 'git-archive --format=zip --prefix=prefix/ HEAD >e.zip' + +test_expect_success \ + 'extract ZIP archive with prefix' \ + '(mkdir e && cd e && $UNZIP ../e.zip)' + +test_expect_success \ + 'validate filenames with prefix' \ + '(cd e/prefix/a && find .) | sort >e.lst && + diff a.lst e.lst' + +test_expect_success \ + 'validate file contents with prefix' \ + 'diff -r a e/prefix/a' + test_done
--
1.4.2.3.gf59615