]> git.ipfire.org Git - thirdparty/git.git/blobdiff - sha1_file.c
Lazily open pack index files on demand
[thirdparty/git.git] / sha1_file.c
index 32244d704e1c747780aed461bb78cf4a72199f18..6a5ba635003858d70e449122351b502b823de13a 100644 (file)
@@ -530,6 +530,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,
@@ -605,6 +620,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;
@@ -757,8 +775,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 +783,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 +993,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 +1055,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;
@@ -1564,10 +1593,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 +1638,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;
@@ -1962,40 +2002,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 +2068,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 +2283,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 {