rev-parse --branches/--tags/--remotes=pattern
[gitweb.git] / builtin-unpack-objects.c
index 9d2a8549509658d32f25a1bc6af0552dc8380988..685566e0b5e458c510fdf989744d63dda29e28f0 100644 (file)
 #include "fsck.h"
 
 static int dry_run, quiet, recover, has_errors, strict;
-static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
+static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
 
 /* We always read in 4kB chunks. */
 static unsigned char buffer[4096];
 static unsigned int offset, len;
 static off_t consumed_bytes;
-static SHA_CTX ctx;
+static git_SHA_CTX ctx;
 
+/*
+ * When running under --strict mode, objects whose reachability are
+ * suspect are kept in core without getting written in the object
+ * store.
+ */
 struct obj_buffer {
        char *buffer;
        unsigned long size;
@@ -54,7 +59,7 @@ static void *fill(int min)
        if (min > sizeof(buffer))
                die("cannot fill %d bytes", min);
        if (offset) {
-               SHA1_Update(&ctx, buffer, offset);
+               git_SHA1_Update(&ctx, buffer, offset);
                memmove(buffer, buffer + offset, len);
                offset = 0;
        }
@@ -63,7 +68,7 @@ static void *fill(int min)
                if (ret <= 0) {
                        if (!ret)
                                die("early EOF");
-                       die("read error on input: %s", strerror(errno));
+                       die_errno("read error on input");
                }
                len += ret;
        } while (len < min);
@@ -94,10 +99,10 @@ static void *get_data(unsigned long size)
        stream.avail_out = size;
        stream.next_in = fill(1);
        stream.avail_in = len;
-       inflateInit(&stream);
+       git_inflate_init(&stream);
 
        for (;;) {
-               int ret = inflate(&stream, 0);
+               int ret = git_inflate(&stream, 0);
                use(len - stream.avail_in);
                if (stream.total_out == size && ret == Z_STREAM_END)
                        break;
@@ -113,7 +118,7 @@ static void *get_data(unsigned long size)
                stream.next_in = fill(1);
                stream.avail_in = len;
        }
-       inflateEnd(&stream);
+       git_inflate_end(&stream);
        return buf;
 }
 
@@ -153,8 +158,12 @@ struct obj_info {
 #define FLAG_WRITTEN (1u<<21)
 
 static struct obj_info *obj_list;
-unsigned nr_objects;
+static unsigned nr_objects;
 
+/*
+ * Called only from check_object() after it verified this object
+ * is Ok.
+ */
 static void write_cached_object(struct object *obj)
 {
        unsigned char sha1[20];
@@ -164,13 +173,18 @@ static void write_cached_object(struct object *obj)
        obj->flags |= FLAG_WRITTEN;
 }
 
+/*
+ * At the very end of the processing, write_rest() scans the objects
+ * that have reachability requirements and calls this function.
+ * Verify its reachability and validity recursively and write it out.
+ */
 static int check_object(struct object *obj, int type, void *data)
 {
        if (!obj)
-               return 0;
+               return 1;
 
        if (obj->flags & FLAG_WRITTEN)
-               return 1;
+               return 0;
 
        if (type != OBJ_ANY && obj->type != type)
                die("object type mismatch");
@@ -181,40 +195,48 @@ static int check_object(struct object *obj, int type, void *data)
                if (type != obj->type || type <= 0)
                        die("object of unexpected type");
                obj->flags |= FLAG_WRITTEN;
-               return 1;
+               return 0;
        }
 
        if (fsck_object(obj, 1, fsck_error_function))
                die("Error in object");
-       if (!fsck_walk(obj, check_object, 0))
+       if (fsck_walk(obj, check_object, NULL))
                die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
        write_cached_object(obj);
-       return 1;
+       return 0;
 }
 
 static void write_rest(void)
 {
        unsigned i;
-       for (i = 0; i < nr_objects; i++)
-               check_object(obj_list[i].obj, OBJ_ANY, 0);
+       for (i = 0; i < nr_objects; i++) {
+               if (obj_list[i].obj)
+                       check_object(obj_list[i].obj, OBJ_ANY, NULL);
+       }
 }
 
 static void added_object(unsigned nr, enum object_type type,
                         void *data, unsigned long size);
 
