X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=sha1_file.c;h=631a605201e3a737e8e3db25f85f01a228b01282;hb=3a3e89b897e122f1f154293e55b1d6c863ffbd2c;hp=a80d849f15936c8fa7aa8f362bcb54b98a892f08;hpb=4d569a2c422a9655390e7d33cad0bab88379f13d;p=git.git diff --git a/sha1_file.c b/sha1_file.c index a80d849f..631a6052 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -9,6 +9,10 @@ #include "cache.h" #include "delta.h" #include "pack.h" +#include "blob.h" +#include "commit.h" +#include "tag.h" +#include "tree.h" #ifndef O_NOATIME #if defined(__linux__) && (defined(__i386__) || defined(__PPC__)) @@ -104,9 +108,10 @@ int safe_create_leading_directories(char *path) char * sha1_to_hex(const unsigned char *sha1) { - static char buffer[50]; + static int bufno; + static char hexbuffer[4][50]; static const char hex[] = "0123456789abcdef"; - char *buf = buffer; + char *buffer = hexbuffer[3 & ++bufno], *buf = buffer; int i; for (i = 0; i < 20; i++) { @@ -212,6 +217,8 @@ char *sha1_pack_index_name(const unsigned char *sha1) struct alternate_object_database *alt_odb_list; static struct alternate_object_database **alt_odb_tail; +static void read_info_alternates(const char * alternates, int depth); + /* * Prepare alternate object database registry. * @@ -227,14 +234,85 @@ static struct alternate_object_database **alt_odb_tail; * SHA1, an extra slash for the first level indirection, and the * terminating NUL. */ -static void link_alt_odb_entries(const char *alt, const char *ep, int sep, - const char *relative_base) +static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth) { - const char *cp, *last; - struct alternate_object_database *ent; + struct stat st; const char *objdir = get_object_directory(); + struct alternate_object_database *ent; + struct alternate_object_database *alt; + /* 43 = 40-byte + 2 '/' + terminating NUL */ + int pfxlen = len; + int entlen = pfxlen + 43; int base_len = -1; + if (*entry != '/' && relative_base) { + /* Relative alt-odb */ + if (base_len < 0) + base_len = strlen(relative_base) + 1; + entlen += base_len; + pfxlen += base_len; + } + ent = xmalloc(sizeof(*ent) + entlen); + + if (*entry != '/' && relative_base) { + memcpy(ent->base, relative_base, base_len - 1); + ent->base[base_len - 1] = '/'; + memcpy(ent->base + base_len, entry, len); + } + else + memcpy(ent->base, entry, pfxlen); + + ent->name = ent->base + pfxlen + 1; + ent->base[pfxlen + 3] = '/'; + ent->base[pfxlen] = ent->base[entlen-1] = 0; + + /* Detect cases where alternate disappeared */ + if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) { + error("object directory %s does not exist; " + "check .git/objects/info/alternates.", + ent->base); + free(ent); + return -1; + } + + /* Prevent the common mistake of listing the same + * thing twice, or object directory itself. + */ + for (alt = alt_odb_list; alt; alt = alt->next) { + if (!memcmp(ent->base, alt->base, pfxlen)) { + free(ent); + return -1; + } + } + if (!memcmp(ent->base, objdir, pfxlen)) { + free(ent); + return -1; + } + + /* add the alternate entry */ + *alt_odb_tail = ent; + alt_odb_tail = &(ent->next); + ent->next = NULL; + + /* recursively add alternates */ + read_info_alternates(ent->base, depth + 1); + + ent->base[pfxlen] = '/'; + + return 0; +} + +static void link_alt_odb_entries(const char *alt, const char *ep, int sep, + const char *relative_base, int depth) +{ + const char *cp, *last; + + if (depth > 5) { + error("%s: ignoring alternate object stores, nesting too deep.", + relative_base); + return; + } + last = alt; while (last < ep) { cp = last; @@ -244,60 +322,15 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep, last = cp + 1; continue; } - for ( ; cp < ep && *cp != sep; cp++) - ; + while (cp < ep && *cp != sep) + cp++; if (last != cp) { - struct stat st; - struct alternate_object_database *alt; - /* 43 = 40-byte + 2 '/' + terminating NUL */ - int pfxlen = cp - last; - int entlen = pfxlen + 43; - - if (*last != '/' && relative_base) { - /* Relative alt-odb */ - if (base_len < 0) - base_len = strlen(relative_base) + 1; - entlen += base_len; - pfxlen += base_len; - } - ent = xmalloc(sizeof(*ent) + entlen); - - if (*last != '/' && relative_base) { - memcpy(ent->base, relative_base, base_len - 1); - ent->base[base_len - 1] = '/'; - memcpy(ent->base + base_len, - last, cp - last); - } - else - memcpy(ent->base, last, pfxlen); - - ent->name = ent->base + pfxlen + 1; - ent->base[pfxlen + 3] = '/'; - ent->base[pfxlen] = ent->base[entlen-1] = 0; - - /* Detect cases where alternate disappeared */ - if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) { - error("object directory %s does not exist; " - "check .git/objects/info/alternates.", - ent->base); - goto bad; - } - ent->base[pfxlen] = '/'; - - /* Prevent the common mistake of listing the same - * thing twice, or object directory itself. - */ - for (alt = alt_odb_list; alt; alt = alt->next) - if (!memcmp(ent->base, alt->base, pfxlen)) - goto bad; - if (!memcmp(ent->base, objdir, pfxlen)) { - bad: - free(ent); - } - else { - *alt_odb_tail = ent; - alt_odb_tail = &(ent->next); - ent->next = NULL; + if ((*last != '/') && depth) { + error("%s: ignoring relative alternate object store %s", + relative_base, last); + } else { + link_alt_odb_entry(last, cp - last, + relative_base, depth); } } while (cp < ep && *cp == sep) @@ -306,23 +339,14 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep, } } -void prepare_alt_odb(void) +static void read_info_alternates(const char * relative_base, int depth) { - char path[PATH_MAX]; char *map; - int fd; struct stat st; - char *alt; - - 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); + char path[PATH_MAX]; + int fd; - sprintf(path, "%s/info/alternates", get_object_directory()); + sprintf(path, "%s/info/alternates", relative_base); fd = open(path, O_RDONLY); if (fd < 0) return; @@ -335,11 +359,26 @@ void prepare_alt_odb(void) if (map == MAP_FAILED) return; - link_alt_odb_entries(map, map + st.st_size, '\n', - get_object_directory()); + link_alt_odb_entries(map, map + st.st_size, '\n', relative_base, depth); + munmap(map, st.st_size); } +void prepare_alt_odb(void) +{ + char *alt; + + 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); + + read_info_alternates(get_object_directory(), 0); +} + static char *find_sha1_file(const unsigned char *sha1, struct stat *st) { char *name = sha1_file_name(sha1); @@ -804,10 +843,12 @@ static int packed_delta_info(unsigned char *base_sha1, * the result size. */ data = delta_head; - get_delta_hdr_size(&data); /* ignore base size */ + + /* ignore base size */ + get_delta_hdr_size(&data, delta_head+sizeof(delta_head)); /* Read the result size */ - result_size = get_delta_hdr_size(&data); + result_size = get_delta_hdr_size(&data, delta_head+sizeof(delta_head)); *sizep = result_size; } return 0; @@ -868,17 +909,19 @@ void packed_object_info_detail(struct pack_entry *e, unsigned char *base_sha1) { struct packed_git *p = e->p; - unsigned long offset, left; + unsigned long offset; 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 { unsigned int chain_length = 0; + if (p->pack_size <= offset + 20) + die("pack file %s records an incomplete delta base", + p->pack_name); memcpy(base_sha1, pack, 20); do { struct pack_entry base_ent; @@ -894,16 +937,16 @@ void packed_object_info_detail(struct pack_entry *e, } switch (kind) { case OBJ_COMMIT: - strcpy(type, "commit"); + strcpy(type, commit_type); break; case OBJ_TREE: - strcpy(type, "tree"); + strcpy(type, tree_type); break; case OBJ_BLOB: - strcpy(type, "blob"); + strcpy(type, blob_type); break; case OBJ_TAG: - strcpy(type, "tag"); + strcpy(type, tag_type); break; default: die("corrupted pack file %s containing object of kind %d", @@ -934,16 +977,16 @@ static int packed_object_info(struct pack_entry *entry, unuse_packed_git(p); return retval; case OBJ_COMMIT: - strcpy(type, "commit"); + strcpy(type, commit_type); break; case OBJ_TREE: - strcpy(type, "tree"); + strcpy(type, tree_type); break; case OBJ_BLOB: - strcpy(type, "blob"); + strcpy(type, blob_type); break; case OBJ_TAG: - strcpy(type, "tag"); + strcpy(type, tag_type); break; default: die("corrupted pack file %s containing object of kind %d", @@ -973,6 +1016,16 @@ static void *unpack_delta_entry(unsigned char *base_sha1, if (left < 20) die("truncated pack file"); + + /* 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)); + data = base_sha1 + 20; data_size = left - 20; delta_data = xmalloc(delta_size); @@ -990,14 +1043,6 @@ static void *unpack_delta_entry(unsigned char *base_sha1, if ((st != Z_STREAM_END) || stream.total_out != delta_size) die("delta data unpack failed"); - /* 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)); result = patch_delta(base, base_size, delta_data, delta_size, &result_size); @@ -1069,16 +1114,16 @@ void *unpack_entry_gently(struct pack_entry *entry, retval = unpack_delta_entry(pack, size, left, type, sizep, p); return retval; case OBJ_COMMIT: - strcpy(type, "commit"); + strcpy(type, commit_type); break; case OBJ_TREE: - strcpy(type, "tree"); + strcpy(type, tree_type); break; case OBJ_BLOB: - strcpy(type, "blob"); + strcpy(type, blob_type); break; case OBJ_TAG: - strcpy(type, "tag"); + strcpy(type, tag_type); break; default: return NULL; @@ -1116,7 +1161,7 @@ int find_pack_entry_one(const unsigned char *sha1, int mi = (lo + hi) / 2; int cmp = memcmp(index + 24 * mi + 4, sha1, 20); if (!cmp) { - e->offset = ntohl(*((int*)(index + 24 * mi))); + e->offset = ntohl(*((uint32_t *)(index + 24 * mi))); memcpy(e->sha1, sha1, 20); e->p = p; return 1; @@ -1239,9 +1284,9 @@ void *read_object_with_reference(const unsigned char *sha1, return buffer; } /* Handle references */ - else if (!strcmp(type, "commit")) + else if (!strcmp(type, commit_type)) ref_type = "tree "; - else if (!strcmp(type, "tag")) + else if (!strcmp(type, tag_type)) ref_type = "object "; else { free(buffer); @@ -1623,7 +1668,7 @@ int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object) return -1; } if (!type) - type = "blob"; + type = blob_type; if (write_object) ret = write_sha1_file(buf, off, type, sha1); else { @@ -1650,7 +1695,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, con return -1; if (!type) - type = "blob"; + type = blob_type; if (write_object) ret = write_sha1_file(buf, size, type, sha1); else { @@ -1688,9 +1733,9 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write if (!write_object) { unsigned char hdr[50]; int hdrlen; - write_sha1_file_prepare(target, st->st_size, "blob", + write_sha1_file_prepare(target, st->st_size, blob_type, sha1, hdr, &hdrlen); - } else if (write_sha1_file(target, st->st_size, "blob", sha1)) + } else if (write_sha1_file(target, st->st_size, blob_type, sha1)) return error("%s: failed to insert into database", path); free(target);