static unsigned int sha1_file_open_flag = O_NOATIME;
-static unsigned hexval(char c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- return ~0;
-}
+signed char hexval_table[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 00-07 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 08-0f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 10-17 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 18-1f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 20-27 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 28-2f */
+ 0, 1, 2, 3, 4, 5, 6, 7, /* 30-37 */
+ 8, 9, -1, -1, -1, -1, -1, -1, /* 38-3f */
+ -1, 10, 11, 12, 13, 14, 15, -1, /* 40-47 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 48-4f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 50-57 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 58-5f */
+ -1, 10, 11, 12, 13, 14, 15, -1, /* 60-67 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 68-67 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 70-77 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 78-7f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 80-87 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 88-8f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 90-97 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 98-9f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* a0-a7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* a8-af */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* b0-b7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* b8-bf */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* c0-c7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* c8-cf */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* d0-d7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* d8-df */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* e0-e7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* e8-ef */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* f0-f7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* f8-ff */
+};
int get_sha1_hex(const char *hex, unsigned char *sha1)
{
/*
* 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
+ * careful about using it. Do a "xstrdup()" if you need to save the
* filename.
*
* Also note that this returns the location for creating. Reading
return 0;
}
-static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
+unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
{
+ unsigned shift;
unsigned char c;
- unsigned int bits;
unsigned long size;
- static const char *typename[8] = {
- NULL, /* OBJ_EXT */
- "commit", "tree", "blob", "tag",
- NULL, NULL, NULL
+ unsigned long used = 0;
+
+ c = buf[used++];
+ *type = (c >> 4) & 7;
+ size = c & 15;
+ shift = 4;
+ while (c & 0x80) {
+ if (len <= used)
+ return 0;
+ if (sizeof(long) * 8 <= shift)
+ return 0;
+ c = buf[used++];
+ size += (c & 0x7f) << shift;
+ shift += 7;
+ }
+ *sizep = size;
+ return used;
+}
+
+static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
+{
+ unsigned long size, used;
+ static const char valid_loose_object_type[8] = {
+ 0, /* OBJ_EXT */
+ 1, 1, 1, 1, /* "commit", "tree", "blob", "tag" */
+ 0, /* "delta" and others are invalid in a loose object */
};
- const char *type;
+ enum object_type type;
/* Get the data stream */
memset(stream, 0, sizeof(*stream));
return inflate(stream, 0);
}
- c = *map++;
- mapsize--;
- type = typename[(c >> 4) & 7];
- if (!type)
+ used = unpack_object_header_gently(map, mapsize, &type, &size);
+ if (!used || !valid_loose_object_type[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--;
- }
+ map += used;
+ mapsize -= used;
/* Set up the stream for the rest.. */
stream->next_in = map;
inflateInit(stream);
/* And generate the fake traditional header */
- stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu", type, size);
+ stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
+ type_names[type], size);
return 0;
}
}
/* forward declaration for a mutually recursive function */
-static int packed_object_info(struct pack_entry *entry,
+static int packed_object_info(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep);
-static int packed_delta_info(unsigned char *base_sha1,
- unsigned long delta_size,
- unsigned long left,
+static int packed_delta_info(struct packed_git *p,
+ unsigned long offset,
char *type,
- unsigned long *sizep,
- struct packed_git *p)
+ unsigned long *sizep)
{
- struct pack_entry base_ent;
+ unsigned long base_offset;
+ unsigned char *base_sha1 = (unsigned char *) p->pack_base + offset;
- if (left < 20)
+ if (p->pack_size < offset + 20)
die("truncated pack file");
-
/* The base entry _must_ be in the same pack */
- if (!find_pack_entry_one(base_sha1, &base_ent, p))
+ base_offset = find_pack_entry_one(base_sha1, p);
+ if (!base_offset)
die("failed to find delta-pack base object %s",
sha1_to_hex(base_sha1));
+ offset += 20;
/* We choose to only get the type of the base object and
* ignore potentially corrupt pack file that expects the delta
* based on a base with a wrong size. This saves tons of
* inflate() calls.
*/
-
- if (packed_object_info(&base_ent, type, NULL))
+ if (packed_object_info(p, base_offset, type, NULL))
die("cannot get info for delta-pack base");
if (sizep) {
memset(&stream, 0, sizeof(stream));
- data = stream.next_in = base_sha1 + 20;
- stream.avail_in = left - 20;
+ stream.next_in = (unsigned char *) p->pack_base + offset;
+ stream.avail_in = p->pack_size - offset;
stream.next_out = delta_head;
stream.avail_out = sizeof(delta_head);
static unsigned long unpack_object_header(struct packed_git *p, unsigned long offset,
enum object_type *type, unsigned long *sizep)
{
- unsigned shift;
- unsigned char c;
- unsigned long size;
+ unsigned long used;
- if (offset >= p->pack_size)
+ if (p->pack_size <= offset)
die("object offset outside of pack file");
- c = *((unsigned char *)p->pack_base + offset++);
- *type = (c >> 4) & 7;
- size = c & 15;
- shift = 4;
- while (c & 0x80) {
- if (offset >= p->pack_size)
- die("object offset outside of pack file");
- c = *((unsigned char *)p->pack_base + offset++);
- size += (c & 0x7f) << shift;
- shift += 7;
- }
- *sizep = size;
- return offset;
+
+ used = unpack_object_header_gently((unsigned char *)p->pack_base +
+ offset,
+ p->pack_size - offset, type, sizep);
+ if (!used)
+ die("object offset outside of pack file");
+
+ return offset + used;
}
int check_reuse_pack_delta(struct packed_git *p, unsigned long offset,
return status;
}
-void packed_object_info_detail(struct pack_entry *e,
+void packed_object_info_detail(struct packed_git *p,
+ unsigned long offset,
char *type,
unsigned long *size,
unsigned long *store_size,
unsigned int *delta_chain_length,
unsigned char *base_sha1)
{
- struct packed_git *p = e->p;
- unsigned long offset;
- unsigned char *pack;
+ unsigned long val;
+ unsigned char *next_sha1;
enum object_type kind;
- offset = unpack_object_header(p, e->offset, &kind, size);
- pack = (unsigned char *) p->pack_base + offset;
- if (kind != OBJ_DELTA)
- *delta_chain_length = 0;
- else {
- unsigned int chain_length = 0;
- if (p->pack_size <= offset + 20)
- die("pack file %s records an incomplete delta base",
- p->pack_name);
- hashcpy(base_sha1, pack);
- do {
- struct pack_entry base_ent;
- unsigned long junk;
-
- find_pack_entry_one(pack, &base_ent, p);
- offset = unpack_object_header(p, base_ent.offset,
- &kind, &junk);
- pack = (unsigned char *) p->pack_base + offset;
- chain_length++;
- } while (kind == OBJ_DELTA);
- *delta_chain_length = chain_length;
- }
- switch (kind) {
- case OBJ_COMMIT:
- case OBJ_TREE:
- case OBJ_BLOB:
- case OBJ_TAG:
- strcpy(type, type_names[kind]);
- break;
- default:
- die("corrupted pack file %s containing object of kind %d",
- p->pack_name, kind);
+ *delta_chain_length = 0;
+ offset = unpack_object_header(p, offset, &kind, size);
+
+ for (;;) {
+ switch (kind) {
+ default:
+ die("corrupted pack file %s containing object of kind %d",
+ p->pack_name, kind);
+ case OBJ_COMMIT:
+ case OBJ_TREE:
+ case OBJ_BLOB:
+ case OBJ_TAG:
+ strcpy(type, type_names[kind]);
+ *store_size = 0; /* notyet */
+ return;
+ case OBJ_DELTA:
+ if (p->pack_size <= offset + 20)
+ die("pack file %s records an incomplete delta base",
+ p->pack_name);
+ next_sha1 = (unsigned char *) p->pack_base + offset;
+ if (*delta_chain_length == 0)
+ hashcpy(base_sha1, next_sha1);
+ offset = find_pack_entry_one(next_sha1, p);
+ break;
+ }
+ offset = unpack_object_header(p, offset, &kind, &val);
+ (*delta_chain_length)++;
}
- *store_size = 0; /* notyet */
}
-static int packed_object_info(struct pack_entry *entry,
+static int packed_object_info(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep)
{
- struct packed_git *p = entry->p;
- unsigned long offset, size, left;
- unsigned char *pack;
+ unsigned long size;
enum object_type kind;
- int retval;
- if (use_packed_git(p))
- die("cannot map packed file");
+ offset = unpack_object_header(p, offset, &kind, &size);
- offset = unpack_object_header(p, entry->offset, &kind, &size);
- pack = (unsigned char *) p->pack_base + offset;
- left = p->pack_size - offset;
+ if (kind == OBJ_DELTA)
+ return packed_delta_info(p, offset, type, sizep);
switch (kind) {
- case OBJ_DELTA:
- retval = packed_delta_info(pack, size, left, type, sizep, p);
- unuse_packed_git(p);
- return retval;
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
}
if (sizep)
*sizep = size;
- unuse_packed_git(p);
return 0;
}
char *type,
unsigned long *sizep)
{
- struct pack_entry base_ent;
void *delta_data, *result, *base;
- unsigned long result_size, base_size;
- unsigned char* base_sha1;
+ unsigned long result_size, base_size, base_offset;
+ unsigned char *base_sha1;
- if ((offset + 20) >= p->pack_size)
+ if (p->pack_size < offset + 20)
die("truncated pack file");
-
/* The base entry _must_ be in the same pack */
base_sha1 = (unsigned char*)p->pack_base + offset;
- if (!find_pack_entry_one(base_sha1, &base_ent, p))
+ base_offset = find_pack_entry_one(base_sha1, p);
+ if (!base_offset)
die("failed to find delta-pack base object %s",
sha1_to_hex(base_sha1));
- base = unpack_entry_gently(&base_ent, type, &base_size);
+ offset += 20;
+
+ base = unpack_entry_gently(p, base_offset, type, &base_size);
if (!base)
- die("failed to read delta-pack base object %s",
- sha1_to_hex(base_sha1));
+ die("failed to read delta base object at %lu from %s",
+ base_offset, p->pack_name);
- delta_data = unpack_compressed_entry(p, offset + 20, delta_size);
+ delta_data = unpack_compressed_entry(p, offset, delta_size);
result = patch_delta(base, base_size,
delta_data, delta_size,
&result_size);
if (use_packed_git(p))
die("cannot map packed file");
- retval = unpack_entry_gently(entry, type, sizep);
+ retval = unpack_entry_gently(p, entry->offset, type, sizep);
unuse_packed_git(p);
if (!retval)
die("corrupted pack file %s", p->pack_name);
}
/* The caller is responsible for use_packed_git()/unuse_packed_git() pair */
-void *unpack_entry_gently(struct pack_entry *entry,
+void *unpack_entry_gently(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep)
{
- struct packed_git *p = entry->p;
- unsigned long offset, size;
+ unsigned long size;
enum object_type kind;
- offset = unpack_object_header(p, entry->offset, &kind, &size);
+ offset = unpack_object_header(p, offset, &kind, &size);
switch (kind) {
case OBJ_DELTA:
return unpack_delta_entry(p, offset, size, type, sizep);
return 0;
}
-int find_pack_entry_one(const unsigned char *sha1,
- struct pack_entry *e, struct packed_git *p)
+unsigned long find_pack_entry_one(const unsigned char *sha1,
+ struct packed_git *p)
{
unsigned int *level1_ofs = p->index_base;
int hi = ntohl(level1_ofs[*sha1]);
do {
int mi = (lo + hi) / 2;
int cmp = hashcmp((unsigned char *)index + (24 * mi) + 4, sha1);
- if (!cmp) {
- e->offset = ntohl(*((unsigned int *) ((char *) index + (24 * mi))));
- hashcpy(e->sha1, sha1);
- e->p = p;
- return 1;
- }
+ if (!cmp)
+ return ntohl(*((unsigned int *) ((char *) index + (24 * mi))));
if (cmp > 0)
hi = mi;
else
return 0;
}
-static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
+static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
{
struct packed_git *p;
+ unsigned long offset;
+
prepare_packed_git();
for (p = packed_git; p; p = p->next) {
- if (find_pack_entry_one(sha1, e, p))
+ if (ignore_packed) {
+ const char **ig;
+ for (ig = ignore_packed; *ig; ig++)
+ if (!strcmp(p->pack_name, *ig))
+ break;
+ if (*ig)
+ continue;
+ }
+ offset = find_pack_entry_one(sha1, p);
+ if (offset) {
+ e->offset = offset;
+ e->p = p;
+ hashcpy(e->sha1, sha1);
return 1;
+ }
}
return 0;
}
struct packed_git *packs)
{
struct packed_git *p;
- struct pack_entry e;
for (p = packs; p; p = p->next) {
- if (find_pack_entry_one(sha1, &e, p))
+ if (find_pack_entry_one(sha1, p))
return p;
}
return NULL;
if (!map) {
struct pack_entry e;
- if (find_pack_entry(sha1, &e))
- return packed_object_info(&e, type, sizep);
- reprepare_packed_git();
- if (find_pack_entry(sha1, &e))
- return packed_object_info(&e, type, sizep);
- return error("unable to find %s", sha1_to_hex(sha1));
+ if (!find_pack_entry(sha1, &e, NULL)) {
+ reprepare_packed_git();
+ if (!find_pack_entry(sha1, &e, NULL))
+ return error("unable to find %s", sha1_to_hex(sha1));
+ }
+ if (use_packed_git(e.p))
+ die("cannot map packed file");
+ status = packed_object_info(e.p, e.offset, type, sizep);
+ unuse_packed_git(e.p);
+ return status;
}
if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
status = error("unable to unpack %s header",
{
struct pack_entry e;
- if (!find_pack_entry(sha1, &e)) {
+ if (!find_pack_entry(sha1, &e, NULL)) {
error("cannot read sha1_file for %s", sha1_to_hex(sha1));
return NULL;
}
void *map, *buf;
struct pack_entry e;
- if (find_pack_entry(sha1, &e))
+ if (find_pack_entry(sha1, &e, NULL))
return read_packed_sha1(sha1, type, size);
map = map_sha1_file(sha1, &mapsize);
if (map) {
return buf;
}
reprepare_packed_git();
- if (find_pack_entry(sha1, &e))
+ if (find_pack_entry(sha1, &e, NULL))
return read_packed_sha1(sha1, type, size);
return NULL;
}
*
* Returns the errno on failure, 0 on success.
*/
-static int link_temp_to_file(const char *tmpfile, char *filename)
+static int link_temp_to_file(const char *tmpfile, const char *filename)
{
int ret;
char *dir;
/*
* Move the just written object into its final resting place
*/
-int move_temp_to_file(const char *tmpfile, char *filename)
+int move_temp_to_file(const char *tmpfile, const char *filename)
{
int ret = link_temp_to_file(tmpfile, filename);
return 1;
}
-int has_sha1_pack(const unsigned char *sha1)
+int has_sha1_pack(const unsigned char *sha1, const char **ignore_packed)
{
struct pack_entry e;
- return find_pack_entry(sha1, &e);
+ return find_pack_entry(sha1, &e, ignore_packed);
}
int has_sha1_file(const unsigned char *sha1)
struct stat st;
struct pack_entry e;
- if (find_pack_entry(sha1, &e))
+ if (find_pack_entry(sha1, &e, NULL))
return 1;
return find_sha1_file(sha1, &st) ? 1 : 0;
}
int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
{
unsigned long size = 4096;
- char *buf = malloc(size);
+ char *buf = xmalloc(size);
int ret;
unsigned char hdr[50];
int hdrlen;