Sync with 1.7.6.1
[gitweb.git] / sha1_file.c
index a6aac70923cad6ed3f2afec631dcc67d5f28a019..44444ae8f4a01938e4f1b08cb7a270253dfe174b 100644 (file)
@@ -1217,14 +1217,34 @@ static int experimental_loose_object(unsigned char *map)
        unsigned int word;
 
        /*
-        * Is it a zlib-compressed buffer? If so, the first byte
-        * must be 0x78 (15-bit window size, deflated), and the
-        * first 16-bit word is evenly divisible by 31. If so,
-        * we are looking at the official format, not the experimental
-        * one.
+        * We must determine if the buffer contains the standard
+        * zlib-deflated stream or the experimental format based
+        * on the in-pack object format. Compare the header byte
+        * for each format:
+        *
+        * RFC1950 zlib w/ deflate : 0www1000 : 0 <= www <= 7
+        * Experimental pack-based : Stttssss : ttt = 1,2,3,4
+        *
+        * If bit 7 is clear and bits 0-3 equal 8, the buffer MUST be
+        * in standard loose-object format, UNLESS it is a Git-pack
+        * format object *exactly* 8 bytes in size when inflated.
+        *
+        * However, RFC1950 also specifies that the 1st 16-bit word
+        * must be divisible by 31 - this checksum tells us our buffer
+        * is in the standard format, giving a false positive only if
+        * the 1st word of the Git-pack format object happens to be
+        * divisible by 31, ie:
+        *      ((byte0 * 256) + byte1) % 31 = 0
+        *   =>        0ttt10000www1000 % 31 = 0
+        *
+        * As it happens, this case can only arise for www=3 & ttt=1
+        * - ie, a Commit object, which would have to be 8 bytes in
+        * size. As no Commit can be that small, we find that the
+        * combination of these two criteria (bitmask & checksum)
+        * can always correctly determine the buffer format.
         */
        word = (map[0] << 8) + map[1];
-       if (map[0] == 0x78 && !(word % 31))
+       if ((map[0] & 0x8F) == 0x08 && !(word % 31))
                return 0;
        else
                return 1;
@@ -1553,61 +1573,6 @@ int unpack_object_header(struct packed_git *p,
        return type;
 }
 
-int packed_object_info_detail(struct packed_git *p,
-                                     off_t obj_offset,
-                                     unsigned long *size,
-                                     unsigned long *store_size,
-                                     unsigned int *delta_chain_length,
-                                     unsigned char *base_sha1)
-{
-       struct pack_window *w_curs = NULL;
-       off_t curpos;
-       unsigned long dummy;
-       unsigned char *next_sha1;
-       enum object_type type;
-       struct revindex_entry *revidx;
-
-       *delta_chain_length = 0;
-       curpos = obj_offset;
-       type = unpack_object_header(p, &w_curs, &curpos, size);
-
-       revidx = find_pack_revindex(p, obj_offset);
-       *store_size = revidx[1].offset - obj_offset;
-
-       for (;;) {
-               switch (type) {
-               default:
-                       die("pack %s contains unknown object type %d",
-                           p->pack_name, type);
-               case OBJ_COMMIT:
-               case OBJ_TREE:
-               case OBJ_BLOB:
-               case OBJ_TAG:
-                       unuse_pack(&w_curs);
-                       return type;
-               case OBJ_OFS_DELTA:
-                       obj_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
-                       if (!obj_offset)
-                               die("pack %s contains bad delta base reference of type %s",
-                                   p->pack_name, typename(type));
-                       if (*delta_chain_length == 0) {
-                               revidx = find_pack_revindex(p, obj_offset);
-                               hashcpy(base_sha1, nth_packed_object_sha1(p, revidx->nr));
-                       }
-                       break;
-               case OBJ_REF_DELTA:
-                       next_sha1 = use_pack(p, &w_curs, curpos, NULL);
-                       if (*delta_chain_length == 0)
-                               hashcpy(base_sha1, next_sha1);
-                       obj_offset = find_pack_entry_one(next_sha1, p);
-                       break;
-               }
-               (*delta_chain_length)++;
-               curpos = obj_offset;
-               type = unpack_object_header(p, &w_curs, &curpos, &dummy);
-       }
-}
-
 static int packed_object_info(struct packed_git *p, off_t obj_offset,
                              unsigned long *sizep, int *rtype)
 {
@@ -1852,6 +1817,24 @@ static void *unpack_delta_entry(struct packed_git *p,
        return result;
 }
 
+static void write_pack_access_log(struct packed_git *p, off_t obj_offset)
+{
+       static FILE *log_file;
+
+       if (!log_file) {
+               log_file = fopen(log_pack_access, "w");
+               if (!log_file) {
+                       error("cannot open pack access log '%s' for writing: %s",
+                             log_pack_access, strerror(errno));
+                       log_pack_access = NULL;
+                       return;
+               }
+       }
+       fprintf(log_file, "%s %"PRIuMAX"\n",
+               p->pack_name, (uintmax_t)obj_offset);
+       fflush(log_file);
+}
+
 int do_check_packed_object_crc;
 
 void *unpack_entry(struct packed_git *p, off_t obj_offset,
@@ -1861,6 +1844,9 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
        off_t curpos = obj_offset;
        void *data;
 
+       if (log_pack_access)
+               write_pack_access_log(p, obj_offset);
+
        if (do_check_packed_object_crc && p->index_version > 1) {
                struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
                unsigned long len = revidx[1].offset - obj_offset;