X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=sha1_file.c;h=f007874cbb034ec9efa7f73c42831e0037d452fa;hb=e2b7eaf0ca3897940961d23392d4ff718867ea9f;hp=1d328c8d61d97314c4fd7f83888b0d30b22ac301;hpb=9cb18f56fdee6885884f5f08bd5335a42d9034dc;p=git.git diff --git a/sha1_file.c b/sha1_file.c index 1d328c8d6..f007874cb 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -193,7 +193,7 @@ char *sha1_pack_name(const unsigned char *sha1) *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; } - + return base; } @@ -218,7 +218,7 @@ char *sha1_pack_index_name(const unsigned char *sha1) *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; } - + return base; } @@ -380,11 +380,12 @@ void prepare_alt_odb(void) { const char *alt; + if (alt_odb_tail) + return; + alt = getenv(ALTERNATE_DB_ENVIRONMENT); if (!alt) alt = ""; - if (alt_odb_tail) - return; alt_odb_tail = &alt_odb_list; link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0); @@ -416,7 +417,7 @@ static size_t peak_pack_mapped; static size_t pack_mapped; struct packed_git *packed_git; -void pack_report() +void pack_report(void) { fprintf(stderr, "pack_report: getpagesize() = %10" SZ_FMT "\n" @@ -496,7 +497,7 @@ static int check_packed_git_idx(const char *path, struct packed_git *p) */ if (idx_size != 4*256 + nr * 24 + 20 + 20) { munmap(idx_map, idx_size); - return error("wrong index file size in %s", path); + return error("wrong index v1 file size in %s", path); } } else if (version == 2) { /* @@ -518,15 +519,17 @@ static int check_packed_git_idx(const char *path, struct packed_git *p) max_size += (nr - 1)*8; if (idx_size < min_size || idx_size > max_size) { munmap(idx_map, idx_size); - return error("wrong index file size in %s", path); + return error("wrong index v2 file size in %s", path); } - if (idx_size != min_size) { - /* make sure we can deal with large pack offsets */ - off_t x = 0x7fffffffUL, y = 0xffffffffUL; - if (x > (x + 1) || y > (y + 1)) { - munmap(idx_map, idx_size); - return error("pack too large for current definition of off_t in %s", path); - } + if (idx_size != min_size && + /* + * make sure we can deal with large pack offsets. + * 31-bit signed offset won't be enough, neither + * 32-bit unsigned one will be. + */ + (sizeof(off_t) <= 4)) { + munmap(idx_map, idx_size); + return error("pack too large for current definition of off_t in %s", path); } } @@ -537,6 +540,21 @@ static int check_packed_git_idx(const char *path, struct packed_git *p) return 0; } +int open_pack_index(struct packed_git *p) +{ + char *idx_name; + int ret; + + if (p->index_data) + return 0; + + idx_name = xstrdup(p->pack_name); + strcpy(idx_name + strlen(idx_name) - strlen(".pack"), ".idx"); + ret = check_packed_git_idx(idx_name, p); + free(idx_name); + return ret; +} + static void scan_windows(struct packed_git *p, struct packed_git **lru_p, struct pack_window **lru_w, @@ -612,6 +630,9 @@ static int open_packed_git_1(struct packed_git *p) unsigned char *idx_sha1; long fd_flag; + if (!p->index_data && open_pack_index(p)) + return error("packfile %s index unavailable", p->pack_name); + p->pack_fd = open(p->pack_name, O_RDONLY); if (p->pack_fd < 0 || fstat(p->pack_fd, &st)) return -1; @@ -764,8 +785,7 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local) return NULL; memcpy(p->pack_name, path, path_len); strcpy(p->pack_name + path_len, ".pack"); - if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode) || - check_packed_git_idx(path, p)) { + if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) { free(p); return NULL; } @@ -773,6 +793,10 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local) /* ok, it looks sane as far as we can check without * actually mapping the pack file. */ + p->index_version = 0; + p->index_data = NULL; + p->index_size = 0; + p->num_objects = 0; p->pack_size = st.st_size; p->next = NULL; p->windows = NULL; @@ -950,7 +974,7 @@ int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long siz return hashcmp(sha1, real_sha1) ? -1 : 0; } -void *map_sha1_file(const unsigned char *sha1, unsigned long *size) +static void *map_sha1_file(const unsigned char *sha1, unsigned long *size) { struct stat st; void *map; @@ -985,7 +1009,7 @@ void *map_sha1_file(const unsigned char *sha1, unsigned long *size) return map; } -int legacy_loose_object(unsigned char *map) +static int legacy_loose_object(unsigned char *map) { unsigned int word; @@ -1047,6 +1071,14 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon return inflate(stream, 0); } + + /* + * There used to be a second loose object header format which + * was meant to mimic the in-pack format, allowing for direct + * copy of the object data. This format turned up not to be + * really worth it and we don't write it any longer. But we + * can still read it. + */ used = unpack_object_header_gently(map, mapsize, &type, &size); if (!used || !valid_loose_object_type[type]) return -1; @@ -1122,7 +1154,7 @@ static int parse_sha1_header(const char *hdr, unsigned long *sizep) unsigned long size; /* - * The type can be at most ten bytes (including the + * The type can be at most ten bytes (including the * terminating '\0' that we add), and is followed by * a space. */ @@ -1461,11 +1493,8 @@ found_cache_entry: ent->lru.next->prev = ent->lru.prev; ent->lru.prev->next = ent->lru.next; delta_base_cached -= ent->size; - } - else { - ret = xmalloc(ent->size + 1); - memcpy(ret, ent->data, ent->size); - ((char *)ret)[ent->size] = 0; + } else { + ret = xmemdupz(ent->data, ent->size); } *type = ent->type; *base_size = ent->size; @@ -1540,6 +1569,10 @@ static void *unpack_delta_entry(struct packed_git *p, (uintmax_t)base_offset, p->pack_name); delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size); + if (!delta_data) + die("failed to unpack compressed delta" + " at %"PRIuMAX" from %s", + (uintmax_t)curpos, p->pack_name); result = patch_delta(base, base_size, delta_data, delta_size, sizep); @@ -1577,10 +1610,15 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset, return data; } -const unsigned char *nth_packed_object_sha1(const struct packed_git *p, +const unsigned char *nth_packed_object_sha1(struct packed_git *p, uint32_t n) { const unsigned char *index = p->index_data; + if (!index) { + if (open_pack_index(p)) + return NULL; + index = p->index_data; + } if (n >= p->num_objects) return NULL; index += 4 * 256; @@ -1617,6 +1655,12 @@ off_t find_pack_entry_one(const unsigned char *sha1, const unsigned char *index = p->index_data; unsigned hi, lo; + if (!index) { + if (open_pack_index(p)) + return 0; + level1_ofs = p->index_data; + index = p->index_data; + } if (p->index_version > 1) { level1_ofs += 2; index += 8; @@ -1639,40 +1683,45 @@ off_t find_pack_entry_one(const unsigned char *sha1, return 0; } -static int matches_pack_name(struct packed_git *p, const char *ig) +int matches_pack_name(struct packed_git *p, const char *name) { const char *last_c, *c; - if (!strcmp(p->pack_name, ig)) - return 0; + if (!strcmp(p->pack_name, name)) + return 1; for (c = p->pack_name, last_c = c; *c;) if (*c == '/') last_c = ++c; else ++c; - if (!strcmp(last_c, ig)) - return 0; + if (!strcmp(last_c, name)) + return 1; - return 1; + return 0; } static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed) { + static struct packed_git *last_found = (void *)1; struct packed_git *p; off_t offset; prepare_packed_git(); + if (!packed_git) + return 0; + p = (last_found == (void *)1) ? packed_git : last_found; - for (p = packed_git; p; p = p->next) { + do { if (ignore_packed) { const char **ig; for (ig = ignore_packed; *ig; ig++) - if (!matches_pack_name(p, *ig)) + if (matches_pack_name(p, *ig)) break; if (*ig) - continue; + goto next; } + offset = find_pack_entry_one(sha1, p); if (offset) { /* @@ -1685,18 +1734,27 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, cons */ if (p->pack_fd == -1 && open_packed_git(p)) { error("packfile %s cannot be accessed", p->pack_name); - continue; + goto next; } e->offset = offset; e->p = p; hashcpy(e->sha1, sha1); + last_found = p; return 1; } - } + + next: + if (p == last_found) + p = packed_git; + else + p = p->next; + if (p == last_found) + p = p->next; + } while (p); return 0; } -struct packed_git *find_sha1_pack(const unsigned char *sha1, +struct packed_git *find_sha1_pack(const unsigned char *sha1, struct packed_git *packs) { struct packed_git *p; @@ -1813,12 +1871,9 @@ void *read_sha1_file(const unsigned char *sha1, enum object_type *type, co = find_cached_object(sha1); if (co) { - buf = xmalloc(co->size + 1); - memcpy(buf, co->buf, co->size); - ((char*)buf)[co->size] = 0; *type = co->type; *size = co->size; - return buf; + return xmemdupz(co->buf, co->size); } buf = read_packed_sha1(sha1, type, size); @@ -1975,40 +2030,6 @@ static int write_buffer(int fd, const void *buf, size_t len) return 0; } -static int write_binary_header(unsigned char *hdr, enum object_type type, unsigned long len) -{ - int hdr_len; - unsigned char c; - - c = (type << 4) | (len & 15); - len >>= 4; - hdr_len = 1; - while (len) { - *hdr++ = c | 0x80; - hdr_len++; - c = (len & 0x7f); - len >>= 7; - } - *hdr = c; - return hdr_len; -} - -static void setup_object_header(z_stream *stream, const char *type, unsigned long len) -{ - int obj_type, hdrlen; - - if (use_legacy_headers) { - while (deflate(stream, 0) == Z_OK) - /* nothing */; - return; - } - obj_type = type_from_string(type); - hdrlen = write_binary_header(stream->next_out, obj_type, len); - stream->total_out = hdrlen; - stream->next_out += hdrlen; - stream->avail_out -= hdrlen; -} - int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1) { @@ -2075,7 +2096,8 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha /* First header.. */ stream.next_in = (unsigned char *)hdr; stream.avail_in = hdrlen; - setup_object_header(&stream, type, len); + while (deflate(&stream, 0) == Z_OK) + /* nothing */; /* Then the data itself.. */ stream.next_in = buf; @@ -2276,59 +2298,25 @@ int has_sha1_file(const unsigned char *sha1) return find_sha1_file(sha1, &st) ? 1 : 0; } -/* - * reads from fd as long as possible into a supplied buffer of size bytes. - * If necessary the buffer's size is increased using realloc() - * - * returns 0 if anything went fine and -1 otherwise - * - * NOTE: both buf and size may change, but even when -1 is returned - * you still have to free() it yourself. - */ -int read_pipe(int fd, char** return_buf, unsigned long* return_size) -{ - char* buf = *return_buf; - unsigned long size = *return_size; - ssize_t iret; - unsigned long off = 0; - - do { - iret = xread(fd, buf + off, size - off); - if (iret > 0) { - off += iret; - if (off == size) { - size *= 2; - buf = xrealloc(buf, size); - } - } - } while (iret > 0); - - *return_buf = buf; - *return_size = off; - - if (iret < 0) - return -1; - return 0; -} - int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object) { - unsigned long size = 4096; - char *buf = xmalloc(size); + struct strbuf buf; int ret; - if (read_pipe(fd, &buf, &size)) { - free(buf); + strbuf_init(&buf, 0); + if (strbuf_read(&buf, fd, 4096) < 0) { + strbuf_release(&buf); return -1; } if (!type) type = blob_type; if (write_object) - ret = write_sha1_file(buf, size, type, sha1); + ret = write_sha1_file(buf.buf, buf.len, type, sha1); else - ret = hash_sha1_file(buf, size, type, sha1); - free(buf); + ret = hash_sha1_file(buf.buf, buf.len, type, sha1); + strbuf_release(&buf); + return ret; } @@ -2350,12 +2338,11 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, * Convert blobs to git internal format */ if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) { - unsigned long nsize = size; - char *nbuf = convert_to_git(path, buf, &nsize); - if (nbuf) { + struct strbuf nbuf; + strbuf_init(&nbuf, 0); + if (convert_to_git(path, buf, size, &nbuf)) { munmap(buf, size); - size = nsize; - buf = nbuf; + buf = strbuf_detach(&nbuf, &size); re_allocated = 1; } }