Document levenshtein.c
[gitweb.git] / index-pack.c
index 82843e7e8df2a77ec1aca41acee5ac8834724586..60ed41a993bf9e213b7dfde5ff43528eff6b6252 100644 (file)
@@ -221,17 +221,23 @@ static void bad_object(unsigned long offset, const char *format, ...)
        die("pack has bad object at offset %lu: %s", offset, buf);
 }
 
+static void free_base_data(struct base_data *c)
+{
+       if (c->data) {
+               free(c->data);
+               c->data = NULL;
+               base_cache_used -= c->size;
+       }
+}
+
 static void prune_base_data(struct base_data *retain)
 {
        struct base_data *b = base_cache;
        for (b = base_cache;
             base_cache_used > delta_base_cache_limit && b;
             b = b->child) {
-               if (b->data && b != retain) {
-                       free(b->data);
-                       b->data = NULL;
-                       base_cache_used -= b->size;
-               }
+               if (b->data && b != retain)
+                       free_base_data(b);
        }
 }
 
@@ -256,10 +262,7 @@ static void unlink_base_data(struct base_data *c)
                base->child = NULL;
        else
                base_cache = NULL;
-       if (c->data) {
-               free(c->data);
-               base_cache_used -= c->size;
-       }
+       free_base_data(c);
 }
 
 static void *unpack_entry_data(unsigned long offset, unsigned long size)
@@ -335,7 +338,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
                        base_offset = (base_offset << 7) + (c & 127);
                }
                delta_base->offset = obj->idx.offset - base_offset;
-               if (delta_base->offset >= obj->idx.offset)
+               if (delta_base->offset <= 0 || delta_base->offset >= obj->idx.offset)
                        bad_object(obj->idx.offset, "delta base offset is out of bound");
                break;
        case OBJ_COMMIT:
@@ -409,22 +412,24 @@ static int find_delta(const union delta_base *base)
         return -first-1;
 }
 
