summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/config.txt6
-rw-r--r--cache.h1
-rw-r--r--config.c5
-rw-r--r--environment.c1
-rw-r--r--sha1_file.c106
5 files changed, 111 insertions, 8 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 9d08dfceda..465eb13e76 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -97,6 +97,12 @@ core.compression::
compression, and 1..9 are various speed/size tradeoffs, 9 being
slowest.
+core.legacyheaders::
+ A boolean which enables the legacy object header format in case
+ you want to interoperate with old clients accessing the object
+ database directly (where the "http://" and "rsync://" protocols
+ count as direct access).
+
alias.*::
Command aliases for the gitlink:git[1] command wrapper - e.g.
after defining "alias.last = cat-file commit HEAD", the invocation
diff --git a/cache.h b/cache.h
index d433d46f23..eee5fc9f8d 100644
--- a/cache.h
+++ b/cache.h
@@ -176,6 +176,7 @@ extern int commit_lock_file(struct lock_file *);
extern void rollback_lock_file(struct lock_file *);
/* Environment bits from configuration mechanism */
+extern int use_legacy_headers;
extern int trust_executable_bit;
extern int assume_unchanged;
extern int prefer_symlink_refs;
diff --git a/config.c b/config.c
index 8445f7dcab..0ac6aebbbc 100644
--- a/config.c
+++ b/config.c
@@ -279,6 +279,11 @@ int git_default_config(const char *var, const char *value)
return 0;
}
+ if (!strcmp(var, "core.legacyheaders")) {
+ use_legacy_headers = git_config_bool(var, value);
+ return 0;
+ }
+
if (!strcmp(var, "core.compression")) {
int level = git_config_int(var, value);
if (level == -1)
diff --git a/environment.c b/environment.c
index 97d42b172b..42f39d657e 100644
--- a/environment.c
+++ b/environment.c
@@ -11,6 +11,7 @@
char git_default_email[MAX_GITNAME];
char git_default_name[MAX_GITNAME];
+int use_legacy_headers = 1;
int trust_executable_bit = 1;
int assume_unchanged = 0;
int prefer_symlink_refs = 0;
diff --git a/sha1_file.c b/sha1_file.c
index e666aec502..43bc2ea0cf 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -684,26 +684,74 @@ static void *map_sha1_file_internal(const unsigned char *sha1,
return map;
}
-static int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size)
+static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
{
+ unsigned char c;
+ unsigned int word, bits;
+ unsigned long size;
+ static const char *typename[8] = {
+ NULL, /* OBJ_EXT */
+ "commit", "tree", "blob", "tag",
+ NULL, NULL, NULL
+ };
+ const char *type;
+
/* Get the data stream */
memset(stream, 0, sizeof(*stream));
stream->next_in = map;
stream->avail_in = mapsize;
stream->next_out = buffer;
- stream->avail_out = size;
+ stream->avail_out = bufsiz;
+
+ /*
+ * Is it a zlib-compressed buffer? If so, the first byte
+ * must be 0x78 (15-bit window size, deflated), and the
+ * first 16-bit word is evenly divisible by 31
+ */
+ word = (map[0] << 8) + map[1];
+ if (map[0] == 0x78 && !(word % 31)) {
+ inflateInit(stream);
+ return inflate(stream, 0);
+ }
+
+ c = *map++;
+ mapsize--;
+ type = typename[(c >> 4) & 7];
+ if (!type)
+ return -1;
+
+ bits = 4;
+ size = c & 0xf;
+ while ((c & 0x80)) {
+ if (bits >= 8*sizeof(long))
+ return -1;
+ c = *map++;
+ size += (c & 0x7f) << bits;
+ bits += 7;
+ mapsize--;
+ }
+ /* Set up the stream for the rest.. */
+ stream->next_in = map;
+ stream->avail_in = mapsize;
inflateInit(stream);
- return inflate(stream, 0);
+
+ /* And generate the fake traditional header */
+ stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu", type, size);
+ return 0;
}
static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size)
{
int bytes = strlen(buffer) + 1;
unsigned char *buf = xmalloc(1+size);
+ unsigned long n;
- memcpy(buf, (char *) buffer + bytes, stream->total_out - bytes);
- bytes = stream->total_out - bytes;
+ n = stream->total_out - bytes;
+ if (n > size)
+ n = size;
+ memcpy(buf, (char *) buffer + bytes, n);
+ bytes = n;
if (bytes < size) {
stream->next_out = buf + bytes;
stream->avail_out = size - bytes;
@@ -1412,6 +1460,49 @@ static int write_buffer(int fd, const void *buf, size_t len)
return 0;
}
+static int write_binary_header(unsigned char *hdr, enum object_type type, unsigned long len)
+{
+ int hdr_len;
+ unsigned char c;
+
+ c = (type << 4) | (len & 15);
+ len >>= 4;
+ hdr_len = 1;
+ while (len) {
+ *hdr++ = c | 0x80;
+ hdr_len++;
+ c = (len & 0x7f);
+ len >>= 7;
+ }
+ *hdr = c;
+ return hdr_len;
+}
+
+static void setup_object_header(z_stream *stream, const char *type, unsigned long len)
+{
+ int obj_type, hdr;
+
+ if (use_legacy_headers) {
+ while (deflate(stream, 0) == Z_OK)
+ /* nothing */;
+ return;
+ }
+ if (!strcmp(type, blob_type))
+ obj_type = OBJ_BLOB;
+ else if (!strcmp(type, tree_type))
+ obj_type = OBJ_TREE;
+ else if (!strcmp(type, commit_type))
+ obj_type = OBJ_COMMIT;
+ else if (!strcmp(type, tag_type))
+ obj_type = OBJ_TAG;
+ else
+ die("trying to generate bogus object of type '%s'", type);
+ hdr = write_binary_header(stream->next_out, obj_type, len);
+ stream->total_out = hdr;
+ stream->next_out += hdr;
+ stream->avail_out -= hdr;
+}
+
int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
{
int size;
@@ -1457,7 +1548,7 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
/* Set it up */
memset(&stream, 0, sizeof(stream));
deflateInit(&stream, zlib_compression_level);
- size = deflateBound(&stream, len+hdrlen);
+ size = 8 + deflateBound(&stream, len+hdrlen);
compressed = xmalloc(size);
/* Compress it */
@@ -1467,8 +1558,7 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
/* First header.. */
stream.next_in = hdr;
stream.avail_in = hdrlen;
- while (deflate(&stream, 0) == Z_OK)
- /* nothing */;
+ setup_object_header(&stream, type, len);
/* Then the data itself.. */
stream.next_in = buf;