diff options
Diffstat (limited to 'builtin-pack-objects.c')
-rw-r--r-- | builtin-pack-objects.c | 127 |
1 files changed, 72 insertions, 55 deletions
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index c2f7c30817..7af1776673 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -59,17 +59,16 @@ struct object_entry { * heuristics. */ -static unsigned char object_list_sha1[20]; static int non_empty; static int no_reuse_delta; static int local; static int incremental; static int allow_ofs_delta; -static struct object_entry **sorted_by_sha; static struct object_entry *objects; static uint32_t nr_objects, nr_alloc, nr_result; -static const char *base_name; +static const char *pack_tmp_name, *idx_tmp_name; +static char tmpname[PATH_MAX]; static unsigned char pack_file_sha1[20]; static int progress = 1; static volatile sig_atomic_t progress_update; @@ -578,13 +577,19 @@ static off_t write_pack_file(void) unsigned last_percent = 999; int do_progress = progress; - if (!base_name) { + if (pack_to_stdout) { f = sha1fd(1, "<stdout>"); do_progress >>= 1; + } else { + int fd; + snprintf(tmpname, sizeof(tmpname), "tmp_pack_XXXXXX"); + fd = mkstemp(tmpname); + if (fd < 0) + die("unable to create %s: %s\n", tmpname, strerror(errno)); + pack_tmp_name = xstrdup(tmpname); + f = sha1fd(fd, pack_tmp_name); } - else - f = sha1create("%s-%s.%s", base_name, - sha1_to_hex(object_list_sha1), "pack"); + if (do_progress) fprintf(stderr, "Writing %u objects.\n", nr_result); @@ -618,18 +623,46 @@ static off_t write_pack_file(void) return last_obj_offset; } +static int sha1_sort(const void *_a, const void *_b) +{ + const struct object_entry *a = *(struct object_entry **)_a; + const struct object_entry *b = *(struct object_entry **)_b; + return hashcmp(a->sha1, b->sha1); +} + static uint32_t index_default_version = 1; static uint32_t index_off32_limit = 0x7fffffff; -static void write_index_file(off_t last_obj_offset) +static void write_index_file(off_t last_obj_offset, unsigned char *sha1) { - uint32_t i; - struct sha1file *f = sha1create("%s-%s.%s", base_name, - sha1_to_hex(object_list_sha1), "idx"); - struct object_entry **list = sorted_by_sha; - struct object_entry **last = list + nr_result; + struct sha1file *f; + struct object_entry **sorted_by_sha, **list, **last; uint32_t array[256]; - uint32_t index_version; + uint32_t i, index_version; + SHA_CTX ctx; + int fd; + + snprintf(tmpname, sizeof(tmpname), "tmp_idx_XXXXXX"); + fd = mkstemp(tmpname); + if (fd < 0) + die("unable to create %s: %s\n", tmpname, strerror(errno)); + idx_tmp_name = xstrdup(tmpname); + f = sha1fd(fd, idx_tmp_name); + + if (nr_result) { + uint32_t j = 0; + sorted_by_sha = + xcalloc(nr_result, sizeof(struct object_entry *)); + for (i = 0; i < nr_objects; i++) + if (!objects[i].preferred_base) + sorted_by_sha[j++] = objects + i; + if (j != nr_result) + die("listed %u objects while expecting %u", j, nr_result); + qsort(sorted_by_sha, nr_result, sizeof(*sorted_by_sha), sha1_sort); + list = sorted_by_sha; + last = sorted_by_sha + nr_result; + } else + sorted_by_sha = list = last = NULL; /* if last object's offset is >= 2^31 we should use index V2 */ index_version = (last_obj_offset >> 31) ? 2 : index_default_version; @@ -660,9 +693,10 @@ static void write_index_file(off_t last_obj_offset) } sha1write(f, array, 256 * 4); - /* - * Write the actual SHA1 entries.. - */ + /* Compute the SHA1 hash of sorted object names. */ + SHA1_Init(&ctx); + + /* Write the actual SHA1 entries. */ list = sorted_by_sha; for (i = 0; i < nr_result; i++) { struct object_entry *entry = *list++; @@ -671,6 +705,7 @@ static void write_index_file(off_t last_obj_offset) sha1write(f, &offset, 4); } sha1write(f, entry->sha1, 20); + SHA1_Update(&ctx, entry->sha1, 20); } if (index_version >= 2) { @@ -711,6 +746,8 @@ static void write_index_file(off_t last_obj_offset) sha1write(f, pack_file_sha1, 20); sha1close(f, NULL, 1); + free(sorted_by_sha); + SHA1_Final(sha1, &ctx); } static int locate_object_entry_hash(const unsigned char *sha1) @@ -789,6 +826,8 @@ static int add_object_entry(const unsigned char *sha1, unsigned hash, int exclud if (ix >= 0) { if (exclude) { entry = objects + object_ix[ix] - 1; + if (!entry->preferred_base) + nr_result--; entry->preferred_base = 1; } return 0; @@ -821,6 +860,8 @@ static int add_object_entry(const unsigned char *sha1, unsigned hash, int exclud entry->hash = hash; if (exclude) entry->preferred_base = 1; + else + nr_result++; if (found_pack) { entry->in_pack = found_pack; entry->in_pack_offset = found_offset; @@ -1181,30 +1222,6 @@ static void get_object_details(void) check_object(entry); } -static int sha1_sort(const void *_a, const void *_b) -{ - const struct object_entry *a = *(struct object_entry **)_a; - const struct object_entry *b = *(struct object_entry **)_b; - return hashcmp(a->sha1, b->sha1); -} - -static struct object_entry **create_final_object_list(void) -{ - struct object_entry **list; - uint32_t i, j; - - for (i = nr_result = 0; i < nr_objects; i++) - if (!objects[i].preferred_base) - nr_result++; - list = xmalloc(nr_result * sizeof(struct object_entry *)); - for (i = j = 0; i < nr_objects; i++) { - if (!objects[i].preferred_base) - list[j++] = objects + i; - } - qsort(list, nr_result, sizeof(struct object_entry *), sha1_sort); - return list; -} - static int type_size_sort(const void *_a, const void *_b) { const struct object_entry *a = *(struct object_entry **)_a; @@ -1561,13 +1578,12 @@ static void get_object_list(int ac, const char **av) int cmd_pack_objects(int argc, const char **argv, const char *prefix) { - SHA_CTX ctx; int depth = 10; - struct object_entry **list; - off_t last_obj_offset; int use_internal_rev_list = 0; int thin = 0; uint32_t i; + off_t last_obj_offset; + const char *base_name = NULL; const char **rp_av; int rp_ac_alloc = 64; int rp_ac; @@ -1712,20 +1728,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) if (progress) fprintf(stderr, "Done counting %u objects.\n", nr_objects); - sorted_by_sha = create_final_object_list(); if (non_empty && !nr_result) return 0; - - SHA1_Init(&ctx); - list = sorted_by_sha; - for (i = 0; i < nr_result; i++) { - struct object_entry *entry = *list++; - SHA1_Update(&ctx, entry->sha1, 20); - } - SHA1_Final(object_list_sha1, &ctx); if (progress && (nr_objects != nr_result)) fprintf(stderr, "Result has %u objects.\n", nr_result); - if (nr_result) prepare_pack(window, depth); if (progress == 1 && pack_to_stdout) { @@ -1737,7 +1743,18 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) } last_obj_offset = write_pack_file(); if (!pack_to_stdout) { - write_index_file(last_obj_offset); + unsigned char object_list_sha1[20]; + write_index_file(last_obj_offset, object_list_sha1); + snprintf(tmpname, sizeof(tmpname), "%s-%s.pack", + base_name, sha1_to_hex(object_list_sha1)); + if (rename(pack_tmp_name, tmpname)) + die("unable to rename temporary pack file: %s", + strerror(errno)); + snprintf(tmpname, sizeof(tmpname), "%s-%s.idx", + base_name, sha1_to_hex(object_list_sha1)); + if (rename(idx_tmp_name, tmpname)) + die("unable to rename temporary index file: %s", + strerror(errno)); puts(sha1_to_hex(object_list_sha1)); } if (progress) |