log: fix -L bounds checking bug
[gitweb.git] / sha1_file.c
index 8fb10e451cba0e07481c0c6f40ee97a7039c6360..8e27db1bd2b49f28b235fcd7e18a0dda43a1f045 100644 (file)
@@ -36,6 +36,9 @@ static inline uintmax_t sz_fmt(size_t s) { return s; }
 
 const unsigned char null_sha1[20];
 
+static const char *no_log_pack_access = "no_log_pack_access";
+static const char *log_pack_access;
+
 /*
  * This is meant to hold a *small* number of objects that you would
  * want read_sha1_file() to be able to return, but yet you do not want
@@ -1780,20 +1783,20 @@ static enum object_type packed_to_object_type(struct packed_git *p,
 }
 
 static int packed_object_info(struct packed_git *p, off_t obj_offset,
-                             unsigned long *sizep, int *rtype,
-                             unsigned long *disk_sizep)
+                             struct object_info *oi)
 {
        struct pack_window *w_curs = NULL;
        unsigned long size;
        off_t curpos = obj_offset;
        enum object_type type;
 
+       /*
+        * We always get the representation type, but only convert it to
+        * a "real" type later if the caller is interested.
+        */
        type = unpack_object_header(p, &w_curs, &curpos, &size);
 
-       if (rtype)
-               *rtype = type; /* representation type */
-
-       if (sizep) {
+       if (oi->sizep) {
                if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
                        off_t tmp_pos = curpos;
                        off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
@@ -1802,22 +1805,28 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
                                type = OBJ_BAD;
                                goto out;
                        }
-                       *sizep = get_size_from_delta(p, &w_curs, tmp_pos);
-                       if (*sizep == 0) {
+                       *oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
+                       if (*oi->sizep == 0) {
                                type = OBJ_BAD;
                                goto out;
                        }
                } else {
-                       *sizep = size;
+                       *oi->sizep = size;
                }
        }
 
-       if (disk_sizep) {
+       if (oi->disk_sizep) {
                struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
-               *disk_sizep = revidx[1].offset - obj_offset;
+               *oi->disk_sizep = revidx[1].offset - obj_offset;
        }
 
-       type = packed_to_object_type(p, obj_offset, type, &w_curs, curpos);
+       if (oi->typep) {
+               *oi->typep = packed_to_object_type(p, obj_offset, type, &w_curs, curpos);
+               if (*oi->typep < 0) {
+                       type = OBJ_BAD;
+                       goto out;
+               }
+       }
 
 out:
        unuse_pack(&w_curs);
@@ -1995,12 +2004,19 @@ static void write_pack_access_log(struct packed_git *p, off_t obj_offset)
 {
        static FILE *log_file;
 
+       if (!log_pack_access)
+               log_pack_access = getenv("GIT_TRACE_PACK_ACCESS");
+       if (!log_pack_access)
+               log_pack_access = no_log_pack_access;
+       if (log_pack_access == no_log_pack_access)
+               return;
+
        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;
+                       log_pack_access = no_log_pack_access;
                        return;
                }
        }
@@ -2031,7 +2047,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
        int delta_stack_nr = 0, delta_stack_alloc = UNPACK_ENTRY_STACK_PREALLOC;
        int base_from_cache = 0;
 
-       if (log_pack_access)
+       if (log_pack_access != no_log_pack_access)
                write_pack_access_log(p, obj_offset);
 
        /* PHASE 1: drill down to the innermost base object */
@@ -2174,10 +2190,19 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
                data = patch_delta(base, base_size,
                                   delta_data, delta_size,
                                   &size);
+
+               /*
+                * We could not apply the delta; warn the user, but keep going.
+                * Our failure will be noticed either in the next iteration of
+                * the loop, or if this is the final delta, in the caller when
+                * we return NULL. Those code paths will take care of making
+                * a more explicit warning and retrying with another copy of
+                * the object.
+                */
                if (!data)
-                       die("failed to apply delta");
+                       error("failed to apply delta");
 
-               free (delta_data);
+               free(delta_data);
        }
 
        *final_type = type;
