diff options
Diffstat (limited to 'sha1-file.c')
-rw-r--r-- | sha1-file.c | 325 |
1 files changed, 205 insertions, 120 deletions
diff --git a/sha1-file.c b/sha1-file.c index 5bd11c85bc..c8da9f3475 100644 --- a/sha1-file.c +++ b/sha1-file.c @@ -40,10 +40,20 @@ #define EMPTY_TREE_SHA1_BIN_LITERAL \ "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \ "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04" +#define EMPTY_TREE_SHA256_BIN_LITERAL \ + "\x6e\xf1\x9b\x41\x22\x5c\x53\x69\xf1\xc1" \ + "\x04\xd4\x5d\x8d\x85\xef\xa9\xb0\x57\xb5" \ + "\x3b\x14\xb4\xb9\xb9\x39\xdd\x74\xde\xcc" \ + "\x53\x21" #define EMPTY_BLOB_SHA1_BIN_LITERAL \ "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \ "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91" +#define EMPTY_BLOB_SHA256_BIN_LITERAL \ + "\x47\x3a\x0f\x4c\x3b\xe8\xa9\x36\x81\xa2" \ + "\x67\xe3\xb1\xe9\xa7\xdc\xda\x11\x85\x43" \ + "\x6f\xe1\x41\xf7\x74\x91\x20\xa3\x03\x72" \ + "\x18\x13" const unsigned char null_sha1[GIT_MAX_RAWSZ]; const struct object_id null_oid; @@ -53,6 +63,12 @@ static const struct object_id empty_tree_oid = { static const struct object_id empty_blob_oid = { EMPTY_BLOB_SHA1_BIN_LITERAL }; +static const struct object_id empty_tree_oid_sha256 = { + EMPTY_TREE_SHA256_BIN_LITERAL +}; +static const struct object_id empty_blob_oid_sha256 = { + EMPTY_BLOB_SHA256_BIN_LITERAL +}; static void git_hash_sha1_init(git_hash_ctx *ctx) { @@ -69,6 +85,22 @@ static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx) git_SHA1_Final(hash, &ctx->sha1); } + +static void git_hash_sha256_init(git_hash_ctx *ctx) +{ + git_SHA256_Init(&ctx->sha256); +} + +static void git_hash_sha256_update(git_hash_ctx *ctx, const void *data, size_t len) +{ + git_SHA256_Update(&ctx->sha256, data, len); +} + +static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx) +{ + git_SHA256_Final(hash, &ctx->sha256); +} + static void git_hash_unknown_init(git_hash_ctx *ctx) { BUG("trying to init unknown hash"); @@ -90,6 +122,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { 0x00000000, 0, 0, + 0, git_hash_unknown_init, git_hash_unknown_update, git_hash_unknown_final, @@ -97,17 +130,31 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { NULL, }, { - "sha-1", + "sha1", /* "sha1", big-endian */ 0x73686131, GIT_SHA1_RAWSZ, GIT_SHA1_HEXSZ, + GIT_SHA1_BLKSZ, git_hash_sha1_init, git_hash_sha1_update, git_hash_sha1_final, &empty_tree_oid, &empty_blob_oid, }, + { + "sha256", + /* "s256", big-endian */ + 0x73323536, + GIT_SHA256_RAWSZ, + GIT_SHA256_HEXSZ, + GIT_SHA256_BLKSZ, + git_hash_sha256_init, + git_hash_sha256_update, + git_hash_sha256_final, + &empty_tree_oid_sha256, + &empty_blob_oid_sha256, + } }; const char *empty_tree_oid_hex(void) @@ -122,6 +169,27 @@ const char *empty_blob_oid_hex(void) return oid_to_hex_r(buf, the_hash_algo->empty_blob); } +int hash_algo_by_name(const char *name) +{ + int i; + if (!name) + return GIT_HASH_UNKNOWN; + for (i = 1; i < GIT_HASH_NALGOS; i++) + if (!strcmp(name, hash_algos[i].name)) + return i; + return GIT_HASH_UNKNOWN; +} + +int hash_algo_by_id(uint32_t format_id) +{ + int i; + for (i = 1; i < GIT_HASH_NALGOS; i++) + if (format_id == hash_algos[i].format_id) + return i; + return GIT_HASH_UNKNOWN; +} + + /* * This is meant to hold a *small* number of objects that you would * want read_sha1_file() to be able to return, but yet you do not want @@ -346,25 +414,21 @@ static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1) } } -void sha1_file_name(struct repository *r, struct strbuf *buf, const unsigned char *sha1) +static const char *odb_loose_path(struct object_directory *odb, + struct strbuf *buf, + const unsigned char *sha1) { - strbuf_addstr(buf, r->objects->objectdir); + strbuf_reset(buf); + strbuf_addstr(buf, odb->path); strbuf_addch(buf, '/'); fill_sha1_path(buf, sha1); + return buf->buf; } -struct strbuf *alt_scratch_buf(struct alternate_object_database *alt) +const char *loose_object_path(struct repository *r, struct strbuf *buf, + const unsigned char *sha1) { - strbuf_setlen(&alt->scratch, alt->base_len); - return &alt->scratch; -} - -static const char *alt_sha1_path(struct alternate_object_database *alt, - const unsigned char *sha1) -{ - struct strbuf *buf = alt_scratch_buf(alt); - fill_sha1_path(buf, sha1); - return buf->buf; + return odb_loose_path(r->objects->odb, buf, sha1); } /* @@ -374,7 +438,7 @@ static int alt_odb_usable(struct raw_object_store *o, struct strbuf *path, const char *normalized_objdir) { - struct alternate_object_database *alt; + struct object_directory *odb; /* Detect cases where alternate disappeared */ if (!is_directory(path->buf)) { @@ -388,8 +452,8 @@ static int alt_odb_usable(struct raw_object_store *o, * Prevent the common mistake of listing the same * thing twice, or object directory itself. */ - for (alt = o->alt_odb_list; alt; alt = alt->next) { - if (!fspathcmp(path->buf, alt->path)) + for (odb = o->odb; odb; odb = odb->next) { + if (!fspathcmp(path->buf, odb->path)) return 0; } if (!fspathcmp(path->buf, normalized_objdir)) @@ -402,7 +466,7 @@ static int alt_odb_usable(struct raw_object_store *o, * Prepare alternate object database registry. * * The variable alt_odb_list points at the list of struct - * alternate_object_database. The elements on this list come from + * object_directory. The elements on this list come from * non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT * environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates, * whose contents is similar to that environment variable but can be @@ -419,7 +483,7 @@ static void read_info_alternates(struct repository *r, static int link_alt_odb_entry(struct repository *r, const char *entry, const char *relative_base, int depth, const char *normalized_objdir) { - struct alternate_object_database *ent; + struct object_directory *ent; struct strbuf pathbuf = STRBUF_INIT; if (!is_absolute_path(entry) && relative_base) { @@ -447,11 +511,12 @@ static int link_alt_odb_entry(struct repository *r, const char *entry, return -1; } - ent = alloc_alt_odb(pathbuf.buf); + ent = xcalloc(1, sizeof(*ent)); + ent->path = xstrdup(pathbuf.buf); /* add the alternate entry */ - *r->objects->alt_odb_tail = ent; - r->objects->alt_odb_tail = &(ent->next); + *r->objects->odb_tail = ent; + r->objects->odb_tail = &(ent->next); ent->next = NULL; /* recursively add alternates */ @@ -505,7 +570,7 @@ static void link_alt_odb_entries(struct repository *r, const char *alt, return; } - strbuf_add_absolute_path(&objdirbuf, r->objects->objectdir); + strbuf_add_absolute_path(&objdirbuf, r->objects->odb->path); if (strbuf_normalize_path(&objdirbuf) < 0) die(_("unable to normalize object directory: %s"), objdirbuf.buf); @@ -540,18 +605,6 @@ static void read_info_alternates(struct repository *r, free(path); } -struct alternate_object_database *alloc_alt_odb(const char *dir) -{ - struct alternate_object_database *ent; - - FLEX_ALLOC_STR(ent, path, dir); - strbuf_init(&ent->scratch, 0); - strbuf_addf(&ent->scratch, "%s/", dir); - ent->base_len = ent->scratch.len; - - return ent; -} - void add_to_alternates_file(const char *reference) { struct lock_file lock = LOCK_INIT; @@ -588,7 +641,7 @@ void add_to_alternates_file(const char *reference) fprintf_or_die(out, "%s\n", reference); if (commit_lock_file(&lock)) die_errno(_("unable to move new alternates file into place")); - if (the_repository->objects->alt_odb_tail) + if (the_repository->objects->loaded_alternates) link_alt_odb_entries(the_repository, reference, '\n', NULL, 0); } @@ -684,11 +737,11 @@ out: int foreach_alt_odb(alt_odb_fn fn, void *cb) { - struct alternate_object_database *ent; + struct object_directory *ent; int r = 0; prepare_alt_odb(the_repository); - for (ent = the_repository->objects->alt_odb_list; ent; ent = ent->next) { + for (ent = the_repository->objects->odb->next; ent; ent = ent->next) { r = fn(ent, cb); if (r) break; @@ -698,13 +751,13 @@ int foreach_alt_odb(alt_odb_fn fn, void *cb) void prepare_alt_odb(struct repository *r) { - if (r->objects->alt_odb_tail) + if (r->objects->loaded_alternates) return; - r->objects->alt_odb_tail = &r->objects->alt_odb_list; link_alt_odb_entries(r, r->objects->alternate_db, PATH_SEP, NULL, 0); - read_info_alternates(r, r->objects->objectdir, 0); + read_info_alternates(r, r->objects->odb->path, 0); + r->objects->loaded_alternates = 1; } /* Returns 1 if we have successfully freshened the file, 0 otherwise. */ @@ -731,23 +784,27 @@ int check_and_freshen_file(const char *fn, int freshen) return 1; } -static int check_and_freshen_local(const struct object_id *oid, int freshen) +static int check_and_freshen_odb(struct object_directory *odb, + const struct object_id *oid, + int freshen) { - static struct strbuf buf = STRBUF_INIT; - - strbuf_reset(&buf); - sha1_file_name(the_repository, &buf, oid->hash); + static struct strbuf path = STRBUF_INIT; + odb_loose_path(odb, &path, oid->hash); + return check_and_freshen_file(path.buf, freshen); +} - return check_and_freshen_file(buf.buf, freshen); +static int check_and_freshen_local(const struct object_id *oid, int freshen) +{ + return check_and_freshen_odb(the_repository->objects->odb, oid, freshen); } static int check_and_freshen_nonlocal(const struct object_id *oid, int freshen) { - struct alternate_object_database *alt; + struct object_directory *odb; + prepare_alt_odb(the_repository); - for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) { - const char *path = alt_sha1_path(alt, oid->hash); - if (check_and_freshen_file(path, freshen)) + for (odb = the_repository->objects->odb->next; odb; odb = odb->next) { + if (check_and_freshen_odb(odb, oid, freshen)) return 1; } return 0; @@ -888,25 +945,17 @@ int git_open_cloexec(const char *name, int flags) * * The "path" out-parameter will give the path of the object we found (if any). * Note that it may point to static storage and is only valid until another - * call to sha1_file_name(), etc. + * call to stat_sha1_file(). */ static int stat_sha1_file(struct repository *r, const unsigned char *sha1, struct stat *st, const char **path) { - struct alternate_object_database *alt; + struct object_directory *odb; static struct strbuf buf = STRBUF_INIT; - strbuf_reset(&buf); - sha1_file_name(r, &buf, sha1); - *path = buf.buf; - - if (!lstat(*path, st)) - return 0; - prepare_alt_odb(r); - errno = ENOENT; - for (alt = r->objects->alt_odb_list; alt; alt = alt->next) { - *path = alt_sha1_path(alt, sha1); + for (odb = r->objects->odb; odb; odb = odb->next) { + *path = odb_loose_path(odb, &buf, sha1); if (!lstat(*path, st)) return 0; } @@ -922,25 +971,17 @@ static int open_sha1_file(struct repository *r, const unsigned char *sha1, const char **path) { int fd; - struct alternate_object_database *alt; - int most_interesting_errno; + struct object_directory *odb; + int most_interesting_errno = ENOENT; static struct strbuf buf = STRBUF_INIT; - strbuf_reset(&buf); - sha1_file_name(r, &buf, sha1); - *path = buf.buf; - - fd = git_open(*path); - if (fd >= 0) - return fd; - most_interesting_errno = errno; - prepare_alt_odb(r); - for (alt = r->objects->alt_odb_list; alt; alt = alt->next) { - *path = alt_sha1_path(alt, sha1); + for (odb = r->objects->odb; odb; odb = odb->next) { + *path = odb_loose_path(odb, &buf, sha1); fd = git_open(*path); if (fd >= 0) return fd; + if (most_interesting_errno == ENOENT) most_interesting_errno = errno; } @@ -948,6 +989,22 @@ static int open_sha1_file(struct repository *r, return -1; } +static int quick_has_loose(struct repository *r, + const unsigned char *sha1) +{ + struct object_id oid; + struct object_directory *odb; + + hashcpy(oid.hash, sha1); + + prepare_alt_odb(r); + for (odb = r->objects->odb; odb; odb = odb->next) { + if (oid_array_lookup(odb_loose_cache(odb, &oid), &oid) >= 0) + return 1; + } + return 0; +} + /* * Map the loose object at "path" if it is not NULL, or the path found by * searching for a loose object named "sha1". @@ -971,6 +1028,7 @@ static void *map_sha1_file_1(struct repository *r, const char *path, if (!*size) { /* mmap() is forbidden on empty files */ error(_("object file %s is empty"), path); + close(fd); return NULL; } map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0); @@ -1198,6 +1256,8 @@ static int sha1_loose_object_info(struct repository *r, if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) { const char *path; struct stat st; + if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK)) + return quick_has_loose(r, sha1) ? 0 : -1; if (stat_sha1_file(r, sha1, &st, &path) < 0) return -1; if (oi->disk_sizep) @@ -1361,7 +1421,9 @@ int oid_object_info(struct repository *r, return type; } -static void *read_object(const unsigned char *sha1, enum object_type *type, +static void *read_object(struct repository *r, + const unsigned char *sha1, + enum object_type *type, unsigned long *size) { struct object_id oid; @@ -1373,7 +1435,7 @@ static void *read_object(const unsigned char *sha1, enum object_type *type, hashcpy(oid.hash, sha1); - if (oid_object_info_extended(the_repository, &oid, &oi, 0) < 0) + if (oid_object_info_extended(r, &oid, &oi, 0) < 0) return NULL; return content; } @@ -1401,7 +1463,8 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type, * deal with them should arrange to call read_object() and give error * messages themselves. */ -void *read_object_file_extended(const struct object_id *oid, +void *read_object_file_extended(struct repository *r, + const struct object_id *oid, enum object_type *type, unsigned long *size, int lookup_replace) @@ -1411,10 +1474,10 @@ void *read_object_file_extended(const struct object_id *oid, const char *path; struct stat st; const struct object_id *repl = lookup_replace ? - lookup_replace_object(the_repository, oid) : oid; + lookup_replace_object(r, oid) : oid; errno = 0; - data = read_object(repl->hash, type, size); + data = read_object(r, repl->hash, type, size); if (data) return data; @@ -1426,11 +1489,11 @@ void *read_object_file_extended(const struct object_id *oid, die(_("replacement %s not found for %s"), oid_to_hex(repl), oid_to_hex(oid)); - if (!stat_sha1_file(the_repository, repl->hash, &st, &path)) + if (!stat_sha1_file(r, repl->hash, &st, &path)) die(_("loose object %s (stored in %s) is corrupt"), oid_to_hex(repl), path); - if ((p = has_packed_and_bad(repl->hash)) != NULL) + if ((p = has_packed_and_bad(r, repl->hash)) != NULL) die(_("packed object %s (stored in %s) is corrupt"), oid_to_hex(repl), p->pack_name); @@ -1626,8 +1689,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr, static struct strbuf tmp_file = STRBUF_INIT; static struct strbuf filename = STRBUF_INIT; - strbuf_reset(&filename); - sha1_file_name(the_repository, &filename, oid->hash); + loose_object_path(the_repository, &filename, oid->hash); fd = create_tmpfile(&tmp_file, filename.buf); if (fd < 0) { @@ -1755,7 +1817,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime) if (has_loose_object(oid)) return 0; - buf = read_object(oid->hash, &type, &len); + buf = read_object(the_repository, oid->hash, &type, &len); if (!buf) return error(_("cannot read sha1_file for %s"), oid_to_hex(oid)); hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1; @@ -1765,24 +1827,27 @@ int force_object_loose(const struct object_id *oid, time_t mtime) return ret; } -int has_sha1_file_with_flags(const unsigned char *sha1, int flags) +int repo_has_sha1_file_with_flags(struct repository *r, + const unsigned char *sha1, int flags) { struct object_id oid; if (!startup_info->have_repository) return 0; hashcpy(oid.hash, sha1); - return oid_object_info_extended(the_repository, &oid, NULL, + return oid_object_info_extended(r, &oid, NULL, flags | OBJECT_INFO_SKIP_CACHED) >= 0; } -int has_object_file(const struct object_id *oid) +int repo_has_object_file(struct repository *r, + const struct object_id *oid) { - return has_sha1_file(oid->hash); + return repo_has_sha1_file(r, oid->hash); } -int has_object_file_with_flags(const struct object_id *oid, int flags) +int repo_has_object_file_with_flags(struct repository *r, + const struct object_id *oid, int flags) { - return has_sha1_file_with_flags(oid->hash, flags); + return repo_has_sha1_file_with_flags(r, oid->hash, flags); } static void check_tree(const void *buf, size_t size) @@ -2134,43 +2199,63 @@ int for_each_loose_file_in_objdir(const char *path, return r; } -struct loose_alt_odb_data { - each_loose_object_fn *cb; - void *data; -}; +int for_each_loose_object(each_loose_object_fn cb, void *data, + enum for_each_object_flags flags) +{ + struct object_directory *odb; + + prepare_alt_odb(the_repository); + for (odb = the_repository->objects->odb; odb; odb = odb->next) { + int r = for_each_loose_file_in_objdir(odb->path, cb, NULL, + NULL, data); + if (r) + return r; -static int loose_from_alt_odb(struct alternate_object_database *alt, - void *vdata) + if (flags & FOR_EACH_OBJECT_LOCAL_ONLY) + break; + } + + return 0; +} + +static int append_loose_object(const struct object_id *oid, const char *path, + void *data) { - struct loose_alt_odb_data *data = vdata; + oid_array_append(data, oid); + return 0; +} + +struct oid_array *odb_loose_cache(struct object_directory *odb, + const struct object_id *oid) +{ + int subdir_nr = oid->hash[0]; struct strbuf buf = STRBUF_INIT; - int r; - strbuf_addstr(&buf, alt->path); - r = for_each_loose_file_in_objdir_buf(&buf, - data->cb, NULL, NULL, - data->data); + if (subdir_nr < 0 || + subdir_nr >= ARRAY_SIZE(odb->loose_objects_subdir_seen)) + BUG("subdir_nr out of range"); + + if (odb->loose_objects_subdir_seen[subdir_nr]) + return &odb->loose_objects_cache[subdir_nr]; + + strbuf_addstr(&buf, odb->path); + for_each_file_in_obj_subdir(subdir_nr, &buf, + append_loose_object, + NULL, NULL, + &odb->loose_objects_cache[subdir_nr]); + odb->loose_objects_subdir_seen[subdir_nr] = 1; strbuf_release(&buf); - return r; + return &odb->loose_objects_cache[subdir_nr]; } -int for_each_loose_object(each_loose_object_fn cb, void *data, - enum for_each_object_flags flags) +void odb_clear_loose_cache(struct object_directory *odb) { - struct loose_alt_odb_data alt; - int r; - - r = for_each_loose_file_in_objdir(get_object_directory(), - cb, NULL, NULL, data); - if (r) - return r; - - if (flags & FOR_EACH_OBJECT_LOCAL_ONLY) - return 0; + int i; - alt.cb = cb; - alt.data = data; - return foreach_alt_odb(loose_from_alt_odb, &alt); + for (i = 0; i < ARRAY_SIZE(odb->loose_objects_cache); i++) + oid_array_clear(&odb->loose_objects_cache[i]); + memset(&odb->loose_objects_subdir_seen, 0, + sizeof(odb->loose_objects_subdir_seen)); } static int check_stream_sha1(git_zstream *stream, |