t5800: point out that deleting branches does not work
[git/dscho.git] / archive-zip.c
blobf5af81f904df081002dad46a71be2eca8e3bebab
1 /*
2  * Copyright (c) 2006 Rene Scharfe
3  */
4 #include "cache.h"
5 #include "archive.h"
6 #include "streaming.h"
8 static int zip_date;
9 static int zip_time;
11 static unsigned char *zip_dir;
12 static unsigned int zip_dir_size;
14 static unsigned int zip_offset;
15 static unsigned int zip_dir_offset;
16 static unsigned int zip_dir_entries;
18 #define ZIP_DIRECTORY_MIN_SIZE  (1024 * 1024)
19 #define ZIP_STREAM (8)
21 struct zip_local_header {
22         unsigned char magic[4];
23         unsigned char version[2];
24         unsigned char flags[2];
25         unsigned char compression_method[2];
26         unsigned char mtime[2];
27         unsigned char mdate[2];
28         unsigned char crc32[4];
29         unsigned char compressed_size[4];
30         unsigned char size[4];
31         unsigned char filename_length[2];
32         unsigned char extra_length[2];
33         unsigned char _end[1];
36 struct zip_data_desc {
37         unsigned char magic[4];
38         unsigned char crc32[4];
39         unsigned char compressed_size[4];
40         unsigned char size[4];
41         unsigned char _end[1];
44 struct zip_dir_header {
45         unsigned char magic[4];
46         unsigned char creator_version[2];
47         unsigned char version[2];
48         unsigned char flags[2];
49         unsigned char compression_method[2];
50         unsigned char mtime[2];
51         unsigned char mdate[2];
52         unsigned char crc32[4];
53         unsigned char compressed_size[4];
54         unsigned char size[4];
55         unsigned char filename_length[2];
56         unsigned char extra_length[2];
57         unsigned char comment_length[2];
58         unsigned char disk[2];
59         unsigned char attr1[2];
60         unsigned char attr2[4];
61         unsigned char offset[4];
62         unsigned char _end[1];
65 struct zip_dir_trailer {
66         unsigned char magic[4];
67         unsigned char disk[2];
68         unsigned char directory_start_disk[2];
69         unsigned char entries_on_this_disk[2];
70         unsigned char entries[2];
71         unsigned char size[4];
72         unsigned char offset[4];
73         unsigned char comment_length[2];
74         unsigned char _end[1];
78  * On ARM, padding is added at the end of the struct, so a simple
79  * sizeof(struct ...) reports two bytes more than the payload size
80  * we're interested in.
81  */
82 #define ZIP_LOCAL_HEADER_SIZE   offsetof(struct zip_local_header, _end)
83 #define ZIP_DATA_DESC_SIZE      offsetof(struct zip_data_desc, _end)
84 #define ZIP_DIR_HEADER_SIZE     offsetof(struct zip_dir_header, _end)
85 #define ZIP_DIR_TRAILER_SIZE    offsetof(struct zip_dir_trailer, _end)
87 static void copy_le16(unsigned char *dest, unsigned int n)
89         dest[0] = 0xff & n;
90         dest[1] = 0xff & (n >> 010);
93 static void copy_le32(unsigned char *dest, unsigned int n)
95         dest[0] = 0xff & n;
96         dest[1] = 0xff & (n >> 010);
97         dest[2] = 0xff & (n >> 020);
98         dest[3] = 0xff & (n >> 030);
101 static void *zlib_deflate(void *data, unsigned long size,
102                 int compression_level, unsigned long *compressed_size)
104         git_zstream stream;
105         unsigned long maxsize;
106         void *buffer;
107         int result;
109         memset(&stream, 0, sizeof(stream));
110         git_deflate_init(&stream, compression_level);
111         maxsize = git_deflate_bound(&stream, size);
112         buffer = xmalloc(maxsize);
114         stream.next_in = data;
115         stream.avail_in = size;
116         stream.next_out = buffer;
117         stream.avail_out = maxsize;
119         do {
120                 result = git_deflate(&stream, Z_FINISH);
121         } while (result == Z_OK);
123         if (result != Z_STREAM_END) {
124                 free(buffer);
125                 return NULL;
126         }
128         git_deflate_end(&stream);
129         *compressed_size = stream.total_out;
131         return buffer;
134 static void write_zip_data_desc(unsigned long size,
135                                 unsigned long compressed_size,
136                                 unsigned long crc)
138         struct zip_data_desc trailer;
140         copy_le32(trailer.magic, 0x08074b50);
141         copy_le32(trailer.crc32, crc);
142         copy_le32(trailer.compressed_size, compressed_size);
143         copy_le32(trailer.size, size);
144         write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE);
147 static void set_zip_dir_data_desc(struct zip_dir_header *header,
148                                   unsigned long size,
149                                   unsigned long compressed_size,
150                                   unsigned long crc)
152         copy_le32(header->crc32, crc);
153         copy_le32(header->compressed_size, compressed_size);
154         copy_le32(header->size, size);
157 static void set_zip_header_data_desc(struct zip_local_header *header,
158                                      unsigned long size,
159                                      unsigned long compressed_size,
160                                      unsigned long crc)
162         copy_le32(header->crc32, crc);
163         copy_le32(header->compressed_size, compressed_size);
164         copy_le32(header->size, size);
167 #define STREAM_BUFFER_SIZE (1024 * 16)
169 static int write_zip_entry(struct archiver_args *args,
170                            const unsigned char *sha1,
171                            const char *path, size_t pathlen,
172                            unsigned int mode)
174         struct zip_local_header header;
175         struct zip_dir_header dirent;
176         unsigned long attr2;
177         unsigned long compressed_size;
178         unsigned long crc;
179         unsigned long direntsize;
180         int method;
181         unsigned char *out;
182         void *deflated = NULL;
183         void *buffer;
184         struct git_istream *stream = NULL;
185         unsigned long flags = 0;
186         unsigned long size;
188         crc = crc32(0, NULL, 0);
190         if (pathlen > 0xffff) {
191                 return error("path too long (%d chars, SHA1: %s): %s",
192                                 (int)pathlen, sha1_to_hex(sha1), path);
193         }
195         if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
196                 method = 0;
197                 attr2 = 16;
198                 out = NULL;
199                 size = 0;
200                 compressed_size = 0;
201                 buffer = NULL;
202                 size = 0;
203         } else if (S_ISREG(mode) || S_ISLNK(mode)) {
204                 enum object_type type = sha1_object_info(sha1, &size);
206                 method = 0;
207                 attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
208                         (mode & 0111) ? ((mode) << 16) : 0;
209                 if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
210                         method = 8;
211                 compressed_size = size;
213                 if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert &&
214                     size > big_file_threshold) {
215                         stream = open_istream(sha1, &type, &size, NULL);
216                         if (!stream)
217                                 return error("cannot stream blob %s",
218                                              sha1_to_hex(sha1));
219                         flags |= ZIP_STREAM;
220                         out = buffer = NULL;
221                 } else {
222                         buffer = sha1_file_to_archive(args, path, sha1, mode,
223                                                       &type, &size);
224                         if (!buffer)
225                                 return error("cannot read %s",
226                                              sha1_to_hex(sha1));
227                         crc = crc32(crc, buffer, size);
228                         out = buffer;
229                 }
230         } else {
231                 return error("unsupported file mode: 0%o (SHA1: %s)", mode,
232                                 sha1_to_hex(sha1));
233         }
235         if (buffer && method == 8) {
236                 deflated = zlib_deflate(buffer, size, args->compression_level,
237                                 &compressed_size);
238                 if (deflated && compressed_size - 6 < size) {
239                         /* ZLIB --> raw compressed data (see RFC 1950) */
240                         /* CMF and FLG ... */
241                         out = (unsigned char *)deflated + 2;
242                         compressed_size -= 6;   /* ... and ADLER32 */
243                 } else {
244                         method = 0;
245                         compressed_size = size;
246                 }
247         }
249         /* make sure we have enough free space in the dictionary */
250         direntsize = ZIP_DIR_HEADER_SIZE + pathlen;
251         while (zip_dir_size < zip_dir_offset + direntsize) {
252                 zip_dir_size += ZIP_DIRECTORY_MIN_SIZE;
253                 zip_dir = xrealloc(zip_dir, zip_dir_size);
254         }
256         copy_le32(dirent.magic, 0x02014b50);
257         copy_le16(dirent.creator_version,
258                 S_ISLNK(mode) || (S_ISREG(mode) && (mode & 0111)) ? 0x0317 : 0);
259         copy_le16(dirent.version, 10);
260         copy_le16(dirent.flags, flags);
261         copy_le16(dirent.compression_method, method);
262         copy_le16(dirent.mtime, zip_time);
263         copy_le16(dirent.mdate, zip_date);
264         set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
265         copy_le16(dirent.filename_length, pathlen);
266         copy_le16(dirent.extra_length, 0);
267         copy_le16(dirent.comment_length, 0);
268         copy_le16(dirent.disk, 0);
269         copy_le16(dirent.attr1, 0);
270         copy_le32(dirent.attr2, attr2);
271         copy_le32(dirent.offset, zip_offset);
273         copy_le32(header.magic, 0x04034b50);
274         copy_le16(header.version, 10);
275         copy_le16(header.flags, flags);
276         copy_le16(header.compression_method, method);
277         copy_le16(header.mtime, zip_time);
278         copy_le16(header.mdate, zip_date);
279         if (flags & ZIP_STREAM)
280                 set_zip_header_data_desc(&header, 0, 0, 0);
281         else
282                 set_zip_header_data_desc(&header, size, compressed_size, crc);
283         copy_le16(header.filename_length, pathlen);
284         copy_le16(header.extra_length, 0);
285         write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
286         zip_offset += ZIP_LOCAL_HEADER_SIZE;
287         write_or_die(1, path, pathlen);
288         zip_offset += pathlen;
289         if (stream && method == 0) {
290                 unsigned char buf[STREAM_BUFFER_SIZE];
291                 ssize_t readlen;
293                 for (;;) {
294                         readlen = read_istream(stream, buf, sizeof(buf));
295                         if (readlen <= 0)
296                                 break;
297                         crc = crc32(crc, buf, readlen);
298                         write_or_die(1, buf, readlen);
299                 }
300                 close_istream(stream);
301                 if (readlen)
302                         return readlen;
304                 compressed_size = size;
305                 zip_offset += compressed_size;
307                 write_zip_data_desc(size, compressed_size, crc);
308                 zip_offset += ZIP_DATA_DESC_SIZE;
310                 set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
311         } else if (stream && method == 8) {
312                 unsigned char buf[STREAM_BUFFER_SIZE];
313                 ssize_t readlen;
314                 git_zstream zstream;
315                 int result;
316                 size_t out_len;
317                 unsigned char compressed[STREAM_BUFFER_SIZE * 2];
319                 memset(&zstream, 0, sizeof(zstream));
320                 git_deflate_init(&zstream, args->compression_level);
322                 compressed_size = 0;
323                 zstream.next_out = compressed;
324                 zstream.avail_out = sizeof(compressed);
326                 for (;;) {
327                         readlen = read_istream(stream, buf, sizeof(buf));
328                         if (readlen <= 0)
329                                 break;
330                         crc = crc32(crc, buf, readlen);
332                         zstream.next_in = buf;
333                         zstream.avail_in = readlen;
334                         result = git_deflate(&zstream, 0);
335                         if (result != Z_OK)
336                                 die("deflate error (%d)", result);
337                         out = compressed;
338                         if (!compressed_size)
339                                 out += 2;
340                         out_len = zstream.next_out - out;
342                         if (out_len > 0) {
343                                 write_or_die(1, out, out_len);
344                                 compressed_size += out_len;
345                                 zstream.next_out = compressed;
346                                 zstream.avail_out = sizeof(compressed);
347                         }
349                 }
350                 close_istream(stream);
351                 if (readlen)
352                         return readlen;
354                 zstream.next_in = buf;
355                 zstream.avail_in = 0;
356                 result = git_deflate(&zstream, Z_FINISH);
357                 if (result != Z_STREAM_END)
358                         die("deflate error (%d)", result);
360                 git_deflate_end(&zstream);
361                 out = compressed;
362                 if (!compressed_size)
363                         out += 2;
364                 out_len = zstream.next_out - out - 4;
365                 write_or_die(1, out, out_len);
366                 compressed_size += out_len;
367                 zip_offset += compressed_size;
369                 write_zip_data_desc(size, compressed_size, crc);
370                 zip_offset += ZIP_DATA_DESC_SIZE;
372                 set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
373         } else if (compressed_size > 0) {
374                 write_or_die(1, out, compressed_size);
375                 zip_offset += compressed_size;
376         }
378         free(deflated);
379         free(buffer);
381         memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE);
382         zip_dir_offset += ZIP_DIR_HEADER_SIZE;
383         memcpy(zip_dir + zip_dir_offset, path, pathlen);
384         zip_dir_offset += pathlen;
385         zip_dir_entries++;
387         return 0;
390 static void write_zip_trailer(const unsigned char *sha1)
392         struct zip_dir_trailer trailer;
394         copy_le32(trailer.magic, 0x06054b50);
395         copy_le16(trailer.disk, 0);
396         copy_le16(trailer.directory_start_disk, 0);
397         copy_le16(trailer.entries_on_this_disk, zip_dir_entries);
398         copy_le16(trailer.entries, zip_dir_entries);
399         copy_le32(trailer.size, zip_dir_offset);
400         copy_le32(trailer.offset, zip_offset);
401         copy_le16(trailer.comment_length, sha1 ? 40 : 0);
403         write_or_die(1, zip_dir, zip_dir_offset);
404         write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE);
405         if (sha1)
406                 write_or_die(1, sha1_to_hex(sha1), 40);
409 static void dos_time(time_t *time, int *dos_date, int *dos_time)
411         struct tm *t = localtime(time);
413         *dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +
414                     (t->tm_year + 1900 - 1980) * 512;
415         *dos_time = t->tm_sec / 2 + t->tm_min * 32 + t->tm_hour * 2048;
418 static int write_zip_archive(const struct archiver *ar,
419                              struct archiver_args *args)
421         int err;
423         dos_time(&args->time, &zip_date, &zip_time);
425         zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
426         zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
428         err = write_archive_entries(args, write_zip_entry);
429         if (!err)
430                 write_zip_trailer(args->commit_sha1);
432         free(zip_dir);
434         return err;
437 static struct archiver zip_archiver = {
438         "zip",
439         write_zip_archive,
440         ARCHIVER_WANT_COMPRESSION_LEVELS|ARCHIVER_REMOTE
443 void init_zip_archiver(void)
445         register_archiver(&zip_archiver);