t9010 (svn-fe): Eliminate dependency on svn perl bindings
[gitweb.git] / sha1_file.c
index 0375159604205cb1fe00adf7d33533224475a61d..e42ef96d457f6aa12ab7d0057acf936db0335d40 100644 (file)
@@ -35,13 +35,6 @@ static size_t sz_fmt(size_t s) { return s; }
 
 const unsigned char null_sha1[20];
 
-static inline int offset_1st_component(const char *path)
-{
-       if (has_dos_drive_prefix(path))
-               return 2 + (path[2] == '/');
-       return *path == '/';
-}
-
 int safe_create_leading_directories(char *path)
 {
        char *pos = path + offset_1st_component(path);
@@ -109,20 +102,22 @@ static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
  */
 char *sha1_file_name(const unsigned char *sha1)
 {
-       static char *name, *base;
+       static char buf[PATH_MAX];
+       const char *objdir;
+       int len;
 
-       if (!base) {
-               const char *sha1_file_directory = get_object_directory();
-               int len = strlen(sha1_file_directory);
-               base = xmalloc(len + 60);
-               memcpy(base, sha1_file_directory, len);
-               memset(base+len, 0, 60);
-               base[len] = '/';
-               base[len+3] = '/';
-               name = base + len + 1;
-       }
-       fill_sha1_path(name, sha1);
-       return base;
+       objdir = get_object_directory();
+       len = strlen(objdir);
+
+       /* '/' + sha1(2) + '/' + sha1(38) + '\0' */
+       if (len + 43 > PATH_MAX)
+               die("insanely long object directory %s", objdir);
+       memcpy(buf, objdir, len);
+       buf[len] = '/';
+       buf[len+3] = '/';
+       buf[len+42] = '\0';
+       fill_sha1_path(buf + len + 1, sha1);
+       return buf;
 }
 
 static char *sha1_get_pack_name(const unsigned char *sha1,
@@ -606,6 +601,14 @@ void unuse_pack(struct pack_window **w_cursor)
        }
 }
 
+void close_pack_index(struct packed_git *p)
+{
+       if (p->index_data) {
+               munmap((void *)p->index_data, p->index_size);
+               p->index_data = NULL;
+       }
+}
+
 /*
  * 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
@@ -627,8 +630,7 @@ void free_pack_by_name(const char *pack_name)
                        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);
+                       close_pack_index(p);
                        free(p->bad_object_sha1);
                        *pp = p->next;
                        free(p);
@@ -838,9 +840,8 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
        return p;
 }
 
-struct packed_git *parse_pack_index(unsigned char *sha1)
+struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)
 {
-       const char *idx_path = sha1_pack_index_name(sha1);
        const char *path = sha1_pack_name(sha1);
        struct packed_git *p = alloc_packed_git(strlen(path) + 1);
 
@@ -2206,7 +2207,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
        }
 
 out:
-       if (set_shared_perm(filename, (S_IFREG|0444)))
+       if (adjust_shared_perm(filename))
                return error("unable to set permission to '%s'", filename);
        return 0;
 }
@@ -2262,7 +2263,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);
+       fd = git_mkstemp_mode(buffer, 0444);
        if (fd < 0 && dirlen && errno == ENOENT) {
                /* Make sure the directory exists */
                memcpy(buffer, filename, dirlen);
@@ -2272,18 +2273,19 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
 
                /* Try again */
                strcpy(buffer + dirlen - 1, "/tmp_obj_XXXXXX");
-               fd = mkstemp(buffer);
+               fd = git_mkstemp_mode(buffer, 0444);
        }
        return fd;
 }
 
 static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
-                             void *buf, unsigned long len, time_t mtime)
+                             const void *buf, unsigned long len, time_t mtime)
 {
        int fd, ret;
-       size_t size;
-       unsigned char *compressed;
+       unsigned char compressed[4096];
        z_stream stream;
+       git_SHA_CTX c;
+       unsigned char parano_sha1[20];
        char *filename;
        static char tmpfile[PATH_MAX];
 
@@ -2301,36 +2303,40 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        /* Set it up */
        memset(&stream, 0, sizeof(stream));
        deflateInit(&stream, zlib_compression_level);
-       size = 8 + deflateBound(&stream, len+hdrlen);
-       compressed = xmalloc(size);
-
-       /* Compress it */
        stream.next_out = compressed;
-       stream.avail_out = size;
+       stream.avail_out = sizeof(compressed);
+       git_SHA1_Init(&c);
 
        /* First header.. */
        stream.next_in = (unsigned char *)hdr;
        stream.avail_in = hdrlen;
        while (deflate(&stream, 0) == Z_OK)
                /* nothing */;
+       git_SHA1_Update(&c, hdr, hdrlen);
 
        /* Then the data itself.. */
-       stream.next_in = buf;
+       stream.next_in = (void *)buf;
        stream.avail_in = len;
-       ret = deflate(&stream, Z_FINISH);
+       do {
+               unsigned char *in0 = stream.next_in;
+               ret = deflate(&stream, Z_FINISH);
+               git_SHA1_Update(&c, in0, stream.next_in - in0);
+               if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
+                       die("unable to write sha1 file");
+               stream.next_out = compressed;
+               stream.avail_out = sizeof(compressed);
+       } while (ret == Z_OK);
+
        if (ret != Z_STREAM_END)
                die("unable to deflate new object %s (%d)", sha1_to_hex(sha1), ret);
-
        ret = deflateEnd(&stream);
        if (ret != Z_OK)
                die("deflateEnd on object %s failed (%d)", sha1_to_hex(sha1), ret);
+       git_SHA1_Final(parano_sha1, &c);
+       if (hashcmp(sha1, parano_sha1) != 0)
+               die("confused by unstable object source data for %s", sha1_to_hex(sha1));
 
-       size = stream.total_out;
-
-       if (write_buffer(fd, compressed, size) < 0)
-               die("unable to write sha1 file");
        close_sha1_file(fd);
-       free(compressed);
 
        if (mtime) {
                struct utimbuf utb;
@@ -2344,7 +2350,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        return move_temp_to_file(tmpfile, filename);
 }
 
-int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
+int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
 {
        unsigned char sha1[20];
        char hdr[32];
@@ -2450,6 +2456,8 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
                else
                        ret = -1;
                strbuf_release(&sbuf);
+       } else if (!size) {
+               ret = index_mem(sha1, NULL, size, write_object, type, path);
        } else if (size <= SMALL_FILE_SIZE) {
                char *buf = xmalloc(size);
                if (size == read_in_full(fd, buf, size))
@@ -2458,12 +2466,11 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
                else
                        ret = error("short read %s", strerror(errno));
                free(buf);
-       } else if (size) {
+       } else {
                void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
                ret = index_mem(sha1, buf, size, write_object, type, path);
                munmap(buf, size);
-       } else
-               ret = index_mem(sha1, NULL, size, write_object, type, path);
+       }
        close(fd);
        return ret;
 }
@@ -2518,3 +2525,13 @@ int read_pack_header(int fd, struct pack_header *header)
                return PH_ERROR_PROTOCOL;
        return 0;
 }
+
+void assert_sha1_type(const unsigned char *sha1, enum object_type expect)
+{
+       enum object_type type = sha1_object_info(sha1, NULL);
+       if (type < 0)
+               die("%s is not a valid object", sha1_to_hex(sha1));
+       if (type != expect)
+               die("%s is not a valid '%s' object", sha1_to_hex(sha1),
+                   typename(expect));
+}