tree-diff: remove special-case diff-emitting code for empty-tree cases
[gitweb.git] / sha1_file.c
index a2ff2961b1a2a5b69707a7963411f93deb1a6f56..6e8c05d10825ee93d8248f749d4bef513d772be4 100644 (file)
@@ -105,50 +105,63 @@ int mkdir_in_gitdir(const char *path)
        return adjust_shared_perm(path);
 }
 
-int safe_create_leading_directories(char *path)
+enum scld_error safe_create_leading_directories(char *path)
 {
-       char *pos = path + offset_1st_component(path);
-       struct stat st;
+       char *next_component = path + offset_1st_component(path);
+       enum scld_error ret = SCLD_OK;
+
+       while (ret == SCLD_OK && next_component) {
+               struct stat st;
+               char *slash = next_component, slash_character;
 
-       while (pos) {
-               pos = strchr(pos, '/');
-               if (!pos)
+               while (*slash && !is_dir_sep(*slash))
+                       slash++;
+
+               if (!*slash)
                        break;
-               while (*++pos == '/')
-                       ;
-               if (!*pos)
+
+               next_component = slash + 1;
+               while (is_dir_sep(*next_component))
+                       next_component++;
+               if (!*next_component)
                        break;
-               *--pos = '\0';
+
+               slash_character = *slash;
+               *slash = '\0';
                if (!stat(path, &st)) {
                        /* path exists */
-                       if (!S_ISDIR(st.st_mode)) {
-                               *pos = '/';
-                               return -3;
-                       }
-               }
-               else if (mkdir(path, 0777)) {
+                       if (!S_ISDIR(st.st_mode))
+                               ret = SCLD_EXISTS;
+               } else if (mkdir(path, 0777)) {
                        if (errno == EEXIST &&
-                           !stat(path, &st) && S_ISDIR(st.st_mode)) {
+                           !stat(path, &st) && S_ISDIR(st.st_mode))
                                ; /* somebody created it since we checked */
-                       } else {
-                               *pos = '/';
-                               return -1;
-                       }
-               }
-               else if (adjust_shared_perm(path)) {
-                       *pos = '/';
-                       return -2;
+                       else if (errno == ENOENT)
+                               /*
+                                * Either mkdir() failed because
+                                * somebody just pruned the containing
+                                * directory, or stat() failed because
+                                * the file that was in our way was
+                                * just removed.  Either way, inform
+                                * the caller that it might be worth
+                                * trying again:
+                                */
+                               ret = SCLD_VANISHED;
+                       else
+                               ret = SCLD_FAILED;
+               } else if (adjust_shared_perm(path)) {
+                       ret = SCLD_PERMS;
                }
-               *pos++ = '/';
+               *slash = slash_character;
        }
-       return 0;
+       return ret;
 }
 
-int safe_create_leading_directories_const(const char *path)
+enum scld_error safe_create_leading_directories_const(const char *path)
 {
        /* path points to cache entries, so xstrdup before messing with it */
        char *buf = xstrdup(path);
-       int result = safe_create_leading_directories(buf);
+       enum scld_error result = safe_create_leading_directories(buf);
        free(buf);
        return result;
 }
@@ -1690,6 +1703,38 @@ static off_t get_delta_base(struct packed_git *p,
        return base_offset;
 }
 
+/*
+ * Like get_delta_base above, but we return the sha1 instead of the pack
+ * offset. This means it is cheaper for REF deltas (we do not have to do
+ * the final object lookup), but more expensive for OFS deltas (we
+ * have to load the revidx to convert the offset back into a sha1).
+ */
+static const unsigned char *get_delta_base_sha1(struct packed_git *p,
+                                               struct pack_window **w_curs,
+                                               off_t curpos,
+                                               enum object_type type,
+                                               off_t delta_obj_offset)
+{
+       if (type == OBJ_REF_DELTA) {
+               unsigned char *base = use_pack(p, w_curs, curpos, NULL);
+               return base;
+       } else if (type == OBJ_OFS_DELTA) {
+               struct revindex_entry *revidx;
+               off_t base_offset = get_delta_base(p, w_curs, &curpos,
+                                                  type, delta_obj_offset);
+
+               if (!base_offset)
+                       return NULL;
+
+               revidx = find_pack_revindex(p, base_offset);
+               if (!revidx)
+                       return NULL;
+
+               return nth_packed_object_sha1(p, revidx->nr);
+       } else
+               return NULL;
+}
+
 int unpack_object_header(struct packed_git *p,
                         struct pack_window **w_curs,
                         off_t *curpos,
@@ -1847,6 +1892,22 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
                }
        }
 
+       if (oi->delta_base_sha1) {
+               if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+                       const unsigned char *base;
+
+                       base = get_delta_base_sha1(p, &w_curs, curpos,
+                                                  type, obj_offset);
+                       if (!base) {
+                               type = OBJ_BAD;
+                               goto out;
+                       }
+
+                       hashcpy(oi->delta_base_sha1, base);
+               } else
+                       hashclr(oi->delta_base_sha1);
+       }
+
 out:
        unuse_pack(&w_curs);
        return type;
@@ -2430,6 +2491,9 @@ static int sha1_loose_object_info(const unsigned char *sha1,
        git_zstream stream;
        char hdr[32];
 
+       if (oi->delta_base_sha1)
+               hashclr(oi->delta_base_sha1);
+
        /*
         * If we don't care about type or size, then we don't
         * need to look inside the object at all. Note that we
@@ -2481,6 +2545,8 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
                        *(oi->sizep) = co->size;
                if (oi->disk_sizep)
                        *(oi->disk_sizep) = 0;
+               if (oi->delta_base_sha1)
+                       hashclr(oi->delta_base_sha1);
                oi->whence = OI_CACHED;
                return 0;
        }