diff options
Diffstat (limited to 'sha1_file.c')
| -rw-r--r-- | sha1_file.c | 134 |
1 files changed, 85 insertions, 49 deletions
diff --git a/sha1_file.c b/sha1_file.c index 657825e14e..0cd9435619 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -35,13 +35,6 @@ static size_t sz_fmt(size_t s) { return s; } const unsigned char null_sha1[20]; -static inline int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + (path[2] == '/'); - return *path == '/'; -} - int safe_create_leading_directories(char *path) { char *pos = path + offset_1st_component(path); @@ -109,20 +102,22 @@ static void fill_sha1_path(char *pathbuf, const unsigned char *sha1) */ char *sha1_file_name(const unsigned char *sha1) { - static char *name, *base; + static char buf[PATH_MAX]; + const char *objdir; + int len; - if (!base) { - const char *sha1_file_directory = get_object_directory(); - int len = strlen(sha1_file_directory); - base = xmalloc(len + 60); - memcpy(base, sha1_file_directory, len); - memset(base+len, 0, 60); - base[len] = '/'; - base[len+3] = '/'; - name = base + len + 1; - } - fill_sha1_path(name, sha1); - return base; + objdir = get_object_directory(); + len = strlen(objdir); + + /* '/' + sha1(2) + '/' + sha1(38) + '\0' */ + if (len + 43 > PATH_MAX) + die("insanely long object directory %s", objdir); + memcpy(buf, objdir, len); + buf[len] = '/'; + buf[len+3] = '/'; + buf[len+42] = '\0'; + fill_sha1_path(buf + len + 1, sha1); + return buf; } static char *sha1_get_pack_name(const unsigned char *sha1, @@ -606,6 +601,14 @@ void unuse_pack(struct pack_window **w_cursor) } } +void close_pack_index(struct packed_git *p) +{ + if (p->index_data) { + munmap((void *)p->index_data, p->index_size); + p->index_data = NULL; + } +} + /* * This is used by git-repack in case a newly created pack happens to * contain the same set of objects as an existing one. In that case @@ -627,8 +630,7 @@ void free_pack_by_name(const char *pack_name) close_pack_windows(p); if (p->pack_fd != -1) close(p->pack_fd); - if (p->index_data) - munmap((void *)p->index_data, p->index_size); + close_pack_index(p); free(p->bad_object_sha1); *pp = p->next; free(p); @@ -838,9 +840,8 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local) return p; } -struct packed_git *parse_pack_index(unsigned char *sha1) +struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path) { - const char *idx_path = sha1_pack_index_name(sha1); const char *path = sha1_pack_name(sha1); struct packed_git *p = alloc_packed_git(strlen(path) + 1); @@ -2085,6 +2086,7 @@ void *read_sha1_file_repl(const unsigned char *sha1, { const unsigned char *repl = lookup_replace_object(sha1); void *data = read_object(repl, type, size); + char *path; /* die if we replaced an object with one that does not exist */ if (!data && repl != sha1) @@ -2092,8 +2094,16 @@ void *read_sha1_file_repl(const unsigned char *sha1, sha1_to_hex(repl), sha1_to_hex(sha1)); /* legacy behavior is to die on corrupted objects */ - if (!data && (has_loose_object(repl) || has_packed_and_bad(repl))) - die("object %s is corrupted", sha1_to_hex(repl)); + if (!data) { + if (has_loose_object(repl)) { + path = sha1_file_name(sha1); + die("loose object %s (stored in %s) is corrupted", sha1_to_hex(repl), path); + } + if (has_packed_and_bad(repl)) { + path = sha1_pack_name(sha1); + die("packed object %s (stored in %s) is corrupted", sha1_to_hex(repl), path); + } + } if (replacement) *replacement = repl; @@ -2206,7 +2216,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename) } out: - if (set_shared_perm(filename, (S_IFREG|0444))) + if (adjust_shared_perm(filename)) return error("unable to set permission to '%s'", filename); return 0; } @@ -2262,7 +2272,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename) } memcpy(buffer, filename, dirlen); strcpy(buffer + dirlen, "tmp_obj_XXXXXX"); - fd = mkstemp(buffer); + fd = git_mkstemp_mode(buffer, 0444); if (fd < 0 && dirlen && errno == ENOENT) { /* Make sure the directory exists */ memcpy(buffer, filename, dirlen); @@ -2272,18 +2282,19 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename) /* Try again */ strcpy(buffer + dirlen - 1, "/tmp_obj_XXXXXX"); - fd = mkstemp(buffer); + fd = git_mkstemp_mode(buffer, 0444); } return fd; } static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen, - void *buf, unsigned long len, time_t mtime) + const void *buf, unsigned long len, time_t mtime) { int fd, ret; - size_t size; - unsigned char *compressed; + unsigned char compressed[4096]; z_stream stream; + git_SHA_CTX c; + unsigned char parano_sha1[20]; char *filename; static char tmpfile[PATH_MAX]; @@ -2301,36 +2312,40 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen, /* Set it up */ memset(&stream, 0, sizeof(stream)); deflateInit(&stream, zlib_compression_level); - size = 8 + deflateBound(&stream, len+hdrlen); - compressed = xmalloc(size); - - /* Compress it */ stream.next_out = compressed; - stream.avail_out = size; + stream.avail_out = sizeof(compressed); + git_SHA1_Init(&c); /* First header.. */ stream.next_in = (unsigned char *)hdr; stream.avail_in = hdrlen; while (deflate(&stream, 0) == Z_OK) /* nothing */; + git_SHA1_Update(&c, hdr, hdrlen); /* Then the data itself.. */ - stream.next_in = buf; + stream.next_in = (void *)buf; stream.avail_in = len; - ret = deflate(&stream, Z_FINISH); + do { + unsigned char *in0 = stream.next_in; + ret = deflate(&stream, Z_FINISH); + git_SHA1_Update(&c, in0, stream.next_in - in0); + if (write_buffer(fd, compressed, stream.next_out - compressed) < 0) + die("unable to write sha1 file"); + stream.next_out = compressed; + stream.avail_out = sizeof(compressed); + } while (ret == Z_OK); + if (ret != Z_STREAM_END) die("unable to deflate new object %s (%d)", sha1_to_hex(sha1), ret); - ret = deflateEnd(&stream); if (ret != Z_OK) die("deflateEnd on object %s failed (%d)", sha1_to_hex(sha1), ret); + git_SHA1_Final(parano_sha1, &c); + if (hashcmp(sha1, parano_sha1) != 0) + die("confused by unstable object source data for %s", sha1_to_hex(sha1)); - size = stream.total_out; - - if (write_buffer(fd, compressed, size) < 0) - die("unable to write sha1 file"); close_sha1_file(fd); - free(compressed); if (mtime) { struct utimbuf utb; @@ -2344,7 +2359,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen, return move_temp_to_file(tmpfile, filename); } -int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1) +int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1) { unsigned char sha1[20]; char hdr[32]; @@ -2434,6 +2449,8 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, return ret; } +#define SMALL_FILE_SIZE (32*1024) + int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path) { @@ -2448,12 +2465,21 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, else ret = -1; strbuf_release(&sbuf); - } else if (size) { + } else if (!size) { + ret = index_mem(sha1, NULL, size, write_object, type, path); + } else if (size <= SMALL_FILE_SIZE) { + char *buf = xmalloc(size); + if (size == read_in_full(fd, buf, size)) + ret = index_mem(sha1, buf, size, write_object, type, + path); + else + ret = error("short read %s", strerror(errno)); + free(buf); + } else { void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); ret = index_mem(sha1, buf, size, write_object, type, path); munmap(buf, size); - } else - ret = index_mem(sha1, NULL, size, write_object, type, path); + } close(fd); return ret; } @@ -2508,3 +2534,13 @@ int read_pack_header(int fd, struct pack_header *header) return PH_ERROR_PROTOCOL; return 0; } + +void assert_sha1_type(const unsigned char *sha1, enum object_type expect) +{ + enum object_type type = sha1_object_info(sha1, NULL); + if (type < 0) + die("%s is not a valid object", sha1_to_hex(sha1)); + if (type != expect) + die("%s is not a valid '%s' object", sha1_to_hex(sha1), + typename(expect)); +} |
