@ -346,25 +346,21 @@ static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1)
@@ -346,25 +346,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)
{
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)
const char *loose_object_path(struct repository *r, struct strbuf *buf,
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 +370,7 @@ static int alt_odb_usable(struct raw_object_store *o,
@@ -374,7 +370,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 +384,8 @@ static int alt_odb_usable(struct raw_object_store *o,
@@ -388,8 +384,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 +398,7 @@ static int alt_odb_usable(struct raw_object_store *o,
@@ -402,7 +398,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 +415,7 @@ static void read_info_alternates(struct repository *r,
@@ -419,7 +415,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 +443,12 @@ static int link_alt_odb_entry(struct repository *r, const char *entry,
@@ -447,11 +443,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 +502,7 @@ static void link_alt_odb_entries(struct repository *r, const char *alt,
@@ -505,7 +502,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 +537,6 @@ static void read_info_alternates(struct repository *r,
@@ -540,18 +537,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 +573,7 @@ void add_to_alternates_file(const char *reference)
@@ -588,7 +573,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 +669,11 @@ out:
@@ -684,11 +669,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 +683,13 @@ int foreach_alt_odb(alt_odb_fn fn, void *cb)
@@ -698,13 +683,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 +716,27 @@ int check_and_freshen_file(const char *fn, int freshen)
@@ -731,23 +716,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 +877,17 @@ int git_open_cloexec(const char *name, int flags)
@@ -888,25 +877,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 +903,17 @@ static int open_sha1_file(struct repository *r,
@@ -922,25 +903,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 +921,24 @@ static int open_sha1_file(struct repository *r,
@@ -948,6 +921,24 @@ static int open_sha1_file(struct repository *r,
return -1;
}
static int quick_has_loose(struct repository *r,
const unsigned char *sha1)
{
int subdir_nr = sha1[0];
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) {
odb_load_loose_cache(odb, subdir_nr);
if (oid_array_lookup(&odb->loose_objects_cache, &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".
@ -1198,6 +1189,8 @@ static int sha1_loose_object_info(struct repository *r,
@@ -1198,6 +1189,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)
@ -1626,8 +1619,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
@@ -1626,8 +1619,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) {
@ -2134,43 +2126,50 @@ int for_each_loose_file_in_objdir(const char *path,
@@ -2134,43 +2126,50 @@ int for_each_loose_file_in_objdir(const char *path,
return r;
}
struct loose_alt_odb_data {
each_loose_object_fn *cb;
void *data;
};
static int loose_from_alt_odb(struct alternate_object_database *alt,
void *vdata)
int for_each_loose_object(each_loose_object_fn cb, void *data,
enum for_each_object_flags flags)
{
struct loose_alt_odb_data *data = vdata;
struct strbuf buf = STRBUF_INIT;
int r;
struct object_directory *odb;
strbuf_addstr(&buf, alt->path);
r = for_each_loose_file_in_objdir_buf(&buf,
data->cb, NULL, NULL,
data->data);
strbuf_release(&buf);
return r;
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;
if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
break;
}
return 0;
}
int for_each_loose_object(each_loose_object_fn cb, void *data,
enum for_each_object_flags flags)
static int append_loose_object(const struct object_id *oid, const char *path,
void *data)
{
struct loose_alt_odb_data alt;
int r;
oid_array_append(data, oid);
return 0;
}
r = for_each_loose_file_in_objdir(get_object_directory(),
cb, NULL, NULL, data);
if (r)
return r;
void odb_load_loose_cache(struct object_directory *odb, int subdir_nr)
{
struct strbuf buf = STRBUF_INIT;
if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
return 0;
if (subdir_nr < 0 ||
subdir_nr >= ARRAY_SIZE(odb->loose_objects_subdir_seen))
BUG("subdir_nr out of range");
alt.cb = cb;
alt.data = data;
return foreach_alt_odb(loose_from_alt_odb, &alt);
if (odb->loose_objects_subdir_seen[subdir_nr])
return;
strbuf_addstr(&buf, odb->path);
for_each_file_in_obj_subdir(subdir_nr, &buf,
append_loose_object,
NULL, NULL,
&odb->loose_objects_cache);
odb->loose_objects_subdir_seen[subdir_nr] = 1;
strbuf_release(&buf);
}
static int check_stream_sha1(git_zstream *stream,