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