"git diff <tree>{3,}": do not reverse order of arguments
[gitweb.git] / sha1_file.c
index 2df78b5afd57cf8e86f01134bf6c49d74defc52a..c35469d488596bd1279c06bc391d744565f35e59 100644 (file)
@@ -385,7 +385,7 @@ static void read_info_alternates(const char * relative_base, int depth)
 void add_to_alternates_file(const char *reference)
 {
        struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
-       int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), 1);
+       int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), LOCK_DIE_ON_ERROR);
        char *alt = mkpath("%s/objects\n", reference);
        write_or_die(fd, alt, strlen(alt));
        if (commit_lock_file(lock))
@@ -410,23 +410,30 @@ void prepare_alt_odb(void)
        read_info_alternates(get_object_directory(), 0);
 }
 
-static int has_loose_object(const unsigned char *sha1)
+static int has_loose_object_local(const unsigned char *sha1)
 {
        char *name = sha1_file_name(sha1);
-       struct alternate_object_database *alt;
+       return !access(name, F_OK);
+}
 
-       if (!access(name, F_OK))
-               return 1;
+int has_loose_object_nonlocal(const unsigned char *sha1)
+{
+       struct alternate_object_database *alt;
        prepare_alt_odb();
        for (alt = alt_odb_list; alt; alt = alt->next) {
-               name = alt->name;
-               fill_sha1_path(name, sha1);
+               fill_sha1_path(alt->name, sha1);
                if (!access(alt->base, F_OK))
                        return 1;
        }
        return 0;
 }
 
+static int has_loose_object(const unsigned char *sha1)
+{
+       return has_loose_object_local(sha1) ||
+              has_loose_object_nonlocal(sha1);
+}
+
 static unsigned int pack_used_ctr;
 static unsigned int pack_mmap_calls;
 static unsigned int peak_pack_open_windows;
@@ -828,6 +835,11 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
                return NULL;
        }
        memcpy(p->pack_name, path, path_len);
+
+       strcpy(p->pack_name + path_len, ".keep");
+       if (!access(p->pack_name, F_OK))
+               p->pack_keep = 1;
+
        strcpy(p->pack_name + path_len, ".pack");
        if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) {
                free(p);
@@ -990,6 +1002,7 @@ void prepare_packed_git(void)
 
 void reprepare_packed_git(void)
 {
+       discard_revindex();
        prepare_packed_git_run_once = 0;
        prepare_packed_git();
 }
@@ -1006,6 +1019,18 @@ static void mark_bad_packed_object(struct packed_git *p,
        p->num_bad_objects++;
 }
 
+static int has_packed_and_bad(const unsigned char *sha1)
+{
+       struct packed_git *p;
+       unsigned i;
+
+       for (p = packed_git; p; p = p->next)
+               for (i = 0; i < p->num_bad_objects; i++)
+                       if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
+                               return 1;
+       return 0;
+}
+
 int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
 {
        unsigned char real_sha1[20];
@@ -1647,7 +1672,7 @@ static void *unpack_delta_entry(struct packed_git *p,
                      sha1_to_hex(base_sha1), (uintmax_t)base_offset,
                      p->pack_name);
                mark_bad_packed_object(p, base_sha1);
-               base = read_sha1_file(base_sha1, type, &base_size);
+               base = read_object(base_sha1, type, &base_size);
                if (!base)
                        return NULL;
        }
@@ -1917,11 +1942,18 @@ static int sha1_loose_object_info(const unsigned char *sha1, unsigned long *size
 int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
 {
        struct pack_entry e;
+       int status;
 
        if (!find_pack_entry(sha1, &e, NULL)) {
+               /* Most likely it's a loose object. */
+               status = sha1_loose_object_info(sha1, sizep);
+               if (status >= 0)
+                       return status;
+
+               /* Not a loose object; someone else may have just packed it. */
                reprepare_packed_git();
                if (!find_pack_entry(sha1, &e, NULL))
-                       return sha1_loose_object_info(sha1, sizep);
+                       return status;
        }
        return packed_object_info(e.p, e.offset, sizep);
 }
@@ -1945,7 +1977,7 @@ static void *read_packed_sha1(const unsigned char *sha1,
                error("failed to read object %s at offset %"PRIuMAX" from %s",
                      sha1_to_hex(sha1), (uintmax_t)e.offset, e.p->pack_name);
                mark_bad_packed_object(e.p, sha1);
-               data = read_sha1_file(sha1, type, size);
+               data = read_object(sha1, type, size);
        }
        return data;
 }
@@ -2010,8 +2042,8 @@ int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
        return 0;
 }
 
-void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
-                    unsigned long *size)
+void *read_object(const unsigned char *sha1, enum object_type *type,
+                 unsigned long *size)
 {
        unsigned long mapsize;
        void *map, *buf;
@@ -2037,6 +2069,16 @@ void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
        return read_packed_sha1(sha1, type, size);
 }
 
+void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
+                    unsigned long *size)
+{
+       void *data = read_object(sha1, type, size);
+       /* legacy behavior is to die on corrupted objects */
+       if (!data && (has_loose_object(sha1) || has_packed_and_bad(sha1)))
+               die("object %s is corrupted", sha1_to_hex(sha1));
+       return data;
+}
+
 void *read_object_with_reference(const unsigned char *sha1,
                                 const char *required_type_name,
                                 unsigned long *size,
@@ -2106,7 +2148,9 @@ static void write_sha1_file_prepare(const void *buf, unsigned long len,
  */
 int move_temp_to_file(const char *tmpfile, const char *filename)
 {
-       int ret = link(tmpfile, filename);
+       int ret = 0;
+       if (link(tmpfile, filename))
+               ret = errno;
 
        /*
         * Coda hack - coda doesn't like cross-directory links,
@@ -2188,7 +2232,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
        memcpy(buffer, filename, dirlen);
        strcpy(buffer + dirlen, "tmp_obj_XXXXXX");
        fd = mkstemp(buffer);
-       if (fd < 0 && dirlen) {
+       if (fd < 0 && dirlen && errno == ENOENT) {
                /* Make sure the directory exists */
                memcpy(buffer, filename, dirlen);
                buffer[dirlen-1] = 0;
@@ -2214,7 +2258,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        filename = sha1_file_name(sha1);
        fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
        if (fd < 0) {
-               if (errno == EPERM)
+               if (errno == EACCES)
                        return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
                else
                        return error("unable to create temporary sha1 filename %s: %s\n", tmpfile, strerror(errno));
@@ -2290,6 +2334,7 @@ int force_object_loose(const unsigned char *sha1, time_t mtime)
        enum object_type type;
        char hdr[32];
        int hdrlen;
+       int ret;
 
        if (has_loose_object(sha1))
                return 0;
@@ -2297,7 +2342,10 @@ int force_object_loose(const unsigned char *sha1, time_t mtime)
        if (!buf)
                return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
        hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
-       return write_loose_object(sha1, hdr, hdrlen, buf, len, mtime);
+       ret = write_loose_object(sha1, hdr, hdrlen, buf, len, mtime);
+       free(buf);
+
+       return ret;
 }
 
 int has_pack_index(const unsigned char *sha1)