]> git.ipfire.org Git - thirdparty/git.git/blobdiff - packfile.c
pack: move find_pack_entry() and make it global
[thirdparty/git.git] / packfile.c
index f251e38783c12e6cf4d40790d3779e117a844e52..22bdbbcf2c0aac6c9845c3bf5fc25ab40df16112 100644 (file)
@@ -7,6 +7,7 @@
 #include "delta.h"
 #include "list.h"
 #include "streaming.h"
+#include "sha1-lookup.h"
 
 char *odb_pack_name(struct strbuf *buf,
                    const unsigned char *sha1,
@@ -509,7 +510,7 @@ static int open_packed_git_1(struct packed_git *p)
        return 0;
 }
 
-int open_packed_git(struct packed_git *p)
+static int open_packed_git(struct packed_git *p)
 {
        if (!open_packed_git_1(p))
                return 0;
@@ -1700,3 +1701,142 @@ off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
                                   ntohl(*((uint32_t *)(index + 4)));
        }
 }
+
+off_t find_pack_entry_one(const unsigned char *sha1,
+                                 struct packed_git *p)
+{
+       const uint32_t *level1_ofs = p->index_data;
+       const unsigned char *index = p->index_data;
+       unsigned hi, lo, stride;
+       static int debug_lookup = -1;
+
+       if (debug_lookup < 0)
+               debug_lookup = !!getenv("GIT_DEBUG_LOOKUP");
+
+       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;
+       }
+       index += 4 * 256;
+       hi = ntohl(level1_ofs[*sha1]);
+       lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
+       if (p->index_version > 1) {
+               stride = 20;
+       } else {
+               stride = 24;
+               index += 4;
+       }
+
+       if (debug_lookup)
+               printf("%02x%02x%02x... lo %u hi %u nr %"PRIu32"\n",
+                      sha1[0], sha1[1], sha1[2], lo, hi, p->num_objects);
+
+       while (lo < hi) {
+               unsigned mi = (lo + hi) / 2;
+               int cmp = hashcmp(index + mi * stride, sha1);
+
+               if (debug_lookup)
+                       printf("lo %u hi %u rg %u mi %u\n",
+                              lo, hi, hi - lo, mi);
+               if (!cmp)
+                       return nth_packed_object_offset(p, mi);
+               if (cmp > 0)
+                       hi = mi;
+               else
+                       lo = mi+1;
+       }
+       return 0;
+}
+
+int is_pack_valid(struct packed_git *p)
+{
+       /* An already open pack is known to be valid. */
+       if (p->pack_fd != -1)
+               return 1;
+
+       /* If the pack has one window completely covering the
+        * file size, the pack is known to be valid even if
+        * the descriptor is not currently open.
+        */
+       if (p->windows) {
+               struct pack_window *w = p->windows;
+
+               if (!w->offset && w->len == p->pack_size)
+                       return 1;
+       }
+
+       /* Force the pack to open to prove its valid. */
+       return !open_packed_git(p);
+}
+
+struct packed_git *find_sha1_pack(const unsigned char *sha1,
+                                 struct packed_git *packs)
+{
+       struct packed_git *p;
+
+       for (p = packs; p; p = p->next) {
+               if (find_pack_entry_one(sha1, p))
+                       return p;
+       }
+       return NULL;
+
+}
+
+static int fill_pack_entry(const unsigned char *sha1,
+                          struct pack_entry *e,
+                          struct packed_git *p)
+{
+       off_t offset;
+
+       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))
+                               return 0;
+       }
+
+       offset = find_pack_entry_one(sha1, p);
+       if (!offset)
+               return 0;
+
+       /*
+        * We are about to tell the caller where they can locate the
+        * requested object.  We better make sure the packfile is
+        * still here and can be accessed before supplying that
+        * answer, as it may have been deleted since the index was
+        * loaded!
+        */
+       if (!is_pack_valid(p))
+               return 0;
+       e->offset = offset;
+       e->p = p;
+       hashcpy(e->sha1, sha1);
+       return 1;
+}
+
+/*
+ * Iff a pack file contains the object named by sha1, return true and
+ * store its location to e.
+ */
+int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
+{
+       struct mru_entry *p;
+
+       prepare_packed_git();
+       if (!packed_git)
+               return 0;
+
+       for (p = packed_git_mru->head; p; p = p->next) {
+               if (fill_pack_entry(sha1, e, p->item)) {
+                       mru_mark(packed_git_mru, p);
+                       return 1;
+               }
+       }
+       return 0;
+}