summaryrefslogtreecommitdiff
path: root/sha1_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'sha1_file.c')
-rw-r--r--sha1_file.c76
1 files changed, 49 insertions, 27 deletions
diff --git a/sha1_file.c b/sha1_file.c
index 1754606..25208d2 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -10,6 +10,7 @@
#include <dirent.h>
#include "cache.h"
#include "delta.h"
+#include "pack.h"
#ifndef O_NOATIME
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -385,6 +386,7 @@ static struct packed_git *add_packed_git(char *path, int path_len)
p->pack_size = st.st_size;
p->index_base = idx_map;
p->next = NULL;
+ p->pack_base = NULL;
p->pack_last_used = 0;
return p;
}
@@ -654,37 +656,60 @@ static int packed_delta_info(unsigned char *base_sha1,
return 0;
}
+static unsigned long unpack_object_header(struct packed_git *p, unsigned long offset,
+ enum object_type *type, unsigned long *sizep)
+{
+ unsigned char *pack, c;
+ unsigned long size;
+
+ if (offset >= p->pack_size)
+ die("object offset outside of pack file");
+
+ pack = p->pack_base + offset;
+ c = *pack++;
+ offset++;
+ *type = (c >> 4) & 7;
+ size = c & 15;
+ while (c & 0x80) {
+ if (offset >= p->pack_size)
+ die("object offset outside of pack file");
+ c = *pack++;
+ offset++;
+ size = (size << 7) | (c & 0x7f);
+ }
+ *sizep = size;
+ return offset;
+}
+
static int packed_object_info(struct pack_entry *entry,
char *type, unsigned long *sizep)
{
struct packed_git *p = entry->p;
unsigned long offset, size, left;
unsigned char *pack;
-
- offset = entry->offset;
- if (p->pack_size - 5 < offset)
- die("object offset outside of pack file");
+ enum object_type kind;
if (use_packed_git(p))
die("cannot map packed file");
+ offset = unpack_object_header(p, entry->offset, &kind, &size);
pack = p->pack_base + offset;
- size = (pack[1] << 24) + (pack[2] << 16) + (pack[3] << 8) + pack[4];
- left = p->pack_size - offset - 5;
- switch (*pack) {
- case 'D':
- return packed_delta_info(pack+5, size, left, type, sizep);
+ left = p->pack_size - offset;
+
+ switch (kind) {
+ case OBJ_DELTA:
+ return packed_delta_info(pack, size, left, type, sizep);
break;
- case 'C':
+ case OBJ_COMMIT:
strcpy(type, "commit");
break;
- case 'T':
+ case OBJ_TREE:
strcpy(type, "tree");
break;
- case 'B':
+ case OBJ_BLOB:
strcpy(type, "blob");
break;
- case 'G':
+ case OBJ_TAG:
strcpy(type, "tag");
break;
default:
@@ -776,37 +801,34 @@ static void *unpack_entry(struct pack_entry *entry,
struct packed_git *p = entry->p;
unsigned long offset, size, left;
unsigned char *pack;
-
- offset = entry->offset;
- if (p->pack_size - 5 < offset)
- die("object offset outside of pack file");
+ enum object_type kind;
if (use_packed_git(p))
die("cannot map packed file");
+ offset = unpack_object_header(p, entry->offset, &kind, &size);
pack = p->pack_base + offset;
- size = (pack[1] << 24) + (pack[2] << 16) + (pack[3] << 8) + pack[4];
- left = p->pack_size - offset - 5;
- switch (*pack) {
- case 'D':
- return unpack_delta_entry(pack+5, size, left, type, sizep);
- case 'C':
+ left = p->pack_size - offset;
+ switch (kind) {
+ case OBJ_DELTA:
+ return unpack_delta_entry(pack, size, left, type, sizep);
+ case OBJ_COMMIT:
strcpy(type, "commit");
break;
- case 'T':
+ case OBJ_TREE:
strcpy(type, "tree");
break;
- case 'B':
+ case OBJ_BLOB:
strcpy(type, "blob");
break;
- case 'G':
+ case OBJ_TAG:
strcpy(type, "tag");
break;
default:
die("corrupted pack file");
}
*sizep = size;
- return unpack_non_delta_entry(pack+5, size, left);
+ return unpack_non_delta_entry(pack, size, left);
}
int num_packed_objects(const struct packed_git *p)