+/*
+ * Write out nr-th object from the list, now we know the contents
+ * of it.  Under --strict, this buffers structured objects in-core,
+ * to be checked at the end.
+ */
 static void write_object(unsigned nr, enum object_type type,
                         void *buf, unsigned long size)
 {
-       added_object(nr, type, buf, size);
        if (!strict) {
                if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
                        die("failed to write object");
+               added_object(nr, type, buf, size);
                free(buf);
-               obj_list[nr].obj = 0;
+               obj_list[nr].obj = NULL;
        } else if (type == OBJ_BLOB) {
                struct blob *blob;
                if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
                        die("failed to write object");
+               added_object(nr, type, buf, size);
                free(buf);
 
                blob = lookup_blob(obj_list[nr].sha1);
@@ -222,15 +244,15 @@ static void write_object(unsigned nr, enum object_type type,
                        blob->object.flags |= FLAG_WRITTEN;
                else
                        die("invalid blob object");
-               obj_list[nr].obj = 0;
+               obj_list[nr].obj = NULL;
        } else {
                struct object *obj;
                int eaten;
                hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
+               added_object(nr, type, buf, size);
                obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
                if (!obj)
                        die("invalid %s", typename(type));
-               /* buf is stored via add_object_buffer and in obj, if its a tree or commit */
                add_object_buffer(obj, buf, size);
                obj->flags |= FLAG_OPEN;
                obj_list[nr].obj = obj;
@@ -253,6 +275,10 @@ static void resolve_delta(unsigned nr, enum object_type type,
        write_object(nr, type, result, result_size);
 }
 
+/*
+ * We now know the contents of an object (which is nr-th in the pack);
+ * resolve all the deltified objects that are based on it.
+ */
 static void added_object(unsigned nr, enum object_type type,
                         void *data, unsigned long size)
 {
@@ -284,13 +310,28 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
                free(buf);
 }
 
+static int resolve_against_held(unsigned nr, const unsigned char *base,
+                               void *delta_data, unsigned long delta_size)
+{
+       struct object *obj;
+       struct obj_buffer *obj_buffer;
+       obj = lookup_object(base);
+       if (!obj)
+               return 0;
+       obj_buffer = lookup_object_buffer(obj);
+       if (!obj_buffer)
+               return 0;
+       resolve_delta(nr, obj->type, obj_buffer->buffer,
+                     obj_buffer->size, delta_data, delta_size);
+       return 1;
+}
+
 static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                               unsigned nr)
 {
        void *delta_data, *base;
        unsigned long base_size;
        unsigned char base_sha1[20];
-       struct object *obj;
 
        if (type == OBJ_REF_DELTA) {
                hashcpy(base_sha1, fill(20));
@@ -300,7 +341,13 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                        free(delta_data);
                        return;
                }
-               if (!has_sha1_file(base_sha1)) {
+               if (has_sha1_file(base_sha1))
+                       ; /* Ok we have this one */
+               else if (resolve_against_held(nr, base_sha1,
+                                             delta_data, delta_size))
+                       return; /* we are done */
+               else {
+                       /* cannot resolve yet --- queue it */
                        hashcpy(obj_list[nr].sha1, null_sha1);
                        add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
                        return;
@@ -325,6 +372,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                        base_offset = (base_offset << 7) + (c & 127);
                }
                base_offset = obj_list[nr].offset - base_offset;
+               if (base_offset <= 0 || base_offset >= obj_list[nr].offset)
+                       die("offset value out of bound for delta base object");
 
                delta_data = get_data(delta_size);
                if (dry_run || !delta_data) {
@@ -346,22 +395,18 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                        }
                }
                if (!base_found) {
-                       /* The delta base object is itself a delta that
-                          has not been resolved yet. */
+                       /*
+                        * The delta base object is itself a delta that
+                        * has not been resolved yet.
+                        */
                        hashcpy(obj_list[nr].sha1, null_sha1);
                        add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
                        return;
                }
        }
 
-       obj = lookup_object(base_sha1);
-       if (obj) {
-               struct obj_buffer *obj_buf = lookup_object_buffer(obj);
-               if (obj_buf) {
-                       resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
-                       return;
-               }
-       }
+       if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
+               return;
 
        base = read_sha1_file(base_sha1, &type, &base_size);
        if (!base) {
@@ -379,8 +424,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
 static void unpack_one(unsigned nr)
 {
        unsigned shift;
-       unsigned char *pack, c;
-       unsigned long size;
+       unsigned char *pack;
+       unsigned long size, c;
        enum object_type type;
 
        obj_list[nr].offset = consumed_bytes;
@@ -430,13 +475,13 @@ static void unpack_all(void)
        if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
                die("bad pack file");
        if (!pack_version_ok(hdr->hdr_version))
-               die("unknown pack file version %d", ntohl(hdr->hdr_version));
+               die("unknown pack file version %"PRIu32,
+                       ntohl(hdr->hdr_version));
        use(sizeof(struct pack_header));
 
        if (!quiet)
                progress = start_progress("Unpacking objects", nr_objects);
-       obj_list = xmalloc(nr_objects * sizeof(*obj_list));
-       memset(obj_list, 0, nr_objects * sizeof(*obj_list));
+       obj_list = xcalloc(nr_objects, sizeof(*obj_list));
        for (i = 0; i < nr_objects; i++) {
                unpack_one(i);
                display_progress(progress, i + 1);
@@ -452,7 +497,9 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
        int i;
        unsigned char sha1[20];
 
-       git_config(git_default_config);
+       read_replace_refs = 0;
+
+       git_config(git_default_config, NULL);
 
        quiet = !isatty(2);
 
@@ -497,10 +544,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
                /* We don't take any non-flag arguments now.. Maybe some day */
                usage(unpack_usage);
        }
-       SHA1_Init(&ctx);
+       git_SHA1_Init(&ctx);
        unpack_all();
-       SHA1_Update(&ctx, buffer, offset);
-       SHA1_Final(sha1, &ctx);
+       git_SHA1_Update(&ctx, buffer, offset);
+       git_SHA1_Final(sha1, &ctx);
        if (strict)
                write_rest();
        if (hashcmp(fill(20), sha1))