diff --git a/fast-import.c b/fast-import.c index c9c48c5869..98c5d1cbdd 100644 --- a/fast-import.c +++ b/fast-import.c @@ -24,14 +24,39 @@ struct object_entry_block struct last_object { void *data; - unsigned long len; - int depth; + unsigned int len; + unsigned int depth; unsigned char sha1[20]; }; +struct tree; +struct tree_entry +{ + struct tree *tree; + mode_t mode; + unsigned char sha1[20]; + char name[FLEX_ARRAY]; /* more */ +}; + +struct tree +{ + struct last_object last_tree; + unsigned long entry_count; + struct tree_entry **entries; +}; + +struct branch +{ + struct branch *next_branch; + struct tree_entry tree; + unsigned char sha1[20]; + const char *name; +}; + /* Stats and misc. counters. */ static int max_depth = 10; static unsigned long alloc_count; +static unsigned long branch_count; static unsigned long object_count; static unsigned long duplicate_count; static unsigned long object_count_by_type[9]; @@ -49,6 +74,10 @@ struct object_entry *object_table[1 << 16]; /* Our last blob */ struct last_object last_blob; +/* Branch data */ +struct branch *branches; +struct branch *current_branch; + static void alloc_objects(int cnt) { struct object_entry_block *b; @@ -129,6 +158,32 @@ static ssize_t ywrite(int fd, void *buffer, size_t length) return ret; } +static const char* read_string() +{ + static char sn[PATH_MAX]; + unsigned long slen; + + if (yread(0, &slen, 4) != 4) + die("Can't obtain string"); + if (!slen) + return 0; + if (slen > (PATH_MAX - 1)) + die("Can't handle excessive string length %lu", slen); + + if (yread(0, sn, slen) != slen) + die("Can't obtain string of length %lu", slen); + sn[slen] = 0; + return sn; +} + +static const char* read_required_string() +{ + const char *r = read_string(); + if (!r) + die("Expected string command parameter, didn't find one"); + return r; +} + static unsigned long encode_header( enum object_type type, unsigned long size, @@ -156,7 +211,8 @@ static int store_object( enum object_type type, void *dat, unsigned long datlen, - struct last_object *last) + struct last_object *last, + unsigned char *sha1out) { void *out, *delta; struct object_entry *e; @@ -171,6 +227,8 @@ static int store_object( SHA1_Update(&c, hdr, hdrlen); SHA1_Update(&c, dat, datlen); SHA1_Final(sha1, &c); + if (sha1out) + memcpy(sha1out, sha1, sizeof(sha1)); e = insert_object(sha1); if (e->offset) { @@ -347,10 +405,108 @@ static void new_blob() if (yread(0, dat, datlen) != datlen) die("Con't obtain %lu bytes of blob data", datlen); - if (!store_object(OBJ_BLOB, dat, datlen, &last_blob)) + if (!store_object(OBJ_BLOB, dat, datlen, &last_blob, 0)) free(dat); } +static struct branch* lookup_branch(const char *name) +{ + struct branch *b; + for (b = branches; b; b = b->next_branch) { + if (!strcmp(name, b->name)) + return b; + } + die("No branch named '%s' has been declared", name); +} + +static struct tree* deep_copy_tree (struct tree *t) +{ + struct tree *r = xmalloc(sizeof(struct tree)); + unsigned long i; + + if (t->last_tree.data) { + r->last_tree.data = xmalloc(t->last_tree.len); + r->last_tree.len = t->last_tree.len; + r->last_tree.depth = t->last_tree.depth; + memcpy(r->last_tree.data, t->last_tree.data, t->last_tree.len); + memcpy(r->last_tree.sha1, t->last_tree.sha1, sizeof(t->last_tree.sha1)); + } + + r->entry_count = t->entry_count; + r->entries = xmalloc(t->entry_count * sizeof(struct tree_entry*)); + for (i = 0; i < t->entry_count; i++) { + struct tree_entry *a = t->entries[i]; + struct tree_entry *b; + + b = xmalloc(sizeof(struct tree_entry) + strlen(a->name) + 1); + b->tree = a->tree ? deep_copy_tree(a->tree) : 0; + b->mode = a->mode; + memcpy(b->sha1, a->sha1, sizeof(a->sha1)); + strcpy(b->name, a->name); + r->entries[i] = b; + } + + return r; +} + +static void store_tree (struct tree_entry *e) +{ + struct tree *t = e->tree; + unsigned long maxlen, i; + char *buf, *c; + + if (memcmp(null_sha1, e->sha1, sizeof(e->sha1))) + return; + + maxlen = t->entry_count * 32; + for (i = 0; i < t->entry_count; i++) + maxlen += strlen(t->entries[i]->name); + + buf = c = xmalloc(maxlen); + for (i = 0; i < t->entry_count; i++) { + struct tree_entry *e = t->entries[i]; + c += sprintf(c, "%o %s", e->mode, e->name) + 1; + if (e->tree) + store_tree(e); + memcpy(c, e->sha1, sizeof(e->sha1)); + c += sizeof(e->sha1); + } + + if (!store_object(OBJ_TREE, buf, c - buf, &t->last_tree, e->sha1)) + free(buf); +} + +static void new_branch() +{ + struct branch *nb = xcalloc(1, sizeof(struct branch)); + const char *source_name; + + nb->name = strdup(read_required_string()); + source_name = read_string(); + if (source_name) { + struct branch *sb = lookup_branch(source_name); + nb->tree.tree = deep_copy_tree(sb->tree.tree); + memcpy(nb->tree.sha1, sb->tree.sha1, sizeof(sb->tree.sha1)); + memcpy(nb->sha1, sb->sha1, sizeof(sb->sha1)); + } else { + nb->tree.tree = xcalloc(1, sizeof(struct tree)); + nb->tree.tree->entries = xmalloc(8*sizeof(struct tree_entry*)); + } + nb->next_branch = branches; + branches = nb; + branch_count++; +} + +static void set_branch() +{ + current_branch = lookup_branch(read_required_string()); +} + +static void commit() +{ + store_tree(¤t_branch->tree); +} + int main(int argc, const char **argv) { const char *base_name = argv[1]; @@ -376,7 +532,10 @@ int main(int argc, const char **argv) break; switch (cmd) { - case 'blob': new_blob(); break; + case 'blob': new_blob(); break; + case 'newb': new_branch(); break; + case 'setb': set_branch(); break; + case 'comt': commit(); break; default: die("Invalid command %lu", cmd); } @@ -393,6 +552,7 @@ int main(int argc, const char **argv) fprintf(stderr, " trees : %10lu (%10lu duplicates)\n", object_count_by_type[OBJ_TREE], duplicate_count_by_type[OBJ_TREE]); fprintf(stderr, " commits: %10lu (%10lu duplicates)\n", object_count_by_type[OBJ_COMMIT], duplicate_count_by_type[OBJ_COMMIT]); fprintf(stderr, " tags : %10lu (%10lu duplicates)\n", object_count_by_type[OBJ_TAG], duplicate_count_by_type[OBJ_TAG]); + fprintf(stderr, "Total branches: %10lu\n", branch_count); fprintf(stderr, "---------------------------------------------------\n"); stat(pack_name, &sb);