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
d5ef408b9afb5b4417f4e7e1593a96302d666650
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);