]> git.ipfire.org Git - thirdparty/git.git/blobdiff - fast-import.c
Correct a few types to be unsigned in fast-import.
[thirdparty/git.git] / fast-import.c
index ebffa7c904bc892dc086aa8a53257253764d2453..2c500d6be32e8b83e8c7bd0c3768f3b9e6a08907 100644 (file)
@@ -72,6 +72,7 @@ Format of STDIN stream:
   path_str    ::= path    | '"' quoted(path)    '"' ;
 
   declen ::= # unsigned 32 bit value, ascii base10 notation;
+  bigint ::= # unsigned integer value, ascii base10 notation;
   binary_data ::= # file content, not interpreted;
 
   sp ::= # ASCII space character;
@@ -81,7 +82,7 @@ Format of STDIN stream:
         # an idnum.  This is to distinguish it from a ref or tag name as
      # GIT does not permit ':' in ref or tag strings.
         #
-  idnum   ::= ':' declen;
+  idnum   ::= ':' bigint;
   path    ::= # GIT style file path, e.g. "a/b/c";
   ref     ::= # GIT ref name, e.g. "refs/heads/MOZ_GECKO_EXPERIMENT";
   tag     ::= # GIT tag name, e.g. "FIREFOX_1_5";
@@ -129,11 +130,11 @@ struct object_entry_pool
 
 struct mark_set
 {
-       int shift;
        union {
                struct object_entry *marked[1024];
                struct mark_set *sets[1024];
        } data;
+       unsigned int shift;
 };
 
 struct last_object
@@ -156,7 +157,7 @@ struct mem_pool
 struct atom_str
 {
        struct atom_str *next_atom;
-       int str_len;
+       unsigned int str_len;
        char str_dat[FLEX_ARRAY]; /* more */
 };
 
@@ -191,8 +192,9 @@ struct branch
        struct branch *table_next_branch;
        struct branch *active_next_branch;
        const char *name;
-       unsigned long last_commit;
        struct tree_entry branch_tree;
+       unsigned long last_commit;
+       unsigned int pack_id;
        unsigned char sha1[20];
 };
 
@@ -200,6 +202,7 @@ struct tag
 {
        struct tag *next_tag;
        const char *name;
+       unsigned int pack_id;
        unsigned char sha1[20];
 };
 
@@ -217,16 +220,16 @@ struct hash_list
 
 /* Configured limits on output */
 static unsigned long max_depth = 10;
-static unsigned long max_packsize = -1;
+static unsigned long max_packsize = (1LL << 32) - 1;
 static uintmax_t max_objects = -1;
 
 /* Stats and misc. counters */
 static uintmax_t alloc_count;
-static uintmax_t object_count;
 static uintmax_t marks_set_count;
 static uintmax_t object_count_by_type[1 << TYPE_BITS];
 static uintmax_t duplicate_count_by_type[1 << TYPE_BITS];
 static uintmax_t delta_count_by_type[1 << TYPE_BITS];
+static unsigned long object_count;
 static unsigned long branch_count;
 static unsigned long branch_load_count;
 
@@ -241,14 +244,10 @@ 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;
 static unsigned long pack_size;
-static unsigned char pack_sha1[20];
 
 /* Table of objects we've written. */
 static unsigned int object_entry_alloc = 5000;
@@ -590,38 +589,26 @@ static void release_tree_entry(struct tree_entry *e)
        avail_tree_entry = e;
 }
 
-static void yread(int fd, void *buffer, size_t length)
-{
-       ssize_t ret = 0;
-       while (ret < length) {
-               ssize_t size = xread(fd, (char *) buffer + ret, length - ret);
-               if (!size)
-                       die("Read from descriptor %i: end of stream", fd);
-               if (size < 0)
-                       die("Read from descriptor %i: %s", fd, strerror(errno));
-               ret += size;
-       }
-}
-
 static void start_packfile()
 {
+       static char tmpfile[PATH_MAX];
        struct packed_git *p;
        struct pack_header hdr;
+       int pack_fd;
 
-       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);
        hdr.hdr_version = htonl(2);
        hdr.hdr_entries = 0;
-       write_or_die(pack_fd, &hdr, sizeof(hdr));
+       write_or_die(p->pack_fd, &hdr, sizeof(hdr));
 
        pack_data = p;
        pack_size = sizeof(hdr);
@@ -633,6 +620,7 @@ static void start_packfile()
 
 static void fixup_header_footer()
 {
+       int pack_fd = pack_data->pack_fd;
        SHA_CTX c;
        char hdr[8];
        unsigned long cnt;
@@ -642,7 +630,8 @@ static void fixup_header_footer()
                die("Failed seeking to start: %s", strerror(errno));
 
        SHA1_Init(&c);
-       yread(pack_fd, hdr, 8);
+       if (read_in_full(pack_fd, hdr, 8) != 8)
+               die("Unable to reread header of %s", pack_data->pack_name);
        SHA1_Update(&c, hdr, 8);
 
        cnt = htonl(object_count);
@@ -658,8 +647,9 @@ static void fixup_header_footer()
        }
        free(buf);
 
