Merge branch 'sg/gpg-tests-fix'
[gitweb.git] / packfile.c
index d625481b7adaf9835037bea284f1c31ac76cd46c..7cd45aa4b2a0e098d597e4dea633d9b097b9b94c 100644 (file)
@@ -84,6 +84,7 @@ static int check_packed_git_idx(const char *path, struct packed_git *p)
        uint32_t version, nr, i, *index;
        int fd = git_open(path);
        struct stat st;
+       const unsigned int hashsz = the_hash_algo->rawsz;
 
        if (fd < 0)
                return -1;
@@ -92,7 +93,7 @@ static int check_packed_git_idx(const char *path, struct packed_git *p)
                return -1;
        }
        idx_size = xsize_t(st.st_size);
-       if (idx_size < 4 * 256 + 20 + 20) {
+       if (idx_size < 4 * 256 + hashsz + hashsz) {
                close(fd);
                return error("index file %s is too small", path);
        }
@@ -129,11 +130,11 @@ static int check_packed_git_idx(const char *path, struct packed_git *p)
                /*
                 * Total size:
                 *  - 256 index entries 4 bytes each
-                *  - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
-                *  - 20-byte SHA1 of the packfile
-                *  - 20-byte SHA1 file checksum
+                *  - 24-byte entries * nr (object ID + 4-byte offset)
+                *  - hash of the packfile
+                *  - file checksum
                 */
-               if (idx_size != 4*256 + nr * 24 + 20 + 20) {
+               if (idx_size != 4*256 + nr * (hashsz + 4) + hashsz + hashsz) {
                        munmap(idx_map, idx_size);
                        return error("wrong index v1 file size in %s", path);
                }
@@ -142,16 +143,16 @@ static int check_packed_git_idx(const char *path, struct packed_git *p)
                 * Minimum size:
                 *  - 8 bytes of header
                 *  - 256 index entries 4 bytes each
-                *  - 20-byte sha1 entry * nr
+                *  - object ID entry * nr
                 *  - 4-byte crc entry * nr
                 *  - 4-byte offset entry * nr
-                *  - 20-byte SHA1 of the packfile
-                *  - 20-byte SHA1 file checksum
+                *  - hash of the packfile
+                *  - file checksum
                 * And after the 4-byte offset table might be a
                 * variable sized table containing 8-byte entries
                 * for offsets larger than 2^31.
                 */
-               unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20;
+               unsigned long min_size = 8 + 4*256 + nr*(hashsz + 4 + 4) + hashsz + hashsz;
                unsigned long max_size = min_size;
                if (nr)
                        max_size += (nr - 1)*8;
@@ -444,10 +445,11 @@ static int open_packed_git_1(struct packed_git *p)
 {
        struct stat st;
        struct pack_header hdr;
-       unsigned char sha1[20];
-       unsigned char *idx_sha1;
+       unsigned char hash[GIT_MAX_RAWSZ];
+       unsigned char *idx_hash;
        long fd_flag;
        ssize_t read_result;
+       const unsigned hashsz = the_hash_algo->rawsz;
 
        if (!p->index_data && open_pack_index(p))
                return error("packfile %s index unavailable", p->pack_name);
@@ -507,15 +509,15 @@ static int open_packed_git_1(struct packed_git *p)
                             " while index indicates %"PRIu32" objects",
                             p->pack_name, ntohl(hdr.hdr_entries),
                             p->num_objects);
-       if (lseek(p->pack_fd, p->pack_size - sizeof(sha1), SEEK_SET) == -1)
+       if (lseek(p->pack_fd, p->pack_size - hashsz, SEEK_SET) == -1)
                return error("end of packfile %s is unavailable", p->pack_name);
-       read_result = read_in_full(p->pack_fd, sha1, sizeof(sha1));
+       read_result = read_in_full(p->pack_fd, hash, hashsz);
        if (read_result < 0)
                return error_errno("error reading from %s", p->pack_name);
-       if (read_result != sizeof(sha1))
+       if (read_result != hashsz)
                return error("packfile %s signature is unavailable", p->pack_name);
-       idx_sha1 = ((unsigned char *)p->index_data) + p->index_size - 40;
-       if (hashcmp(sha1, idx_sha1))
+       idx_hash = ((unsigned char *)p->index_data) + p->index_size - hashsz * 2;
+       if (hashcmp(hash, idx_hash))
                return error("packfile %s does not match index", p->pack_name);
        return 0;
 }
@@ -530,7 +532,7 @@ static int open_packed_git(struct packed_git *p)
 
 static int in_window(struct pack_window *win, off_t offset)
 {
-       /* We must promise at least 20 bytes (one hash) after the
+       /* We must promise at least one full hash after the
         * offset is available from this window, otherwise the offset
         * is not actually in this window and a different window (which
         * has that one hash excess) must be used.  This is to support
@@ -538,7 +540,7 @@ static int in_window(struct pack_window *win, off_t offset)
         */
        off_t win_off = win->offset;
        return win_off <= offset
-               && (offset + 20) <= (win_off + win->len);
+               && (offset + the_hash_algo->rawsz) <= (win_off + win->len);
 }
 
 unsigned char *use_pack(struct packed_git *p,
@@ -555,7 +557,7 @@ unsigned char *use_pack(struct packed_git *p,
         */
        if (!p->pack_size && p->pack_fd == -1 && open_packed_git(p))
                die("packfile %s cannot be accessed", p->pack_name);
-       if (offset > (p->pack_size - 20))
+       if (offset > (p->pack_size - the_hash_algo->rawsz))
                die("offset beyond end of packfile (truncated pack?)");
        if (offset < 0)
                die(_("offset before end of packfile (broken .idx?)"));
@@ -675,7 +677,8 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
        p->pack_size = st.st_size;
        p->pack_local = local;
        p->mtime = st.st_mtime;
-       if (path_len < 40 || get_sha1_hex(path + path_len - 40, p->sha1))
+       if (path_len < the_hash_algo->hexsz ||
+           get_sha1_hex(path + path_len - the_hash_algo->hexsz, p->sha1))
                hashclr(p->sha1);
        return p;
 }
@@ -1028,7 +1031,8 @@ const struct packed_git *has_packed_and_bad(const unsigned char *sha1)
 
        for (p = the_repository->objects->packed_git; p; p = p->next)
                for (i = 0; i < p->num_bad_objects; i++)
-                       if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
+                       if (!hashcmp(sha1,
+                                    p->bad_object_sha1 + the_hash_algo->rawsz * i))
                                return p;
        return NULL;
 }
@@ -1066,7 +1070,7 @@ static off_t get_delta_base(struct packed_git *p,
        } else if (type == OBJ_REF_DELTA) {
                /* The base entry _must_ be in the same pack */
                base_offset = find_pack_entry_one(base_info, p);
-               *curpos += 20;
+               *curpos += the_hash_algo->rawsz;
        } else
                die("I am totally screwed");
        return base_offset;
@@ -1450,6 +1454,9 @@ static void *unpack_compressed_entry(struct packed_git *p,
                return NULL;
        }
 
+       /* versions of zlib can clobber unconsumed portion of outbuf */
+       buffer[size] = '\0';
+
        return buffer;
 }
 
