X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=sha1_file.c;h=8d189d4919f83c243c306973285cefb5b55e2f19;hb=3e386508f87278610d1892aaaa08cd17907f71c5;hp=63cbdded86ca43e4c28626c4644037c3d1d2c694;hpb=f9253394a271a9fefdd234a86c228adeb6d0136a;p=git.git diff --git a/sha1_file.c b/sha1_file.c index 63cbdded..8d189d49 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -46,22 +46,8 @@ int get_sha1_hex(const char *hex, unsigned char *sha1) return 0; } -static int get_sha1_file(const char *path, unsigned char *result) -{ - char buffer[60]; - int fd = open(path, O_RDONLY); - int len; - - if (fd < 0) - return -1; - len = read(fd, buffer, sizeof(buffer)); - close(fd); - if (len < 40) - return -1; - return get_sha1_hex(buffer, result); -} - -static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir; +static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir, + *git_graft_file; static void setup_git_env(void) { git_dir = gitenv(GIT_DIR_ENVIRONMENT); @@ -79,6 +65,9 @@ static void setup_git_env(void) git_index_file = xmalloc(strlen(git_dir) + 7); sprintf(git_index_file, "%s/index", git_dir); } + git_graft_file = gitenv(GRAFT_ENVIRONMENT); + if (!git_graft_file) + git_graft_file = strdup(git_path("info/grafts")); } char *get_object_directory(void) @@ -102,32 +91,30 @@ char *get_index_file(void) return git_index_file; } -int get_sha1(const char *str, unsigned char *sha1) +char *get_graft_file(void) { - static char pathname[PATH_MAX]; - static const char *prefix[] = { - "", - "refs", - "refs/tags", - "refs/heads", - "refs/snap", - NULL - }; - const char **p; - - if (!get_sha1_hex(str, sha1)) - return 0; - - if (!git_dir) + if (!git_graft_file) setup_git_env(); - for (p = prefix; *p; p++) { - snprintf(pathname, sizeof(pathname), "%s/%s/%s", - git_dir, *p, str); - if (!get_sha1_file(pathname, sha1)) - return 0; - } + return git_graft_file; +} + +int safe_create_leading_directories(char *path) +{ + char *pos = path; - return -1; + while (pos) { + pos = strchr(pos, '/'); + if (!pos) + break; + *pos = 0; + if (mkdir(path, 0777) < 0) + if (errno != EEXIST) { + *pos = '/'; + return -1; + } + *pos++ = '/'; + } + return 0; } char * sha1_to_hex(const unsigned char *sha1) @@ -185,6 +172,56 @@ char *sha1_file_name(const unsigned char *sha1) return base; } +char *sha1_pack_name(const unsigned char *sha1) +{ + static const char hex[] = "0123456789abcdef"; + static char *name, *base, *buf; + int i; + + if (!base) { + const char *sha1_file_directory = get_object_directory(); + int len = strlen(sha1_file_directory); + base = xmalloc(len + 60); + sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.pack", sha1_file_directory); + name = base + len + 11; + } + + buf = name; + + for (i = 0; i < 20; i++) { + unsigned int val = *sha1++; + *buf++ = hex[val >> 4]; + *buf++ = hex[val & 0xf]; + } + + return base; +} + +char *sha1_pack_index_name(const unsigned char *sha1) +{ + static const char hex[] = "0123456789abcdef"; + static char *name, *base, *buf; + int i; + + if (!base) { + const char *sha1_file_directory = get_object_directory(); + int len = strlen(sha1_file_directory); + base = xmalloc(len + 60); + sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.idx", sha1_file_directory); + name = base + len + 11; + } + + buf = name; + + for (i = 0; i < 20; i++) { + unsigned int val = *sha1++; + *buf++ = hex[val >> 4]; + *buf++ = hex[val & 0xf]; + } + + return base; +} + struct alternate_object_database *alt_odb; /* @@ -272,12 +309,6 @@ static int pack_used_ctr; static unsigned long pack_mapped; struct packed_git *packed_git; -struct pack_entry { - unsigned int offset; - unsigned char sha1[20]; - struct packed_git *p; -}; - static int check_packed_git_idx(const char *path, unsigned long *idx_size_, void **idx_map_) { @@ -300,6 +331,8 @@ static int check_packed_git_idx(const char *path, unsigned long *idx_size_, return -1; index = idx_map; + *idx_map_ = idx_map; + *idx_size_ = idx_size; /* check index map */ if (idx_size < 4*256 + 20 + 20) @@ -322,8 +355,6 @@ static int check_packed_git_idx(const char *path, unsigned long *idx_size_, if (idx_size != 4*256 + nr * 24 + 20 + 20) return error("wrong index file size"); - *idx_map_ = idx_map; - *idx_size_ = idx_size; return 0; } @@ -351,6 +382,14 @@ void unuse_packed_git(struct packed_git *p) int use_packed_git(struct packed_git *p) { + if (!p->pack_size) { + struct stat st; + // We created the struct before we had the pack + stat(p->pack_name, &st); + if (!S_ISREG(st.st_mode)) + die("packfile %s not a regular file", p->pack_name); + p->pack_size = st.st_size; + } if (!p->pack_base) { int fd; struct stat st; @@ -378,8 +417,10 @@ int use_packed_git(struct packed_git *p) * this is cheap. */ if (memcmp((char*)(p->index_base) + p->index_size - 40, - p->pack_base + p->pack_size - 20, 20)) + p->pack_base + p->pack_size - 20, 20)) { + die("packfile %s does not match index.", p->pack_name); + } } p->pack_last_used = pack_used_ctr++; p->pack_use_cnt++; @@ -417,6 +458,37 @@ struct packed_git *add_packed_git(char *path, int path_len) return p; } +struct packed_git *parse_pack_index(unsigned char *sha1) +{ + struct packed_git *p; + unsigned long idx_size; + void *idx_map; + char *path = sha1_pack_index_name(sha1); + + if (check_packed_git_idx(path, &idx_size, &idx_map)) + return NULL; + + path = sha1_pack_name(sha1); + + p = xmalloc(sizeof(*p) + strlen(path) + 2); + strcpy(p->pack_name, path); + p->index_size = idx_size; + p->pack_size = 0; + p->index_base = idx_map; + p->next = NULL; + p->pack_base = NULL; + p->pack_last_used = 0; + p->pack_use_cnt = 0; + memcpy(p->sha1, sha1, 20); + return p; +} + +void install_packed_git(struct packed_git *pack) +{ + pack->next = packed_git; + packed_git = pack; +} + static void prepare_packed_git_one(char *objdir) { char path[PATH_MAX]; @@ -445,6 +517,7 @@ static void prepare_packed_git_one(char *objdir) p->next = packed_git; packed_git = p; } + closedir(dir); } void prepare_packed_git(void) @@ -477,8 +550,7 @@ int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long siz } static void *map_sha1_file_internal(const unsigned char *sha1, - unsigned long *size, - int say_error) + unsigned long *size) { struct stat st; void *map; @@ -486,8 +558,6 @@ static void *map_sha1_file_internal(const unsigned char *sha1, char *filename = find_sha1_file(sha1, &st); if (!filename) { - if (say_error) - error("cannot map sha1 file %s", sha1_to_hex(sha1)); return NULL; } @@ -501,8 +571,6 @@ static void *map_sha1_file_internal(const unsigned char *sha1, break; /* Fallthrough */ case 0: - if (say_error) - perror(filename); return NULL; } @@ -513,17 +581,12 @@ static void *map_sha1_file_internal(const unsigned char *sha1, } map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - if (-1 == (int)(long)map) + if (map == MAP_FAILED) return NULL; *size = st.st_size; return map; } -void *map_sha1_file(const unsigned char *sha1, unsigned long *size) -{ - return map_sha1_file_internal(sha1, size, 1); -} - int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size) { /* Get the data stream */ @@ -537,7 +600,7 @@ int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void return inflate(stream, 0); } -void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size) +static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size) { int bytes = strlen(buffer) + 1; unsigned char *buf = xmalloc(1+size); @@ -618,47 +681,67 @@ void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned l return unpack_sha1_rest(&stream, hdr, *size); } +/* forward declaration for a mutually recursive function */ +static int packed_object_info(struct pack_entry *entry, + char *type, unsigned long *sizep); + static int packed_delta_info(unsigned char *base_sha1, unsigned long delta_size, unsigned long left, char *type, - unsigned long *sizep) + unsigned long *sizep, + struct packed_git *p) { - const unsigned char *data; - unsigned char delta_head[64]; - unsigned long result_size, base_size, verify_base_size; - z_stream stream; - int st; + struct pack_entry base_ent; if (left < 20) die("truncated pack file"); - if (sha1_object_info(base_sha1, type, &base_size)) - die("cannot get info for delta-pack base"); - memset(&stream, 0, sizeof(stream)); + /* The base entry _must_ be in the same pack */ + if (!find_pack_entry_one(base_sha1, &base_ent, p)) + die("failed to find delta-pack base object %s", + sha1_to_hex(base_sha1)); - data = stream.next_in = base_sha1 + 20; - stream.avail_in = left - 20; - stream.next_out = delta_head; - stream.avail_out = sizeof(delta_head); + /* We choose to only get the type of the base object and + * ignore potentially corrupt pack file that expects the delta + * based on a base with a wrong size. This saves tons of + * inflate() calls. + */ - inflateInit(&stream); - st = inflate(&stream, Z_FINISH); - inflateEnd(&stream); - if ((st != Z_STREAM_END) && stream.total_out != sizeof(delta_head)) - die("delta data unpack-initial failed"); + if (packed_object_info(&base_ent, type, NULL)) + die("cannot get info for delta-pack base"); - /* Examine the initial part of the delta to figure out - * the result size. Verify the base size while we are at it. - */ - data = delta_head; - verify_base_size = get_delta_hdr_size(&data); - if (verify_base_size != base_size) - die("delta base size mismatch"); + if (sizep) { + const unsigned char *data; + unsigned char delta_head[64]; + unsigned long result_size; + z_stream stream; + int st; + + memset(&stream, 0, sizeof(stream)); + + data = stream.next_in = base_sha1 + 20; + stream.avail_in = left - 20; + stream.next_out = delta_head; + stream.avail_out = sizeof(delta_head); + + inflateInit(&stream); + st = inflate(&stream, Z_FINISH); + inflateEnd(&stream); + if ((st != Z_STREAM_END) && + stream.total_out != sizeof(delta_head)) + die("delta data unpack-initial failed"); + + /* Examine the initial part of the delta to figure out + * the result size. + */ + data = delta_head; + get_delta_hdr_size(&data); /* ignore base size */ - /* Read the result size */ - result_size = get_delta_hdr_size(&data); - *sizep = result_size; + /* Read the result size */ + result_size = get_delta_hdr_size(&data); + *sizep = result_size; + } return 0; } @@ -690,6 +773,57 @@ static unsigned long unpack_object_header(struct packed_git *p, unsigned long of return offset; } +void packed_object_info_detail(struct pack_entry *e, + char *type, + unsigned long *size, + unsigned long *store_size, + int *delta_chain_length, + unsigned char *base_sha1) +{ + struct packed_git *p = e->p; + unsigned long offset, left; + unsigned char *pack; + enum object_type kind; + + offset = unpack_object_header(p, e->offset, &kind, size); + pack = p->pack_base + offset; + left = p->pack_size - offset; + if (kind != OBJ_DELTA) + *delta_chain_length = 0; + else { + int chain_length = 0; + memcpy(base_sha1, pack, 20); + do { + struct pack_entry base_ent; + unsigned long junk; + + find_pack_entry_one(pack, &base_ent, p); + offset = unpack_object_header(p, base_ent.offset, + &kind, &junk); + pack = p->pack_base + offset; + chain_length++; + } while (kind == OBJ_DELTA); + *delta_chain_length = chain_length; + } + switch (kind) { + case OBJ_COMMIT: + strcpy(type, "commit"); + break; + case OBJ_TREE: + strcpy(type, "tree"); + break; + case OBJ_BLOB: + strcpy(type, "blob"); + break; + case OBJ_TAG: + strcpy(type, "tag"); + break; + default: + die("corrupted pack file"); + } + *store_size = 0; /* notyet */ +} + static int packed_object_info(struct pack_entry *entry, char *type, unsigned long *sizep) { @@ -708,7 +842,7 @@ static int packed_object_info(struct pack_entry *entry, switch (kind) { case OBJ_DELTA: - retval = packed_delta_info(pack, size, left, type, sizep); + retval = packed_delta_info(pack, size, left, type, sizep, p); unuse_packed_git(p); return retval; case OBJ_COMMIT: @@ -726,7 +860,8 @@ static int packed_object_info(struct pack_entry *entry, default: die("corrupted pack file"); } - *sizep = size; + if (sizep) + *sizep = size; unuse_packed_git(p); return 0; } @@ -738,8 +873,10 @@ static void *unpack_delta_entry(unsigned char *base_sha1, unsigned long delta_size, unsigned long left, char *type, - unsigned long *sizep) + unsigned long *sizep, + struct packed_git *p) { + struct pack_entry base_ent; void *data, *delta_data, *result, *base; unsigned long data_size, result_size, base_size; z_stream stream; @@ -764,8 +901,11 @@ static void *unpack_delta_entry(unsigned char *base_sha1, if ((st != Z_STREAM_END) || stream.total_out != delta_size) die("delta data unpack failed"); - /* This may recursively unpack the base, which is what we want */ - base = read_sha1_file(base_sha1, type, &base_size); + /* The base entry _must_ be in the same pack */ + if (!find_pack_entry_one(base_sha1, &base_ent, p)) + die("failed to find delta-pack base object %s", + sha1_to_hex(base_sha1)); + base = unpack_entry_gently(&base_ent, type, &base_size); if (!base) die("failed to read delta-pack base object %s", sha1_to_hex(base_sha1)); @@ -786,7 +926,7 @@ static void *unpack_non_delta_entry(unsigned char *data, { int st; z_stream stream; - char *buffer; + unsigned char *buffer; buffer = xmalloc(size + 1); buffer[size] = 0; @@ -811,21 +951,33 @@ static void *unpack_entry(struct pack_entry *entry, char *type, unsigned long *sizep) { struct packed_git *p = entry->p; - unsigned long offset, size, left; - unsigned char *pack; - enum object_type kind; void *retval; if (use_packed_git(p)) die("cannot map packed file"); + retval = unpack_entry_gently(entry, type, sizep); + unuse_packed_git(p); + if (!retval) + die("corrupted pack file"); + return retval; +} + +/* The caller is responsible for use_packed_git()/unuse_packed_git() pair */ +void *unpack_entry_gently(struct pack_entry *entry, + char *type, unsigned long *sizep) +{ + struct packed_git *p = entry->p; + unsigned long offset, size, left; + unsigned char *pack; + enum object_type kind; + void *retval; offset = unpack_object_header(p, entry->offset, &kind, &size); pack = p->pack_base + offset; left = p->pack_size - offset; switch (kind) { case OBJ_DELTA: - retval = unpack_delta_entry(pack, size, left, type, sizep); - unuse_packed_git(p); + retval = unpack_delta_entry(pack, size, left, type, sizep, p); return retval; case OBJ_COMMIT: strcpy(type, "commit"); @@ -840,11 +992,10 @@ static void *unpack_entry(struct pack_entry *entry, strcpy(type, "tag"); break; default: - die("corrupted pack file"); + return NULL; } *sizep = size; retval = unpack_non_delta_entry(pack, size, left); - unuse_packed_git(p); return retval; } @@ -864,10 +1015,10 @@ int nth_packed_object_sha1(const struct packed_git *p, int n, return 0; } -static int find_pack_entry_1(const unsigned char *sha1, - struct pack_entry *e, struct packed_git *p) +int find_pack_entry_one(const unsigned char *sha1, + struct pack_entry *e, struct packed_git *p) { - int *level1_ofs = p->index_base; + unsigned int *level1_ofs = p->index_base; int hi = ntohl(level1_ofs[*sha1]); int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1])); void *index = p->index_base + 256; @@ -895,12 +1046,26 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e) prepare_packed_git(); for (p = packed_git; p; p = p->next) { - if (find_pack_entry_1(sha1, e, p)) + if (find_pack_entry_one(sha1, e, p)) return 1; } return 0; } +struct packed_git *find_sha1_pack(const unsigned char *sha1, + struct packed_git *packs) +{ + struct packed_git *p; + struct pack_entry e; + + for (p = packs; p; p = p->next) { + if (find_pack_entry_one(sha1, &e, p)) + return p; + } + return NULL; + +} + int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep) { int status; @@ -909,18 +1074,13 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep z_stream stream; char hdr[128]; - map = map_sha1_file_internal(sha1, &mapsize, 0); + map = map_sha1_file_internal(sha1, &mapsize); if (!map) { struct pack_entry e; if (!find_pack_entry(sha1, &e)) return error("unable to find %s", sha1_to_hex(sha1)); - if (!packed_object_info(&e, type, sizep)) - return 0; - /* sheesh */ - map = unpack_entry(&e, type, sizep); - free(map); - return (map == NULL) ? 0 : -1; + return packed_object_info(&e, type, sizep); } if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) status = error("unable to unpack %s header", @@ -929,7 +1089,8 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep status = error("unable to parse %s header", sha1_to_hex(sha1)); else { status = 0; - *sizep = size; + if (sizep) + *sizep = size; } inflateEnd(&stream); munmap(map, mapsize); @@ -951,14 +1112,17 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size { unsigned long mapsize; void *map, *buf; + struct pack_entry e; - map = map_sha1_file_internal(sha1, &mapsize, 0); + if (find_pack_entry(sha1, &e)) + return read_packed_sha1(sha1, type, size); + map = map_sha1_file_internal(sha1, &mapsize); if (map) { buf = unpack_sha1_file(map, mapsize, type, size); munmap(map, mapsize); return buf; } - return read_packed_sha1(sha1, type, size); + return NULL; } void *read_object_with_reference(const unsigned char *sha1, @@ -1001,17 +1165,18 @@ void *read_object_with_reference(const unsigned char *sha1, free(buffer); return NULL; } + free(buffer); /* Now we have the ID of the referred-to object in * actual_sha1. Check again. */ } } -static char *write_sha1_file_prepare(void *buf, - unsigned long len, - const char *type, - unsigned char *sha1, - unsigned char *hdr, - int *hdrlen) +char *write_sha1_file_prepare(void *buf, + unsigned long len, + const char *type, + unsigned char *sha1, + unsigned char *hdr, + int *hdrlen) { SHA_CTX c; @@ -1127,14 +1292,83 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha return 0; } -int write_sha1_from_fd(const unsigned char *sha1, int fd) +int write_sha1_to_fd(int fd, const unsigned char *sha1) +{ + ssize_t size; + unsigned long objsize; + int posn = 0; + void *map = map_sha1_file_internal(sha1, &objsize); + void *buf = map; + void *temp_obj = NULL; + z_stream stream; + + if (!buf) { + unsigned char *unpacked; + unsigned long len; + char type[20]; + char hdr[50]; + int hdrlen; + // need to unpack and recompress it by itself + unpacked = read_packed_sha1(sha1, type, &len); + + hdrlen = sprintf(hdr, "%s %lu", type, len) + 1; + + /* Set it up */ + memset(&stream, 0, sizeof(stream)); + deflateInit(&stream, Z_BEST_COMPRESSION); + size = deflateBound(&stream, len + hdrlen); + temp_obj = buf = xmalloc(size); + + /* Compress it */ + stream.next_out = buf; + stream.avail_out = size; + + /* First header.. */ + stream.next_in = (void *)hdr; + stream.avail_in = hdrlen; + while (deflate(&stream, 0) == Z_OK) + /* nothing */; + + /* Then the data itself.. */ + stream.next_in = unpacked; + stream.avail_in = len; + while (deflate(&stream, Z_FINISH) == Z_OK) + /* nothing */; + deflateEnd(&stream); + free(unpacked); + + objsize = stream.total_out; + } + + do { + size = write(fd, buf + posn, objsize - posn); + if (size <= 0) { + if (!size) { + fprintf(stderr, "write closed"); + } else { + perror("write "); + } + return -1; + } + posn += size; + } while (posn < objsize); + + if (map) + munmap(map, objsize); + if (temp_obj) + free(temp_obj); + + return 0; +} + +int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer, + size_t bufsize, size_t *bufposn) { char *filename = sha1_file_name(sha1); int local; z_stream stream; unsigned char real_sha1[20]; - unsigned char buf[4096]; unsigned char discard[4096]; int ret; SHA_CTX c; @@ -1152,7 +1386,24 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd) do { ssize_t size; - size = read(fd, buf, 4096); + if (*bufposn) { + stream.avail_in = *bufposn; + stream.next_in = (unsigned char *) buffer; + do { + stream.next_out = discard; + stream.avail_out = sizeof(discard); + ret = inflate(&stream, Z_SYNC_FLUSH); + SHA1_Update(&c, discard, sizeof(discard) - + stream.avail_out); + } while (stream.avail_in && ret == Z_OK); + write(local, buffer, *bufposn - stream.avail_in); + memmove(buffer, buffer + *bufposn - stream.avail_in, + stream.avail_in); + *bufposn = stream.avail_in; + if (ret != Z_OK) + break; + } + size = read(fd, buffer + *bufposn, bufsize - *bufposn); if (size <= 0) { close(local); unlink(filename); @@ -1161,18 +1412,8 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd) perror("Reading from connection"); return -1; } - write(local, buf, size); - stream.avail_in = size; - stream.next_in = buf; - do { - stream.next_out = discard; - stream.avail_out = sizeof(discard); - ret = inflate(&stream, Z_SYNC_FLUSH); - SHA1_Update(&c, discard, sizeof(discard) - - stream.avail_out); - } while (stream.avail_in && ret == Z_OK); - - } while (ret == Z_OK); + *bufposn += size; + } while (1); inflateEnd(&stream); close(local); @@ -1189,30 +1430,61 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd) return 0; } +int has_pack_index(const unsigned char *sha1) +{ + struct stat st; + if (stat(sha1_pack_index_name(sha1), &st)) + return 0; + return 1; +} + +int has_pack_file(const unsigned char *sha1) +{ + struct stat st; + if (stat(sha1_pack_name(sha1), &st)) + return 0; + return 1; +} + +int has_sha1_pack(const unsigned char *sha1) +{ + struct pack_entry e; + return find_pack_entry(sha1, &e); +} + int has_sha1_file(const unsigned char *sha1) { struct stat st; struct pack_entry e; - if (find_sha1_file(sha1, &st)) + if (find_pack_entry(sha1, &e)) return 1; - return find_pack_entry(sha1, &e); + return find_sha1_file(sha1, &st) ? 1 : 0; } -int index_fd(unsigned char *sha1, int fd, struct stat *st) +int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type) { unsigned long size = st->st_size; void *buf; int ret; + unsigned char hdr[50]; + int hdrlen; buf = ""; if (size) buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - if ((int)(long)buf == -1) + if (buf == MAP_FAILED) return -1; - ret = write_sha1_file(buf, size, "blob", sha1); + if (!type) + type = "blob"; + if (write_object) + ret = write_sha1_file(buf, size, type, sha1); + else { + write_sha1_file_prepare(buf, size, type, sha1, hdr, &hdrlen); + ret = 0; + } if (size) munmap(buf, size); return ret;