-       SHA1_Final(pack_sha1, &c);
-       write_or_die(pack_fd, pack_sha1, sizeof(pack_sha1));
+       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_)
@@ -669,13 +659,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*));
@@ -702,16 +694,67 @@ 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_sha1, sizeof(pack_sha1));
+       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()
@@ -719,26 +762,41 @@ 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();
-               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);
                if (!new_p)
                        die("core git rejected index %s", idx_name);
                new_p->windows = old_p->windows;
-               new_p->pack_fd = old_p->pack_fd;
-               all_packs[pack_id++] = new_p;
+               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 {
-               close(pack_fd);
+       else
                unlink(old_p->pack_name);
-       }
        free(old_p);
-       free(idx_name);
 
        /* We can't carry a delta across packfiles. */
        free(last_blob.data);
@@ -876,23 +934,23 @@ static int store_object(
                last->depth++;
 
                hdrlen = encode_header(OBJ_OFS_DELTA, deltalen, hdr);
-               write_or_die(pack_fd, hdr, hdrlen);
+               write_or_die(pack_data->pack_fd, hdr, hdrlen);
                pack_size += hdrlen;
 
                hdr[pos] = ofs & 127;
                while (ofs >>= 7)
                        hdr[--pos] = 128 | (--ofs & 127);
-               write_or_die(pack_fd, hdr + pos, sizeof(hdr) - pos);
+               write_or_die(pack_data->pack_fd, hdr + pos, sizeof(hdr) - pos);
                pack_size += sizeof(hdr) - pos;
        } else {
                if (last)
                        last->depth = 0;
                hdrlen = encode_header(type, datlen, hdr);
-               write_or_die(pack_fd, hdr, hdrlen);
+               write_or_die(pack_data->pack_fd, hdr, hdrlen);
                pack_size += hdrlen;
        }
 
-       write_or_die(pack_fd, out, s.total_out);
+       write_or_die(pack_data->pack_fd, out, s.total_out);
        pack_size += s.total_out;
 
        free(out);
@@ -1642,6 +1700,7 @@ static void cmd_new_commit()
                new_data.buffer, sp - (char*)new_data.buffer,
                NULL, b->sha1, next_mark);
        b->last_commit = object_count_by_type[OBJ_COMMIT];
+       b->pack_id = pack_id;
 
        if (branch_log) {
                int need_dq = quote_c_style(b->name, NULL, NULL, 0);
@@ -1750,6 +1809,7 @@ static void cmd_new_tag()
 
        store_object(OBJ_TAG, new_data.buffer, sp - (char*)new_data.buffer,
                NULL, t->sha1, 0);
+       t->pack_id = pack_id;
 
        if (branch_log) {
                int need_dq = quote_c_style(t->name, NULL, NULL, 0);
@@ -1803,13 +1863,13 @@ 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)
 {
        int i;
        uintmax_t est_obj_cnt = object_entry_alloc;
-       uintmax_t duplicate_count;
+       uintmax_t total_count, duplicate_count;
 
        setup_ident();
        git_config(git_default_config);
@@ -1839,9 +1899,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);
@@ -1873,10 +1932,14 @@ int main(int argc, const char **argv)
 
        dump_branches();
        dump_tags();
+       unkeep_all_packs();
        dump_marks();
        if (branch_log)
                fclose(branch_log);
 
+       total_count = 0;
+       for (i = 0; i < ARRAY_SIZE(object_count_by_type); i++)
+               total_count += object_count_by_type[i];
        duplicate_count = 0;
        for (i = 0; i < ARRAY_SIZE(duplicate_count_by_type); i++)
                duplicate_count += duplicate_count_by_type[i];
@@ -1884,7 +1947,7 @@ int main(int argc, const char **argv)
        fprintf(stderr, "%s statistics:\n", argv[0]);
        fprintf(stderr, "---------------------------------------------------------------------\n");
        fprintf(stderr, "Alloc'd objects: %10ju (%10ju overflow  )\n", alloc_count, alloc_count - est_obj_cnt);
-       fprintf(stderr, "Total objects:   %10ju (%10ju duplicates                  )\n", object_count, duplicate_count);
+       fprintf(stderr, "Total objects:   %10ju (%10ju duplicates                  )\n", total_count, duplicate_count);
        fprintf(stderr, "      blobs  :   %10ju (%10ju duplicates %10ju deltas)\n", object_count_by_type[OBJ_BLOB], duplicate_count_by_type[OBJ_BLOB], delta_count_by_type[OBJ_BLOB]);
        fprintf(stderr, "      trees  :   %10ju (%10ju duplicates %10ju deltas)\n", object_count_by_type[OBJ_TREE], duplicate_count_by_type[OBJ_TREE], delta_count_by_type[OBJ_TREE]);
        fprintf(stderr, "      commits:   %10ju (%10ju duplicates %10ju deltas)\n", object_count_by_type[OBJ_COMMIT], duplicate_count_by_type[OBJ_COMMIT], delta_count_by_type[OBJ_COMMIT]);