prepare_packed_git_run_once = 1;
}
-static void reprepare_packed_git(void)
+void reprepare_packed_git(void)
{
prepare_packed_git_run_once = 0;
prepare_packed_git();
return unpack_sha1_rest(&stream, hdr, *size);
}
+static unsigned long get_delta_base(struct packed_git *p,
+ unsigned long offset,
+ enum object_type kind,
+ unsigned long delta_obj_offset,
+ unsigned long *base_obj_offset)
+{
+ unsigned char *base_info = (unsigned char *) p->pack_base + offset;
+ unsigned long base_offset;
+
+ /* there must be at least 20 bytes left regardless of delta type */
+ if (p->pack_size <= offset + 20)
+ die("truncated pack file");
+
+ if (kind == OBJ_OFS_DELTA) {
+ unsigned used = 0;
+ unsigned char c = base_info[used++];
+ base_offset = c & 127;
+ while (c & 128) {
+ base_offset += 1;
+ if (!base_offset || base_offset & ~(~0UL >> 7))
+ die("offset value overflow for delta base object");
+ c = base_info[used++];
+ base_offset = (base_offset << 7) + (c & 127);
+ }
+ base_offset = delta_obj_offset - base_offset;
+ if (base_offset >= delta_obj_offset)
+ die("delta base offset out of bound");
+ offset += used;
+ } else if (kind == OBJ_REF_DELTA) {
+ /* The base entry _must_ be in the same pack */
+ base_offset = find_pack_entry_one(base_info, p);
+ if (!base_offset)
+ die("failed to find delta-pack base object %s",
+ sha1_to_hex(base_info));
+ offset += 20;
+ } else
+ die("I am totally screwed");
+ *base_obj_offset = base_offset;
+ return offset;
+}
+
/* forward declaration for a mutually recursive function */
static int packed_object_info(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep);
static int packed_delta_info(struct packed_git *p,
unsigned long offset,
+ enum object_type kind,
+ unsigned long obj_offset,
char *type,
unsigned long *sizep)
{
unsigned long base_offset;
- unsigned char *base_sha1 = (unsigned char *) p->pack_base + offset;
- if (p->pack_size < offset + 20)
- die("truncated pack file");
- /* The base entry _must_ be in the same pack */
- 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;
+ offset = get_delta_base(p, offset, kind, obj_offset, &base_offset);
/* We choose to only get the type of the base object and
* ignore potentially corrupt pack file that expects the delta
return offset + used;
}
-int check_reuse_pack_delta(struct packed_git *p, unsigned long offset,
- unsigned char *base, unsigned long *sizep,
- enum object_type *kindp)
-{
- unsigned long ptr;
- int status = -1;
-
- use_packed_git(p);
- ptr = offset;
- ptr = unpack_object_header(p, ptr, kindp, sizep);
- if (*kindp != OBJ_DELTA)
- goto done;
- hashcpy(base, (unsigned char *) p->pack_base + ptr);
- status = 0;
- done:
- unuse_packed_git(p);
- return status;
-}
-
void packed_object_info_detail(struct packed_git *p,
unsigned long offset,
char *type,
unsigned int *delta_chain_length,
unsigned char *base_sha1)
{
- unsigned long val;
+ unsigned long obj_offset, val;
unsigned char *next_sha1;
enum object_type kind;
*delta_chain_length = 0;
+ obj_offset = offset;
offset = unpack_object_header(p, offset, &kind, size);
for (;;) {
switch (kind) {
default:
- die("corrupted pack file %s containing object of kind %d",
+ die("pack %s contains unknown object type %d",
p->pack_name, kind);
case OBJ_COMMIT:
case OBJ_TREE:
strcpy(type, type_names[kind]);
*store_size = 0; /* notyet */
return;
- case OBJ_DELTA:
+ case OBJ_OFS_DELTA:
+ get_delta_base(p, offset, kind, obj_offset, &offset);
+ if (*delta_chain_length == 0) {
+ /* TODO: find base_sha1 as pointed by offset */
+ }
+ break;
+ case OBJ_REF_DELTA:
if (p->pack_size <= offset + 20)
die("pack file %s records an incomplete delta base",
p->pack_name);
offset = find_pack_entry_one(next_sha1, p);
break;
}
+ obj_offset = offset;
offset = unpack_object_header(p, offset, &kind, &val);
(*delta_chain_length)++;
}
static int packed_object_info(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep)
{
- unsigned long size;
+ unsigned long size, obj_offset = offset;
enum object_type kind;
offset = unpack_object_header(p, offset, &kind, &size);
- if (kind == OBJ_DELTA)
- return packed_delta_info(p, offset, type, sizep);
-
switch (kind) {
+ case OBJ_OFS_DELTA:
+ case OBJ_REF_DELTA:
+ return packed_delta_info(p, offset, kind, obj_offset, type, sizep);
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
strcpy(type, type_names[kind]);
break;
default:
- die("corrupted pack file %s containing object of kind %d",
+ die("pack %s contains unknown object type %d",
p->pack_name, kind);
}
if (sizep)
static void *unpack_delta_entry(struct packed_git *p,
unsigned long offset,
unsigned long delta_size,
+ enum object_type kind,
+ unsigned long obj_offset,
char *type,
unsigned long *sizep)
{
void *delta_data, *result, *base;
unsigned long result_size, base_size, base_offset;
- unsigned char *base_sha1;
-
- 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;
- 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;
+ offset = get_delta_base(p, offset, kind, obj_offset, &base_offset);
base = unpack_entry_gently(p, base_offset, type, &base_size);
if (!base)
die("failed to read delta base object at %lu from %s",
void *unpack_entry_gently(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep)
{
- unsigned long size;
+ unsigned long size, obj_offset = offset;
enum object_type kind;
offset = unpack_object_header(p, offset, &kind, &size);
switch (kind) {
- case OBJ_DELTA:
- return unpack_delta_entry(p, offset, size, type, sizep);
+ case OBJ_OFS_DELTA:
+ case OBJ_REF_DELTA:
+ return unpack_delta_entry(p, offset, size, kind, obj_offset, type, sizep);
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
return 0;
}
+static int matches_pack_name(struct packed_git *p, const char *ig)
+{
+ const char *last_c, *c;
+
+ if (!strcmp(p->pack_name, ig))
+ return 0;
+
+ for (c = p->pack_name, last_c = c; *c;)
+ if (*c == '/')
+ last_c = ++c;
+ else
+ ++c;
+ if (!strcmp(last_c, ig))
+ return 0;
+
+ return 1;
+}
+
static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
{
struct packed_git *p;
if (ignore_packed) {
const char **ig;
for (ig = ignore_packed; *ig; ig++)
- if (!strcmp(p->pack_name, *ig))
+ if (!matches_pack_name(p, *ig))
break;
if (*ig)
continue;
}
-int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep)
+static int sha1_loose_object_info(const unsigned char *sha1, char *type, unsigned long *sizep)
{
int status;
unsigned long mapsize, size;
char hdr[128];
map = map_sha1_file(sha1, &mapsize);
- if (!map) {
- struct pack_entry e;
-
- 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 (!map)
+ return error("unable to find %s", sha1_to_hex(sha1));
if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
status = error("unable to unpack %s header",
sha1_to_hex(sha1));
return status;
}
+int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep)
+{
+ int status;
+ struct pack_entry e;
+
+ if (!find_pack_entry(sha1, &e, NULL)) {
+ reprepare_packed_git();
+ if (!find_pack_entry(sha1, &e, NULL))
+ return sha1_loose_object_info(sha1, type, sizep);
+ }
+ 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;
+}
+
static void *read_packed_sha1(const unsigned char *sha1, char *type, unsigned long *size)
{
struct pack_entry e;
unlink(tmpfile);
if (ret) {
if (ret != EEXIST) {
- fprintf(stderr, "unable to write sha1 filename %s: %s\n", filename, strerror(ret));
- return -1;
+ return error("unable to write sha1 filename %s: %s\n", filename, strerror(ret));
}
/* FIXME!!! Collision check here ? */
}
}
if (errno != ENOENT) {
- fprintf(stderr, "sha1 file %s: %s\n", filename, strerror(errno));
- return -1;
+ return error("sha1 file %s: %s\n", filename, strerror(errno));
}
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\n", tmpfile, strerror(errno));
- return -1;
+ if (errno == EPERM)
+ return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
+ else
+ return error("unable to create temporary sha1 filename %s: %s\n", tmpfile, strerror(errno));
}
/* Set it up */
snprintf(tmpfile, sizeof(tmpfile), "%s/obj_XXXXXX", get_object_directory());
local = mkstemp(tmpfile);
- if (local < 0)
- return error("Couldn't open %s for %s",
- tmpfile, sha1_to_hex(sha1));
+ if (local < 0) {
+ if (errno == EPERM)
+ return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
+ else
+ return error("unable to create temporary sha1 filename %s: %s\n", tmpfile, strerror(errno));
+ }
memset(&stream, 0, sizeof(stream));