Add gitmodules(5)
[gitweb.git] / sha1_file.c
index 06426640eae9db23a0e68e28b74402662fc4da87..2b860868f55a83ed599f39d7820a9fb227946912 100644 (file)
@@ -33,7 +33,7 @@ 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 */
@@ -193,7 +193,7 @@ char *sha1_pack_name(const unsigned char *sha1)
                *buf++ = hex[val >> 4];
                *buf++ = hex[val & 0xf];
        }
-       
+
        return base;
 }
 
@@ -218,7 +218,7 @@ char *sha1_pack_index_name(const unsigned char *sha1)
                *buf++ = hex[val >> 4];
                *buf++ = hex[val & 0xf];
        }
-       
+
        return base;
 }
 
@@ -376,11 +376,12 @@ void prepare_alt_odb(void)
 {
        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);
 
@@ -530,6 +531,21 @@ static int check_packed_git_idx(const char *path,  struct packed_git *p)
        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,
@@ -549,7 +565,7 @@ static void scan_windows(struct packed_git *p,
        }
 }
 
-static int unuse_one_window(struct packed_git *current)
+static int unuse_one_window(struct packed_git *current, int keep_fd)
 {
        struct packed_git *p, *lru_p = NULL;
        struct pack_window *lru_w = NULL, *lru_l = NULL;
@@ -565,7 +581,7 @@ static int unuse_one_window(struct packed_git *current)
                        lru_l->next = lru_w->next;
                else {
                        lru_p->windows = lru_w->next;
-                       if (!lru_p->windows && lru_p != current) {
+                       if (!lru_p->windows && lru_p->pack_fd != keep_fd) {
                                close(lru_p->pack_fd);
                                lru_p->pack_fd = -1;
                        }
@@ -577,10 +593,10 @@ static int unuse_one_window(struct packed_git *current)
        return 0;
 }
 
-void release_pack_memory(size_t need)
+void release_pack_memory(size_t need, int fd)
 {
        size_t cur = pack_mapped;
-       while (need >= (cur - pack_mapped) && unuse_one_window(NULL))
+       while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd))
                ; /* nothing */
 }
 
@@ -605,6 +621,9 @@ static int open_packed_git_1(struct packed_git *p)
        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;
@@ -713,7 +732,7 @@ unsigned char* use_pack(struct packed_git *p,
                        win->len = (size_t)len;
                        pack_mapped += win->len;
                        while (packed_git_limit < pack_mapped
-                               && unuse_one_window(p))
+                               && unuse_one_window(p, p->pack_fd))
                                ; /* nothing */
                        win->base = xmmap(NULL, win->len,
                                PROT_READ, MAP_PRIVATE,
@@ -757,8 +776,7 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
                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;
        }
@@ -766,6 +784,10 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
        /* 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;
@@ -972,7 +994,7 @@ void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
        return map;
 }
 
-int legacy_loose_object(unsigned char *map)
+static int legacy_loose_object(unsigned char *map)
 {
        unsigned int word;
 
@@ -1034,6 +1056,14 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon
                return inflate(stream, 0);
        }
 
+
+       /*
+        * There used to be a second loose object header format which
+        * was meant to mimic the in-pack format, allowing for direct
+        * copy of the object data.  This format turned up not to be
+        * really worth it and we don't write it any longer.  But we
+        * can still read it.
+        */
        used = unpack_object_header_gently(map, mapsize, &type, &size);
        if (!used || !valid_loose_object_type[type])
                return -1;
@@ -1109,7 +1139,7 @@ static int parse_sha1_header(const char *hdr, unsigned long *sizep)
        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.
         */
@@ -1564,10 +1594,15 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
        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;
@@ -1604,6 +1639,12 @@ off_t find_pack_entry_one(const unsigned char *sha1,
        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;
@@ -1646,20 +1687,25 @@ static int matches_pack_name(struct packed_git *p, const char *ig)
 
 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))
                                        break;
                        if (*ig)
-                               continue;
+                               goto next;
                }
+
                offset = find_pack_entry_one(sha1, p);
                if (offset) {
                        /*
@@ -1672,18 +1718,27 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, cons
                         */
                        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;
@@ -1962,40 +2017,6 @@ static int write_buffer(int fd, const void *buf, size_t len)
        return 0;
 }
 
-static int write_binary_header(unsigned char *hdr, enum object_type type, unsigned long len)
-{
-       int hdr_len;
-       unsigned char c;
-
-       c = (type << 4) | (len & 15);
-       len >>= 4;
-       hdr_len = 1;
-       while (len) {
-               *hdr++ = c | 0x80;
-               hdr_len++;
-               c = (len & 0x7f);
-               len >>= 7;
-       }
-       *hdr = c;
-       return hdr_len;
-}
-
-static void setup_object_header(z_stream *stream, const char *type, unsigned long len)
-{
-       int obj_type, hdrlen;
-
-       if (use_legacy_headers) {
-               while (deflate(stream, 0) == Z_OK)
-                       /* nothing */;
-               return;
-       }
-       obj_type = type_from_string(type);
-       hdrlen = write_binary_header(stream->next_out, obj_type, len);
-       stream->total_out = hdrlen;
-       stream->next_out += hdrlen;
-       stream->avail_out -= hdrlen;
-}
-
 int hash_sha1_file(const void *buf, unsigned long len, const char *type,
                    unsigned char *sha1)
 {
@@ -2062,7 +2083,8 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
        /* First header.. */
        stream.next_in = (unsigned char *)hdr;
        stream.avail_in = hdrlen;
-       setup_object_header(&stream, type, len);
+       while (deflate(&stream, 0) == Z_OK)
+               /* nothing */;
 
        /* Then the data itself.. */
        stream.next_in = buf;
@@ -2276,7 +2298,7 @@ int read_pipe(int fd, char** return_buf, unsigned long* return_size)
 {
        char* buf = *return_buf;
        unsigned long size = *return_size;
-       int iret;
+       ssize_t iret;
        unsigned long off = 0;
 
        do {