-static int find_delta_children(const union delta_base *base,
-                              int *first_index, int *last_index)
+static void find_delta_children(const union delta_base *base,
+                               int *first_index, int *last_index)
 {
        int first = find_delta(base);
        int last = first;
        int end = nr_deltas - 1;
 
-       if (first < 0)
-               return -1;
+       if (first < 0) {
+               *first_index = 0;
+               *last_index = -1;
+               return;
+       }
        while (first > 0 && !memcmp(&deltas[first - 1].base, base, UNION_BASE_SZ))
                --first;
        while (last < end && !memcmp(&deltas[last + 1].base, base, UNION_BASE_SZ))
                ++last;
        *first_index = first;
        *last_index = last;
-       return 0;
 }
 
 static void sha1_object(const void *data, unsigned long size,
@@ -509,15 +514,14 @@ static void *get_base_data(struct base_data *c)
 static void resolve_delta(struct object_entry *delta_obj,
                          struct base_data *base, struct base_data *result)
 {
-       void *delta_data;
-       unsigned long delta_size;
+       void *base_data, *delta_data;
 
-       delta_obj->real_type = base->obj->type;
+       delta_obj->real_type = base->obj->real_type;
        delta_data = get_data_from_pack(delta_obj);
-       delta_size = delta_obj->size;
+       base_data = get_base_data(base);
        result->obj = delta_obj;
-       result->data = patch_delta(get_base_data(base), base->obj->size,
-                                  delta_data, delta_size, &result->size);
+       result->data = patch_delta(base_data, base->size,
+                                  delta_data, delta_obj->size, &result->size);
        free(delta_data);
        if (!result->data)
                bad_object(delta_obj->idx.offset, "failed to apply delta");
@@ -529,7 +533,7 @@ static void resolve_delta(struct object_entry *delta_obj,
 static void find_unresolved_deltas(struct base_data *base,
                                   struct base_data *prev_base)
 {
-       int i, ref, ref_first, ref_last, ofs, ofs_first, ofs_last;
+       int i, ref_first, ref_last, ofs_first, ofs_last;
 
        /*
         * This is a recursive function. Those brackets should help reducing
@@ -539,37 +543,39 @@ static void find_unresolved_deltas(struct base_data *base,
                union delta_base base_spec;
 
                hashcpy(base_spec.sha1, base->obj->idx.sha1);
-               ref = !find_delta_children(&base_spec, &ref_first, &ref_last);
+               find_delta_children(&base_spec, &ref_first, &ref_last);
 
                memset(&base_spec, 0, sizeof(base_spec));
                base_spec.offset = base->obj->idx.offset;
-               ofs = !find_delta_children(&base_spec, &ofs_first, &ofs_last);
+               find_delta_children(&base_spec, &ofs_first, &ofs_last);
        }
 
-       if (!ref && !ofs)
+       if (ref_last == -1 && ofs_last == -1) {
+               free(base->data);
                return;
+       }
 
        link_base_data(prev_base, base);
 
-       if (ref) {
-               for (i = ref_first; i <= ref_last; i++) {
-                       struct object_entry *child = objects + deltas[i].obj_no;
-                       if (child->real_type == OBJ_REF_DELTA) {
-                               struct base_data result;
-                               resolve_delta(child, base, &result);
-                               find_unresolved_deltas(&result, base);
-                       }
+       for (i = ref_first; i <= ref_last; i++) {
+               struct object_entry *child = objects + deltas[i].obj_no;
+               if (child->real_type == OBJ_REF_DELTA) {
+                       struct base_data result;
+                       resolve_delta(child, base, &result);
+                       if (i == ref_last && ofs_last == -1)
+                               free_base_data(base);
+                       find_unresolved_deltas(&result, base);
                }
        }
 
-       if (ofs) {
-               for (i = ofs_first; i <= ofs_last; i++) {
-                       struct object_entry *child = objects + deltas[i].obj_no;
-                       if (child->real_type == OBJ_OFS_DELTA) {
-                               struct base_data result;
-                               resolve_delta(child, base, &result);
-                               find_unresolved_deltas(&result, base);
-                       }
+       for (i = ofs_first; i <= ofs_last; i++) {
+               struct object_entry *child = objects + deltas[i].obj_no;
+               if (child->real_type == OBJ_OFS_DELTA) {
+                       struct base_data result;
+                       resolve_delta(child, base, &result);
+                       if (i == ofs_last)
+                               free_base_data(base);
+                       find_unresolved_deltas(&result, base);
                }
        }
 
@@ -783,7 +789,6 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                err = close(output_fd);
                if (err)
                        die("error while closing pack file: %s", strerror(errno));
-               chmod(curr_pack_name, 0444);
        }
 
        if (keep_msg) {
@@ -817,8 +822,9 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                if (move_temp_to_file(curr_pack_name, final_pack_name))
                        die("cannot store pack file");
        }
+       if (from_stdin)
+               chmod(final_pack_name, 0444);
 
-       chmod(curr_index_name, 0444);
        if (final_index_name != curr_index_name) {
                if (!final_index_name) {
                        snprintf(name, sizeof(name), "%s/pack/pack-%s.idx",
@@ -828,6 +834,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                if (move_temp_to_file(curr_index_name, final_index_name))
                        die("cannot store index file");
        }
+       chmod(final_index_name, 0444);
 
        if (!from_stdin) {
                printf("%s\n", sha1_to_hex(sha1));
@@ -872,10 +879,26 @@ int main(int argc, char **argv)
        char *index_name_buf = NULL, *keep_name_buf = NULL;
        struct pack_idx_entry **idx_objects;
        unsigned char pack_sha1[20];
-       int nongit = 0;
 
-       setup_git_directory_gently(&nongit);
-       git_config(git_index_pack_config, NULL);
+       /*
+        * We wish to read the repository's config file if any, and
+        * for that it is necessary to call setup_git_directory_gently().
+        * However if the cwd was inside .git/objects/pack/ then we need
+        * to go back there or all the pack name arguments will be wrong.
+        * And in that case we cannot rely on any prefix returned by
+        * setup_git_directory_gently() either.
+        */
+       {
+               char cwd[PATH_MAX+1];
+               int nongit;
+
+               if (!getcwd(cwd, sizeof(cwd)-1))
+                       die("Unable to get current working directory");
+               setup_git_directory_gently(&nongit);
+               git_config(git_index_pack_config, NULL);
+               if (chdir(cwd))
+                       die("Cannot come back to cwd");
+       }
 
        for (i = 1; i < argc; i++) {
                char *arg = argv[i];