@@ -1677,6 +1684,7 @@ int bsearch_pack(const struct object_id *oid, const struct packed_git *p, uint32
 {
        const unsigned char *index_fanout = p->index_data;
        const unsigned char *index_lookup;
+       const unsigned int hashsz = the_hash_algo->rawsz;
        int index_lookup_width;
 
        if (!index_fanout)
@@ -1684,10 +1692,10 @@ int bsearch_pack(const struct object_id *oid, const struct packed_git *p, uint32
 
        index_lookup = index_fanout + 4 * 256;
        if (p->index_version == 1) {
-               index_lookup_width = 24;
+               index_lookup_width = hashsz + 4;
                index_lookup += 4;
        } else {
-               index_lookup_width = 20;
+               index_lookup_width = hashsz;
                index_fanout += 8;
                index_lookup += 8;
        }
@@ -1700,6 +1708,7 @@ const unsigned char *nth_packed_object_sha1(struct packed_git *p,
                                            uint32_t n)
 {
        const unsigned char *index = p->index_data;
+       const unsigned int hashsz = the_hash_algo->rawsz;
        if (!index) {
                if (open_pack_index(p))
                        return NULL;
@@ -1709,10 +1718,10 @@ const unsigned char *nth_packed_object_sha1(struct packed_git *p,
                return NULL;
        index += 4 * 256;
        if (p->index_version == 1) {
-               return index + 24 * n + 4;
+               return index + (hashsz + 4) * n + 4;
        } else {
                index += 8;
-               return index + 20 * n;
+               return index + hashsz * n;
        }
 }
 
@@ -1744,12 +1753,13 @@ void check_pack_index_ptr(const struct packed_git *p, const void *vptr)
 off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
 {
        const unsigned char *index = p->index_data;
+       const unsigned int hashsz = the_hash_algo->rawsz;
        index += 4 * 256;
        if (p->index_version == 1) {
-               return ntohl(*((uint32_t *)(index + 24 * n)));
+               return ntohl(*((uint32_t *)(index + (hashsz + 4) * n)));
        } else {
                uint32_t off;
-               index += 8 + p->num_objects * (20 + 4);
+               index += 8 + p->num_objects * (hashsz + 4);
                off = ntohl(*((uint32_t *)(index + 4 * n)));
                if (!(off & 0x80000000))
                        return off;
@@ -1811,7 +1821,7 @@ struct packed_git *find_sha1_pack(const unsigned char *sha1,
 
 }
 
-static int fill_pack_entry(const unsigned char *sha1,
+static int fill_pack_entry(const struct object_id *oid,
                           struct pack_entry *e,
                           struct packed_git *p)
 {
@@ -1820,11 +1830,12 @@ static int fill_pack_entry(const unsigned char *sha1,
        if (p->num_bad_objects) {
                unsigned i;
                for (i = 0; i < p->num_bad_objects; i++)
-                       if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
+                       if (!hashcmp(oid->hash,
+                                    p->bad_object_sha1 + the_hash_algo->rawsz * i))
                                return 0;
        }
 
-       offset = find_pack_entry_one(sha1, p);
+       offset = find_pack_entry_one(oid->hash, p);
        if (!offset)
                return 0;
 
@@ -1839,11 +1850,10 @@ static int fill_pack_entry(const unsigned char *sha1,
                return 0;
        e->offset = offset;
        e->p = p;
-       hashcpy(e->sha1, sha1);
        return 1;
 }
 
-int find_pack_entry(struct repository *r, const unsigned char *sha1, struct pack_entry *e)
+int find_pack_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e)
 {
        struct list_head *pos;
 
@@ -1853,7 +1863,7 @@ int find_pack_entry(struct repository *r, const unsigned char *sha1, struct pack
 
        list_for_each(pos, &r->objects->packed_git_mru) {
                struct packed_git *p = list_entry(pos, struct packed_git, mru);
-               if (fill_pack_entry(sha1, e, p)) {
+               if (fill_pack_entry(oid, e, p)) {
                        list_move(&p->mru, &r->objects->packed_git_mru);
                        return 1;
                }
@@ -1861,10 +1871,10 @@ int find_pack_entry(struct repository *r, const unsigned char *sha1, struct pack
        return 0;
 }
 
-int has_sha1_pack(const unsigned char *sha1)
+int has_object_pack(const struct object_id *oid)
 {
        struct pack_entry e;
-       return find_pack_entry(the_repository, sha1, &e);
+       return find_pack_entry(the_repository, oid, &e);
 }
 
 int has_pack_index(const unsigned char *sha1)