summaryrefslogtreecommitdiff
path: root/sha1-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'sha1-file.c')
-rw-r--r--sha1-file.c837
1 files changed, 550 insertions, 287 deletions
diff --git a/sha1-file.c b/sha1-file.c
index 5bd11c85bc..c3c49d2fa5 100644
--- a/sha1-file.c
+++ b/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
@@ -40,12 +40,21 @@
#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;
static const struct object_id empty_tree_oid = {
EMPTY_TREE_SHA1_BIN_LITERAL
@@ -53,12 +62,23 @@ 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)
{
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);
@@ -69,11 +89,37 @@ 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_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);
+}
+
+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");
}
+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");
@@ -90,24 +136,42 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
0x00000000,
0,
0,
+ 0,
git_hash_unknown_init,
+ git_hash_unknown_clone,
git_hash_unknown_update,
git_hash_unknown_final,
NULL,
NULL,
},
{
- "sha-1",
+ "sha1",
/* "sha1", big-endian */
0x73686131,
GIT_SHA1_RAWSZ,
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,
&empty_blob_oid,
},
+ {
+ "sha256",
+ /* "s256", big-endian */
+ 0x73323536,
+ GIT_SHA256_RAWSZ,
+ 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,
+ &empty_blob_oid_sha256,
+ }
};
const char *empty_tree_oid_hex(void)
@@ -122,9 +186,38 @@ 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;
+}
+
+int hash_algo_by_length(int len)
+{
+ int i;
+ for (i = 1; i < GIT_HASH_NALGOS; i++)
+ if (len == hash_algos[i].rawsz)
+ 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
+ * want read_object_file() to be able to return, but yet you do not want
* to write them into the object store (e.g. a browse-only
* application).
*/
@@ -198,7 +291,7 @@ int mkdir_in_gitdir(const char *path)
return adjust_shared_perm(path);
}
-enum scld_error safe_create_leading_directories(char *path)
+static enum scld_error safe_create_leading_directories_1(char *path, int share)
{
char *next_component = path + offset_1st_component(path);
enum scld_error ret = SCLD_OK;
@@ -244,7 +337,7 @@ enum scld_error safe_create_leading_directories(char *path)
ret = SCLD_VANISHED;
else
ret = SCLD_FAILED;
- } else if (adjust_shared_perm(path)) {
+ } else if (share && adjust_shared_perm(path)) {
ret = SCLD_PERMS;
}
*slash = slash_character;
@@ -252,6 +345,16 @@ enum scld_error safe_create_leading_directories(char *path)
return ret;
}
+enum scld_error safe_create_leading_directories(char *path)
+{
+ return safe_create_leading_directories_1(path, 1);
+}
+
+enum scld_error safe_create_leading_directories_no_share(char *path)
+{
+ return safe_create_leading_directories_1(path, 0);
+}
+
enum scld_error safe_create_leading_directories_const(const char *path)
{
int save_errno;
@@ -333,12 +436,12 @@ out:
return ret;
}
-static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1)
+static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
{
int i;
for (i = 0; i < the_hash_algo->rawsz; i++) {
static char hex[] = "0123456789abcdef";
- unsigned int val = sha1[i];
+ unsigned int val = oid->hash[i];
strbuf_addch(buf, hex[val >> 4]);
strbuf_addch(buf, hex[val & 0xf]);
if (!i)
@@ -346,25 +449,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 struct object_id *oid)
{
- strbuf_addstr(buf, r->objects->objectdir);
+ strbuf_reset(buf);
+ strbuf_addstr(buf, odb->path);
strbuf_addch(buf, '/');
- fill_sha1_path(buf, sha1);
-}
-
-struct strbuf *alt_scratch_buf(struct alternate_object_database *alt)
-{
- strbuf_setlen(&alt->scratch, alt->base_len);
- return &alt->scratch;
+ fill_loose_path(buf, oid);
+ return buf->buf;
}
-static const char *alt_sha1_path(struct alternate_object_database *alt,
- const unsigned char *sha1)
+const char *loose_object_path(struct repository *r, struct strbuf *buf,
+ const struct object_id *oid)
{
- struct strbuf *buf = alt_scratch_buf(alt);
- fill_sha1_path(buf, sha1);
- return buf->buf;
+ return odb_loose_path(r->objects->odb, buf, oid);
}
/*
@@ -374,7 +473,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 +487,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 +501,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 +518,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 +546,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 +605,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 +640,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 +676,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);
}
@@ -616,20 +704,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)
@@ -682,13 +765,111 @@ out:
return ref_git;
}
+static void fill_alternate_refs_command(struct child_process *cmd,
+ const char *repo_path)
+{
+ const char *value;
+
+ if (!git_config_get_value("core.alternateRefsCommand", &value)) {
+ cmd->use_shell = 1;
+
+ strvec_push(&cmd->args, value);
+ strvec_push(&cmd->args, repo_path);
+ } else {
+ cmd->git_cmd = 1;
+
+ 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)) {
+ strvec_push(&cmd->args, "--");
+ strvec_split(&cmd->args, value);
+ }
+ }
+
+ cmd->env = local_repo_env;
+ cmd->out = -1;
+}
+
+static void read_alternate_refs(const char *path,
+ alternate_ref_fn *cb,
+ void *data)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ struct strbuf line = STRBUF_INIT;
+ FILE *fh;
+
+ fill_alternate_refs_command(&cmd, path);
+
+ if (start_command(&cmd))
+ return;
+
+ fh = xfdopen(cmd.out, "r");
+ while (strbuf_getline_lf(&line, fh) != EOF) {
+ struct object_id oid;
+ const char *p;
+
+ if (parse_oid_hex(line.buf, &oid, &p) || *p) {
+ warning(_("invalid line while parsing alternate refs: %s"),
+ line.buf);
+ break;
+ }
+
+ cb(&oid, data);
+ }
+
+ fclose(fh);
+ finish_command(&cmd);
+ strbuf_release(&line);
+}
+
+struct alternate_refs_data {
+ alternate_ref_fn *fn;
+ void *data;
+};
+
+static int refs_from_alternate_cb(struct object_directory *e,
+ void *data)
+{
+ struct strbuf path = STRBUF_INIT;
+ size_t base_len;
+ struct alternate_refs_data *cb = data;
+
+ if (!strbuf_realpath(&path, e->path, 0))
+ goto out;
+ if (!strbuf_strip_suffix(&path, "/objects"))
+ goto out;
+ base_len = path.len;
+
+ /* Is this a git repository with refs? */
+ strbuf_addstr(&path, "/refs");
+ if (!is_directory(path.buf))
+ goto out;
+ strbuf_setlen(&path, base_len);
+
+ read_alternate_refs(path.buf, cb->fn, cb->data);
+
+out:
+ strbuf_release(&path);
+ return 0;
+}
+
+void for_each_alternate_ref(alternate_ref_fn fn, void *data)
+{
+ struct alternate_refs_data cb;
+ cb.fn = fn;
+ cb.data = data;
+ foreach_alt_odb(refs_from_alternate_cb, &cb);
+}
+
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,21 +879,19 @@ 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. */
static int freshen_file(const char *fn)
{
- struct utimbuf t;
- t.actime = t.modtime = time(NULL);
- return !utime(fn, &t);
+ return !utime(fn, NULL);
}
/*
@@ -731,23 +910,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);
+ 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;
@@ -789,12 +972,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;
}
@@ -809,12 +988,12 @@ void *xmmap(void *start, size_t length,
/*
* With an in-core object data in "map", rehash it to make sure the
- * object name actually matches "sha1" to detect object corruption.
- * With "map" == NULL, try reading the object named with "sha1" using
+ * object name actually matches "oid" to detect object corruption.
+ * 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;
@@ -824,11 +1003,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;
@@ -836,8 +1015,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));
@@ -848,9 +1027,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;
}
@@ -883,30 +1062,22 @@ int git_open_cloexec(const char *name, int flags)
}
/*
- * Find "sha1" as a loose object in the local repository or in an alternate.
+ * Find "oid" as a loose object in the local repository or in an alternate.
* Returns 0 on success, negative on failure.
*
* 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_loose_object().
*/
-static int stat_sha1_file(struct repository *r, const unsigned char *sha1,
- struct stat *st, const char **path)
+static int stat_loose_object(struct repository *r, const struct object_id *oid,
+ 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, oid);
if (!lstat(*path, st))
return 0;
}
@@ -915,32 +1086,24 @@ static int stat_sha1_file(struct repository *r, const unsigned char *sha1,
}
/*
- * Like stat_sha1_file(), but actually open the object and return the
+ * Like stat_loose_object(), but actually open the object and return the
* descriptor. See the caveats on the "path" parameter above.
*/
-static int open_sha1_file(struct repository *r,
- const unsigned char *sha1, const char **path)
+static int open_loose_object(struct repository *r,
+ const struct object_id *oid, 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, oid);
fd = git_open(*path);
if (fd >= 0)
return fd;
+
if (most_interesting_errno == ENOENT)
most_interesting_errno = errno;
}
@@ -948,12 +1111,25 @@ static int open_sha1_file(struct repository *r,
return -1;
}
+static int quick_has_loose(struct repository *r,
+ const struct object_id *oid)
+{
+ struct object_directory *odb;
+
+ 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".
+ * searching for a loose object named "oid".
*/
-static void *map_sha1_file_1(struct repository *r, const char *path,
- const unsigned char *sha1, unsigned long *size)
+static void *map_loose_object_1(struct repository *r, const char *path,
+ const struct object_id *oid, unsigned long *size)
{
void *map;
int fd;
@@ -961,7 +1137,7 @@ static void *map_sha1_file_1(struct repository *r, const char *path,
if (path)
fd = git_open(path);
else
- fd = open_sha1_file(r, sha1, &path);
+ fd = open_loose_object(r, oid, &path);
map = NULL;
if (fd >= 0) {
struct stat st;
@@ -971,6 +1147,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);
@@ -980,16 +1157,19 @@ static void *map_sha1_file_1(struct repository *r, const char *path,
return map;
}
-void *map_sha1_file(struct repository *r,
- const unsigned char *sha1, unsigned long *size)
+void *map_loose_object(struct repository *r,
+ const struct object_id *oid,
+ unsigned long *size)
{
- return map_sha1_file_1(r, NULL, sha1, size);
+ return map_loose_object_1(r, NULL, oid, size);
}
-static int unpack_sha1_short_header(git_zstream *stream,
- unsigned char *map, unsigned long mapsize,
- void *buffer, unsigned long bufsiz)
+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;
@@ -998,15 +1178,19 @@ static int unpack_sha1_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_sha1_header(git_zstream *stream,
- unsigned char *map, unsigned long mapsize,
- void *buffer, unsigned long bufsiz)
+int unpack_loose_header(git_zstream *stream,
+ unsigned char *map, unsigned long mapsize,
+ void *buffer, unsigned long bufsiz)
{
- int status = unpack_sha1_short_header(stream, map, mapsize,
- buffer, bufsiz);
+ int status = unpack_loose_short_header(stream, map, mapsize,
+ buffer, bufsiz);
if (status < Z_OK)
return status;
@@ -1017,13 +1201,13 @@ int unpack_sha1_header(git_zstream *stream,
return 0;
}
-static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
- unsigned long mapsize, void *buffer,
- unsigned long bufsiz, struct strbuf *header)
+static int unpack_loose_header_to_strbuf(git_zstream *stream, unsigned char *map,
+ unsigned long mapsize, void *buffer,
+ unsigned long bufsiz, struct strbuf *header)
{
int status;
- status = unpack_sha1_short_header(stream, map, mapsize, buffer, bufsiz);
+ status = unpack_loose_short_header(stream, map, mapsize, buffer, bufsiz);
if (status < Z_OK)
return -1;
@@ -1043,7 +1227,9 @@ static int unpack_sha1_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;
@@ -1053,7 +1239,9 @@ static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
return -1;
}
-static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
+static void *unpack_loose_rest(git_zstream *stream,
+ void *buffer, unsigned long size,
+ const struct object_id *oid)
{
int bytes = strlen(buffer) + 1;
unsigned char *buf = xmallocz(size);
@@ -1081,8 +1269,11 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
*/
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);
@@ -1090,10 +1281,10 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
}
if (status < 0)
- error(_("corrupt loose object '%s'"), sha1_to_hex(sha1));
+ error(_("corrupt loose object '%s'"), oid_to_hex(oid));
else if (stream->avail_in)
error(_("garbage at end of loose object '%s'"),
- sha1_to_hex(sha1));
+ oid_to_hex(oid));
free(buf);
return NULL;
}
@@ -1103,8 +1294,8 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
* too permissive for what we want to check. So do an anal
* object header parse by hand.
*/
-static int parse_sha1_header_extended(const char *hdr, struct object_info *oi,
- unsigned int flags)
+static int parse_loose_header_extended(const char *hdr, struct object_info *oi,
+ unsigned int flags)
{
const char *type_buf = hdr;
unsigned long size;
@@ -1164,17 +1355,17 @@ static int parse_sha1_header_extended(const char *hdr, struct object_info *oi,
return *hdr ? -1 : type;
}
-int parse_sha1_header(const char *hdr, unsigned long *sizep)
+int parse_loose_header(const char *hdr, unsigned long *sizep)
{
struct object_info oi = OBJECT_INFO_INIT;
oi.sizep = sizep;
- return parse_sha1_header_extended(hdr, &oi, 0);
+ return parse_loose_header_extended(hdr, &oi, 0);
}
-static int sha1_loose_object_info(struct repository *r,
- const unsigned char *sha1,
- struct object_info *oi, int flags)
+static int loose_object_info(struct repository *r,
+ const struct object_id *oid,
+ struct object_info *oi, int flags)
{
int status = 0;
unsigned long mapsize;
@@ -1184,8 +1375,8 @@ static int sha1_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
@@ -1198,14 +1389,16 @@ 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 (stat_sha1_file(r, sha1, &st, &path) < 0)
+ if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
+ return quick_has_loose(r, oid) ? 0 : -1;
+ if (stat_loose_object(r, oid, &st, &path) < 0)
return -1;
if (oi->disk_sizep)
*oi->disk_sizep = st.st_size;
return 0;
}
- map = map_sha1_file(r, sha1, &mapsize);
+ map = map_loose_object(r, oid, &mapsize);
if (!map)
return -1;
@@ -1215,24 +1408,24 @@ static int sha1_loose_object_info(struct repository *r,
if (oi->disk_sizep)
*oi->disk_sizep = mapsize;
if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE)) {
- if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
+ if (unpack_loose_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
status = error(_("unable to unpack %s header with --allow-unknown-type"),
- sha1_to_hex(sha1));
- } else if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
+ oid_to_hex(oid));
+ } else if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
status = error(_("unable to unpack %s header"),
- sha1_to_hex(sha1));
+ oid_to_hex(oid));
if (status < 0)
; /* Do nothing */
else if (hdrbuf.len) {
- if ((status = parse_sha1_header_extended(hdrbuf.buf, oi, flags)) < 0)
+ if ((status = parse_loose_header_extended(hdrbuf.buf, oi, flags)) < 0)
status = error(_("unable to parse %s header with --allow-unknown-type"),
- sha1_to_hex(sha1));
- } else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0)
- status = error(_("unable to parse %s header"), sha1_to_hex(sha1));
+ oid_to_hex(oid));
+ } else if ((status = parse_loose_header_extended(hdr, oi, flags)) < 0)
+ status = error(_("unable to parse %s header"), oid_to_hex(oid));
if (status >= 0 && oi->contentp) {
- *oi->contentp = unpack_sha1_rest(&stream, hdr,
- *oi->sizep, sha1);
+ *oi->contentp = unpack_loose_rest(&stream, hdr,
+ *oi->sizep, oid);
if (!*oi->contentp) {
git_inflate_end(&stream);
status = -1;
@@ -1250,17 +1443,41 @@ static int sha1_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);
@@ -1270,24 +1487,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) {
@@ -1298,7 +1513,7 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
return -1;
/* Most likely it's a loose object. */
- if (!sha1_loose_object_info(r, real->hash, oi, flags))
+ if (!loose_object_info(r, real, oi, flags))
return 0;
/* Not a loose object; someone else may have just packed it. */
@@ -1309,15 +1524,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 &&
- !already_retried && r == the_repository) {
+ 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;
}
@@ -1334,7 +1551,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;
@@ -1345,6 +1562,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,
@@ -1361,19 +1589,17 @@ 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 struct object_id *oid, enum object_type *type,
unsigned long *size)
{
- struct object_id oid;
struct object_info oi = OBJECT_INFO_INIT;
void *content;
oi.typep = type;
oi.sizep = size;
oi.contentp = &content;
- 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;
}
@@ -1383,8 +1609,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_sha1_file(oid->hash) || 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++];
@@ -1401,7 +1628,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,13 +1639,14 @@ 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, type, size);
if (data)
return data;
+ obj_read_lock();
if (errno && errno != ENOENT)
die_errno(_("failed to read object %s"), oid_to_hex(oid));
@@ -1426,18 +1655,20 @@ 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_loose_object(r, repl, &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);
+ obj_read_unlock();
return NULL;
}
-void *read_object_with_reference(const struct object_id *oid,
+void *read_object_with_reference(struct repository *r,
+ const struct object_id *oid,
const char *required_type_name,
unsigned long *size,
struct object_id *actual_oid_return)
@@ -1453,7 +1684,7 @@ void *read_object_with_reference(const struct object_id *oid,
int ref_length = -1;
const char *ref_type = NULL;
- buffer = read_object_file(&actual_oid, &type, &isize);
+ buffer = repo_read_object_file(r, &actual_oid, &type, &isize);
if (!buffer)
return NULL;
if (type == required_type) {
@@ -1485,7 +1716,8 @@ void *read_object_with_reference(const struct object_id *oid,
}
}
-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)
{
@@ -1495,10 +1727,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);
}
/*
@@ -1533,7 +1765,7 @@ int finalize_object_file(const char *tmpfile, const char *filename)
unlink_or_warn(tmpfile);
if (ret) {
if (ret != EEXIST) {
- return error_errno(_("unable to write sha1 filename %s"), filename);
+ return error_errno(_("unable to write file %s"), filename);
}
/* FIXME!!! Collision check here ? */
}
@@ -1551,22 +1783,23 @@ 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;
}
/* Finalize a file on disk, and close it. */
-static void close_sha1_file(int fd)
+static void close_loose_object(int fd)
{
if (fsync_object_files)
- fsync_or_die(fd, "sha1 file");
+ fsync_or_die(fd, "loose object file");
if (close(fd) != 0)
- die_errno(_("error when closing sha1 file"));
+ die_errno(_("error when closing loose object file"));
}
/* Size of directory component, including the ending '/' */
@@ -1626,8 +1859,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);
fd = create_tmpfile(&tmp_file, filename.buf);
if (fd < 0) {
@@ -1658,7 +1890,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
ret = git_deflate(&stream, Z_FINISH);
the_hash_algo->update_fn(&c, in0, stream.next_in - in0);
if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
- die(_("unable to write sha1 file"));
+ die(_("unable to write loose object file"));
stream.next_out = compressed;
stream.avail_out = sizeof(compressed);
} while (ret == Z_OK);
@@ -1675,7 +1907,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
die(_("confused by unstable object source data for %s"),
oid_to_hex(oid));
- close_sha1_file(fd);
+ close_loose_object(fd);
if (mtime) {
struct utimbuf utb;
@@ -1715,7 +1947,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);
@@ -1731,7 +1964,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;
@@ -1755,9 +1989,9 @@ 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, &type, &len);
if (!buf)
- return error(_("cannot read sha1_file for %s"), oid_to_hex(oid));
+ return error(_("cannot read object for %s"), oid_to_hex(oid));
hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1;
ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime);
free(buf);
@@ -1765,24 +1999,30 @@ 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 has_object(struct repository *r, const struct object_id *oid,
+ unsigned flags)
{
- struct object_id oid;
+ 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;
- hashcpy(oid.hash, sha1);
- return oid_object_info_extended(the_repository, &oid, NULL,
- flags | OBJECT_INFO_SKIP_CACHED) >= 0;
+ return oid_object_info_extended(r, oid, NULL, object_info_flags) >= 0;
}
-int has_object_file(const struct object_id *oid)
+int repo_has_object_file_with_flags(struct repository *r,
+ const struct object_id *oid, int flags)
{
- return has_sha1_file(oid->hash);
+ if (!startup_info->have_repository)
+ return 0;
+ return oid_object_info_extended(r, oid, NULL, flags) >= 0;
}
-int has_object_file_with_flags(const struct object_id *oid, int flags)
+int repo_has_object_file(struct repository *r,
+ const struct object_id *oid)
{
- return has_sha1_file_with_flags(oid->hash, flags);
+ return repo_has_object_file_with_flags(r, oid, 0);
}
static void check_tree(const void *buf, size_t size)
@@ -1847,7 +2087,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;
@@ -1873,8 +2114,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;
}
@@ -1992,7 +2233,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);
@@ -2134,53 +2376,73 @@ 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,
- const char *hdr,
- unsigned long size,
- const char *path,
- const unsigned char *expected_sha1)
+static int check_stream_oid(git_zstream *stream,
+ const char *hdr,
+ unsigned long size,
+ const char *path,
+ const struct object_id *expected_oid)
{
git_hash_ctx c;
- unsigned char real_sha1[GIT_MAX_RAWSZ];
+ struct object_id real_oid;
unsigned char buf[4096];
unsigned long total_read;
int status = Z_OK;
@@ -2196,7 +2458,7 @@ static int check_stream_sha1(git_zstream *stream,
/*
* This size comparison must be "<=" to read the final zlib packets;
- * see the comment in unpack_sha1_rest for details.
+ * see the comment in unpack_loose_rest for details.
*/
while (total_read <= size &&
(status == Z_OK ||
@@ -2212,19 +2474,19 @@ static int check_stream_sha1(git_zstream *stream,
git_inflate_end(stream);
if (status != Z_STREAM_END) {
- error(_("corrupt loose object '%s'"), sha1_to_hex(expected_sha1));
+ error(_("corrupt loose object '%s'"), oid_to_hex(expected_oid));
return -1;
}
if (stream->avail_in) {
error(_("garbage at end of loose object '%s'"),
- sha1_to_hex(expected_sha1));
+ oid_to_hex(expected_oid));
return -1;
}
- the_hash_algo->final_fn(real_sha1, &c);
- if (!hasheq(expected_sha1, real_sha1)) {
- error(_("sha1 mismatch for %s (expected %s)"), path,
- sha1_to_hex(expected_sha1));
+ the_hash_algo->final_fn(real_oid.hash, &c);
+ if (!oideq(expected_oid, &real_oid)) {
+ error(_("hash mismatch for %s (expected %s)"), path,
+ oid_to_hex(expected_oid));
return -1;
}
@@ -2245,18 +2507,18 @@ int read_loose_object(const char *path,
*contents = NULL;
- map = map_sha1_file_1(the_repository, path, NULL, &mapsize);
+ map = map_loose_object_1(the_repository, path, NULL, &mapsize);
if (!map) {
error_errno(_("unable to mmap %s"), path);
goto out;
}
- if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) {
+ if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) {
error(_("unable to unpack header of %s"), path);
goto out;
}
- *type = parse_sha1_header(hdr, size);
+ *type = parse_loose_header(hdr, size);
if (*type < 0) {
error(_("unable to parse header of %s"), path);
git_inflate_end(&stream);
@@ -2264,18 +2526,19 @@ int read_loose_object(const char *path,
}
if (*type == OBJ_BLOB && *size > big_file_threshold) {
- if (check_stream_sha1(&stream, hdr, *size, path, expected_oid->hash) < 0)
+ if (check_stream_oid(&stream, hdr, *size, path, expected_oid) < 0)
goto out;
} else {
- *contents = unpack_sha1_rest(&stream, hdr, *size, expected_oid->hash);
+ *contents = unpack_loose_rest(&stream, hdr, *size, expected_oid);
if (!*contents) {
error(_("unable to unpack contents of %s"), path);
git_inflate_end(&stream);
goto out;
}
- if (check_object_signature(expected_oid, *contents,
- *size, type_name(*type))) {
- error(_("sha1 mismatch for %s (expected %s)"), path,
+ 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);
goto out;