#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];
static unsigned int sha1_file_open_flag = O_NOATIME;
-signed char hexval_table[256] = {
+const 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 */
char *pos = path;
struct stat st;
- if (*pos == '/')
+ if (is_absolute_path(path))
pos++;
while (pos) {
/*
* 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
*buf++ = hex[val >> 4];
*buf++ = hex[val & 0xf];
}
-
+
return base;
}
*buf++ = hex[val >> 4];
*buf++ = hex[val & 0xf];
}
-
+
return base;
}
int entlen = pfxlen + 43;
int base_len = -1;
- if (*entry != '/' && relative_base) {
+ if (!is_absolute_path(entry) && relative_base) {
/* Relative alt-odb */
if (base_len < 0)
base_len = strlen(relative_base) + 1;
}
ent = xmalloc(sizeof(*ent) + entlen);
- if (*entry != '/' && relative_base) {
+ if (!is_absolute_path(entry) && relative_base) {
memcpy(ent->base, relative_base, base_len - 1);
ent->base[base_len - 1] = '/';
memcpy(ent->base + base_len, entry, len);
while (cp < ep && *cp != sep)
cp++;
if (last != cp) {
- if ((*last != '/') && depth) {
+ if (!is_absolute_path(last) && depth) {
error("%s: ignoring relative alternate object store %s",
relative_base, last);
} else {
char *map;
size_t mapsz;
struct stat st;
- char path[PATH_MAX];
+ const char alt_file_name[] = "info/alternates";
+ /* Given that relative_base is no longer than PATH_MAX,
+ ensure that "path" has enough space to append "/", the
+ file name, "info/alternates", and a trailing NUL. */
+ char path[PATH_MAX + 1 + sizeof alt_file_name];
int fd;
- sprintf(path, "%s/info/alternates", relative_base);
+ sprintf(path, "%s/%s", relative_base, alt_file_name);
fd = open(path, O_RDONLY);
if (fd < 0)
return;
{
const char *alt;
+ if (alt_odb_tail)
+ return;
+
alt = getenv(ALTERNATE_DB_ENVIRONMENT);
if (!alt) alt = "";
- if (alt_odb_tail)
- return;
alt_odb_tail = &alt_odb_list;
link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0);
static size_t pack_mapped;
struct packed_git *packed_git;
-void pack_report()
+void pack_report(void)
{
fprintf(stderr,
"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)
*/
if (idx_size != 4*256 + nr * 24 + 20 + 20) {
munmap(idx_map, idx_size);
- return error("wrong index file size in %s", path);
+ return error("wrong index v1 file size in %s", path);
}
} else if (version == 2) {
/*
* for offsets larger than 2^31.
*/
unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20;
- if (idx_size < min_size || idx_size > min_size + (nr - 1)*8) {
+ unsigned long max_size = min_size;
+ if (nr)
+ max_size += (nr - 1)*8;
+ if (idx_size < min_size || idx_size > max_size) {
munmap(idx_map, idx_size);
- return error("wrong index file size in %s", path);
+ return error("wrong index v2 file size in %s", path);
}
- if (idx_size != min_size) {
- /* make sure we can deal with large pack offsets */
- off_t x = 0x7fffffffUL, y = 0xffffffffUL;
- if (x > (x + 1) || y > (y + 1)) {
- munmap(idx_map, idx_size);
- return error("pack too large for current definition of off_t in %s", path);
- }
+ if (idx_size != min_size &&
+ /*
+ * make sure we can deal with large pack offsets.
+ * 31-bit signed offset won't be enough, neither
+ * 32-bit unsigned one will be.
+ */
+ (sizeof(off_t) <= 4)) {
+ munmap(idx_map, idx_size);
+ return error("pack too large for current definition of off_t in %s", path);
}
}
return 0;
}
+int open_pack_index(struct packed_git *p)
+{
+ char *idx_name;
+ int ret;
+
+ if (p->index_data)
+ return 0;
+
+ idx_name = xstrdup(p->pack_name);
+ strcpy(idx_name + strlen(idx_name) - strlen(".pack"), ".idx");
+ ret = check_packed_git_idx(idx_name, p);
+ free(idx_name);
+ return ret;
+}
+
static void scan_windows(struct packed_git *p,
struct packed_git **lru_p,
struct pack_window **lru_w,
; /* 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 char *idx_sha1;
long fd_flag;
+ if (!p->index_data && open_pack_index(p))
+ return error("packfile %s index unavailable", p->pack_name);
+
p->pack_fd = open(p->pack_name, O_RDONLY);
if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
return -1;
return NULL;
memcpy(p->pack_name, path, path_len);
strcpy(p->pack_name + path_len, ".pack");
- if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode) ||
- check_packed_git_idx(path, p)) {
+ if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) {
free(p);
return NULL;
}
/* ok, it looks sane as far as we can check without
* actually mapping the pack file.
*/
+ p->index_version = 0;
+ p->index_data = NULL;
+ p->index_size = 0;
+ p->num_objects = 0;
p->pack_size = st.st_size;
p->next = NULL;
p->windows = NULL;
static void prepare_packed_git_one(char *objdir, int local)
{
- char path[PATH_MAX];
+ /* Ensure that this buffer is large enough so that we can
+ append "/pack/" without clobbering the stack even if
+ strlen(objdir) were PATH_MAX. */
+ char path[PATH_MAX + 1 + 4 + 1 + 1];
int len;
DIR *dir;
struct dirent *de;
if (!has_extension(de->d_name, ".idx"))
continue;
+ if (len + namelen + 1 > sizeof(path))
+ continue;
+
/* Don't reopen a pack we already have. */
strcpy(path + len, de->d_name);
for (p = packed_git; p; p = p->next) {
return hashcmp(sha1, real_sha1) ? -1 : 0;
}
-void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+static void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
{
struct stat st;
void *map;
unsigned long size;
/*
- * The type can be at most ten bytes (including the
+ * The type can be at most ten bytes (including the
* terminating '\0' that we add), and is followed by
* a space.
*/
ent->lru.next->prev = ent->lru.prev;
ent->lru.prev->next = ent->lru.next;
delta_base_cached -= ent->size;
- }
- else {
- ret = xmalloc(ent->size + 1);
- memcpy(ret, ent->data, ent->size);
- ((char *)ret)[ent->size] = 0;
+ } else {
+ ret = xmemdupz(ent->data, ent->size);
}
*type = ent->type;
*base_size = ent->size;
(uintmax_t)base_offset, p->pack_name);
delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size);
+ if (!delta_data)
+ die("failed to unpack compressed delta"
+ " at %"PRIuMAX" from %s",
+ (uintmax_t)curpos, p->pack_name);
result = patch_delta(base, base_size,
delta_data, delta_size,
sizep);
return data;
}
-const unsigned char *nth_packed_object_sha1(const struct packed_git *p,
+const unsigned char *nth_packed_object_sha1(struct packed_git *p,
uint32_t n)
{
const unsigned char *index = p->index_data;
+ if (!index) {
+ if (open_pack_index(p))
+ return NULL;
+ index = p->index_data;
+ }
if (n >= p->num_objects)
return NULL;
index += 4 * 256;
const unsigned char *index = p->index_data;
unsigned hi, lo;
+ if (!index) {
+ if (open_pack_index(p))
+ return 0;
+ level1_ofs = p->index_data;
+ index = p->index_data;
+ }
if (p->index_version > 1) {
level1_ofs += 2;
index += 8;
return 0;
}
-static int matches_pack_name(struct packed_git *p, const char *ig)
+int matches_pack_name(struct packed_git *p, const char *name)
{
const char *last_c, *c;
- if (!strcmp(p->pack_name, ig))
- return 0;
+ if (!strcmp(p->pack_name, name))
+ return 1;
for (c = p->pack_name, last_c = c; *c;)
if (*c == '/')
last_c = ++c;
else
++c;
- if (!strcmp(last_c, ig))
- return 0;
+ if (!strcmp(last_c, name))
+ return 1;
- return 1;
+ return 0;
}
static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
{
+ static struct packed_git *last_found = (void *)1;
struct packed_git *p;
off_t offset;
prepare_packed_git();
+ if (!packed_git)
+ return 0;
+ p = (last_found == (void *)1) ? packed_git : last_found;
- for (p = packed_git; p; p = p->next) {
+ do {
if (ignore_packed) {
const char **ig;
for (ig = ignore_packed; *ig; ig++)
- if (!matches_pack_name(p, *ig))
+ if (matches_pack_name(p, *ig))
break;
if (*ig)
- continue;
+ goto next;
}
+
offset = find_pack_entry_one(sha1, p);
if (offset) {
/*
*/
if (p->pack_fd == -1 && open_packed_git(p)) {
error("packfile %s cannot be accessed", p->pack_name);
- continue;
+ goto next;
}
e->offset = offset;
e->p = p;
hashcpy(e->sha1, sha1);
+ last_found = p;
return 1;
}
- }
+
+ next:
+ if (p == last_found)
+ p = packed_git;
+ else
+ p = p->next;
+ if (p == last_found)
+ p = p->next;
+ } while (p);
return 0;
}
-struct packed_git *find_sha1_pack(const unsigned char *sha1,
+struct packed_git *find_sha1_pack(const unsigned char *sha1,
struct packed_git *packs)
{
struct packed_git *p;
co = find_cached_object(sha1);
if (co) {
- buf = xmalloc(co->size + 1);
- memcpy(buf, co->buf, co->size);
- ((char*)buf)[co->size] = 0;
*type = co->type;
*size = co->size;
- return buf;
+ return xmemdupz(co->buf, co->size);
}
buf = read_packed_sha1(sha1, type, size);
}
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;
return find_sha1_file(sha1, &st) ? 1 : 0;
}
-/*
- * reads from fd as long as possible into a supplied buffer of size bytes.
- * If necessary the buffer's size is increased using realloc()
- *
- * returns 0 if anything went fine and -1 otherwise
- *
- * NOTE: both buf and size may change, but even when -1 is returned
- * you still have to free() it yourself.
- */
-int read_pipe(int fd, char** return_buf, unsigned long* return_size)
-{
- char* buf = *return_buf;
- unsigned long size = *return_size;
- ssize_t iret;
- unsigned long off = 0;
-
- do {
- iret = xread(fd, buf + off, size - off);
- if (iret > 0) {
- off += iret;
- if (off == size) {
- size *= 2;
- buf = xrealloc(buf, size);
- }
- }
- } while (iret > 0);
-
- *return_buf = buf;
- *return_size = off;
-
- if (iret < 0)
- return -1;
- return 0;
-}
-
int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
{
- unsigned long size = 4096;
- char *buf = xmalloc(size);
+ struct strbuf buf;
int ret;
- if (read_pipe(fd, &buf, &size)) {
- free(buf);
+ strbuf_init(&buf, 0);
+ if (strbuf_read(&buf, fd, 4096) < 0) {
+ strbuf_release(&buf);
return -1;
}
if (!type)
type = blob_type;
if (write_object)
- ret = write_sha1_file(buf, size, type, sha1);
+ ret = write_sha1_file(buf.buf, buf.len, type, sha1);
else
- ret = hash_sha1_file(buf, size, type, sha1);
- free(buf);
+ ret = hash_sha1_file(buf.buf, buf.len, type, sha1);
+ strbuf_release(&buf);
+
return ret;
}
* Convert blobs to git internal format
*/
if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) {
- unsigned long nsize = size;
- char *nbuf = convert_to_git(path, buf, &nsize);
- if (nbuf) {
+ struct strbuf nbuf;
+ strbuf_init(&nbuf, 0);
+ if (convert_to_git(path, buf, size, &nbuf)) {
munmap(buf, size);
- size = nsize;
- buf = nbuf;
+ buf = strbuf_detach(&nbuf, &size);
re_allocated = 1;
}
}