2 * Copyright (c) 2006 Rene Scharfe
12 static const char zip_tree_usage
[] =
13 "git-zip-tree [-0|...|-9] <tree-ish> [ <base> ]";
18 static unsigned char *zip_dir
;
19 static unsigned int zip_dir_size
;
21 static unsigned int zip_offset
;
22 static unsigned int zip_dir_offset
;
23 static unsigned int zip_dir_entries
;
25 #define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
27 struct zip_local_header
{
28 unsigned char magic
[4];
29 unsigned char version
[2];
30 unsigned char flags
[2];
31 unsigned char compression_method
[2];
32 unsigned char mtime
[2];
33 unsigned char mdate
[2];
34 unsigned char crc32
[4];
35 unsigned char compressed_size
[4];
36 unsigned char size
[4];
37 unsigned char filename_length
[2];
38 unsigned char extra_length
[2];
41 struct zip_dir_header
{
42 unsigned char magic
[4];
43 unsigned char creator_version
[2];
44 unsigned char version
[2];
45 unsigned char flags
[2];
46 unsigned char compression_method
[2];
47 unsigned char mtime
[2];
48 unsigned char mdate
[2];
49 unsigned char crc32
[4];
50 unsigned char compressed_size
[4];
51 unsigned char size
[4];
52 unsigned char filename_length
[2];
53 unsigned char extra_length
[2];
54 unsigned char comment_length
[2];
55 unsigned char disk
[2];
56 unsigned char attr1
[2];
57 unsigned char attr2
[4];
58 unsigned char offset
[4];
61 struct zip_dir_trailer
{
62 unsigned char magic
[4];
63 unsigned char disk
[2];
64 unsigned char directory_start_disk
[2];
65 unsigned char entries_on_this_disk
[2];
66 unsigned char entries
[2];
67 unsigned char size
[4];
68 unsigned char offset
[4];
69 unsigned char comment_length
[2];
72 static void copy_le16(unsigned char *dest
, unsigned int n
)
75 dest
[1] = 0xff & (n
>> 010);
78 static void copy_le32(unsigned char *dest
, unsigned int n
)
81 dest
[1] = 0xff & (n
>> 010);
82 dest
[2] = 0xff & (n
>> 020);
83 dest
[3] = 0xff & (n
>> 030);
86 static void *zlib_deflate(void *data
, unsigned long size
,
87 unsigned long *compressed_size
)
90 unsigned long maxsize
;
94 memset(&stream
, 0, sizeof(stream
));
95 deflateInit(&stream
, zlib_compression_level
);
96 maxsize
= deflateBound(&stream
, size
);
97 buffer
= xmalloc(maxsize
);
99 stream
.next_in
= data
;
100 stream
.avail_in
= size
;
101 stream
.next_out
= buffer
;
102 stream
.avail_out
= maxsize
;
105 result
= deflate(&stream
, Z_FINISH
);
106 } while (result
== Z_OK
);
108 if (result
!= Z_STREAM_END
) {
114 *compressed_size
= stream
.total_out
;
119 static char *construct_path(const char *base
, int baselen
,
120 const char *filename
, int isdir
, int *pathlen
)
122 int filenamelen
= strlen(filename
);
123 int len
= baselen
+ filenamelen
;
128 p
= path
= xmalloc(len
+ 1);
130 memcpy(p
, base
, baselen
);
132 memcpy(p
, filename
, filenamelen
);
143 static int write_zip_entry(const unsigned char *sha1
,
144 const char *base
, int baselen
,
145 const char *filename
, unsigned mode
, int stage
)
147 struct zip_local_header header
;
148 struct zip_dir_header dirent
;
149 unsigned long compressed_size
;
150 unsigned long uncompressed_size
;
152 unsigned long direntsize
;
161 void *deflated
= NULL
;
163 crc
= crc32(0, Z_NULL
, 0);
165 path
= construct_path(base
, baselen
, filename
, S_ISDIR(mode
), &pathlen
);
166 if (pathlen
> 0xffff) {
167 error("path too long (%d chars, SHA1: %s): %s", pathlen
,
168 sha1_to_hex(sha1
), path
);
174 result
= READ_TREE_RECURSIVE
;
176 uncompressed_size
= 0;
178 } else if (S_ISREG(mode
)) {
179 method
= zlib_compression_level
== 0 ? 0 : 8;
181 buffer
= read_sha1_file(sha1
, type
, &size
);
183 die("cannot read %s", sha1_to_hex(sha1
));
184 crc
= crc32(crc
, buffer
, size
);
186 uncompressed_size
= size
;
187 compressed_size
= size
;
189 error("unsupported file mode: 0%o (SHA1: %s)", mode
,
195 deflated
= zlib_deflate(buffer
, size
, &compressed_size
);
196 if (deflated
&& compressed_size
- 6 < size
) {
197 /* ZLIB --> raw compressed data (see RFC 1950) */
198 /* CMF and FLG ... */
199 out
= (unsigned char *)deflated
+ 2;
200 compressed_size
-= 6; /* ... and ADLER32 */
203 compressed_size
= size
;
207 /* make sure we have enough free space in the dictionary */
208 direntsize
= sizeof(struct zip_dir_header
) + pathlen
;
209 while (zip_dir_size
< zip_dir_offset
+ direntsize
) {
210 zip_dir_size
+= ZIP_DIRECTORY_MIN_SIZE
;
211 zip_dir
= xrealloc(zip_dir
, zip_dir_size
);
214 copy_le32(dirent
.magic
, 0x02014b50);
215 copy_le16(dirent
.creator_version
, 0);
216 copy_le16(dirent
.version
, 20);
217 copy_le16(dirent
.flags
, 0);
218 copy_le16(dirent
.compression_method
, method
);
219 copy_le16(dirent
.mtime
, zip_time
);
220 copy_le16(dirent
.mdate
, zip_date
);
221 copy_le32(dirent
.crc32
, crc
);
222 copy_le32(dirent
.compressed_size
, compressed_size
);
223 copy_le32(dirent
.size
, uncompressed_size
);
224 copy_le16(dirent
.filename_length
, pathlen
);
225 copy_le16(dirent
.extra_length
, 0);
226 copy_le16(dirent
.comment_length
, 0);
227 copy_le16(dirent
.disk
, 0);
228 copy_le16(dirent
.attr1
, 0);
229 copy_le32(dirent
.attr2
, 0);
230 copy_le32(dirent
.offset
, zip_offset
);
231 memcpy(zip_dir
+ zip_dir_offset
, &dirent
, sizeof(struct zip_dir_header
));
232 zip_dir_offset
+= sizeof(struct zip_dir_header
);
233 memcpy(zip_dir
+ zip_dir_offset
, path
, pathlen
);
234 zip_dir_offset
+= pathlen
;
237 copy_le32(header
.magic
, 0x04034b50);
238 copy_le16(header
.version
, 20);
239 copy_le16(header
.flags
, 0);
240 copy_le16(header
.compression_method
, method
);
241 copy_le16(header
.mtime
, zip_time
);
242 copy_le16(header
.mdate
, zip_date
);
243 copy_le32(header
.crc32
, crc
);
244 copy_le32(header
.compressed_size
, compressed_size
);
245 copy_le32(header
.size
, uncompressed_size
);
246 copy_le16(header
.filename_length
, pathlen
);
247 copy_le16(header
.extra_length
, 0);
248 write_or_die(1, &header
, sizeof(struct zip_local_header
));
249 zip_offset
+= sizeof(struct zip_local_header
);
250 write_or_die(1, path
, pathlen
);
251 zip_offset
+= pathlen
;
252 if (compressed_size
> 0) {
253 write_or_die(1, out
, compressed_size
);
254 zip_offset
+= compressed_size
;
265 static void write_zip_trailer(const unsigned char *sha1
)
267 struct zip_dir_trailer trailer
;
269 copy_le32(trailer
.magic
, 0x06054b50);
270 copy_le16(trailer
.disk
, 0);
271 copy_le16(trailer
.directory_start_disk
, 0);
272 copy_le16(trailer
.entries_on_this_disk
, zip_dir_entries
);
273 copy_le16(trailer
.entries
, zip_dir_entries
);
274 copy_le32(trailer
.size
, zip_dir_offset
);
275 copy_le32(trailer
.offset
, zip_offset
);
276 copy_le16(trailer
.comment_length
, sha1
? 40 : 0);
278 write_or_die(1, zip_dir
, zip_dir_offset
);
279 write_or_die(1, &trailer
, sizeof(struct zip_dir_trailer
));
281 write_or_die(1, sha1_to_hex(sha1
), 40);
284 static void dos_time(time_t *time
, int *dos_date
, int *dos_time
)
286 struct tm
*t
= localtime(time
);
288 *dos_date
= t
->tm_mday
+ (t
->tm_mon
+ 1) * 32 +
289 (t
->tm_year
+ 1900 - 1980) * 512;
290 *dos_time
= t
->tm_sec
/ 2 + t
->tm_min
* 32 + t
->tm_hour
* 2048;
293 int cmd_zip_tree(int argc
, const char **argv
, const char *prefix
)
295 unsigned char sha1
[20];
297 struct commit
*commit
;
302 git_config(git_default_config
);
304 if (argc
> 1 && argv
[1][0] == '-') {
305 if (isdigit(argv
[1][1]) && argv
[1][2] == '\0') {
306 zlib_compression_level
= argv
[1][1] - '0';
314 base
= xstrdup(argv
[2]);
315 baselen
= strlen(base
);
322 usage(zip_tree_usage
);
325 if (get_sha1(argv
[1], sha1
))
326 die("Not a valid object name %s", argv
[1]);
328 commit
= lookup_commit_reference_gently(sha1
, 1);
329 archive_time
= commit
? commit
->date
: time(NULL
);
330 dos_time(&archive_time
, &zip_date
, &zip_time
);
332 zip_dir
= xmalloc(ZIP_DIRECTORY_MIN_SIZE
);
333 zip_dir_size
= ZIP_DIRECTORY_MIN_SIZE
;
335 tree
= parse_tree_indirect(sha1
);
337 die("not a tree object");
340 write_zip_entry(tree
->object
.sha1
, "", 0, base
, 040777, 0);
341 base
= xrealloc(base
, baselen
+ 1);
344 base
[baselen
] = '\0';
346 read_tree_recursive(tree
, base
, baselen
, 0, NULL
, write_zip_entry
);
347 write_zip_trailer(commit
? commit
->object
.sha1
: NULL
);