diff options
Diffstat (limited to 'third_party/git/sha1-file.c')
-rw-r--r-- | third_party/git/sha1-file.c | 242 |
1 files changed, 157 insertions, 85 deletions
diff --git a/third_party/git/sha1-file.c b/third_party/git/sha1-file.c index 487ea35d2d39..dd65bd5c6815 100644 --- a/third_party/git/sha1-file.c +++ b/third_party/git/sha1-file.c @@ -30,8 +30,8 @@ #include "mergesort.h" #include "quote.h" #include "packfile.h" -#include "fetch-object.h" #include "object-store.h" +#include "promisor-remote.h" /* The maximum size for an object header. */ #define MAX_HEADER_LEN 32 @@ -55,7 +55,6 @@ "\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; static const struct object_id empty_tree_oid = { EMPTY_TREE_SHA1_BIN_LITERAL @@ -75,6 +74,11 @@ static void git_hash_sha1_init(git_hash_ctx *ctx) git_SHA1_Init(&ctx->sha1); } +static void git_hash_sha1_clone(git_hash_ctx *dst, const git_hash_ctx *src) +{ + git_SHA1_Clone(&dst->sha1, &src->sha1); +} + static void git_hash_sha1_update(git_hash_ctx *ctx, const void *data, size_t len) { git_SHA1_Update(&ctx->sha1, data, len); @@ -91,6 +95,11 @@ static void git_hash_sha256_init(git_hash_ctx *ctx) git_SHA256_Init(&ctx->sha256); } +static void git_hash_sha256_clone(git_hash_ctx *dst, const git_hash_ctx *src) +{ + git_SHA256_Clone(&dst->sha256, &src->sha256); +} + static void git_hash_sha256_update(git_hash_ctx *ctx, const void *data, size_t len) { git_SHA256_Update(&ctx->sha256, data, len); @@ -106,6 +115,11 @@ static void git_hash_unknown_init(git_hash_ctx *ctx) BUG("trying to init unknown hash"); } +static void git_hash_unknown_clone(git_hash_ctx *dst, const git_hash_ctx *src) +{ + BUG("trying to clone unknown hash"); +} + static void git_hash_unknown_update(git_hash_ctx *ctx, const void *data, size_t len) { BUG("trying to update unknown hash"); @@ -124,6 +138,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { 0, 0, git_hash_unknown_init, + git_hash_unknown_clone, git_hash_unknown_update, git_hash_unknown_final, NULL, @@ -137,6 +152,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { GIT_SHA1_HEXSZ, GIT_SHA1_BLKSZ, git_hash_sha1_init, + git_hash_sha1_clone, git_hash_sha1_update, git_hash_sha1_final, &empty_tree_oid, @@ -150,6 +166,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { GIT_SHA256_HEXSZ, GIT_SHA256_BLKSZ, git_hash_sha256_init, + git_hash_sha256_clone, git_hash_sha256_update, git_hash_sha256_final, &empty_tree_oid_sha256, @@ -677,20 +694,15 @@ void add_to_alternates_memory(const char *reference) char *compute_alternate_path(const char *path, struct strbuf *err) { char *ref_git = NULL; - const char *repo, *ref_git_s; + const char *repo; int seen_error = 0; - ref_git_s = real_path_if_valid(path); - if (!ref_git_s) { + ref_git = real_pathdup(path, 0); + if (!ref_git) { seen_error = 1; strbuf_addf(err, _("path '%s' does not exist"), path); goto out; - } else - /* - * Beware: read_gitfile(), real_path() and mkpath() - * return static buffer - */ - ref_git = xstrdup(ref_git_s); + } repo = read_gitfile(ref_git); if (!repo) @@ -751,18 +763,18 @@ static void fill_alternate_refs_command(struct child_process *cmd, if (!git_config_get_value("core.alternateRefsCommand", &value)) { cmd->use_shell = 1; - argv_array_push(&cmd->args, value); - argv_array_push(&cmd->args, repo_path); + strvec_push(&cmd->args, value); + strvec_push(&cmd->args, repo_path); } else { cmd->git_cmd = 1; - argv_array_pushf(&cmd->args, "--git-dir=%s", repo_path); - argv_array_push(&cmd->args, "for-each-ref"); - argv_array_push(&cmd->args, "--format=%(objectname)"); + strvec_pushf(&cmd->args, "--git-dir=%s", repo_path); + strvec_push(&cmd->args, "for-each-ref"); + strvec_push(&cmd->args, "--format=%(objectname)"); if (!git_config_get_value("core.alternateRefsPrefixes", &value)) { - argv_array_push(&cmd->args, "--"); - argv_array_split(&cmd->args, value); + strvec_push(&cmd->args, "--"); + strvec_split(&cmd->args, value); } } @@ -869,9 +881,7 @@ void prepare_alt_odb(struct repository *r) /* Returns 1 if we have successfully freshened the file, 0 otherwise. */ static int freshen_file(const char *fn) { - struct utimbuf t; - t.actime = t.modtime = time(NULL); - return !utime(fn, &t); + return !utime(fn, NULL); } /* @@ -952,12 +962,8 @@ void *xmmap_gently(void *start, size_t length, mmap_limit_check(length); ret = mmap(start, length, prot, flags, fd, offset); - if (ret == MAP_FAILED) { - if (!length) - return NULL; - release_pack_memory(length); - ret = mmap(start, length, prot, flags, fd, offset); - } + if (ret == MAP_FAILED && !length) + ret = NULL; return ret; } @@ -976,8 +982,8 @@ void *xmmap(void *start, size_t length, * With "map" == NULL, try reading the object named with "oid" using * the streaming interface and rehash it to do the same. */ -int check_object_signature(const struct object_id *oid, void *map, - unsigned long size, const char *type) +int check_object_signature(struct repository *r, const struct object_id *oid, + void *map, unsigned long size, const char *type) { struct object_id real_oid; enum object_type obj_type; @@ -987,11 +993,11 @@ int check_object_signature(const struct object_id *oid, void *map, int hdrlen; if (map) { - hash_object_file(map, size, type, &real_oid); + hash_object_file(r->hash_algo, map, size, type, &real_oid); return !oideq(oid, &real_oid) ? -1 : 0; } - st = open_istream(oid, &obj_type, &size, NULL); + st = open_istream(r, oid, &obj_type, &size, NULL); if (!st) return -1; @@ -999,8 +1005,8 @@ int check_object_signature(const struct object_id *oid, void *map, hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(obj_type), (uintmax_t)size) + 1; /* Sha1.. */ - the_hash_algo->init_fn(&c); - the_hash_algo->update_fn(&c, hdr, hdrlen); + r->hash_algo->init_fn(&c); + r->hash_algo->update_fn(&c, hdr, hdrlen); for (;;) { char buf[1024 * 16]; ssize_t readlen = read_istream(st, buf, sizeof(buf)); @@ -1011,9 +1017,9 @@ int check_object_signature(const struct object_id *oid, void *map, } if (!readlen) break; - the_hash_algo->update_fn(&c, buf, readlen); + r->hash_algo->update_fn(&c, buf, readlen); } - the_hash_algo->final_fn(real_oid.hash, &c); + r->hash_algo->final_fn(real_oid.hash, &c); close_istream(st); return !oideq(oid, &real_oid) ? -1 : 0; } @@ -1152,6 +1158,8 @@ static int unpack_loose_short_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz) { + int ret; + /* Get the data stream */ memset(stream, 0, sizeof(*stream)); stream->next_in = map; @@ -1160,7 +1168,11 @@ static int unpack_loose_short_header(git_zstream *stream, stream->avail_out = bufsiz; git_inflate_init(stream); - return git_inflate(stream, 0); + obj_read_unlock(); + ret = git_inflate(stream, 0); + obj_read_lock(); + + return ret; } int unpack_loose_header(git_zstream *stream, @@ -1205,7 +1217,9 @@ static int unpack_loose_header_to_strbuf(git_zstream *stream, unsigned char *map stream->avail_out = bufsiz; do { + obj_read_unlock(); status = git_inflate(stream, 0); + obj_read_lock(); strbuf_add(header, buffer, stream->next_out - (unsigned char *)buffer); if (memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer)) return 0; @@ -1245,8 +1259,11 @@ static void *unpack_loose_rest(git_zstream *stream, */ stream->next_out = buf + bytes; stream->avail_out = size - bytes; - while (status == Z_OK) + while (status == Z_OK) { + obj_read_unlock(); status = git_inflate(stream, Z_FINISH); + obj_read_lock(); + } } if (status == Z_STREAM_END && !stream->avail_in) { git_inflate_end(stream); @@ -1348,8 +1365,8 @@ static int loose_object_info(struct repository *r, struct strbuf hdrbuf = STRBUF_INIT; unsigned long size_scratch; - if (oi->delta_base_sha1) - hashclr(oi->delta_base_sha1); + if (oi->delta_base_oid) + oidclr(oi->delta_base_oid); /* * If we don't care about type or size, then we don't @@ -1416,17 +1433,41 @@ static int loose_object_info(struct repository *r, return (status < 0) ? status : 0; } +int obj_read_use_lock = 0; +pthread_mutex_t obj_read_mutex; + +void enable_obj_read_lock(void) +{ + if (obj_read_use_lock) + return; + + obj_read_use_lock = 1; + init_recursive_mutex(&obj_read_mutex); +} + +void disable_obj_read_lock(void) +{ + if (!obj_read_use_lock) + return; + + obj_read_use_lock = 0; + pthread_mutex_destroy(&obj_read_mutex); +} + int fetch_if_missing = 1; -int oid_object_info_extended(struct repository *r, const struct object_id *oid, - struct object_info *oi, unsigned flags) +static int do_oid_object_info_extended(struct repository *r, + const struct object_id *oid, + struct object_info *oi, unsigned flags) { static struct object_info blank_oi = OBJECT_INFO_INIT; + struct cached_object *co; struct pack_entry e; int rtype; const struct object_id *real = oid; int already_retried = 0; + if (flags & OBJECT_INFO_LOOKUP_REPLACE) real = lookup_replace_object(r, oid); @@ -1436,24 +1477,22 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid, if (!oi) oi = &blank_oi; - if (!(flags & OBJECT_INFO_SKIP_CACHED)) { - struct cached_object *co = find_cached_object(real); - if (co) { - if (oi->typep) - *(oi->typep) = co->type; - if (oi->sizep) - *(oi->sizep) = co->size; - if (oi->disk_sizep) - *(oi->disk_sizep) = 0; - if (oi->delta_base_sha1) - hashclr(oi->delta_base_sha1); - if (oi->type_name) - strbuf_addstr(oi->type_name, type_name(co->type)); - if (oi->contentp) - *oi->contentp = xmemdupz(co->buf, co->size); - oi->whence = OI_CACHED; - return 0; - } + co = find_cached_object(real); + if (co) { + if (oi->typep) + *(oi->typep) = co->type; + if (oi->sizep) + *(oi->sizep) = co->size; + if (oi->disk_sizep) + *(oi->disk_sizep) = 0; + if (oi->delta_base_oid) + oidclr(oi->delta_base_oid); + if (oi->type_name) + strbuf_addstr(oi->type_name, type_name(co->type)); + if (oi->contentp) + *oi->contentp = xmemdupz(co->buf, co->size); + oi->whence = OI_CACHED; + return 0; } while (1) { @@ -1475,16 +1514,17 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid, } /* Check if it is a missing object */ - if (fetch_if_missing && repository_format_partial_clone && + if (fetch_if_missing && has_promisor_remote() && !already_retried && r == the_repository && !(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) { /* - * TODO Investigate having fetch_object() return - * TODO error/success and stopping the music here. - * TODO Pass a repository struct through fetch_object, - * such that arbitrary repositories work. + * TODO Investigate checking promisor_remote_get_direct() + * TODO return value and stopping on error here. + * TODO Pass a repository struct through + * promisor_remote_get_direct(), such that arbitrary + * repositories work. */ - fetch_objects(repository_format_partial_clone, real, 1); + promisor_remote_get_direct(r, real, 1); already_retried = 1; continue; } @@ -1501,7 +1541,7 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid, rtype = packed_object_info(r, e.p, e.offset, oi); if (rtype < 0) { mark_bad_packed_object(e.p, real->hash); - return oid_object_info_extended(r, real, oi, 0); + return do_oid_object_info_extended(r, real, oi, 0); } else if (oi->whence == OI_PACKED) { oi->u.packed.offset = e.offset; oi->u.packed.pack = e.p; @@ -1512,6 +1552,17 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid, return 0; } +int oid_object_info_extended(struct repository *r, const struct object_id *oid, + struct object_info *oi, unsigned flags) +{ + int ret; + obj_read_lock(); + ret = do_oid_object_info_extended(r, oid, oi, flags); + obj_read_unlock(); + return ret; +} + + /* returns enum object_type or negative */ int oid_object_info(struct repository *r, const struct object_id *oid, @@ -1548,8 +1599,9 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type, { struct cached_object *co; - hash_object_file(buf, len, type_name(type), oid); - if (has_object_file(oid) || find_cached_object(oid)) + hash_object_file(the_hash_algo, buf, len, type_name(type), oid); + if (has_object_file_with_flags(oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) || + find_cached_object(oid)) return 0; ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc); co = &cached_objects[cached_object_nr++]; @@ -1584,6 +1636,7 @@ void *read_object_file_extended(struct repository *r, if (data) return data; + obj_read_lock(); if (errno && errno != ENOENT) die_errno(_("failed to read object %s"), oid_to_hex(oid)); @@ -1599,6 +1652,7 @@ void *read_object_file_extended(struct repository *r, 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); + obj_read_unlock(); return NULL; } @@ -1652,7 +1706,8 @@ void *read_object_with_reference(struct repository *r, } } -static void write_object_file_prepare(const void *buf, unsigned long len, +static void write_object_file_prepare(const struct git_hash_algo *algo, + const void *buf, unsigned long len, const char *type, struct object_id *oid, char *hdr, int *hdrlen) { @@ -1662,10 +1717,10 @@ static void write_object_file_prepare(const void *buf, unsigned long len, *hdrlen = xsnprintf(hdr, *hdrlen, "%s %"PRIuMAX , type, (uintmax_t)len)+1; /* Sha1.. */ - the_hash_algo->init_fn(&c); - the_hash_algo->update_fn(&c, hdr, *hdrlen); - the_hash_algo->update_fn(&c, buf, len); - the_hash_algo->final_fn(oid->hash, &c); + algo->init_fn(&c); + algo->update_fn(&c, hdr, *hdrlen); + algo->update_fn(&c, buf, len); + algo->final_fn(oid->hash, &c); } /* @@ -1718,12 +1773,13 @@ static int write_buffer(int fd, const void *buf, size_t len) return 0; } -int hash_object_file(const void *buf, unsigned long len, const char *type, +int hash_object_file(const struct git_hash_algo *algo, const void *buf, + unsigned long len, const char *type, struct object_id *oid) { char hdr[MAX_HEADER_LEN]; int hdrlen = sizeof(hdr); - write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen); + write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen); return 0; } @@ -1881,7 +1937,8 @@ int write_object_file(const void *buf, unsigned long len, const char *type, /* Normally if we have it in the pack then we do not bother writing * it out into .git/objects/??/?{38} file. */ - write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen); + write_object_file_prepare(the_hash_algo, buf, len, type, oid, hdr, + &hdrlen); if (freshen_packed_object(oid) || freshen_loose_object(oid)) return 0; return write_loose_object(oid, hdr, hdrlen, buf, len, 0); @@ -1897,7 +1954,8 @@ int hash_object_file_literally(const void *buf, unsigned long len, /* type string, SP, %lu of the length plus NUL must fit this */ hdrlen = strlen(type) + MAX_HEADER_LEN; header = xmalloc(hdrlen); - write_object_file_prepare(buf, len, type, oid, header, &hdrlen); + write_object_file_prepare(the_hash_algo, buf, len, type, oid, header, + &hdrlen); if (!(flags & HASH_WRITE_OBJECT)) goto cleanup; @@ -1931,13 +1989,24 @@ int force_object_loose(const struct object_id *oid, time_t mtime) return ret; } +int has_object(struct repository *r, const struct object_id *oid, + unsigned flags) +{ + int quick = !(flags & HAS_OBJECT_RECHECK_PACKED); + unsigned object_info_flags = OBJECT_INFO_SKIP_FETCH_OBJECT | + (quick ? OBJECT_INFO_QUICK : 0); + + if (!startup_info->have_repository) + return 0; + return oid_object_info_extended(r, oid, NULL, object_info_flags) >= 0; +} + int repo_has_object_file_with_flags(struct repository *r, const struct object_id *oid, int flags) { if (!startup_info->have_repository) return 0; - return oid_object_info_extended(r, oid, NULL, - flags | OBJECT_INFO_SKIP_CACHED) >= 0; + return oid_object_info_extended(r, oid, NULL, flags) >= 0; } int repo_has_object_file(struct repository *r, @@ -2008,7 +2077,8 @@ static int index_mem(struct index_state *istate, if (write_object) ret = write_object_file(buf, size, type_name(type), oid); else - ret = hash_object_file(buf, size, type_name(type), oid); + ret = hash_object_file(the_hash_algo, buf, size, + type_name(type), oid); if (re_allocated) free(buf); return ret; @@ -2034,8 +2104,8 @@ static int index_stream_convert_blob(struct index_state *istate, ret = write_object_file(sbuf.buf, sbuf.len, type_name(OBJ_BLOB), oid); else - ret = hash_object_file(sbuf.buf, sbuf.len, type_name(OBJ_BLOB), - oid); + ret = hash_object_file(the_hash_algo, sbuf.buf, sbuf.len, + type_name(OBJ_BLOB), oid); strbuf_release(&sbuf); return ret; } @@ -2153,7 +2223,8 @@ int index_path(struct index_state *istate, struct object_id *oid, if (strbuf_readlink(&sb, path, st->st_size)) return error_errno("readlink(\"%s\")", path); if (!(flags & HASH_WRITE_OBJECT)) - hash_object_file(sb.buf, sb.len, blob_type, oid); + hash_object_file(the_hash_algo, sb.buf, sb.len, + blob_type, oid); else if (write_object_file(sb.buf, sb.len, blob_type, oid)) rc = error(_("%s: failed to insert into database"), path); strbuf_release(&sb); @@ -2454,8 +2525,9 @@ int read_loose_object(const char *path, git_inflate_end(&stream); goto out; } - if (check_object_signature(expected_oid, *contents, - *size, type_name(*type))) { + if (check_object_signature(the_repository, expected_oid, + *contents, *size, + type_name(*type))) { error(_("hash mismatch for %s (expected %s)"), path, oid_to_hex(expected_oid)); free(*contents); |