Commit ace1534d authored by Junio C Hamano's avatar Junio C Hamano

Introduce SHA1_FILE_DIRECTORIES to support multiple object databases.

SHA1_FILE_DIRECTORIES environment variable is a colon separated paths
used when looking for SHA1 files not found in the usual place for
reading.  Creating a new SHA1 file does not use this alternate object
database location mechanism.  This is useful to archive older, rarely
used objects into separate directories.
Signed-off-by: default avatarJunio C Hamano <[email protected]>
parent e7d3dd24
......@@ -101,6 +101,7 @@ unsigned int active_nr, active_alloc, active_cache_changed;
#define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
#define DEFAULT_DB_ENVIRONMENT ".git/objects"
#define ALTERNATE_DB_ENVIRONMENT "SHA1_FILE_DIRECTORIES"
#define get_object_directory() (getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT)
......
......@@ -306,7 +306,7 @@ int main(int argc, char **argv)
usage("fsck-cache [--tags] [[--unreachable] [--cache] <head-sha1>*]");
}
sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
sha1_dir = get_object_directory();
for (i = 0; i < 256; i++) {
static char dir[4096];
sprintf(dir, "%s/%02x", sha1_dir, i);
......
......@@ -100,18 +100,34 @@ char * sha1_to_hex(const unsigned char *sha1)
return buffer;
}
static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
{
int i;
for (i = 0; i < 20; i++) {
static char hex[] = "0123456789abcdef";
unsigned int val = sha1[i];
char *pos = pathbuf + i*2 + (i > 0);
*pos++ = hex[val >> 4];
*pos = hex[val & 0xf];
}
}
/*
* NOTE! This returns a statically allocated buffer, so you have to be
* careful about using it. Do a "strdup()" if you need to save the
* filename.
*
* Also note that this returns the location for creating. Reading
* SHA1 file can happen from any alternate directory listed in the
* SHA1_FILE_DIRECTORIES environment variable if it is not found in
* the primary object database.
*/
char *sha1_file_name(const unsigned char *sha1)
{
int i;
static char *name, *base;
if (!base) {
char *sha1_file_directory = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
char *sha1_file_directory = get_object_directory();
int len = strlen(sha1_file_directory);
base = xmalloc(len + 60);
memcpy(base, sha1_file_directory, len);
......@@ -120,16 +136,74 @@ char *sha1_file_name(const unsigned char *sha1)
base[len+3] = '/';
name = base + len + 1;
}
for (i = 0; i < 20; i++) {
static char hex[] = "0123456789abcdef";
unsigned int val = sha1[i];
char *pos = name + i*2 + (i > 0);
*pos++ = hex[val >> 4];
*pos = hex[val & 0xf];
}
fill_sha1_path(name, sha1);
return base;
}
static struct alternate_object_database
{
char *base;
char *name;
} *alt_odb;
static void prepare_alt_odb(void)
{
int pass, totlen, i;
void *buf;
const char *cp, *last;
char *op = 0;
const char *alt = getenv(ALTERNATE_DB_ENVIRONMENT) ? : "";
for (totlen = pass = 0; pass < 2; pass++) {
last = alt;
i = 0;
do {
cp = strchr(last, ':') ? : last + strlen(last);
if (last != cp) {
/* 43 = 40-byte + 2 '/' + terminating NUL */
int pfxlen = cp - last;
int entlen = pfxlen + 43;
if (pass == 0)
totlen += entlen;
else {
alt_odb[i].base = op;
alt_odb[i].name = op + pfxlen + 1;
memcpy(op, last, pfxlen);
op[pfxlen] = op[pfxlen + 3] = '/';
op[entlen-1] = 0;
op += entlen;
}
i++;
}
while (*cp && *cp == ':')
cp++;
last = cp;
} while (*cp);
if (pass)
break;
alt_odb = buf = xmalloc(sizeof(*alt_odb) * (i + 1) + totlen);
alt_odb[i].base = alt_odb[i].name = 0;
op = (char*)(&alt_odb[i+1]);
}
}
static char *find_sha1_file(const unsigned char *sha1, struct stat *st)
{
int i;
char *name = sha1_file_name(sha1);
if (!stat(name, st))
return name;
if (!alt_odb)
prepare_alt_odb();
for (i = 0; (name = alt_odb[i].name) != NULL; i++) {
fill_sha1_path(name, sha1);
if (!stat(alt_odb[i].base, st))
return alt_odb[i].base;
}
return NULL;
}
int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type)
{
char header[100];
......@@ -145,10 +219,15 @@ int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, con
void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
{
char *filename = sha1_file_name(sha1);
struct stat st;
void *map;
int fd;
char *filename = find_sha1_file(sha1, &st);
if (!filename) {
error("cannot map sha1 file %s", sha1_to_hex(sha1));
return NULL;
}
fd = open(filename, O_RDONLY | sha1_file_open_flag);
if (fd < 0) {
......@@ -167,10 +246,6 @@ void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
/* If it failed once, it will probably fail again. Stop using O_NOATIME */
sha1_file_open_flag = 0;
}
if (fstat(fd, &st) < 0) {
close(fd);
return NULL;
}
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
if (-1 == (int)(long)map)
......@@ -315,6 +390,7 @@ int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned cha
}
snprintf(tmpfile, sizeof(tmpfile), "%s/obj_XXXXXX", get_object_directory());
fd = mkstemp(tmpfile);
if (fd < 0) {
fprintf(stderr, "unable to create temporary sha1 filename %s: %s", tmpfile, strerror(errno));
......@@ -442,12 +518,8 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd)
int has_sha1_file(const unsigned char *sha1)
{
char *filename = sha1_file_name(sha1);
struct stat st;
if (!stat(filename, &st))
return 1;
return 0;
return !!find_sha1_file(sha1, &st);
}
int index_fd(unsigned char *sha1, int fd, struct stat *st)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment