git-tar-tree: no more void pointer arithmetic
[git.git] / unpack-objects.c
1 #include "cache.h"
2 #include "object.h"
3 #include "delta.h"
4 #include "pack.h"
5 #include "blob.h"
6 #include "commit.h"
7 #include "tag.h"
8 #include "tree.h"
9
10 #include <sys/time.h>
11
12 static int dry_run, quiet;
13 static const char unpack_usage[] = "git-unpack-objects [-n] [-q] < pack-file";
14
15 /* We always read in 4kB chunks. */
16 static unsigned char buffer[4096];
17 static unsigned long offset, len, eof;
18 static SHA_CTX ctx;
19
20 /*
21  * Make sure at least "min" bytes are available in the buffer, and
22  * return the pointer to the buffer.
23  */
24 static void * fill(int min)
25 {
26         if (min <= len)
27                 return buffer + offset;
28         if (eof)
29                 die("unable to fill input");
30         if (min > sizeof(buffer))
31                 die("cannot fill %d bytes", min);
32         if (offset) {
33                 SHA1_Update(&ctx, buffer, offset);
34                 memcpy(buffer, buffer + offset, len);
35                 offset = 0;
36         }
37         do {
38                 int ret = xread(0, buffer + len, sizeof(buffer) - len);
39                 if (ret <= 0) {
40                         if (!ret)
41                                 die("early EOF");
42                         die("read error on input: %s", strerror(errno));
43                 }
44                 len += ret;
45         } while (len < min);
46         return buffer;
47 }
48
49 static void use(int bytes)
50 {
51         if (bytes > len)
52                 die("used more bytes than were available");
53         len -= bytes;
54         offset += bytes;
55 }
56
57 static void *get_data(unsigned long size)
58 {
59         z_stream stream;
60         void *buf = xmalloc(size);
61
62         memset(&stream, 0, sizeof(stream));
63
64         stream.next_out = buf;
65         stream.avail_out = size;
66         stream.next_in = fill(1);
67         stream.avail_in = len;
68         inflateInit(&stream);
69
70         for (;;) {
71                 int ret = inflate(&stream, 0);
72                 use(len - stream.avail_in);
73                 if (stream.total_out == size && ret == Z_STREAM_END)
74                         break;
75                 if (ret != Z_OK)
76                         die("inflate returned %d\n", ret);
77                 stream.next_in = fill(1);
78                 stream.avail_in = len;
79         }
80         inflateEnd(&stream);
81         return buf;
82 }
83
84 struct delta_info {
85         unsigned char base_sha1[20];
86         unsigned long size;
87         void *delta;
88         struct delta_info *next;
89 };
90
91 static struct delta_info *delta_list;
92
93 static void add_delta_to_list(unsigned char *base_sha1, void *delta, unsigned long size)
94 {
95         struct delta_info *info = xmalloc(sizeof(*info));
96
97         memcpy(info->base_sha1, base_sha1, 20);
98         info->size = size;
99         info->delta = delta;
100         info->next = delta_list;
101         delta_list = info;
102 }
103
104 static void added_object(unsigned char *sha1, const char *type, void *data, unsigned long size);
105
106 static void write_object(void *buf, unsigned long size, const char *type)
107 {
108         unsigned char sha1[20];
109         if (write_sha1_file(buf, size, type, sha1) < 0)
110                 die("failed to write object");
111         added_object(sha1, type, buf, size);
112 }
113
114 static int resolve_delta(const char *type,
115         void *base, unsigned long base_size, 
116         void *delta, unsigned long delta_size)
117 {
118         void *result;
119         unsigned long result_size;
120
121         result = patch_delta(base, base_size,
122                              delta, delta_size,
123                              &result_size);
124         if (!result)
125                 die("failed to apply delta");
126         free(delta);
127         write_object(result, result_size, type);
128         free(result);
129         return 0;
130 }
131
132 static void added_object(unsigned char *sha1, const char *type, void *data, unsigned long size)
133 {
134         struct delta_info **p = &delta_list;
135         struct delta_info *info;
136
137         while ((info = *p) != NULL) {
138                 if (!memcmp(info->base_sha1, sha1, 20)) {
139                         *p = info->next;
140                         p = &delta_list;
141                         resolve_delta(type, data, size, info->delta, info->size);
142                         free(info);
143                         continue;
144                 }
145                 p = &info->next;
146         }
147 }
148
149 static int unpack_non_delta_entry(enum object_type kind, unsigned long size)
150 {
151         void *buf = get_data(size);
152         const char *type;
153
154         switch (kind) {
155         case OBJ_COMMIT: type = commit_type; break;
156         case OBJ_TREE:   type = tree_type; break;
157         case OBJ_BLOB:   type = blob_type; break;
158         case OBJ_TAG:    type = tag_type; break;
159         default: die("bad type %d", kind);
160         }
161         if (!dry_run)
162                 write_object(buf, size, type);
163         free(buf);
164         return 0;
165 }
166
167 static int unpack_delta_entry(unsigned long delta_size)
168 {
169         void *delta_data, *base;
170         unsigned long base_size;
171         char type[20];
172         unsigned char base_sha1[20];
173         int result;
174
175         memcpy(base_sha1, fill(20), 20);
176         use(20);
177
178         delta_data = get_data(delta_size);
179         if (dry_run) {
180                 free(delta_data);
181                 return 0;
182         }
183
184         if (!has_sha1_file(base_sha1)) {
185                 add_delta_to_list(base_sha1, delta_data, delta_size);
186                 return 0;
187         }
188         base = read_sha1_file(base_sha1, type, &base_size);
189         if (!base)
190                 die("failed to read delta-pack base object %s", sha1_to_hex(base_sha1));
191         result = resolve_delta(type, base, base_size, delta_data, delta_size);
192         free(base);
193         return result;
194 }
195
196 static void unpack_one(unsigned nr, unsigned total)
197 {
198         unsigned shift;
199         unsigned char *pack, c;
200         unsigned long size;
201         enum object_type type;
202
203         pack = fill(1);
204         c = *pack;
205         use(1);
206         type = (c >> 4) & 7;
207         size = (c & 15);
208         shift = 4;
209         while (c & 0x80) {
210                 pack = fill(1);
211                 c = *pack++;
212                 use(1);
213                 size += (c & 0x7f) << shift;
214                 shift += 7;
215         }
216         if (!quiet) {
217                 static unsigned long last_sec;
218                 static unsigned last_percent;
219                 struct timeval now;
220                 unsigned percentage = (nr * 100) / total;
221
222                 gettimeofday(&now, NULL);
223                 if (percentage != last_percent || now.tv_sec != last_sec) {
224                         last_sec = now.tv_sec;
225                         last_percent = percentage;
226                         fprintf(stderr, "%4u%% (%u/%u) done\r", percentage, nr, total);
227                 }
228         }
229         switch (type) {
230         case OBJ_COMMIT:
231         case OBJ_TREE:
232         case OBJ_BLOB:
233         case OBJ_TAG:
234                 unpack_non_delta_entry(type, size);
235                 return;
236         case OBJ_DELTA:
237                 unpack_delta_entry(size);
238                 return;
239         default:
240                 die("bad object type %d", type);
241         }
242 }
243
244 /*
245  * We unpack from the end, older files first. Now, usually
246  * there are deltas etc, so we'll not actually write the
247  * objects in that order, but we might as well try..
248  */
249 static void unpack_all(void)
250 {
251         int i;
252         struct pack_header *hdr = fill(sizeof(struct pack_header));
253         unsigned nr_objects = ntohl(hdr->hdr_entries);
254
255         if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
256                 die("bad pack file");
257         if (!pack_version_ok(hdr->hdr_version))
258                 die("unknown pack file version %d", ntohl(hdr->hdr_version));
259         fprintf(stderr, "Unpacking %d objects\n", nr_objects);
260
261         use(sizeof(struct pack_header));
262         for (i = 0; i < nr_objects; i++)
263                 unpack_one(i+1, nr_objects);
264         if (delta_list)
265                 die("unresolved deltas left after unpacking");
266 }
267
268 int main(int argc, char **argv)
269 {
270         int i;
271         unsigned char sha1[20];
272
273         setup_git_directory();
274
275         quiet = !isatty(2);
276
277         for (i = 1 ; i < argc; i++) {
278                 const char *arg = argv[i];
279
280                 if (*arg == '-') {
281                         if (!strcmp(arg, "-n")) {
282                                 dry_run = 1;
283                                 continue;
284                         }
285                         if (!strcmp(arg, "-q")) {
286                                 quiet = 1;
287                                 continue;
288                         }
289                         usage(unpack_usage);
290                 }
291
292                 /* We don't take any non-flag arguments now.. Maybe some day */
293                 usage(unpack_usage);
294         }
295         SHA1_Init(&ctx);
296         unpack_all();
297         SHA1_Update(&ctx, buffer, offset);
298         SHA1_Final(sha1, &ctx);
299         if (memcmp(fill(20), sha1, 20))
300                 die("final sha1 did not match");
301         use(20);
302
303         /* Write the last part of the buffer to stdout */
304         while (len) {
305                 int ret = xwrite(1, buffer + offset, len);
306                 if (ret <= 0)
307                         break;
308                 len -= ret;
309                 offset += ret;
310         }
311
312         /* All done */
313         if (!quiet)
314                 fprintf(stderr, "\n");
315         return 0;
316 }