@ -217,6 +217,8 @@ char *sha1_pack_index_name(const unsigned char *sha1)
@@ -217,6 +217,8 @@ char *sha1_pack_index_name(const unsigned char *sha1)
struct alternate_object_database *alt_odb_list;
static struct alternate_object_database **alt_odb_tail;
static void read_info_alternates(const char * alternates, int depth);
/*
* Prepare alternate object database registry.
*
@ -232,14 +234,85 @@ static struct alternate_object_database **alt_odb_tail;
@@ -232,14 +234,85 @@ static struct alternate_object_database **alt_odb_tail;
* SHA1, an extra slash for the first level indirection, and the
* terminating NUL.
*/
static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
const char *relative_base)
static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)
{
const char *cp, *last;
struct alternate_object_database *ent;
struct stat st;
const char *objdir = get_object_directory();
struct alternate_object_database *ent;
struct alternate_object_database *alt;
/* 43 = 40-byte + 2 '/' + terminating NUL */
int pfxlen = len;
int entlen = pfxlen + 43;
int base_len = -1;
if (*entry != '/' && relative_base) {
/* Relative alt-odb */
if (base_len < 0)
base_len = strlen(relative_base) + 1;
entlen += base_len;
pfxlen += base_len;
}
ent = xmalloc(sizeof(*ent) + entlen);
if (*entry != '/' && relative_base) {
memcpy(ent->base, relative_base, base_len - 1);
ent->base[base_len - 1] = '/';
memcpy(ent->base + base_len, entry, len);
}
else
memcpy(ent->base, entry, pfxlen);
ent->name = ent->base + pfxlen + 1;
ent->base[pfxlen + 3] = '/';
ent->base[pfxlen] = ent->base[entlen-1] = 0;
/* Detect cases where alternate disappeared */
if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
error("object directory %s does not exist; "
"check .git/objects/info/alternates.",
ent->base);
free(ent);
return -1;
}
/* Prevent the common mistake of listing the same
* thing twice, or object directory itself.
*/
for (alt = alt_odb_list; alt; alt = alt->next) {
if (!memcmp(ent->base, alt->base, pfxlen)) {
free(ent);
return -1;
}
}
if (!memcmp(ent->base, objdir, pfxlen)) {
free(ent);
return -1;
}
/* add the alternate entry */
*alt_odb_tail = ent;
alt_odb_tail = &(ent->next);
ent->next = NULL;
/* recursively add alternates */
read_info_alternates(ent->base, depth + 1);
ent->base[pfxlen] = '/';
return 0;
}
static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
const char *relative_base, int depth)
{
const char *cp, *last;
if (depth > 5) {
error("%s: ignoring alternate object stores, nesting too deep.",
relative_base);
return;
}
last = alt;
while (last < ep) {
cp = last;
@ -249,60 +322,15 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
@@ -249,60 +322,15 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
last = cp + 1;
continue;
}
for ( ; cp < ep && *cp != sep; cp++)
;
while (cp < ep && *cp != sep)
cp++;
if (last != cp) {
struct stat st;
struct alternate_object_database *alt;
/* 43 = 40-byte + 2 '/' + terminating NUL */
int pfxlen = cp - last;
int entlen = pfxlen + 43;
if (*last != '/' && relative_base) {
/* Relative alt-odb */
if (base_len < 0)
base_len = strlen(relative_base) + 1;
entlen += base_len;
pfxlen += base_len;
}
ent = xmalloc(sizeof(*ent) + entlen);
if (*last != '/' && relative_base) {
memcpy(ent->base, relative_base, base_len - 1);
ent->base[base_len - 1] = '/';
memcpy(ent->base + base_len,
last, cp - last);
}
else
memcpy(ent->base, last, pfxlen);
ent->name = ent->base + pfxlen + 1;
ent->base[pfxlen + 3] = '/';
ent->base[pfxlen] = ent->base[entlen-1] = 0;
/* Detect cases where alternate disappeared */
if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
error("object directory %s does not exist; "
"check .git/objects/info/alternates.",
ent->base);
goto bad;
}
ent->base[pfxlen] = '/';
/* Prevent the common mistake of listing the same
* thing twice, or object directory itself.
*/
for (alt = alt_odb_list; alt; alt = alt->next)
if (!memcmp(ent->base, alt->base, pfxlen))
goto bad;
if (!memcmp(ent->base, objdir, pfxlen)) {
bad:
free(ent);
}
else {
*alt_odb_tail = ent;
alt_odb_tail = &(ent->next);
ent->next = NULL;
if ((*last != '/') && depth) {
error("%s: ignoring relative alternate object store %s",
relative_base, last);
} else {
link_alt_odb_entry(last, cp - last,
relative_base, depth);
}
}
while (cp < ep && *cp == sep)
@ -311,23 +339,14 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
@@ -311,23 +339,14 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
}
}
void prepare_alt_odb(void)
static void read_info_alternates(const char * relative_base, int depth)
{
char path[PATH_MAX];
char *map;
int fd;
struct stat st;
char *alt;
alt = getenv(ALTERNATE_DB_ENVIRONMENT);
if (!alt) alt = "";
if (alt_odb_tail)
return;
alt_odb_tail = &alt_odb_list;
link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL);
char path[PATH_MAX];
int fd;
sprintf(path, "%s/info/alternates", get_object_directory());
sprintf(path, "%s/info/alternates", relative_base);
fd = open(path, O_RDONLY);
if (fd < 0)
return;
@ -340,11 +359,26 @@ void prepare_alt_odb(void)
@@ -340,11 +359,26 @@ void prepare_alt_odb(void)
if (map == MAP_FAILED)
return;
link_alt_odb_entries(map, map + st.st_size, '\n',
get_object_directory());
link_alt_odb_entries(map, map + st.st_size, '\n', relative_base, depth);
munmap(map, st.st_size);
}
void prepare_alt_odb(void)
{
char *alt;
alt = getenv(ALTERNATE_DB_ENVIRONMENT);
if (!alt) alt = "";
if (alt_odb_tail)
return;
alt_odb_tail = &alt_odb_list;
link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0);
read_info_alternates(get_object_directory(), 0);
}
static char *find_sha1_file(const unsigned char *sha1, struct stat *st)
{
char *name = sha1_file_name(sha1);