@@ -2378,9 +2403,7 @@ struct packed_git *find_sha1_pack(const unsigned char *sha1,
 }
 
 static int sha1_loose_object_info(const unsigned char *sha1,
-                                 enum object_type *typep,
-                                 unsigned long *sizep,
-                                 unsigned long *disk_sizep)
+                                 struct object_info *oi)
 {
        int status;
        unsigned long mapsize, size;
@@ -2392,32 +2415,32 @@ static int sha1_loose_object_info(const unsigned char *sha1,
         * If we don't care about type or size, then we don't
         * need to look inside the object at all.
         */
-       if (!typep && !sizep) {
-               if (disk_sizep) {
+       if (!oi->typep && !oi->sizep) {
+               if (oi->disk_sizep) {
                        struct stat st;
                        if (stat_sha1_file(sha1, &st) < 0)
                                return -1;
-                       *disk_sizep = st.st_size;
+                       *oi->disk_sizep = st.st_size;
                }
                return 0;
        }
 
        map = map_sha1_file(sha1, &mapsize);
        if (!map)
-               return error("unable to find %s", sha1_to_hex(sha1));
-       if (disk_sizep)
-               *disk_sizep = mapsize;
+               return -1;
+       if (oi->disk_sizep)
+               *oi->disk_sizep = mapsize;
        if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
                status = error("unable to unpack %s header",
                               sha1_to_hex(sha1));
        else if ((status = parse_sha1_header(hdr, &size)) < 0)
                status = error("unable to parse %s header", sha1_to_hex(sha1));
-       else if (sizep)
-               *sizep = size;
+       else if (oi->sizep)
+               *oi->sizep = size;
        git_inflate_end(&stream);
        munmap(map, mapsize);
-       if (typep)
-               *typep = status;
+       if (oi->typep)
+               *oi->typep = status;
        return 0;
 }
 
@@ -2426,24 +2449,25 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
 {
        struct cached_object *co;
        struct pack_entry e;
-       int type, rtype;
+       int rtype;
 
        co = find_cached_object(sha1);
        if (co) {
+               if (oi->typep)
+                       *(oi->typep) = co->type;
                if (oi->sizep)
                        *(oi->sizep) = co->size;
                if (oi->disk_sizep)
                        *(oi->disk_sizep) = 0;
                oi->whence = OI_CACHED;
-               return co->type;
+               return 0;
        }
 
        if (!find_pack_entry(sha1, &e)) {
                /* Most likely it's a loose object. */
-               if (!sha1_loose_object_info(sha1, &type,
-                                           oi->sizep, oi->disk_sizep)) {
+               if (!sha1_loose_object_info(sha1, oi)) {
                        oi->whence = OI_LOOSE;
-                       return type;
+                       return 0;
                }
 
                /* Not a loose object; someone else may have just packed it. */
@@ -2452,11 +2476,10 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
                        return -1;
        }
 
-       type = packed_object_info(e.p, e.offset, oi->sizep, &rtype,
-                                 oi->disk_sizep);
-       if (type < 0) {
+       rtype = packed_object_info(e.p, e.offset, oi);
+       if (rtype < 0) {
                mark_bad_packed_object(e.p, sha1);
-               type = sha1_object_info_extended(sha1, oi);
+               return sha1_object_info_extended(sha1, oi);
        } else if (in_delta_base_cache(e.p, e.offset)) {
                oi->whence = OI_DBCACHED;
        } else {
@@ -2467,15 +2490,19 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
                                         rtype == OBJ_OFS_DELTA);
        }
 
-       return type;
+       return 0;
 }
 
 int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
 {
-       struct object_info oi = {0};
+       enum object_type type;
+       struct object_info oi = {NULL};
 
+       oi.typep = &type;
        oi.sizep = sizep;
-       return sha1_object_info_extended(sha1, &oi);
+       if (sha1_object_info_extended(sha1, &oi) < 0)
+               return -1;
+       return type;
 }
 
 static void *read_packed_sha1(const unsigned char *sha1,