From: Junio C Hamano <junkio@cox.net>
To: Linus Torvalds <torvalds@osdl.org>
Cc: git@vger.kernel.org
Subject: [PATCH] Introduce SHA1_FILE_DIRECTORIES
Date: Fri, 06 May 2005 16:35:27 -0700 [thread overview]
Message-ID: <7vmzr8apxc.fsf@assigned-by-dhcp.cox.net> (raw)
A new environment variable, SHA1_FILE_DIRECTORIES, is
introduced. This affects the routines that read existing
objects from the object database, but not creation of new
objects.
The environment variable, when exists, is a colon separated list of
directories. If an object is not found in the usual location
SHA1_FILE_DIRECTORY (or .git/objects), this list is consulted and if
object is found there it is returned.
This is an implementation of the idea floated on the GIT list a couple
of days ago to archive really old history on a separate directory, even
on a read-only DVD ROM media.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
cache.h | 5 +-
sha1_file.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 112 insertions(+), 6 deletions(-)
--- a/cache.h
+++ b/cache.h
@@ -101,8 +101,7 @@ unsigned int active_nr, active_alloc;
#define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
#define DEFAULT_DB_ENVIRONMENT ".git/objects"
-
-#define get_object_directory() (getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT)
+#define ALTERNATE_DB_ENVIRONMENT "SHA1_FILE_DIRECTORIES"
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
#define DEFAULT_INDEX_ENVIRONMENT ".git/index"
@@ -130,7 +129,7 @@ extern int index_fd(unsigned char *sha1,
#define DATA_CHANGED 0x0020
#define TYPE_CHANGED 0x0040
-/* Return a statically allocated filename matching the sha1 signature */
+/* Return a statically allocated filename matching the sha1 signature. */
extern char *sha1_file_name(const unsigned char *sha1);
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -100,10 +100,19 @@ char * sha1_to_hex(const unsigned char *
return buffer;
}
+static const char *get_object_directory(void)
+{
+ return getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
+}
+
/*
* 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.
*/
char *sha1_file_name(const unsigned char *sha1)
{
@@ -130,6 +139,99 @@ char *sha1_file_name(const unsigned char
return base;
}
+static char *find_sha1_file(const unsigned char *sha1)
+{
+ struct stat st;
+ char *name = sha1_file_name(sha1);
+ static struct {
+ int pfxlen;
+ char *buf;
+ } *alternates = NULL;
+ static int num_alt = -1;
+ int i;
+
+ if (num_alt < 0) {
+ int cnt;
+ int totlen;
+ const char *cp, *last;
+ const char *alt = getenv(ALTERNATE_DB_ENVIRONMENT);
+ void *buf;
+ char *op;
+
+ if (!alt || !alt[0]) {
+ num_alt = 0;
+ return name;
+ }
+
+ for (last = cp = alt, totlen = cnt = 0; *cp; cp++) {
+ /* We could strip the empty path which would result
+ * in /xx/xxxxx from the filesystem root level,
+ * but who cares. We are only constructing list of
+ * paths to attempt to read not write.
+ */
+ if (*cp == ':') {
+ /* 40 bytes plus two / and terminating NUL */
+ totlen += cp - last + 43;
+ cnt++;
+ last = cp + 1;
+ }
+ }
+ if (cp != last) {
+ totlen += cp - last + 43;
+ cnt++;
+ }
+
+ if (!cnt) {
+ num_alt = 0;
+ return name;
+ }
+ num_alt = cnt;
+
+ buf = xmalloc(sizeof(*alternates) * (cnt + 1) + totlen);
+ alternates = buf;
+ alternates[num_alt].pfxlen = 0;
+ alternates[num_alt].buf = NULL;
+ op = (char*) (&alternates[cnt+1]);
+ for (last = cp = alt, i = 0; i < num_alt; cp++) {
+ if (*cp == ':' || *cp == 0) {
+ alternates[i].buf = op;
+ alternates[i].pfxlen = cp - last;
+ memcpy(op, last, cp - last);
+ op[cp - last] = 0;
+ op += (cp - last + 1);
+ last = cp + 1;
+ i++;
+ }
+ }
+ if (cp != last) {
+ alternates[i].buf = op;
+ alternates[i].pfxlen = last - cp;
+ memcpy(op, last, last - cp);
+ op[last-cp] = 0;
+ }
+ }
+ if (!stat(name, &st))
+ return name;
+ for (i = 0; i < num_alt; i++) {
+ char *alt = alternates[i].buf;
+ int len = alternates[i].pfxlen;
+ char *name = alt + len;
+ alt[len] = '/';
+ alt[len+3] = '/';
+ name = alt + 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];
+ }
+ if (!stat(alt, &st))
+ return alt;
+ }
+ return NULL;
+}
+
int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type)
{
char header[100];
@@ -145,10 +247,14 @@ int check_sha1_signature(unsigned char *
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);
+ 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) {
@@ -442,8 +548,10 @@ int write_sha1_from_fd(const unsigned ch
int has_sha1_file(const unsigned char *sha1)
{
- char *filename = sha1_file_name(sha1);
struct stat st;
+ char *filename = find_sha1_file(sha1);
+ if (!filename)
+ return 0;
if (!stat(filename, &st))
return 1;
----------------------------------------------------------------
next reply other threads:[~2005-05-06 23:33 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-05-06 23:35 Junio C Hamano [this message]
2005-05-07 0:20 ` [PATCH] Introduce SHA1_FILE_DIRECTORIES Sean
2005-05-07 0:24 ` Junio C Hamano
2005-05-07 0:32 ` Sean
2005-05-07 6:31 ` Junio C Hamano
2005-05-07 19:51 ` Junio C Hamano
2005-05-09 13:33 ` H. Peter Anvin
2005-05-09 16:38 ` Junio C Hamano
2005-05-09 16:41 ` Sean
2005-05-09 18:03 ` H. Peter Anvin
2005-05-09 18:50 ` Junio C Hamano
2005-05-09 20:05 ` [RFC] Renaming environment variables Junio C Hamano
2005-05-09 20:15 ` Thomas Glanzmann
2005-05-10 0:32 ` Petr Baudis
2005-05-09 21:04 ` Sean
2005-05-09 23:08 ` Daniel Barkalow
2005-05-10 0:09 ` Junio C Hamano
2005-05-10 0:13 ` Petr Baudis
2005-05-10 0:22 ` Junio C Hamano
2005-05-10 0:27 ` Petr Baudis
2005-05-10 0:38 ` Daniel Barkalow
2005-05-10 0:44 ` Petr Baudis
2005-05-10 0:53 ` Daniel Barkalow
2005-05-10 5:45 ` Junio C Hamano
2005-05-10 6:25 ` Introducing GIT_DIR environment variable Junio C Hamano
2005-05-10 23:39 ` Alex Riesen
2005-05-10 2:16 ` [RFC] Renaming environment variables Junio C Hamano
2005-05-10 3:23 ` Daniel Barkalow
2005-05-10 0:25 ` Petr Baudis
2005-05-10 1:02 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7vmzr8apxc.fsf@assigned-by-dhcp.cox.net \
--to=junkio@cox.net \
--cc=git@vger.kernel.org \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox