[PATCH] Fix unpack-objects for header length information.
[git.git] / unpack-objects.c
1 #include "cache.h"
2 #include "object.h"
3 #include "delta.h"
4 #include "pack.h"
5
6 static int dry_run;
7 static int nr_entries;
8 static const char *base_name;
9 static const char unpack_usage[] = "git-unpack-objects basename";
10
11 struct pack_entry {
12         unsigned int offset; /* network byte order */
13         unsigned char sha1[20];
14 };
15
16 static void *pack_base;
17 static unsigned long pack_size;
18 static void *index_base;
19 static unsigned long index_size;
20
21 static struct pack_entry **pack_list;
22
23 static void *map_file(const char *suffix, unsigned long *sizep)
24 {
25         static char pathname[PATH_MAX];
26         unsigned long len;
27         int fd;
28         struct stat st;
29         void *map;
30
31         len = snprintf(pathname, PATH_MAX, "%s.%s", base_name, suffix);
32         if (len >= PATH_MAX)
33                 die("bad pack base-name");
34         fd = open(pathname, O_RDONLY);
35         if (fd < 0 || fstat(fd, &st))
36                 die("unable to open '%s'", pathname);
37         len = st.st_size;
38         if (!len)
39                 die("bad pack file '%s'", pathname);
40         map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
41         if (-1 == (int)(long)map)
42                 die("unable to mmap '%s'", pathname);
43         close(fd);
44         *sizep = len;
45         return map;
46 }
47
48 static int sort_by_offset(const void *_a, const void *_b)
49 {
50         struct pack_entry *a = *(struct pack_entry **)_a;
51         struct pack_entry *b = *(struct pack_entry **)_b;
52         unsigned int o1, o2;
53
54         o1 = ntohl(a->offset);
55         o2 = ntohl(b->offset);
56         return o1 < o2 ? -1 : 1;
57 }
58
59 static int check_index(void)
60 {
61         unsigned int *array = index_base;
62         unsigned int nr;
63         int i;
64
65         if (index_size < 4*256 + 20)
66                 return error("index file too small");
67         nr = 0;
68         for (i = 0; i < 256; i++) {
69                 unsigned int n = ntohl(array[i]);
70                 if (n < nr)
71                         return error("non-monotonic index");
72                 nr = n;
73         }
74         /*
75          * Total size:
76          *  - 256 index entries 4 bytes each
77          *  - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
78          *  - 20-byte SHA1 of the packfile
79          *  - 20-byte SHA1 file checksum
80          */
81         if (index_size != 4*256 + nr * 24 + 20 + 20)
82                 return error("wrong index file size");
83
84         nr_entries = nr;
85         pack_list = xmalloc(nr * sizeof(struct pack_entry *));
86         for (i = 0; i < nr; i++)
87                 pack_list[i] = index_base + 4*256 + i*24;
88
89         qsort(pack_list, nr, sizeof(*pack_list), sort_by_offset);
90
91         printf("%d entries\n", nr);
92         return 0;
93 }
94
95 static int unpack_non_delta_entry(struct pack_entry *entry,
96                                   enum object_type kind,
97                                   unsigned char *data,
98                                   unsigned long size,
99                                   unsigned long left)
100 {
101         int st;
102         z_stream stream;
103         char *buffer;
104         unsigned char sha1[20];
105         char *type;
106
107         printf("%s %c %lu\n", sha1_to_hex(entry->sha1), ".CTBGD"[kind], size);
108         if (dry_run)
109                 return 0;
110
111         buffer = xmalloc(size + 1);
112         buffer[size] = 0;
113         memset(&stream, 0, sizeof(stream));
114         stream.next_in = data;
115         stream.avail_in = left;
116         stream.next_out = buffer;
117         stream.avail_out = size;
118
119         inflateInit(&stream);
120         st = inflate(&stream, Z_FINISH);
121         inflateEnd(&stream);
122         if ((st != Z_STREAM_END) || stream.total_out != size)
123                 goto err_finish;
124         switch (kind) {
125         case OBJ_COMMIT: type = "commit"; break;
126         case OBJ_TREE:   type = "tree"; break;
127         case OBJ_BLOB:   type = "blob"; break;
128         case OBJ_TAG:    type = "tag"; break;
129         default: goto err_finish;
130         }
131         if (write_sha1_file(buffer, size, type, sha1) < 0)
132                 die("failed to write %s (%s)",
133                     sha1_to_hex(entry->sha1), type);
134         printf("%s %s\n", sha1_to_hex(sha1), type);
135         if (memcmp(sha1, entry->sha1, 20))
136                 die("resulting %s have wrong SHA1", type);
137
138  finish:
139         st = 0;
140         free(buffer);
141         return st;
142  err_finish:
143         st = -1;
144         goto finish;
145 }
146
147 static int find_pack_entry(unsigned char *sha1, struct pack_entry **ent)
148 {
149         int *level1_ofs = index_base;
150         int hi = ntohl(level1_ofs[*sha1]);
151         int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
152         void *index = index_base + 4*256;
153
154         do {
155                 int mi = (lo + hi) / 2;
156                 int cmp = memcmp(index + 24 * mi + 4, sha1, 20);
157                 if (!cmp) {
158                         *ent = index + 24 * mi;
159                         return 1;
160                 }
161                 if (cmp > 0)
162                         hi = mi;
163                 else
164                         lo = mi+1;
165         } while (lo < hi);
166         return 0;
167 }
168
169 /* forward declaration for a mutually recursive function */
170 static void unpack_entry(struct pack_entry *);
171
172 static int unpack_delta_entry(struct pack_entry *entry,
173                               unsigned char *base_sha1,
174                               unsigned long delta_size,
175                               unsigned long left)
176 {
177         void *data, *delta_data, *result, *base;
178         unsigned long data_size, result_size, base_size;
179         z_stream stream;
180         int st;
181         char type[20];
182         unsigned char sha1[20];
183
184         if (left < 20)
185                 die("truncated pack file");
186         data = base_sha1 + 20;
187         data_size = left - 20;
188         printf("%s D %lu", sha1_to_hex(entry->sha1), delta_size);
189         printf(" %s\n", sha1_to_hex(base_sha1));
190
191         if (dry_run)
192                 return 0;
193
194         /* pack+5 is the base sha1, unless we have it, we need to
195          * unpack it first.
196          */
197         if (!has_sha1_file(base_sha1)) {
198                 struct pack_entry *base;
199                 if (!find_pack_entry(base_sha1, &base))
200                         die("cannot find delta-pack base object");
201                 unpack_entry(base);
202         }
203         delta_data = xmalloc(delta_size);
204
205         memset(&stream, 0, sizeof(stream));
206
207         stream.next_in = data;
208         stream.avail_in = data_size;
209         stream.next_out = delta_data;
210         stream.avail_out = delta_size;
211
212         inflateInit(&stream);
213         st = inflate(&stream, Z_FINISH);
214         inflateEnd(&stream);
215         if ((st != Z_STREAM_END) || stream.total_out != delta_size)
216                 die("delta data unpack failed");
217
218         base = read_sha1_file(base_sha1, type, &base_size);
219         if (!base)
220                 die("failed to read delta-pack base object %s", sha1_to_hex(base_sha1));
221         result = patch_delta(base, base_size,
222                              delta_data, delta_size,
223                              &result_size);
224         if (!result)
225                 die("failed to apply delta");
226         free(delta_data);
227
228         if (write_sha1_file(result, result_size, type, sha1) < 0)
229                 die("failed to write %s (%s)",
230                     sha1_to_hex(entry->sha1), type);
231         free(result);
232         printf("%s %s\n", sha1_to_hex(sha1), type);
233         if (memcmp(sha1, entry->sha1, 20))
234                 die("resulting %s have wrong SHA1", type);
235         return 0;
236 }
237
238 static void unpack_entry(struct pack_entry *entry)
239 {
240         unsigned long offset, size, left;
241         unsigned char *pack, c;
242         int type;
243
244         /* Have we done this one already due to deltas based on it? */
245         if (lookup_object(entry->sha1))
246                 return;
247
248         offset = ntohl(entry->offset);
249         if (offset >= pack_size)
250                 goto bad;
251
252         pack = pack_base + offset;
253         c = *pack++;
254         offset++;
255         type = (c >> 4) & 7;
256         size = (c & 15);
257         while (c & 0x80) {
258                 if (offset >= pack_size)
259                         goto bad;
260                 offset++;
261                 c = *pack++;
262                 size = (size << 7) + (c & 0x7f);
263                 
264         }
265         left = pack_size - offset;
266         switch (type) {
267         case OBJ_COMMIT:
268         case OBJ_TREE:
269         case OBJ_BLOB:
270         case OBJ_TAG:
271                 unpack_non_delta_entry(entry, type, pack, size, left);
272                 return;
273         case OBJ_DELTA:
274                 unpack_delta_entry(entry, pack, size, left);
275                 return;
276         }
277 bad:
278         die("corrupted pack file");
279 }
280
281 /*
282  * We unpack from the end, older files first. Now, usually
283  * there are deltas etc, so we'll not actually write the
284  * objects in that order, but we might as well try..
285  */
286 static void unpack_all(void)
287 {
288         int i = nr_entries;
289
290         while (--i >= 0) {
291                 struct pack_entry *entry = pack_list[i];
292                 unpack_entry(entry);
293         }
294 }
295
296 int main(int argc, char **argv)
297 {
298         int i;
299
300         for (i = 1 ; i < argc; i++) {
301                 const char *arg = argv[i];
302
303                 if (*arg == '-') {
304                         if (!strcmp(arg, "-n")) {
305                                 dry_run = 1;
306                                 continue;
307                         }
308                         usage(unpack_usage);
309                 }
310                 if (base_name)
311                         usage(unpack_usage);
312                 base_name = arg;
313         }
314         if (!base_name)
315                 usage(unpack_usage);
316         index_base = map_file("idx", &index_size);
317         pack_base = map_file("pack", &pack_size);
318         if (check_index() < 0)
319                 die("bad index file");
320         unpack_all();
321         return 0;
322 }