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;
# 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";
struct mark_set
{
- int shift;
union {
struct object_entry *marked[1024];
struct mark_set *sets[1024];
} data;
+ unsigned int shift;
};
struct last_object
struct atom_str
{
struct atom_str *next_atom;
- int str_len;
+ unsigned int str_len;
char str_dat[FLEX_ARRAY]; /* more */
};
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];
};
{
struct tag *next_tag;
const char *name;
+ unsigned int pack_id;
unsigned char sha1[20];
};
/* 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;
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;
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);
static void fixup_header_footer()
{
+ int pack_fd = pack_data->pack_fd;
SHA_CTX c;
char hdr[8];
unsigned long cnt;
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);
}
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_)
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*));
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()
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);
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);
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);
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);
}
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);
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);
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];
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]);