Skip to content

Commit

Permalink
git-archive --format=zip: add symlink support
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
Rene Scharfe authored and Junio C Hamano committed Oct 8, 2006
1 parent cf72fb0 commit 62cdce1
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 4 deletions.
13 changes: 9 additions & 4 deletions archive-zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ static int write_zip_entry(const unsigned char *sha1,
{
struct zip_local_header header;
struct zip_dir_header dirent;
unsigned long attr2;
unsigned long compressed_size;
unsigned long uncompressed_size;
unsigned long crc;
Expand Down Expand Up @@ -172,12 +173,16 @@ static int write_zip_entry(const unsigned char *sha1,

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)
Expand Down Expand Up @@ -213,7 +218,7 @@ static int write_zip_entry(const unsigned char *sha1,
}

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);
Expand All @@ -227,7 +232,7 @@ static int write_zip_entry(const unsigned char *sha1,
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);
Expand Down
35 changes: 35 additions & 0 deletions t/t5000-tar-tree.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ commit id embedding:

. ./test-lib.sh
TAR=${TAR:-tar}
UNZIP=${UNZIP:-unzip}

test_expect_success \
'populate workdir' \
Expand Down Expand Up @@ -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

0 comments on commit 62cdce1

Please sign in to comment.