Code

Clear the delta base cache during fast-import checkpoint
[git.git] / sha1_file.c
index 2df78b5afd57cf8e86f01134bf6c49d74defc52a..cbcae24d28f7000d2e55c4a2ef95026f07c5e5cc 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;
@@ -652,6 +659,37 @@ void unuse_pack(struct pack_window **w_cursor)
        }
 }
 
+/*
+ * This is used by git-repack in case a newly created pack happens to
+ * contain the same set of objects as an existing one.  In that case
+ * the resulting file might be different even if its name would be the
+ * same.  It is best to close any reference to the old pack before it is
+ * replaced on disk.  Of course no index pointers nor windows for given pack
+ * must subsist at this point.  If ever objects from this pack are requested
+ * again, the new version of the pack will be reinitialized through
+ * reprepare_packed_git().
+ */
+void free_pack_by_name(const char *pack_name)
+{
+       struct packed_git *p, **pp = &packed_git;
+
+       while (*pp) {
+               p = *pp;
+               if (strcmp(pack_name, p->pack_name) == 0) {
+                       close_pack_windows(p);
+                       if (p->pack_fd != -1)
+                               close(p->pack_fd);
+                       if (p->index_data)
+                               munmap((void *)p->index_data, p->index_size);
+                       free(p->bad_object_sha1);
+                       *pp = p->next;
+                       free(p);
+                       return;
+               }
+               pp = &p->next;
+       }
+}
+
 /*
  * Do not call this directly as this leaks p->pack_fd on error return;
  * call open_packed_git() instead.
@@ -828,6 +866,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 +1033,7 @@ void prepare_packed_git(void)
 
 void reprepare_packed_git(void)
 {
+       discard_revindex();
        prepare_packed_git_run_once = 0;
        prepare_packed_git();
 }
@@ -1006,6 +1050,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];
@@ -1574,6 +1630,13 @@ static inline void release_delta_base_cache(struct delta_base_cache_entry *ent)
        }
 }
 
+void clear_delta_base_cache(void)
+{
+       unsigned long p;
+       for (p = 0; p < MAX_DELTA_CACHE; p++)
+               release_delta_base_cache(&delta_base_cache[p]);
+}
+
 static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
        void *base, unsigned long base_size, enum object_type type)
 {
@@ -1647,7 +1710,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 +1980,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 +2015,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 +2080,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 +2107,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 +2186,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 +2270,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;
@@ -2205,7 +2287,8 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
 static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
                              void *buf, unsigned long len, time_t mtime)
 {
-       int fd, size, ret;
+       int fd, ret;
+       size_t size;
        unsigned char *compressed;
        z_stream stream;
        char *filename;
@@ -2214,7 +2297,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 +2373,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 +2381,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)