#include "dir.h"
#include "mru.h"
#include "list.h"
+#include "mergesort.h"
#ifndef O_NOATIME
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
struct alternate_object_database *alt_odb_list;
static struct alternate_object_database **alt_odb_tail;
+/*
+ * Return non-zero iff the path is usable as an alternate object database.
+ */
+static int alt_odb_usable(struct strbuf *path, const char *normalized_objdir)
+{
+ struct alternate_object_database *alt;
+
+ /* Detect cases where alternate disappeared */
+ if (!is_directory(path->buf)) {
+ error("object directory %s does not exist; "
+ "check .git/objects/info/alternates.",
+ path->buf);
+ return 0;
+ }
+
+ /*
+ * Prevent the common mistake of listing the same
+ * thing twice, or object directory itself.
+ */
+ for (alt = alt_odb_list; alt; alt = alt->next) {
+ if (path->len == alt->name - alt->base - 1 &&
+ !memcmp(path->buf, alt->base, path->len))
+ return 0;
+ }
+ if (!fspathcmp(path->buf, normalized_objdir))
+ return 0;
+
+ return 1;
+}
+
/*
* Prepare alternate object database registry.
*
int depth, const char *normalized_objdir)
{
struct alternate_object_database *ent;
- struct alternate_object_database *alt;
- size_t pfxlen, entlen;
+ size_t entlen;
struct strbuf pathbuf = STRBUF_INIT;
if (!is_absolute_path(entry) && relative_base) {
}
strbuf_addstr(&pathbuf, entry);
- normalize_path_copy(pathbuf.buf, pathbuf.buf);
-
- pfxlen = strlen(pathbuf.buf);
+ if (strbuf_normalize_path(&pathbuf) < 0) {
+ error("unable to normalize alternate object path: %s",
+ pathbuf.buf);
+ strbuf_release(&pathbuf);
+ return -1;
+ }
/*
* The trailing slash after the directory name is given by
* this function at the end. Remove duplicates.
*/
- while (pfxlen && pathbuf.buf[pfxlen-1] == '/')
- pfxlen -= 1;
-
- entlen = st_add(pfxlen, 43); /* '/' + 2 hex + '/' + 38 hex + NUL */
- ent = xmalloc(st_add(sizeof(*ent), entlen));
- memcpy(ent->base, pathbuf.buf, pfxlen);
- strbuf_release(&pathbuf);
+ while (pathbuf.len && pathbuf.buf[pathbuf.len - 1] == '/')
+ strbuf_setlen(&pathbuf, pathbuf.len - 1);
- ent->name = ent->base + pfxlen + 1;
- ent->base[pfxlen + 3] = '/';
- ent->base[pfxlen] = ent->base[entlen-1] = 0;
-
- /* Detect cases where alternate disappeared */
- if (!is_directory(ent->base)) {
- error("object directory %s does not exist; "
- "check .git/objects/info/alternates.",
- ent->base);
- free(ent);
+ if (!alt_odb_usable(&pathbuf, normalized_objdir)) {
+ strbuf_release(&pathbuf);
return -1;
}
- /* Prevent the common mistake of listing the same
- * thing twice, or object directory itself.
- */
- for (alt = alt_odb_list; alt; alt = alt->next) {
- if (pfxlen == alt->name - alt->base - 1 &&
- !memcmp(ent->base, alt->base, pfxlen)) {
- free(ent);
- return -1;
- }
- }
- if (!fspathcmp(ent->base, normalized_objdir)) {
- free(ent);
- return -1;
- }
+ entlen = st_add(pathbuf.len, 43); /* '/' + 2 hex + '/' + 38 hex + NUL */
+ ent = xmalloc(st_add(sizeof(*ent), entlen));
+ memcpy(ent->base, pathbuf.buf, pathbuf.len);
+
+ ent->name = ent->base + pathbuf.len + 1;
+ ent->base[pathbuf.len] = '/';
+ ent->base[pathbuf.len + 3] = '/';
+ ent->base[entlen-1] = 0;
/* add the alternate entry */
*alt_odb_tail = ent;
ent->next = NULL;
/* recursively add alternates */
- read_info_alternates(ent->base, depth + 1);
-
- ent->base[pfxlen] = '/';
+ read_info_alternates(pathbuf.buf, depth + 1);
+ strbuf_release(&pathbuf);
return 0;
}
}
strbuf_add_absolute_path(&objdirbuf, get_object_directory());
- normalize_path_copy(objdirbuf.buf, objdirbuf.buf);
+ if (strbuf_normalize_path(&objdirbuf) < 0)
+ die("unable to normalize object directory: %s",
+ objdirbuf.buf);
alt_copy = xmemdupz(alt, len);
string_list_split_in_place(&entries, alt_copy, sep, -1);
strbuf_release(&path);
}
+static void *get_next_packed_git(const void *p)
+{
+ return ((const struct packed_git *)p)->next;
+}
+
+static void set_next_packed_git(void *p, void *next)
+{
+ ((struct packed_git *)p)->next = next;
+}
+
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_);
+ const struct packed_git *a = a_;
+ const struct packed_git *b = b_;
int st;
/*
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);
+ packed_git = llist_mergesort(packed_git, get_next_packed_git,
+ set_next_packed_git, sort_pack);
}
static void prepare_packed_git_mru(void)
return used;
}
-int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
+static int unpack_sha1_short_header(git_zstream *stream,
+ unsigned char *map, unsigned long mapsize,
+ void *buffer, unsigned long bufsiz)
{
/* Get the data stream */
memset(stream, 0, sizeof(*stream));
return git_inflate(stream, 0);
}
+int unpack_sha1_header(git_zstream *stream,
+ unsigned char *map, unsigned long mapsize,
+ void *buffer, unsigned long bufsiz)
+{
+ int status = unpack_sha1_short_header(stream, map, mapsize,
+ buffer, bufsiz);
+
+ if (status < Z_OK)
+ return status;
+
+ /* Make sure we have the terminating NUL */
+ if (!memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer))
+ return -1;
+ return 0;
+}
+
static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
unsigned long mapsize, void *buffer,
unsigned long bufsiz, struct strbuf *header)
{
int status;
- status = unpack_sha1_header(stream, map, mapsize, buffer, bufsiz);
+ status = unpack_sha1_short_header(stream, map, mapsize, buffer, bufsiz);
+ if (status < Z_OK)
+ return -1;
/*
* Check if entire header is unpacked in the first iteration.
*/
for (;;) {
char c = *hdr++;
+ if (!c)
+ return -1;
if (c == ' ')
break;
type_len++;
void *base, unsigned long base_size, enum object_type type)
{
struct delta_base_cache_entry *ent = xmalloc(sizeof(*ent));
- struct list_head *lru;
+ struct list_head *lru, *tmp;
delta_base_cached += base_size;
- list_for_each(lru, &delta_base_cache_lru) {
+ list_for_each_safe(lru, tmp, &delta_base_cache_lru) {
struct delta_base_cache_entry *f =
list_entry(lru, struct delta_base_cache_entry, lru);
if (delta_base_cached <= delta_base_cache_limit)