#include "tag.h"
#include "tree.h"
#include "refs.h"
+#include "pack-revindex.h"
+#include "sha1-lookup.h"
#ifndef O_NOATIME
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
#ifdef NO_C99_FORMAT
#define SZ_FMT "lu"
+static unsigned long sz_fmt(size_t s) { return (unsigned long)s; }
#else
#define SZ_FMT "zu"
+static size_t sz_fmt(size_t s) { return s; }
#endif
const unsigned char null_sha1[20];
/*
* NOTE! This returns a statically allocated buffer, so you have to be
- * careful about using it. Do a "xstrdup()" if you need to save the
+ * careful about using it. Do an "xstrdup()" if you need to save the
* filename.
*
* Also note that this returns the location for creating. Reading
"pack_report: getpagesize() = %10" SZ_FMT "\n"
"pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n"
"pack_report: core.packedGitLimit = %10" SZ_FMT "\n",
- (size_t) getpagesize(),
- packed_git_window_size,
- packed_git_limit);
+ sz_fmt(getpagesize()),
+ sz_fmt(packed_git_window_size),
+ sz_fmt(packed_git_limit));
fprintf(stderr,
"pack_report: pack_used_ctr = %10u\n"
"pack_report: pack_mmap_calls = %10u\n"
pack_used_ctr,
pack_mmap_calls,
pack_open_windows, peak_pack_open_windows,
- pack_mapped, peak_pack_mapped);
+ sz_fmt(pack_mapped), sz_fmt(peak_pack_mapped));
}
static int check_packed_git_idx(const char *path, struct packed_git *p)
; /* nothing */
}
+void close_pack_windows(struct packed_git *p)
+{
+ while (p->windows) {
+ struct pack_window *w = p->windows;
+
+ if (w->inuse_cnt)
+ die("pack '%s' still has open windows to it",
+ p->pack_name);
+ munmap(w->base, w->len);
+ pack_mapped -= w->len;
+ pack_open_windows--;
+ p->windows = w->next;
+ free(w);
+ }
+}
+
void unuse_pack(struct pack_window **w_cursor)
{
struct pack_window *w = *w_cursor;
unsigned long dummy;
unsigned char *next_sha1;
enum object_type type;
+ struct revindex_entry *revidx;
*delta_chain_length = 0;
curpos = obj_offset;
type = unpack_object_header(p, &w_curs, &curpos, size);
+ revidx = find_pack_revindex(p, obj_offset);
+ *store_size = revidx[1].offset - obj_offset;
+
for (;;) {
switch (type) {
default:
case OBJ_TREE:
case OBJ_BLOB:
case OBJ_TAG:
- *store_size = 0; /* notyet */
unuse_pack(&w_curs);
return typename(type);
case OBJ_OFS_DELTA:
obj_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
if (*delta_chain_length == 0) {
- /* TODO: find base_sha1 as pointed by curpos */
- hashclr(base_sha1);
+ revidx = find_pack_revindex(p, obj_offset);
+ hashcpy(base_sha1, nth_packed_object_sha1(p, revidx->nr));
}
break;
case OBJ_REF_DELTA:
{
const uint32_t *level1_ofs = p->index_data;
const unsigned char *index = p->index_data;
- unsigned hi, lo;
+ unsigned hi, lo, stride;
+ static int use_lookup = -1;
+ static int debug_lookup = -1;
+
+ if (debug_lookup < 0)
+ debug_lookup = !!getenv("GIT_DEBUG_LOOKUP");
if (!index) {
if (open_pack_index(p))
index += 4 * 256;
hi = ntohl(level1_ofs[*sha1]);
lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
+ if (p->index_version > 1) {
+ stride = 20;
+ } else {
+ stride = 24;
+ index += 4;
+ }
+
+ if (debug_lookup)
+ printf("%02x%02x%02x... lo %u hi %u nr %u\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 {
unsigned mi = (lo + hi) / 2;
- unsigned x = (p->index_version > 1) ? (mi * 20) : (mi * 24 + 4);
- int cmp = hashcmp(index + x, sha1);
+ int cmp = hashcmp(index + mi * stride, sha1);
+
+ if (debug_lookup)
+ printf("lo %u hi %u rg %u mi %u\n",
+ lo, hi, hi - lo, mi);
if (!cmp)
return nth_packed_object_offset(p, mi);
if (cmp > 0)
} *cached_objects;
static int cached_object_nr, cached_object_alloc;
+static struct cached_object empty_tree = {
+ /* empty tree sha1: 4b825dc642cb6eb9a060e54bf8d69288fbee4904 */
+ "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60"
+ "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04",
+ OBJ_TREE,
+ "",
+ 0
+};
+
static struct cached_object *find_cached_object(const unsigned char *sha1)
{
int i;
if (!hashcmp(co->sha1, sha1))
return co;
}
+ if (!hashcmp(sha1, empty_tree.sha1))
+ return &empty_tree;
return NULL;
}
}
ref_length = strlen(ref_type);
- if (memcmp(buffer, ref_type, ref_length) ||
+ if (ref_length + 40 > isize ||
+ memcmp(buffer, ref_type, ref_length) ||
get_sha1_hex((char *) buffer + ref_length, actual_sha1)) {
free(buffer);
return NULL;
if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) {
struct strbuf nbuf;
strbuf_init(&nbuf, 0);
- if (convert_to_git(path, buf, size, &nbuf)) {
+ if (convert_to_git(path, buf, size, &nbuf,
+ write_object ? safe_crlf : 0)) {
munmap(buf, size);
buf = strbuf_detach(&nbuf, &size);
re_allocated = 1;
int read_pack_header(int fd, struct pack_header *header)
{
- char *c = (char*)header;
- ssize_t remaining = sizeof(struct pack_header);
- do {
- ssize_t r = xread(fd, c, remaining);
- if (r <= 0)
- /* "eof before pack header was fully read" */
- return PH_ERROR_EOF;
- remaining -= r;
- c += r;
- } while (remaining > 0);
+ if (read_in_full(fd, header, sizeof(*header)) < sizeof(*header))
+ /* "eof before pack header was fully read" */
+ return PH_ERROR_EOF;
+
if (header->hdr_signature != htonl(PACK_SIGNATURE))
/* "protocol error (pack signature mismatch detected)" */
return PH_ERROR_PACK_SIGNATURE;