@matheusbsbs / matheus-bagliano / commits / b41860bf28
Fork 0

unpack-objects: prevent writing of inconsistent objects

This patch introduces a strict mode, which ensures that: - no malformed object will be written - no object with broken links will be written The patch ensures this by delaying the write of all non blob object. These object are written, after all objects they link to are written. An error can only result in unreferenced objects. Signed-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Martin Koegler committed Feb 25, 2008 at 22:46 UTC b41860bf28a16ad6015eb0c55dc95602f1235640
2 files changed +106 -7
Documentation/git-unpack-objects.txt
+3
@@ -40,6 +40,9 @@ OPTIONS
40 and make the best effort to recover as many objects as
41 possible.
42
43 +--strict::
44 + Don't write objects with broken content or links.
45 +
46
47 Author
48 ------
builtin-unpack-objects.c
+103 -7
@@ -7,11 +7,13 @@
7 #include "commit.h"
8 #include "tag.h"
9 #include "tree.h"
10 +#include "tree-walk.h"
11 #include "progress.h"
12 #include "decorate.h"
13 +#include "fsck.h"
14
13 -static int dry_run, quiet, recover, has_errors;
14 -static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
15 +static int dry_run, quiet, recover, has_errors, strict;
16 +static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
17
18 /* We always read in 4kB chunks. */
19 static unsigned char buffer[4096];
@@ -31,6 +33,16 @@ static struct obj_buffer *lookup_object_buffer(struct object *base)
33 return lookup_decoration(&obj_decorate, base);
34 }
35
36 +static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
37 +{
38 + struct obj_buffer *obj;
39 + obj = xcalloc(1, sizeof(struct obj_buffer));
40 + obj->buffer = buffer;
41 + obj->size = size;
42 + if (add_decoration(&obj_decorate, object, obj))
43 + die("object %s tried to add buffer twice!", sha1_to_hex(object->sha1));
44 +}
45 +
46 /*
47 * Make sure at least "min" bytes are available in the buffer, and
48 * return the pointer to the buffer.
@@ -134,9 +146,58 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
146 struct obj_info {
147 off_t offset;
148 unsigned char sha1[20];
149 + struct object *obj;
150 };
151
152 +#define FLAG_OPEN (1u<<20)
153 +#define FLAG_WRITTEN (1u<<21)
154 +
155 static struct obj_info *obj_list;
156 +unsigned nr_objects;
157 +
158 +static void write_cached_object(struct object *obj)
159 +{
160 + unsigned char sha1[20];
161 + struct obj_buffer *obj_buf = lookup_object_buffer(obj);
162 + if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
163 + die("failed to write object %s", sha1_to_hex(obj->sha1));
164 + obj->flags |= FLAG_WRITTEN;
165 +}
166 +
167 +static int check_object(struct object *obj, int type, void *data)
168 +{
169 + if (!obj)
170 + return 0;
171 +
172 + if (obj->flags & FLAG_WRITTEN)
173 + return 1;
174 +
175 + if (type != OBJ_ANY && obj->type != type)
176 + die("object type mismatch");
177 +
178 + if (!(obj->flags & FLAG_OPEN)) {
179 + unsigned long size;
180 + int type = sha1_object_info(obj->sha1, &size);
181 + if (type != obj->type || type <= 0)
182 + die("object of unexpected type");
183 + obj->flags |= FLAG_WRITTEN;
184 + return 1;
185 + }
186 +
187 + if (fsck_object(obj, 1, fsck_error_function))
188 + die("Error in object");
189 + if (!fsck_walk(obj, check_object, 0))
190 + die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
191 + write_cached_object(obj);
192 + return 1;
193 +}
194 +
195 +static void write_rest(void)
196 +{
197 + unsigned i;
198 + for (i = 0; i < nr_objects; i++)
199 + check_object(obj_list[i].obj, OBJ_ANY, 0);
200 +}
201
202 static void added_object(unsigned nr, enum object_type type,
203 void *data, unsigned long size);
@@ -144,9 +205,36 @@ static void added_object(unsigned nr, enum object_type type,
205 static void write_object(unsigned nr, enum object_type type,
206 void *buf, unsigned long size)
207 {
147 - if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
148 - die("failed to write object");
208 added_object(nr, type, buf, size);
209 + if (!strict) {
210 + if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
211 + die("failed to write object");
212 + free(buf);
213 + obj_list[nr].obj = 0;
214 + } else if (type == OBJ_BLOB) {
215 + struct blob *blob;
216 + if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
217 + die("failed to write object");
218 + free(buf);
219 +
220 + blob = lookup_blob(obj_list[nr].sha1);
221 + if (blob)
222 + blob->object.flags |= FLAG_WRITTEN;
223 + else
224 + die("invalid blob object");
225 + obj_list[nr].obj = 0;
226 + } else {
227 + struct object *obj;
228 + int eaten;
229 + hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
230 + obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
231 + if (!obj)
232 + die("invalid %s", typename(type));
233 + /* buf is stored via add_object_buffer and in obj, if its a tree or commit */
234 + add_object_buffer(obj, buf, size);
235 + obj->flags |= FLAG_OPEN;
236 + obj_list[nr].obj = obj;
237 + }
238 }
239
240 static void resolve_delta(unsigned nr, enum object_type type,
@@ -163,7 +251,6 @@ static void resolve_delta(unsigned nr, enum object_type type,
251 die("failed to apply delta");
252 free(delta);
253 write_object(nr, type, result, result_size);
166 - free(result);
254 }
255
256 static void added_object(unsigned nr, enum object_type type,
@@ -193,7 +280,8 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
280
281 if (!dry_run && buf)
282 write_object(nr, type, buf, size);
196 - free(buf);
283 + else
284 + free(buf);
285 }
286
287 static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
@@ -336,7 +424,8 @@ static void unpack_all(void)
424 int i;
425 struct progress *progress = NULL;
426 struct pack_header *hdr = fill(sizeof(struct pack_header));
339 - unsigned nr_objects = ntohl(hdr->hdr_entries);
427 +
428 + nr_objects = ntohl(hdr->hdr_entries);
429
430 if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
431 die("bad pack file");
@@ -347,6 +436,7 @@ static void unpack_all(void)
436 if (!quiet)
437 progress = start_progress("Unpacking objects", nr_objects);
438 obj_list = xmalloc(nr_objects * sizeof(*obj_list));
439 + memset(obj_list, 0, nr_objects * sizeof(*obj_list));
440 for (i = 0; i < nr_objects; i++) {
441 unpack_one(i);
442 display_progress(progress, i + 1);
@@ -382,6 +472,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
472 recover = 1;
473 continue;
474 }
475 + if (!strcmp(arg, "--strict")) {
476 + strict = 1;
477 + continue;
478 + }
479 if (!prefixcmp(arg, "--pack_header=")) {
480 struct pack_header *hdr;
481 char *c;
@@ -407,6 +501,8 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
501 unpack_all();
502 SHA1_Update(&ctx, buffer, offset);
503 SHA1_Final(sha1, &ctx);
504 + if (strict)
505 + write_rest();
506 if (hashcmp(fill(20), sha1))
507 die("final sha1 did not match");
508 use(20);