aboutsummaryrefslogtreecommitdiff
path: root/builtin-pack-objects.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin-pack-objects.c')
-rw-r--r--builtin-pack-objects.c127
1 files changed, 72 insertions, 55 deletions
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index c2f7c3081..7af177667 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)