X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=fast-import.c;h=a523b171e22f83d6a656b372cf20afe52d27d1b2;hb=c64b9ad0fc02134d7271eb841fbdef9bc16660ea;hp=5e83296bf49f9b41b019185539cbd4ec1bf94513;hpb=9d25acc49a98ca82988ad871753a45e41f3c90f5;p=git.git diff --git a/fast-import.c b/fast-import.c index 5e83296bf..a523b171e 100644 --- a/fast-import.c +++ b/fast-import.c @@ -149,7 +149,6 @@ Format of STDIN stream: #include "pack.h" #include "refs.h" #include "csum-file.h" -#include "strbuf.h" #include "quote.h" #define PACK_ID_BITS 16 @@ -186,11 +185,10 @@ struct mark_set struct last_object { - void *data; - unsigned long len; + struct strbuf data; uint32_t offset; unsigned int depth; - unsigned no_free:1; + unsigned no_swap : 1; }; struct mem_pool @@ -198,7 +196,7 @@ struct mem_pool struct mem_pool *next_pool; char *next_free; char *end; - char space[FLEX_ARRAY]; /* more */ + uintmax_t space[FLEX_ARRAY]; /* more */ }; struct atom_str @@ -254,12 +252,6 @@ struct tag unsigned char sha1[20]; }; -struct dbuf -{ - void *buffer; - size_t capacity; -}; - struct hash_list { struct hash_list *next; @@ -283,6 +275,8 @@ struct recent_command static unsigned long max_depth = 10; static off_t max_packsize = (1LL << 32) - 1; static int force_update; +static int pack_compression_level = Z_DEFAULT_COMPRESSION; +static int pack_compression_seen; /* Stats and misc. counters */ static uintmax_t alloc_count; @@ -320,15 +314,15 @@ static struct mark_set *marks; static const char* mark_file; /* Our last blob */ -static struct last_object last_blob; +static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 }; /* Tree management */ static unsigned int tree_entry_alloc = 1000; static void *avail_tree_entry; static unsigned int avail_tree_table_sz = 100; static struct avail_tree_content **avail_tree_table; -static struct dbuf old_tree; -static struct dbuf new_tree; +static struct strbuf old_tree = STRBUF_INIT; +static struct strbuf new_tree = STRBUF_INIT; /* Branch data */ static unsigned long max_active_branches = 5; @@ -343,14 +337,14 @@ static struct tag *last_tag; /* Input stream parsing */ static whenspec_type whenspec = WHENSPEC_RAW; -static struct strbuf command_buf; +static struct strbuf command_buf = STRBUF_INIT; static int unread_command_buf; static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL}; static struct recent_command *cmd_tail = &cmd_hist; static struct recent_command *rc_free; static unsigned int cmd_save = 100; static uintmax_t next_mark; -static struct dbuf new_data; +static struct strbuf new_data = STRBUF_INIT; static void write_branch_report(FILE *rpt, struct branch *b) { @@ -542,15 +536,15 @@ static void *pool_alloc(size_t len) total_allocd += sizeof(struct mem_pool) + mem_pool_alloc; p = xmalloc(sizeof(struct mem_pool) + mem_pool_alloc); p->next_pool = mem_pool; - p->next_free = p->space; + p->next_free = (char *) p->space; p->end = p->next_free + mem_pool_alloc; mem_pool = p; } r = p->next_free; - /* round out to a pointer alignment */ - if (len & (sizeof(void*) - 1)) - len += sizeof(void*) - (len & (sizeof(void*) - 1)); + /* round out to a 'uintmax_t' alignment */ + if (len & (sizeof(uintmax_t) - 1)) + len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1)); p->next_free += len; return r; } @@ -570,17 +564,6 @@ static char *pool_strdup(const char *s) return r; } -static void size_dbuf(struct dbuf *b, size_t maxlen) -{ - if (b->buffer) { - if (b->capacity >= maxlen) - return; - free(b->buffer); - } - b->capacity = ((maxlen / 1024) + 1) * 1024; - b->buffer = xmalloc(b->capacity); -} - static void insert_mark(uintmax_t idnum, struct object_entry *oe) { struct mark_set *s = marks; @@ -661,8 +644,9 @@ static struct branch *new_branch(const char *name) if (b) die("Invalid attempt to create duplicate branch: %s", name); switch (check_ref_format(name)) { - case 0: break; /* its valid */ - case -2: break; /* valid, but too few '/', allow anyway */ + case 0: break; /* its valid */ + case CHECK_REF_FORMAT_ONELEVEL: + break; /* valid, but too few '/', allow anyway */ default: die("Branch name doesn't conform to GIT standards: %s", name); } @@ -896,8 +880,9 @@ static char *keep_pack(char *curr_index_name) 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); + write_or_die(keep_fd, keep_msg, strlen(keep_msg)); + if (close(keep_fd)) + die("failed to write keep file"); snprintf(name, sizeof(name), "%s/pack/pack-%s.pack", get_object_directory(), sha1_to_hex(pack_data->sha1)); @@ -934,6 +919,7 @@ static void end_packfile(void) struct branch *b; struct tag *t; + close_pack_windows(pack_data); fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1, pack_data->pack_name, object_count); close(pack_data->pack_fd); @@ -943,7 +929,6 @@ static void end_packfile(void) 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); @@ -971,9 +956,7 @@ static void end_packfile(void) free(old_p); /* We can't carry a delta across packfiles. */ - free(last_blob.data); - last_blob.data = NULL; - last_blob.len = 0; + strbuf_release(&last_blob.data); last_blob.offset = 0; last_blob.depth = 0; } @@ -1009,8 +992,7 @@ static size_t encode_header( static int store_object( enum object_type type, - void *dat, - size_t datlen, + struct strbuf *dat, struct last_object *last, unsigned char *sha1out, uintmax_t mark) @@ -1024,10 +1006,10 @@ static int store_object( z_stream s; hdrlen = sprintf((char*)hdr,"%s %lu", typename(type), - (unsigned long)datlen) + 1; + (unsigned long)dat->len) + 1; SHA1_Init(&c); SHA1_Update(&c, hdr, hdrlen); - SHA1_Update(&c, dat, datlen); + SHA1_Update(&c, dat->buf, dat->len); SHA1_Final(sha1, &c); if (sha1out) hashcpy(sha1out, sha1); @@ -1046,11 +1028,11 @@ static int store_object( return 1; } - if (last && last->data && last->depth < max_depth) { - delta = diff_delta(last->data, last->len, - dat, datlen, + if (last && last->data.buf && last->depth < max_depth) { + delta = diff_delta(last->data.buf, last->data.len, + dat->buf, dat->len, &deltalen, 0); - if (delta && deltalen >= datlen) { + if (delta && deltalen >= dat->len) { free(delta); delta = NULL; } @@ -1058,13 +1040,13 @@ static int store_object( delta = NULL; memset(&s, 0, sizeof(s)); - deflateInit(&s, zlib_compression_level); + deflateInit(&s, pack_compression_level); if (delta) { s.next_in = delta; s.avail_in = deltalen; } else { - s.next_in = dat; - s.avail_in = datlen; + s.next_in = (void *)dat->buf; + s.avail_in = dat->len; } s.avail_out = deflateBound(&s, s.avail_in); s.next_out = out = xmalloc(s.avail_out); @@ -1086,9 +1068,9 @@ static int store_object( delta = NULL; memset(&s, 0, sizeof(s)); - deflateInit(&s, zlib_compression_level); - s.next_in = dat; - s.avail_in = datlen; + deflateInit(&s, pack_compression_level); + s.next_in = (void *)dat->buf; + s.avail_in = dat->len; s.avail_out = deflateBound(&s, s.avail_in); s.next_out = out = xrealloc(out, s.avail_out); while (deflate(&s, Z_FINISH) == Z_OK) @@ -1121,7 +1103,7 @@ static int store_object( pack_size += sizeof(hdr) - pos; } else { e->depth = 0; - hdrlen = encode_header(type, datlen, hdr); + hdrlen = encode_header(type, dat->len, hdr); write_or_die(pack_data->pack_fd, hdr, hdrlen); pack_size += hdrlen; } @@ -1132,24 +1114,60 @@ static int store_object( free(out); free(delta); if (last) { - if (!last->no_free) - free(last->data); - last->data = dat; + if (last->no_swap) { + last->data = *dat; + } else { + strbuf_swap(&last->data, dat); + } last->offset = e->offset; last->depth = e->depth; - last->len = datlen; } return 0; } +/* All calls must be guarded by find_object() or find_mark() to + * ensure the 'struct object_entry' passed was written by this + * process instance. We unpack the entry by the offset, avoiding + * the need for the corresponding .idx file. This unpacking rule + * works because we only use OBJ_REF_DELTA within the packfiles + * created by fast-import. + * + * oe must not be NULL. Such an oe usually comes from giving + * an unknown SHA-1 to find_object() or an undefined mark to + * find_mark(). Callers must test for this condition and use + * the standard read_sha1_file() when it happens. + * + * oe->pack_id must not be MAX_PACK_ID. Such an oe is usually from + * find_mark(), where the mark was reloaded from an existing marks + * file and is referencing an object that this fast-import process + * instance did not write out to a packfile. Callers must test for + * this condition and use read_sha1_file() instead. + */ static void *gfi_unpack_entry( struct object_entry *oe, unsigned long *sizep) { enum object_type type; struct packed_git *p = all_packs[oe->pack_id]; - if (p == pack_data) + if (p == pack_data && p->pack_size < (pack_size + 20)) { + /* The object is stored in the packfile we are writing to + * and we have modified it since the last time we scanned + * back to read a previously written object. If an old + * window covered [p->pack_size, p->pack_size + 20) its + * data is stale and is not valid. Closing all windows + * and updating the packfile length ensures we can read + * the newly written data. + */ + close_pack_windows(p); + + /* We have to offer 20 bytes additional on the end of + * the packfile as the core unpacker code assumes the + * footer is present at the file end and must promise + * at least 20 bytes within any window it maps. But + * we don't actually create the footer here. + */ p->pack_size = pack_size + 20; + } return unpack_entry(p, oe->offset, &type, sizep); } @@ -1233,14 +1251,10 @@ static int tecmp1 (const void *_a, const void *_b) b->name->str_dat, b->name->str_len, b->versions[1].mode); } -static void mktree(struct tree_content *t, - int v, - unsigned long *szp, - struct dbuf *b) +static void mktree(struct tree_content *t, int v, struct strbuf *b) { size_t maxlen = 0; unsigned int i; - char *c; if (!v) qsort(t->entries,t->entry_count,sizeof(t->entries[0]),tecmp0); @@ -1252,28 +1266,23 @@ static void mktree(struct tree_content *t, maxlen += t->entries[i]->name->str_len + 34; } - size_dbuf(b, maxlen); - c = b->buffer; + strbuf_reset(b); + strbuf_grow(b, maxlen); for (i = 0; i < t->entry_count; i++) { struct tree_entry *e = t->entries[i]; if (!e->versions[v].mode) continue; - c += sprintf(c, "%o", (unsigned int)e->versions[v].mode); - *c++ = ' '; - strcpy(c, e->name->str_dat); - c += e->name->str_len + 1; - hashcpy((unsigned char*)c, e->versions[v].sha1); - c += 20; + strbuf_addf(b, "%o %s%c", (unsigned int)e->versions[v].mode, + e->name->str_dat, '\0'); + strbuf_add(b, e->versions[v].sha1, 20); } - *szp = c - (char*)b->buffer; } static void store_tree(struct tree_entry *root) { struct tree_content *t = root->tree; unsigned int i, j, del; - unsigned long new_len; - struct last_object lo; + struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 }; struct object_entry *le; if (!is_null_sha1(root->versions[1].sha1)) @@ -1285,23 +1294,15 @@ static void store_tree(struct tree_entry *root) } le = find_object(root->versions[0].sha1); - if (!S_ISDIR(root->versions[0].mode) - || !le - || le->pack_id != pack_id) { - lo.data = NULL; - lo.depth = 0; - lo.no_free = 0; - } else { - mktree(t, 0, &lo.len, &old_tree); - lo.data = old_tree.buffer; + if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) { + mktree(t, 0, &old_tree); + lo.data = old_tree; lo.offset = le->offset; lo.depth = t->delta_depth; - lo.no_free = 1; } - mktree(t, 1, &new_len, &new_tree); - store_object(OBJ_TREE, new_tree.buffer, new_len, - &lo, root->versions[1].sha1, 0); + mktree(t, 1, &new_tree); + store_object(OBJ_TREE, &new_tree, &lo, root->versions[1].sha1, 0); t->delta_depth = lo.depth; for (i = 0, j = 0, del = 0; i < t->entry_count; i++) { @@ -1575,33 +1576,57 @@ static void dump_marks(void) f = fdopen(mark_fd, "w"); if (!f) { + int saved_errno = errno; rollback_lock_file(&mark_lock); failure |= error("Unable to write marks file %s: %s", - mark_file, strerror(errno)); + mark_file, strerror(saved_errno)); return; } + /* + * Since the lock file was fdopen()'ed, it should not be close()'ed. + * Assign -1 to the lock file descriptor so that commit_lock_file() + * won't try to close() it. + */ + mark_lock.fd = -1; + dump_marks_helper(f, 0, marks); - fclose(f); - if (commit_lock_file(&mark_lock)) + if (ferror(f) || fclose(f)) { + int saved_errno = errno; + rollback_lock_file(&mark_lock); failure |= error("Unable to write marks file %s: %s", - mark_file, strerror(errno)); + mark_file, strerror(saved_errno)); + return; + } + + if (commit_lock_file(&mark_lock)) { + int saved_errno = errno; + rollback_lock_file(&mark_lock); + failure |= error("Unable to commit marks file %s: %s", + mark_file, strerror(saved_errno)); + return; + } } -static void read_next_command(void) +static int read_next_command(void) { + static int stdin_eof = 0; + + if (stdin_eof) { + unread_command_buf = 0; + return EOF; + } + do { if (unread_command_buf) { unread_command_buf = 0; - if (command_buf.eof) - return; } else { struct recent_command *rc; - command_buf.buf = NULL; - read_line(&command_buf, stdin, '\n'); - if (command_buf.eof) - return; + strbuf_detach(&command_buf, NULL); + stdin_eof = strbuf_getline(&command_buf, stdin, '\n'); + if (stdin_eof) + return EOF; rc = rc_free; if (rc) @@ -1620,6 +1645,8 @@ static void read_next_command(void) cmd_tail = rc; } } while (command_buf.buf[0] == '#'); + + return 0; } static void skip_optional_lf(void) @@ -1639,42 +1666,36 @@ static void cmd_mark(void) next_mark = 0; } -static void *cmd_data (size_t *size) +static void cmd_data(struct strbuf *sb) { - size_t length; - char *buffer; + strbuf_reset(sb); if (prefixcmp(command_buf.buf, "data ")) die("Expected 'data n' command, found: %s", command_buf.buf); if (!prefixcmp(command_buf.buf + 5, "<<")) { char *term = xstrdup(command_buf.buf + 5 + 2); - size_t sz = 8192, term_len = command_buf.len - 5 - 2; - length = 0; - buffer = xmalloc(sz); - command_buf.buf = NULL; + size_t term_len = command_buf.len - 5 - 2; + + strbuf_detach(&command_buf, NULL); for (;;) { - read_line(&command_buf, stdin, '\n'); - if (command_buf.eof) + if (strbuf_getline(&command_buf, stdin, '\n') == EOF) die("EOF in data (terminator '%s' not found)", term); if (term_len == command_buf.len && !strcmp(term, command_buf.buf)) break; - ALLOC_GROW(buffer, length + command_buf.len, sz); - memcpy(buffer + length, - command_buf.buf, - command_buf.len - 1); - length += command_buf.len - 1; - buffer[length++] = '\n'; + strbuf_addbuf(sb, &command_buf); + strbuf_addch(sb, '\n'); } free(term); } else { - size_t n = 0; + size_t n = 0, length; + length = strtoul(command_buf.buf + 5, NULL, 10); - buffer = xmalloc(length); + while (n < length) { - size_t s = fread(buffer + n, 1, length - n, stdin); + size_t s = strbuf_fread(sb, length - n, stdin); if (!s && feof(stdin)) die("EOF in data (%lu bytes remaining)", (unsigned long)(length - n)); @@ -1683,8 +1704,6 @@ static void *cmd_data (size_t *size) } skip_optional_lf(); - *size = length; - return buffer; } static int validate_raw_date(const char *src, char *result, int maxlen) @@ -1747,15 +1766,12 @@ static char *parse_ident(const char *buf) static void cmd_new_blob(void) { - size_t l; - void *d; + static struct strbuf buf = STRBUF_INIT; read_next_command(); cmd_mark(); - d = cmd_data(&l); - - if (store_object(OBJ_BLOB, d, l, &last_blob, NULL, next_mark)) - free(d); + cmd_data(&buf); + store_object(OBJ_BLOB, &buf, &last_blob, NULL, next_mark); } static void unload_one_branch(void) @@ -1805,7 +1821,7 @@ static void load_branch(struct branch *b) static void file_change_m(struct branch *b) { const char *p = command_buf.buf + 2; - char *p_uq; + static struct strbuf uq = STRBUF_INIT; const char *endp; struct object_entry *oe = oe; unsigned char sha1[20]; @@ -1843,22 +1859,23 @@ static void file_change_m(struct branch *b) if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); - p_uq = unquote_c_style(p, &endp); - if (p_uq) { + strbuf_reset(&uq); + if (!unquote_c_style(&uq, p, &endp)) { if (*endp) die("Garbage after path in: %s", command_buf.buf); - p = p_uq; + p = uq.buf; } if (inline_data) { - size_t l; - void *d; - if (!p_uq) - p = p_uq = xstrdup(p); + static struct strbuf buf = STRBUF_INIT; + + if (p != uq.buf) { + strbuf_addstr(&uq, p); + p = uq.buf; + } read_next_command(); - d = cmd_data(&l); - if (store_object(OBJ_BLOB, d, l, &last_blob, sha1, 0)) - free(d); + cmd_data(&buf); + store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0); } else if (oe) { if (oe->type != OBJ_BLOB) die("Not a blob (actually a %s): %s", @@ -1873,58 +1890,54 @@ static void file_change_m(struct branch *b) } tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode, NULL); - free(p_uq); } static void file_change_d(struct branch *b) { const char *p = command_buf.buf + 2; - char *p_uq; + static struct strbuf uq = STRBUF_INIT; const char *endp; - p_uq = unquote_c_style(p, &endp); - if (p_uq) { + strbuf_reset(&uq); + if (!unquote_c_style(&uq, p, &endp)) { if (*endp) die("Garbage after path in: %s", command_buf.buf); - p = p_uq; + p = uq.buf; } tree_content_remove(&b->branch_tree, p, NULL); - free(p_uq); } static void file_change_cr(struct branch *b, int rename) { const char *s, *d; - char *s_uq, *d_uq; + static struct strbuf s_uq = STRBUF_INIT; + static struct strbuf d_uq = STRBUF_INIT; const char *endp; struct tree_entry leaf; s = command_buf.buf + 2; - s_uq = unquote_c_style(s, &endp); - if (s_uq) { + strbuf_reset(&s_uq); + if (!unquote_c_style(&s_uq, s, &endp)) { if (*endp != ' ') die("Missing space after source: %s", command_buf.buf); - } - else { + } else { endp = strchr(s, ' '); if (!endp) die("Missing space after source: %s", command_buf.buf); - s_uq = xmalloc(endp - s + 1); - memcpy(s_uq, s, endp - s); - s_uq[endp - s] = 0; + strbuf_add(&s_uq, s, endp - s); } - s = s_uq; + s = s_uq.buf; endp++; if (!*endp) die("Missing dest: %s", command_buf.buf); d = endp; - d_uq = unquote_c_style(d, &endp); - if (d_uq) { + strbuf_reset(&d_uq); + if (!unquote_c_style(&d_uq, d, &endp)) { if (*endp) die("Garbage after dest in: %s", command_buf.buf); - d = d_uq; + d = d_uq.buf; } memset(&leaf, 0, sizeof(leaf)); @@ -1938,9 +1951,6 @@ static void file_change_cr(struct branch *b, int rename) leaf.versions[1].sha1, leaf.versions[1].mode, leaf.tree); - - free(s_uq); - free(d_uq); } static void file_change_deleteall(struct branch *b) @@ -2065,9 +2075,8 @@ static struct hash_list *cmd_merge(unsigned int *count) static void cmd_new_commit(void) { + static struct strbuf msg = STRBUF_INIT; struct branch *b; - void *msg; - size_t msglen; char *sp; char *author = NULL; char *committer = NULL; @@ -2092,7 +2101,7 @@ static void cmd_new_commit(void) } if (!committer) die("Expected committer but didn't get one"); - msg = cmd_data(&msglen); + cmd_data(&msg); read_next_command(); cmd_from(b); merge_list = cmd_merge(&merge_count); @@ -2104,7 +2113,7 @@ static void cmd_new_commit(void) } /* file_change* */ - while (!command_buf.eof && command_buf.len > 1) { + while (command_buf.len > 0) { if (!prefixcmp(command_buf.buf, "M ")) file_change_m(b); else if (!prefixcmp(command_buf.buf, "D ")) @@ -2119,53 +2128,47 @@ static void cmd_new_commit(void) unread_command_buf = 1; break; } - read_next_command(); + if (read_next_command() == EOF) + break; } /* build the tree and the commit */ store_tree(&b->branch_tree); hashcpy(b->branch_tree.versions[0].sha1, b->branch_tree.versions[1].sha1); - size_dbuf(&new_data, 114 + msglen - + merge_count * 49 - + (author - ? strlen(author) + strlen(committer) - : 2 * strlen(committer))); - sp = new_data.buffer; - sp += sprintf(sp, "tree %s\n", + + strbuf_reset(&new_data); + strbuf_addf(&new_data, "tree %s\n", sha1_to_hex(b->branch_tree.versions[1].sha1)); if (!is_null_sha1(b->sha1)) - sp += sprintf(sp, "parent %s\n", sha1_to_hex(b->sha1)); + strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(b->sha1)); while (merge_list) { struct hash_list *next = merge_list->next; - sp += sprintf(sp, "parent %s\n", sha1_to_hex(merge_list->sha1)); + strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(merge_list->sha1)); free(merge_list); merge_list = next; } - sp += sprintf(sp, "author %s\n", author ? author : committer); - sp += sprintf(sp, "committer %s\n", committer); - *sp++ = '\n'; - memcpy(sp, msg, msglen); - sp += msglen; + strbuf_addf(&new_data, + "author %s\n" + "committer %s\n" + "\n", + author ? author : committer, committer); + strbuf_addbuf(&new_data, &msg); free(author); free(committer); - free(msg); - if (!store_object(OBJ_COMMIT, - new_data.buffer, sp - (char*)new_data.buffer, - NULL, b->sha1, next_mark)) + if (!store_object(OBJ_COMMIT, &new_data, NULL, b->sha1, next_mark)) b->pack_id = pack_id; b->last_commit = object_count_by_type[OBJ_COMMIT]; } static void cmd_new_tag(void) { + static struct strbuf msg = STRBUF_INIT; char *sp; const char *from; char *tagger; struct branch *s; - void *msg; - size_t msglen; struct tag *t; uintmax_t from_mark = 0; unsigned char sha1[20]; @@ -2216,24 +2219,21 @@ static void cmd_new_tag(void) /* tag payload/message */ read_next_command(); - msg = cmd_data(&msglen); + cmd_data(&msg); /* build the tag object */ - size_dbuf(&new_data, 67+strlen(t->name)+strlen(tagger)+msglen); - sp = new_data.buffer; - sp += sprintf(sp, "object %s\n", sha1_to_hex(sha1)); - sp += sprintf(sp, "type %s\n", commit_type); - sp += sprintf(sp, "tag %s\n", t->name); - sp += sprintf(sp, "tagger %s\n", tagger); - *sp++ = '\n'; - memcpy(sp, msg, msglen); - sp += msglen; + strbuf_reset(&new_data); + strbuf_addf(&new_data, + "object %s\n" + "type %s\n" + "tag %s\n" + "tagger %s\n" + "\n", + sha1_to_hex(sha1), commit_type, t->name, tagger); + strbuf_addbuf(&new_data, &msg); free(tagger); - free(msg); - if (store_object(OBJ_TAG, new_data.buffer, - sp - (char*)new_data.buffer, - NULL, t->sha1, 0)) + if (store_object(OBJ_TAG, &new_data, NULL, t->sha1, 0)) t->pack_id = MAX_PACK_ID; else t->pack_id = pack_id; @@ -2259,7 +2259,7 @@ static void cmd_reset_branch(void) else b = new_branch(sp); read_next_command(); - if (!cmd_from(b) && command_buf.len > 1) + if (!cmd_from(b) && command_buf.len > 0) unread_command_buf = 1; } @@ -2276,7 +2276,7 @@ static void cmd_checkpoint(void) static void cmd_progress(void) { - fwrite(command_buf.buf, 1, command_buf.len - 1, stdout); + fwrite(command_buf.buf, 1, command_buf.len, stdout); fputc('\n', stdout); fflush(stdout); skip_optional_lf(); @@ -2317,6 +2317,27 @@ static void import_marks(const char *input_file) fclose(f); } +static int git_pack_config(const char *k, const char *v) +{ + if (!strcmp(k, "pack.depth")) { + max_depth = git_config_int(k, v); + if (max_depth > MAX_DEPTH) + max_depth = MAX_DEPTH; + return 0; + } + if (!strcmp(k, "pack.compression")) { + int level = git_config_int(k, v); + if (level == -1) + level = Z_DEFAULT_COMPRESSION; + else if (level < 0 || level > Z_BEST_COMPRESSION) + die("bad pack compression level %d", level); + pack_compression_level = level; + pack_compression_seen = 1; + return 0; + } + return git_default_config(k, v); +} + static const char fast_import_usage[] = "git-fast-import [--date-format=f] [--max-pack-size=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]"; @@ -2324,9 +2345,12 @@ int main(int argc, const char **argv) { unsigned int i, show_stats = 1; - git_config(git_default_config); + git_config(git_pack_config); + if (!pack_compression_seen && core_compression_seen) + pack_compression_level = core_compression_level; + alloc_objects(object_entry_alloc); - strbuf_init(&command_buf); + strbuf_init(&command_buf, 0); atom_table = xcalloc(atom_table_sz, sizeof(struct atom_str*)); branch_table = xcalloc(branch_table_sz, sizeof(struct branch*)); avail_tree_table = xcalloc(avail_tree_table_sz, sizeof(struct avail_tree_content*)); @@ -2387,11 +2411,8 @@ int main(int argc, const char **argv) prepare_packed_git(); start_packfile(); set_die_routine(die_nicely); - for (;;) { - read_next_command(); - if (command_buf.eof) - break; - else if (!strcmp("blob", command_buf.buf)) + while (read_next_command() != EOF) { + if (!strcmp("blob", command_buf.buf)) cmd_new_blob(); else if (!prefixcmp(command_buf.buf, "commit ")) cmd_new_commit();