* SHA1, an extra slash for the first level indirection, and the
* terminating NUL.
*/
+static void read_info_alternates(const char * relative_base, int depth);
static int link_alt_odb_entry(const char *entry, const char *relative_base,
int depth, const char *normalized_objdir)
{
strbuf_release(&objdirbuf);
}
-void read_info_alternates(const char * relative_base, int depth)
+static void read_info_alternates(const char * relative_base, int depth)
{
char *map;
size_t mapsz;
fd = open(name, flags | o_cloexec);
}
-#if defined(F_GETFL) && defined(F_SETFL) && defined(FD_CLOEXEC)
+#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
{
static int fd_cloexec = FD_CLOEXEC;
if (!o_cloexec && 0 <= fd && fd_cloexec) {
/* Opened w/o O_CLOEXEC? try with fcntl(2) to add it */
- int flags = fcntl(fd, F_GETFL);
- if (fcntl(fd, F_SETFL, flags | fd_cloexec))
+ int flags = fcntl(fd, F_GETFD);
+ if (fcntl(fd, F_SETFD, flags | fd_cloexec))
fd_cloexec = 0;
}
}
* we're obtaining the type using '--allow-unknown-type'
* option.
*/
- if ((flags & LOOKUP_UNKNOWN_OBJECT) && (type < 0))
+ if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE) && (type < 0))
type = 0;
else if (type < 0)
die("invalid object type");
struct object_info oi = OBJECT_INFO_INIT;
oi.sizep = sizep;
- return parse_sha1_header_extended(hdr, &oi, LOOKUP_REPLACE_OBJECT);
-}
-
-static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1)
-{
- int ret;
- git_zstream stream;
- char hdr[8192];
-
- ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
- if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0)
- return NULL;
-
- return unpack_sha1_rest(&stream, hdr, *size, sha1);
+ return parse_sha1_header_extended(hdr, &oi, 0);
}
unsigned long get_size_from_delta(struct packed_git *p,
goto out;
}
-int packed_object_info(struct packed_git *p, off_t obj_offset,
- struct object_info *oi)
-{
- struct pack_window *w_curs = NULL;
- unsigned long size;
- off_t curpos = obj_offset;
- enum object_type type;
-
- /*
- * We always get the representation type, but only convert it to
- * a "real" type later if the caller is interested.
- */
- type = unpack_object_header(p, &w_curs, &curpos, &size);
-
- if (oi->sizep) {
- if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
- off_t tmp_pos = curpos;
- off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
- type, obj_offset);
- if (!base_offset) {
- type = OBJ_BAD;
- goto out;
- }
- *oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
- if (*oi->sizep == 0) {
- type = OBJ_BAD;
- goto out;
- }
- } else {
- *oi->sizep = size;
- }
- }
-
- if (oi->disk_sizep) {
- struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
- *oi->disk_sizep = revidx[1].offset - obj_offset;
- }
-
- if (oi->typep) {
- *oi->typep = packed_to_object_type(p, obj_offset, type, &w_curs, curpos);
- if (*oi->typep < 0) {
- type = OBJ_BAD;
- goto out;
- }
- }
-
- if (oi->delta_base_sha1) {
- if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
- const unsigned char *base;
-
- base = get_delta_base_sha1(p, &w_curs, curpos,
- type, obj_offset);
- if (!base) {
- type = OBJ_BAD;
- goto out;
- }
-
- hashcpy(oi->delta_base_sha1, base);
- } else
- hashclr(oi->delta_base_sha1);
- }
-
-out:
- unuse_pack(&w_curs);
- return type;
-}
-
-static void *unpack_compressed_entry(struct packed_git *p,
- struct pack_window **w_curs,
- off_t curpos,
- unsigned long size)
-{
- int st;
- git_zstream stream;
- unsigned char *buffer, *in;
-
- buffer = xmallocz_gently(size);
- if (!buffer)
- return NULL;
- memset(&stream, 0, sizeof(stream));
- stream.next_out = buffer;
- stream.avail_out = size + 1;
-
- git_inflate_init(&stream);
- do {
- in = use_pack(p, w_curs, curpos, &stream.avail_in);
- stream.next_in = in;
- st = git_inflate(&stream, Z_FINISH);
- if (!stream.avail_out)
- break; /* the payload is larger than it should be */
- curpos += stream.next_in - in;
- } while (st == Z_OK || st == Z_BUF_ERROR);
- git_inflate_end(&stream);
- if ((st != Z_STREAM_END) || stream.total_out != size) {
- free(buffer);
- return NULL;
- }
-
- return buffer;
-}
-
static struct hashmap delta_base_cache;
static size_t delta_base_cached;
return a->p == b->p && a->base_offset == b->base_offset;
}
-static int delta_base_cache_hash_cmp(const void *va, const void *vb,
+static int delta_base_cache_hash_cmp(const void *unused_cmp_data,
+ const void *va, const void *vb,
const void *vkey)
{
const struct delta_base_cache_entry *a = va, *b = vb;
if (!ent)
return unpack_entry(p, base_offset, type, base_size);
- *type = ent->type;
- *base_size = ent->size;
+ if (type)
+ *type = ent->type;
+ if (base_size)
+ *base_size = ent->size;
return xmemdupz(ent->data, ent->size);
}
list_add_tail(&ent->lru, &delta_base_cache_lru);
if (!delta_base_cache.cmpfn)
- hashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, 0);
+ hashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, NULL, 0);
hashmap_entry_init(ent, pack_entry_hash(p, base_offset));
hashmap_add(&delta_base_cache, ent);
}
+int packed_object_info(struct packed_git *p, off_t obj_offset,
+ struct object_info *oi)
+{
+ struct pack_window *w_curs = NULL;
+ unsigned long size;
+ off_t curpos = obj_offset;
+ enum object_type type;
+
+ /*
+ * We always get the representation type, but only convert it to
+ * a "real" type later if the caller is interested.
+ */
+ if (oi->contentp) {
+ *oi->contentp = cache_or_unpack_entry(p, obj_offset, oi->sizep,
+ &type);
+ if (!*oi->contentp)
+ type = OBJ_BAD;
+ } else {
+ type = unpack_object_header(p, &w_curs, &curpos, &size);
+ }
+
+ if (!oi->contentp && oi->sizep) {
+ if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+ off_t tmp_pos = curpos;
+ off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
+ type, obj_offset);
+ if (!base_offset) {
+ type = OBJ_BAD;
+ goto out;
+ }
+ *oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
+ if (*oi->sizep == 0) {
+ type = OBJ_BAD;
+ goto out;
+ }
+ } else {
+ *oi->sizep = size;
+ }
+ }
+
+ if (oi->disk_sizep) {
+ struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
+ *oi->disk_sizep = revidx[1].offset - obj_offset;
+ }
+
+ if (oi->typep || oi->typename) {
+ enum object_type ptot;
+ ptot = packed_to_object_type(p, obj_offset, type, &w_curs,
+ curpos);
+ if (oi->typep)
+ *oi->typep = ptot;
+ if (oi->typename) {
+ const char *tn = typename(ptot);
+ if (tn)
+ strbuf_addstr(oi->typename, tn);
+ }
+ if (ptot < 0) {
+ type = OBJ_BAD;
+ goto out;
+ }
+ }
+
+ if (oi->delta_base_sha1) {
+ if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+ const unsigned char *base;
+
+ base = get_delta_base_sha1(p, &w_curs, curpos,
+ type, obj_offset);
+ if (!base) {
+ type = OBJ_BAD;
+ goto out;
+ }
+
+ hashcpy(oi->delta_base_sha1, base);
+ } else
+ hashclr(oi->delta_base_sha1);
+ }
+
+ oi->whence = in_delta_base_cache(p, obj_offset) ? OI_DBCACHED :
+ OI_PACKED;
+
+out:
+ unuse_pack(&w_curs);
+ return type;
+}
+
+static void *unpack_compressed_entry(struct packed_git *p,
+ struct pack_window **w_curs,
+ off_t curpos,
+ unsigned long size)
+{
+ int st;
+ git_zstream stream;
+ unsigned char *buffer, *in;
+
+ buffer = xmallocz_gently(size);
+ if (!buffer)
+ return NULL;
+ memset(&stream, 0, sizeof(stream));
+ stream.next_out = buffer;
+ stream.avail_out = size + 1;
+
+ git_inflate_init(&stream);
+ do {
+ in = use_pack(p, w_curs, curpos, &stream.avail_in);
+ stream.next_in = in;
+ st = git_inflate(&stream, Z_FINISH);
+ if (!stream.avail_out)
+ break; /* the payload is larger than it should be */
+ curpos += stream.next_in - in;
+ } while (st == Z_OK || st == Z_BUF_ERROR);
+ git_inflate_end(&stream);
+ if ((st != Z_STREAM_END) || stream.total_out != size) {
+ free(buffer);
+ return NULL;
+ }
+
+ return buffer;
+}
+
static void *read_object(const unsigned char *sha1, enum object_type *type,
unsigned long *size);
error("bad packed object CRC for %s",
sha1_to_hex(sha1));
mark_bad_packed_object(p, sha1);
- unuse_pack(&w_curs);
- return NULL;
+ data = NULL;
+ goto out;
}
}
free(external_base);
}
- *final_type = type;
- *final_size = size;
+ if (final_type)
+ *final_type = type;
+ if (final_size)
+ *final_size = size;
+out:
unuse_pack(&w_curs);
if (delta_stack != small_delta_stack)
const uint32_t *level1_ofs = p->index_data;
const unsigned char *index = p->index_data;
unsigned hi, lo, stride;
- static int use_lookup = -1;
static int debug_lookup = -1;
if (debug_lookup < 0)
printf("%02x%02x%02x... lo %u hi %u nr %"PRIu32"\n",
sha1[0], sha1[1], sha1[2], lo, hi, p->num_objects);
- if (use_lookup < 0)
- use_lookup = !!getenv("GIT_USE_LOOKUP");
- if (use_lookup) {
- int pos = sha1_entry_pos(index, stride, 0,
- lo, hi, p->num_objects, sha1);
- if (pos < 0)
- return 0;
- return nth_packed_object_offset(p, pos);
- }
-
- do {
+ while (lo < hi) {
unsigned mi = (lo + hi) / 2;
int cmp = hashcmp(index + mi * stride, sha1);
hi = mi;
else
lo = mi+1;
- } while (lo < hi);
+ }
return 0;
}
git_zstream stream;
char hdr[32];
struct strbuf hdrbuf = STRBUF_INIT;
+ unsigned long size_scratch;
if (oi->delta_base_sha1)
hashclr(oi->delta_base_sha1);
* return value implicitly indicates whether the
* object even exists.
*/
- if (!oi->typep && !oi->typename && !oi->sizep) {
+ if (!oi->typep && !oi->typename && !oi->sizep && !oi->contentp) {
const char *path;
struct stat st;
if (stat_sha1_file(sha1, &st, &path) < 0)
map = map_sha1_file(sha1, &mapsize);
if (!map)
return -1;
+
+ if (!oi->sizep)
+ oi->sizep = &size_scratch;
+
if (oi->disk_sizep)
*oi->disk_sizep = mapsize;
- if ((flags & LOOKUP_UNKNOWN_OBJECT)) {
+ if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE)) {
if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
status = error("unable to unpack %s header with --allow-unknown-type",
sha1_to_hex(sha1));
sha1_to_hex(sha1));
} else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0)
status = error("unable to parse %s header", sha1_to_hex(sha1));
- git_inflate_end(&stream);
+
+ if (status >= 0 && oi->contentp)
+ *oi->contentp = unpack_sha1_rest(&stream, hdr,
+ *oi->sizep, sha1);
+ else
+ git_inflate_end(&stream);
+
munmap(map, mapsize);
if (status && oi->typep)
*oi->typep = status;
+ if (oi->sizep == &size_scratch)
+ oi->sizep = NULL;
strbuf_release(&hdrbuf);
+ oi->whence = OI_LOOSE;
return (status < 0) ? status : 0;
}
int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags)
{
- struct cached_object *co;
+ static struct object_info blank_oi = OBJECT_INFO_INIT;
struct pack_entry e;
int rtype;
- enum object_type real_type;
- const unsigned char *real = lookup_replace_object_extended(sha1, flags);
-
- co = find_cached_object(real);
- if (co) {
- if (oi->typep)
- *(oi->typep) = co->type;
- if (oi->sizep)
- *(oi->sizep) = co->size;
- if (oi->disk_sizep)
- *(oi->disk_sizep) = 0;
- if (oi->delta_base_sha1)
- hashclr(oi->delta_base_sha1);
- if (oi->typename)
- strbuf_addstr(oi->typename, typename(co->type));
- oi->whence = OI_CACHED;
- return 0;
+ const unsigned char *real = (flags & OBJECT_INFO_LOOKUP_REPLACE) ?
+ lookup_replace_object(sha1) :
+ sha1;
+
+ if (!oi)
+ oi = &blank_oi;
+
+ if (!(flags & OBJECT_INFO_SKIP_CACHED)) {
+ struct cached_object *co = find_cached_object(real);
+ if (co) {
+ if (oi->typep)
+ *(oi->typep) = co->type;
+ if (oi->sizep)
+ *(oi->sizep) = co->size;
+ if (oi->disk_sizep)
+ *(oi->disk_sizep) = 0;
+ if (oi->delta_base_sha1)
+ hashclr(oi->delta_base_sha1);
+ if (oi->typename)
+ strbuf_addstr(oi->typename, typename(co->type));
+ if (oi->contentp)
+ *oi->contentp = xmemdupz(co->buf, co->size);
+ oi->whence = OI_CACHED;
+ return 0;
+ }
}
if (!find_pack_entry(real, &e)) {
/* Most likely it's a loose object. */
- if (!sha1_loose_object_info(real, oi, flags)) {
- oi->whence = OI_LOOSE;
+ if (!sha1_loose_object_info(real, oi, flags))
return 0;
- }
/* Not a loose object; someone else may have just packed it. */
- reprepare_packed_git();
- if (!find_pack_entry(real, &e))
+ if (flags & OBJECT_INFO_QUICK) {
return -1;
+ } else {
+ reprepare_packed_git();
+ if (!find_pack_entry(real, &e))
+ return -1;
+ }
}
- /*
- * packed_object_info() does not follow the delta chain to
- * find out the real type, unless it is given oi->typep.
- */
- if (oi->typename && !oi->typep)
- oi->typep = &real_type;
+ if (oi == &blank_oi)
+ /*
+ * We know that the caller doesn't actually need the
+ * information below, so return early.
+ */
+ return 0;
rtype = packed_object_info(e.p, e.offset, oi);
if (rtype < 0) {
mark_bad_packed_object(e.p, real);
- if (oi->typep == &real_type)
- oi->typep = NULL;
return sha1_object_info_extended(real, oi, 0);
- } else if (in_delta_base_cache(e.p, e.offset)) {
- oi->whence = OI_DBCACHED;
- } else {
- oi->whence = OI_PACKED;
+ } else if (oi->whence == OI_PACKED) {
oi->u.packed.offset = e.offset;
oi->u.packed.pack = e.p;
oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA ||
rtype == OBJ_OFS_DELTA);
}
- if (oi->typename)
- strbuf_addstr(oi->typename, typename(*oi->typep));
- if (oi->typep == &real_type)
- oi->typep = NULL;
return 0;
}
oi.typep = &type;
oi.sizep = sizep;
- if (sha1_object_info_extended(sha1, &oi, LOOKUP_REPLACE_OBJECT) < 0)
+ if (sha1_object_info_extended(sha1, &oi,
+ OBJECT_INFO_LOOKUP_REPLACE) < 0)
return -1;
return type;
}
-static void *read_packed_sha1(const unsigned char *sha1,
- enum object_type *type, unsigned long *size)
-{
- struct pack_entry e;
- void *data;
-
- if (!find_pack_entry(sha1, &e))
- return NULL;
- data = cache_or_unpack_entry(e.p, e.offset, size, type);
- if (!data) {
- /*
- * We're probably in deep shit, but let's try to fetch
- * the required object anyway from another pack or loose.
- * This should happen only in the presence of a corrupted
- * pack, and is better than failing outright.
- */
- error("failed to read object %s at offset %"PRIuMAX" from %s",
- sha1_to_hex(sha1), (uintmax_t)e.offset, e.p->pack_name);
- mark_bad_packed_object(e.p, sha1);
- data = read_object(sha1, type, size);
- }
- return data;
-}
-
int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
unsigned char *sha1)
{
static void *read_object(const unsigned char *sha1, enum object_type *type,
unsigned long *size)
{
- unsigned long mapsize;
- void *map, *buf;
- struct cached_object *co;
-
- co = find_cached_object(sha1);
- if (co) {
- *type = co->type;
- *size = co->size;
- return xmemdupz(co->buf, co->size);
- }
+ struct object_info oi = OBJECT_INFO_INIT;
+ void *content;
+ oi.typep = type;
+ oi.sizep = size;
+ oi.contentp = &content;
- buf = read_packed_sha1(sha1, type, size);
- if (buf)
- return buf;
- map = map_sha1_file(sha1, &mapsize);
- if (map) {
- buf = unpack_sha1_file(map, mapsize, type, size, sha1);
- munmap(map, mapsize);
- return buf;
- }
- reprepare_packed_git();
- return read_packed_sha1(sha1, type, size);
+ if (sha1_object_info_extended(sha1, &oi, 0) < 0)
+ return NULL;
+ return content;
}
/*
void *read_sha1_file_extended(const unsigned char *sha1,
enum object_type *type,
unsigned long *size,
- unsigned flag)
+ int lookup_replace)
{
void *data;
const struct packed_git *p;
const char *path;
struct stat st;
- const unsigned char *repl = lookup_replace_object_extended(sha1, flag);
+ const unsigned char *repl = lookup_replace ? lookup_replace_object(sha1)
+ : sha1;
errno = 0;
data = read_object(repl, type, size);
if (has_loose_object(sha1))
return 0;
- buf = read_packed_sha1(sha1, &type, &len);
+ buf = read_object(sha1, &type, &len);
if (!buf)
return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), len) + 1;
int has_sha1_file_with_flags(const unsigned char *sha1, int flags)
{
- struct pack_entry e;
-
if (!startup_info->have_repository)
return 0;
- if (find_pack_entry(sha1, &e))
- return 1;
- if (has_loose_object(sha1))
- return 1;
- if (flags & HAS_SHA1_QUICK)
- return 0;
- reprepare_packed_git();
- return find_pack_entry(sha1, &e);
+ return sha1_object_info_extended(sha1, NULL,
+ flags | OBJECT_INFO_SKIP_CACHED) >= 0;
}
int has_object_file(const struct object_id *oid)
typename(expect));
}
-static int for_each_file_in_obj_subdir(int subdir_nr,
- struct strbuf *path,
- each_loose_object_fn obj_cb,
- each_loose_cruft_fn cruft_cb,
- each_loose_subdir_fn subdir_cb,
- void *data)
+int for_each_file_in_obj_subdir(unsigned int subdir_nr,
+ struct strbuf *path,
+ each_loose_object_fn obj_cb,
+ each_loose_cruft_fn cruft_cb,
+ each_loose_subdir_fn subdir_cb,
+ void *data)
{
- size_t baselen = path->len;
- DIR *dir = opendir(path->buf);
+ size_t origlen, baselen;
+ DIR *dir;
struct dirent *de;
int r = 0;
+ if (subdir_nr > 0xff)
+ BUG("invalid loose object subdirectory: %x", subdir_nr);
+
+ origlen = path->len;
+ strbuf_complete(path, '/');
+ strbuf_addf(path, "%02x", subdir_nr);
+ baselen = path->len;
+
+ dir = opendir(path->buf);
if (!dir) {
- if (errno == ENOENT)
- return 0;
- return error_errno("unable to open %s", path->buf);
+ if (errno != ENOENT)
+ r = error_errno("unable to open %s", path->buf);
+ strbuf_setlen(path, origlen);
+ return r;
}
while ((de = readdir(dir))) {
if (!r && subdir_cb)
r = subdir_cb(subdir_nr, path->buf, data);
+ strbuf_setlen(path, origlen);
+
return r;
}
each_loose_subdir_fn subdir_cb,
void *data)
{
- size_t baselen = path->len;
int r = 0;
int i;
for (i = 0; i < 256; i++) {
- strbuf_addf(path, "/%02x", i);
r = for_each_file_in_obj_subdir(i, path, obj_cb, cruft_cb,
subdir_cb, data);
- strbuf_setlen(path, baselen);
if (r)
break;
}