Code

Merge branch 'maint'
[git.git] / sha1_file.c
index 36dad7261bbb2dde6fe2b038c435b9929c0ab442..f08493f039fa28c90e3edc708bbcf0a527e4f659 100644 (file)
@@ -672,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.
@@ -1669,6 +1700,9 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
        delta_base_cache_lru.prev = &ent->lru;
 }
 
+static void *read_object(const unsigned char *sha1, enum object_type *type,
+                        unsigned long *size);
+
 static void *unpack_delta_entry(struct packed_git *p,
                                struct pack_window **w_curs,
                                off_t curpos,
@@ -2099,8 +2133,8 @@ int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
        return 0;
 }
 
-void *read_object(const unsigned char *sha1, enum object_type *type,
-                 unsigned long *size)
+static void *read_object(const unsigned char *sha1, enum object_type *type,
+                        unsigned long *size)
 {
        unsigned long mapsize;
        void *map, *buf;
@@ -2315,7 +2349,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));
@@ -2492,8 +2526,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:
@@ -2506,20 +2539,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);