Use .keep files in fast-import during processing.
authorShawn O. Pearce <spearce@spearce.org>
Tue, 16 Jan 2007 06:15:31 +0000 (01:15 -0500)
committerShawn O. Pearce <spearce@spearce.org>
Tue, 16 Jan 2007 06:15:31 +0000 (01:15 -0500)
Because fast-import automatically updates all references (heads
and tags) at the end of its run the repository is corrupt unless
the objects are available in the .git/objects/pack directory prior
to the refs being modified.  The easiest way to ensure that is true
is to move the packfile and its associated index directly into the
.git/objects/pack directory as soon as we have finished output to it.

But the only safe way to do this is to create the a temporary .keep
file for that pack, so we use the same tricks that index-pack uses
when its being invoked by receive-pack.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
fast-import.c

index 5767e808c65144739e47cab1e9f32703d2377a91..393020504a1d2ac3690298398a033c6a4d6ea819 100644 (file)
@@ -241,9 +241,7 @@ static unsigned int atom_cnt;
 static struct atom_str **atom_table;
 
 /* The .pack file being generated */
-static const char *base_name;
 static unsigned int pack_id;
-static char *idx_name;
 static struct packed_git *pack_data;
 static struct packed_git **all_packs;
 static int pack_fd;
@@ -591,17 +589,17 @@ static void release_tree_entry(struct tree_entry *e)
 
 static void start_packfile()
 {
+       static char tmpfile[PATH_MAX];
        struct packed_git *p;
        struct pack_header hdr;
 
-       idx_name = xmalloc(strlen(base_name) + 11);
-       p = xcalloc(1, sizeof(*p) + strlen(base_name) + 13);
-       sprintf(p->pack_name, "%s%5.5i.pack", base_name, pack_id + 1);
-       sprintf(idx_name, "%s%5.5i.idx", base_name, pack_id + 1);
-
-       pack_fd = open(p->pack_name, O_RDWR|O_CREAT|O_EXCL, 0666);
+       snprintf(tmpfile, sizeof(tmpfile),
+               "%s/pack_XXXXXX", get_object_directory());
+       pack_fd = mkstemp(tmpfile);
        if (pack_fd < 0)
-               die("Can't create %s: %s", p->pack_name, strerror(errno));
+               die("Can't create %s: %s", tmpfile, strerror(errno));
+       p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
+       strcpy(p->pack_name, tmpfile);
        p->pack_fd = pack_fd;
 
        hdr.hdr_signature = htonl(PACK_SIGNATURE);
@@ -656,13 +654,15 @@ static int oecmp (const void *a_, const void *b_)
        return hashcmp(a->sha1, b->sha1);
 }
 
-static void write_index(const char *idx_name)
+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;
+       int i, idx_fd;
 
        /* Build the sorted table of object IDs. */
        idx = xmalloc(object_count * sizeof(struct object_entry*));
@@ -689,16 +689,68 @@ static void write_index(const char *idx_name)
                c = next;
        }
 
-       f = sha1create("%s", idx_name);
+       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, pack_data->sha1, 1);
+       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");
+       printf("%s\n", name);
+
+       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()
@@ -706,10 +758,10 @@ static void end_packfile()
        struct packed_git *old_p = pack_data, *new_p;
 
        if (object_count) {
+               char *idx_name;
+
                fixup_header_footer();
-               write_index(idx_name);
-               fprintf(stdout, "%s\n", old_p->pack_name);
-               fflush(stdout);
+               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);
@@ -725,7 +777,6 @@ static void end_packfile()
                unlink(old_p->pack_name);
        }
        free(old_p);
-       free(idx_name);
 
        /* We can't carry a delta across packfiles. */
        free(last_blob.data);
@@ -1790,7 +1841,7 @@ static void cmd_checkpoint()
 }
 
 static const char fast_import_usage[] =
-"git-fast-import [--objects=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file] [--branch-log=log] temp.pack";
+"git-fast-import [--objects=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file] [--branch-log=log]";
 
 int main(int argc, const char **argv)
 {
@@ -1826,9 +1877,8 @@ int main(int argc, const char **argv)
                else
                        die("unknown option %s", a);
        }
-       if ((i+1) != argc)
+       if (i != argc)
                usage(fast_import_usage);
-       base_name = argv[i];
 
        alloc_objects(est_obj_cnt);
        strbuf_init(&command_buf);
@@ -1860,6 +1910,7 @@ int main(int argc, const char **argv)
 
        dump_branches();
        dump_tags();
+       unkeep_all_packs();
        dump_marks();
        if (branch_log)
                fclose(branch_log);