static void read_info_alternates(const char * relative_base, int depth)
{
char *map;
+ size_t mapsz;
struct stat st;
char path[PATH_MAX];
int fd;
close(fd);
return;
}
- map = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ mapsz = xsize_t(st.st_size);
+ map = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
- link_alt_odb_entries(map, map + st.st_size, '\n', relative_base, depth);
+ link_alt_odb_entries(map, map + mapsz, '\n', relative_base, depth);
- munmap(map, st.st_size);
+ munmap(map, mapsz);
}
void prepare_alt_odb(void)
{
void *idx_map;
uint32_t *index;
- unsigned long idx_size;
+ size_t idx_size;
uint32_t nr, i;
int fd = open(path, O_RDONLY);
struct stat st;
close(fd);
return -1;
}
- idx_size = st.st_size;
+ idx_size = xsize_t(st.st_size);
if (idx_size < 4 * 256 + 20 + 20) {
close(fd);
return error("index file %s is too small", path);
return -1;
}
-static int in_window(struct pack_window *win, unsigned long offset)
+static int in_window(struct pack_window *win, off_t offset)
{
/* We must promise at least 20 bytes (one hash) after the
* offset is available from this window, otherwise the offset
unsigned char* use_pack(struct packed_git *p,
struct pack_window **w_cursor,
- unsigned long offset,
+ off_t offset,
unsigned int *left)
{
struct pack_window *win = *w_cursor;
}
if (!win) {
size_t window_align = packed_git_window_size / 2;
+ off_t len;
win = xcalloc(1, sizeof(*win));
win->offset = (offset / window_align) * window_align;
- win->len = p->pack_size - win->offset;
- if (win->len > packed_git_window_size)
- win->len = packed_git_window_size;
+ len = p->pack_size - win->offset;
+ if (len > packed_git_window_size)
+ len = packed_git_window_size;
+ win->len = (size_t)len;
pack_mapped += win->len;
while (packed_git_limit < pack_mapped
&& unuse_one_window(p))
}
offset -= win->offset;
if (left)
- *left = win->len - offset;
+ *left = win->len - xsize_t(offset);
return win->base + offset;
}
p->windows = NULL;
p->pack_fd = -1;
p->pack_local = local;
+ p->mtime = st.st_mtime;
if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
hashcpy(p->sha1, sha1);
return p;
closedir(dir);
}
+static int sort_pack(const void *a_, const void *b_)
+{
+ struct packed_git *a = *((struct packed_git **)a_);
+ struct packed_git *b = *((struct packed_git **)b_);
+ int st;
+
+ /*
+ * Local packs tend to contain objects specific to our
+ * variant of the project than remote ones. In addition,
+ * remote ones could be on a network mounted filesystem.
+ * Favor local ones for these reasons.
+ */
+ st = a->pack_local - b->pack_local;
+ if (st)
+ return -st;
+
+ /*
+ * Younger packs tend to contain more recent objects,
+ * and more recent objects tend to get accessed more
+ * often.
+ */
+ if (a->mtime < b->mtime)
+ return 1;
+ else if (a->mtime == b->mtime)
+ return 0;
+ return -1;
+}
+
+static void rearrange_packed_git(void)
+{
+ struct packed_git **ary, *p;
+ int i, n;
+
+ for (n = 0, p = packed_git; p; p = p->next)
+ n++;
+ if (n < 2)
+ return;
+
+ /* prepare an array of packed_git for easier sorting */
+ ary = xcalloc(n, sizeof(struct packed_git *));
+ for (n = 0, p = packed_git; p; p = p->next)
+ ary[n++] = p;
+
+ qsort(ary, n, sizeof(struct packed_git *), sort_pack);
+
+ /* link them back again */
+ for (i = 0; i < n - 1; i++)
+ ary[i]->next = ary[i + 1];
+ ary[n - 1]->next = NULL;
+ packed_git = ary[0];
+
+ free(ary);
+}
+
static int prepare_packed_git_run_once = 0;
void prepare_packed_git(void)
{
prepare_packed_git_one(alt->base, 0);
alt->name[-1] = '/';
}
+ rearrange_packed_git();
prepare_packed_git_run_once = 1;
}
*/
sha1_file_open_flag = 0;
}
- map = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ *size = xsize_t(st.st_size);
+ map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
- *size = st.st_size;
return map;
}
return 0;
}
-static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size)
+static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
{
int bytes = strlen(buffer) + 1;
unsigned char *buf = xmalloc(1+size);
unsigned long n;
+ int status = Z_OK;
n = stream->total_out - bytes;
if (n > size)
if (bytes < size) {
stream->next_out = buf + bytes;
stream->avail_out = size - bytes;
- while (inflate(stream, Z_FINISH) == Z_OK)
- /* nothing */;
+ while (status == Z_OK)
+ status = inflate(stream, Z_FINISH);
}
buf[size] = 0;
- inflateEnd(stream);
- return buf;
+ if ((status == Z_OK || status == Z_STREAM_END) && !stream->avail_in) {
+ inflateEnd(stream);
+ return buf;
+ }
+
+ if (status < 0)
+ error("corrupt loose object '%s'", sha1_to_hex(sha1));
+ else if (stream->avail_in)
+ error("garbage at end of loose object '%s'",
+ sha1_to_hex(sha1));
+ free(buf);
+ return NULL;
}
/*
return *hdr ? -1 : type_from_string(type);
}
-void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size)
+static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1)
{
int ret;
z_stream stream;
if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0)
return NULL;
- return unpack_sha1_rest(&stream, hdr, *size);
+ return unpack_sha1_rest(&stream, hdr, *size, sha1);
}
-static unsigned long get_delta_base(struct packed_git *p,
+static off_t get_delta_base(struct packed_git *p,
struct pack_window **w_curs,
- unsigned long *curpos,
+ off_t *curpos,
enum object_type type,
- unsigned long delta_obj_offset)
+ off_t delta_obj_offset)
{
unsigned char *base_info = use_pack(p, w_curs, *curpos, NULL);
- unsigned long base_offset;
+ off_t base_offset;
/* use_pack() assured us we have [base_info, base_info + 20)
* as a range that we can look at without walking off the
}
/* forward declaration for a mutually recursive function */
-static int packed_object_info(struct packed_git *p, unsigned long offset,
+static int packed_object_info(struct packed_git *p, off_t offset,
unsigned long *sizep);
static int packed_delta_info(struct packed_git *p,
struct pack_window **w_curs,
- unsigned long curpos,
+ off_t curpos,
enum object_type type,
- unsigned long obj_offset,
+ off_t obj_offset,
unsigned long *sizep)
{
- unsigned long base_offset;
+ off_t base_offset;
base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset);
type = packed_object_info(p, base_offset, NULL);
static int unpack_object_header(struct packed_git *p,
struct pack_window **w_curs,
- unsigned long *curpos,
+ off_t *curpos,
unsigned long *sizep)
{
unsigned char *base;
}
const char *packed_object_info_detail(struct packed_git *p,
- unsigned long obj_offset,
+ off_t obj_offset,
unsigned long *size,
unsigned long *store_size,
unsigned int *delta_chain_length,
unsigned char *base_sha1)
{
struct pack_window *w_curs = NULL;
- unsigned long curpos, dummy;
+ off_t curpos;
+ unsigned long dummy;
unsigned char *next_sha1;
enum object_type type;
}
}
-static int packed_object_info(struct packed_git *p, unsigned long obj_offset,
+static int packed_object_info(struct packed_git *p, off_t obj_offset,
unsigned long *sizep)
{
struct pack_window *w_curs = NULL;
- unsigned long size, curpos = obj_offset;
+ unsigned long size;
+ off_t curpos = obj_offset;
enum object_type type;
type = unpack_object_header(p, &w_curs, &curpos, &size);
static void *unpack_compressed_entry(struct packed_git *p,
struct pack_window **w_curs,
- unsigned long curpos,
+ off_t curpos,
unsigned long size)
{
int st;
static void *unpack_delta_entry(struct packed_git *p,
struct pack_window **w_curs,
- unsigned long curpos,
+ off_t curpos,
unsigned long delta_size,
- unsigned long obj_offset,
+ off_t obj_offset,
enum object_type *type,
unsigned long *sizep)
{
void *delta_data, *result, *base;
- unsigned long base_size, base_offset;
+ unsigned long base_size;
+ off_t base_offset;
base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset);
base = unpack_entry(p, base_offset, type, &base_size);
if (!base)
- die("failed to read delta base object at %lu from %s",
- base_offset, p->pack_name);
+ die("failed to read delta base object"
+ " at %"PRIuMAX" from %s",
+ (uintmax_t)base_offset, p->pack_name);
delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size);
result = patch_delta(base, base_size,
return result;
}
-void *unpack_entry(struct packed_git *p, unsigned long obj_offset,
+void *unpack_entry(struct packed_git *p, off_t obj_offset,
enum object_type *type, unsigned long *sizep)
{
struct pack_window *w_curs = NULL;
- unsigned long curpos = obj_offset;
+ off_t curpos = obj_offset;
void *data;
*type = unpack_object_header(p, &w_curs, &curpos, sizep);
uint32_t num_packed_objects(const struct packed_git *p)
{
/* See check_packed_git_idx() */
- return (p->index_size - 20 - 20 - 4*256) / 24;
+ return (uint32_t)((p->index_size - 20 - 20 - 4*256) / 24);
}
int nth_packed_object_sha1(const struct packed_git *p, uint32_t n,
return 0;
}
-unsigned long find_pack_entry_one(const unsigned char *sha1,
+off_t find_pack_entry_one(const unsigned char *sha1,
struct packed_git *p)
{
uint32_t *level1_ofs = p->index_base;
static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
{
struct packed_git *p;
- unsigned long offset;
+ off_t offset;
prepare_packed_git();
return buf;
map = map_sha1_file(sha1, &mapsize);
if (map) {
- buf = unpack_sha1_file(map, mapsize, type, size);
+ buf = unpack_sha1_file(map, mapsize, type, size, sha1);
munmap(map, mapsize);
return buf;
}
int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
enum object_type type, const char *path)
{
- unsigned long size = st->st_size;
+ size_t size = xsize_t(st->st_size);
void *buf = NULL;
int ret, re_allocated = 0;
{
int fd;
char *target;
+ size_t len;
switch (st->st_mode & S_IFMT) {
case S_IFREG:
path);
break;
case S_IFLNK:
- target = xmalloc(st->st_size+1);
- if (readlink(path, target, st->st_size+1) != st->st_size) {
+ len = xsize_t(st->st_size);
+ target = xmalloc(len + 1);
+ if (readlink(path, target, len + 1) != st->st_size) {
char *errstr = strerror(errno);
free(target);
return error("readlink(\"%s\"): %s", path,
errstr);
}
if (!write_object)
- hash_sha1_file(target, st->st_size, blob_type, sha1);
- else if (write_sha1_file(target, st->st_size, blob_type, sha1))
+ hash_sha1_file(target, len, blob_type, sha1);
+ else if (write_sha1_file(target, len, blob_type, sha1))
return error("%s: failed to insert into database",
path);
free(target);