]> asedeno.scripts.mit.edu Git - git.git/blobdiff - sha1_file.c
merge-file: handle freopen() failure
[git.git] / sha1_file.c
index 384a43044e789612446cf1c6cb31fdf0dd037105..52d1ead15b4db62138d9cedd5fe04068bcd10461 100644 (file)
@@ -423,23 +423,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;
@@ -665,6 +672,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.
@@ -841,6 +879,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);
@@ -1388,9 +1431,12 @@ static int packed_delta_info(struct packed_git *p,
                return OBJ_BAD;
        type = packed_object_info(p, base_offset, NULL);
        if (type <= OBJ_NONE) {
-               struct revindex_entry *revidx = find_pack_revindex(p, base_offset);
-               const unsigned char *base_sha1 =
-                                       nth_packed_object_sha1(p, revidx->nr);
+               struct revindex_entry *revidx;
+               const unsigned char *base_sha1;
+               revidx = find_pack_revindex(p, base_offset);
+               if (!revidx)
+                       return OBJ_BAD;
+               base_sha1 = nth_packed_object_sha1(p, revidx->nr);
                mark_bad_packed_object(p, base_sha1);
                type = sha1_object_info(base_sha1, NULL);
                if (type <= OBJ_NONE)
@@ -1682,9 +1728,12 @@ static void *unpack_delta_entry(struct packed_git *p,
                 * This is costly but should happen only in the presence
                 * of a corrupted pack, and is better than failing outright.
                 */
-               struct revindex_entry *revidx = find_pack_revindex(p, base_offset);
-               const unsigned char *base_sha1 =
-                                       nth_packed_object_sha1(p, revidx->nr);
+               struct revindex_entry *revidx;
+               const unsigned char *base_sha1;
+               revidx = find_pack_revindex(p, base_offset);
+               if (!revidx)
+                       return NULL;
+               base_sha1 = nth_packed_object_sha1(p, revidx->nr);
                error("failed to read delta base object %s"
                      " at offset %"PRIuMAX" from %s",
                      sha1_to_hex(base_sha1), (uintmax_t)base_offset,
@@ -1731,6 +1780,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
                        error("bad packed object CRC for %s",
                              sha1_to_hex(sha1));
                        mark_bad_packed_object(p, sha1);
+                       unuse_pack(&w_curs);
                        return NULL;
                }
        }
@@ -2037,9 +2087,7 @@ static struct cached_object {
 static int cached_object_nr, cached_object_alloc;
 
 static struct cached_object empty_tree = {
-       /* empty tree sha1: 4b825dc642cb6eb9a060e54bf8d69288fbee4904 */
-       "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60"
-       "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04",
+       EMPTY_TREE_SHA1_BIN,
        OBJ_TREE,
        "",
        0
@@ -2272,7 +2320,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;
@@ -2298,7 +2346,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));
@@ -2475,8 +2523,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
 int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object)
 {
        int fd;
-       char *target;
-       size_t len;
+       struct strbuf sb = STRBUF_INIT;
 
        switch (st->st_mode & S_IFMT) {
        case S_IFREG:
@@ -2489,20 +2536,17 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
                                     path);
                break;
        case S_IFLNK:
-               len = xsize_t(st->st_size);
-               target = xmalloc(len + 1);
-               if (readlink(path, target, len + 1) != st->st_size) {
+               if (strbuf_readlink(&sb, path, st->st_size)) {
                        char *errstr = strerror(errno);
-                       free(target);
                        return error("readlink(\"%s\"): %s", path,
                                     errstr);
                }
                if (!write_object)
-                       hash_sha1_file(target, len, blob_type, sha1);
-               else if (write_sha1_file(target, len, blob_type, sha1))
+                       hash_sha1_file(sb.buf, sb.len, blob_type, sha1);
+               else if (write_sha1_file(sb.buf, sb.len, blob_type, sha1))
                        return error("%s: failed to insert into database",
                                     path);
-               free(target);
+               strbuf_release(&sb);
                break;
        case S_IFDIR:
                return resolve_gitlink_ref(path, "HEAD", sha1);