+ free(buf);
+
+ SHA1_Final(pack_data->sha1, &c);
+ write_or_die(pack_fd, pack_data->sha1, sizeof(pack_data->sha1));
+ close(pack_fd);
+}
+
+static int oecmp (const void *a_, const void *b_)
+{
+ struct object_entry *a = *((struct object_entry**)a_);
+ struct object_entry *b = *((struct object_entry**)b_);
+ return hashcmp(a->sha1, b->sha1);
+}
+
+static char* create_index()
+{
+ static char tmpfile[PATH_MAX];
+ SHA_CTX ctx;
+ struct sha1file *f;
+ struct object_entry **idx, **c, **last, *e;
+ struct object_entry_pool *o;
+ unsigned int array[256];
+ int i, idx_fd;
+
+ /* Build the sorted table of object IDs. */
+ idx = xmalloc(object_count * sizeof(struct object_entry*));
+ c = idx;
+ for (o = blocks; o; o = o->next_pool)
+ for (e = o->next_free; e-- != o->entries;)
+ if (pack_id == e->pack_id)
+ *c++ = e;
+ last = idx + object_count;
+ if (c != last)
+ die("internal consistency error creating the index");
+ qsort(idx, object_count, sizeof(struct object_entry*), oecmp);
+
+ /* Generate the fan-out array. */
+ c = idx;
+ for (i = 0; i < 256; i++) {
+ struct object_entry **next = c;;
+ while (next < last) {
+ if ((*next)->sha1[0] != i)
+ break;
+ next++;
+ }
+ array[i] = htonl(next - idx);
+ c = next;
+ }
+
+ snprintf(tmpfile, sizeof(tmpfile),
+ "%s/index_XXXXXX", get_object_directory());
+ idx_fd = mkstemp(tmpfile);
+ if (idx_fd < 0)
+ die("Can't create %s: %s", tmpfile, strerror(errno));
+ f = sha1fd(idx_fd, tmpfile);
+ sha1write(f, array, 256 * sizeof(int));
+ SHA1_Init(&ctx);
+ for (c = idx; c != last; c++) {
+ unsigned int offset = htonl((*c)->offset);
+ sha1write(f, &offset, 4);
+ sha1write(f, (*c)->sha1, sizeof((*c)->sha1));
+ SHA1_Update(&ctx, (*c)->sha1, 20);
+ }
+ sha1write(f, pack_data->sha1, sizeof(pack_data->sha1));
+ sha1close(f, NULL, 1);
+ free(idx);
+ SHA1_Final(pack_data->sha1, &ctx);
+ return tmpfile;
+}
+
+static char* keep_pack(char *curr_index_name)
+{
+ static char name[PATH_MAX];
+ static char *keep_msg = "fast-import";
+ int keep_fd;
+
+ chmod(pack_data->pack_name, 0444);
+ chmod(curr_index_name, 0444);
+
+ snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
+ get_object_directory(), sha1_to_hex(pack_data->sha1));
+ keep_fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (keep_fd < 0)
+ die("cannot create keep file");
+ write(keep_fd, keep_msg, strlen(keep_msg));
+ close(keep_fd);
+
+ snprintf(name, sizeof(name), "%s/pack/pack-%s.pack",
+ get_object_directory(), sha1_to_hex(pack_data->sha1));
+ if (move_temp_to_file(pack_data->pack_name, name))
+ die("cannot store pack file");
+
+ snprintf(name, sizeof(name), "%s/pack/pack-%s.idx",
+ get_object_directory(), sha1_to_hex(pack_data->sha1));
+ if (move_temp_to_file(curr_index_name, name))
+ die("cannot store index file");
+ return name;
+}
+
+static void unkeep_all_packs()
+{
+ static char name[PATH_MAX];
+ int k;
+
+ for (k = 0; k < pack_id; k++) {
+ struct packed_git *p = all_packs[k];
+ snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
+ get_object_directory(), sha1_to_hex(p->sha1));
+ unlink(name);
+ }
+}
+
+static void end_packfile()
+{
+ struct packed_git *old_p = pack_data, *new_p;
+
+ if (object_count) {
+ char *idx_name;
+ int i;
+ struct branch *b;
+ struct tag *t;
+
+ fixup_header_footer();
+ idx_name = keep_pack(create_index());
+
+ /* Register the packfile with core git's machinary. */
+ new_p = add_packed_git(idx_name, strlen(idx_name), 1);
+ if (!new_p)
+ die("core git rejected index %s", idx_name);
+ new_p->windows = old_p->windows;
+ all_packs[pack_id] = new_p;
+ install_packed_git(new_p);
+
+ /* Print the boundary */
+ fprintf(stdout, "%s:", new_p->pack_name);
+ for (i = 0; i < branch_table_sz; i++) {
+ for (b = branch_table[i]; b; b = b->table_next_branch) {
+ if (b->pack_id == pack_id)
+ fprintf(stdout, " %s", sha1_to_hex(b->sha1));
+ }
+ }
+ for (t = first_tag; t; t = t->next_tag) {
+ if (t->pack_id == pack_id)
+ fprintf(stdout, " %s", sha1_to_hex(t->sha1));
+ }
+ fputc('\n', stdout);
+
+ pack_id++;
+ }
+ else
+ unlink(old_p->pack_name);
+ free(old_p);
+
+ /* We can't carry a delta across packfiles. */
+ free(last_blob.data);
+ last_blob.data = NULL;
+ last_blob.len = 0;
+ last_blob.offset = 0;
+ last_blob.depth = 0;
+}
+
+static void checkpoint()
+{
+ end_packfile();
+ start_packfile();