[PATCH] write_sha1_to_fd()
[git.git] / sha1_file.c
index fc4e6bf..b13578b 100644 (file)
@@ -1100,12 +1100,12 @@ void *read_object_with_reference(const unsigned char *sha1,
        }
 }
 
-static char *write_sha1_file_prepare(void *buf,
-                                    unsigned long len,
-                                    const char *type,
-                                    unsigned char *sha1,
-                                    unsigned char *hdr,
-                                    int *hdrlen)
+char *write_sha1_file_prepare(void *buf,
+                             unsigned long len,
+                             const char *type,
+                             unsigned char *sha1,
+                             unsigned char *hdr,
+                             int *hdrlen)
 {
        SHA_CTX c;
 
@@ -1221,6 +1221,65 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
        return 0;
 }
 
+int write_sha1_to_fd(int fd, const unsigned char *sha1)
+{
+       ssize_t size;
+       unsigned long objsize;
+       int posn = 0;
+       char *buf = map_sha1_file_internal(sha1, &objsize, 0);
+       z_stream stream;
+       if (!buf) {
+               unsigned char *unpacked;
+               unsigned long len;
+               char type[20];
+               char hdr[50];
+               int hdrlen;
+               // need to unpack and recompress it by itself
+               unpacked = read_packed_sha1(sha1, type, &len);
+
+               hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
+
+               /* Set it up */
+               memset(&stream, 0, sizeof(stream));
+               deflateInit(&stream, Z_BEST_COMPRESSION);
+               size = deflateBound(&stream, len + hdrlen);
+               buf = xmalloc(size);
+
+               /* Compress it */
+               stream.next_out = buf;
+               stream.avail_out = size;
+               
+               /* First header.. */
+               stream.next_in = hdr;
+               stream.avail_in = hdrlen;
+               while (deflate(&stream, 0) == Z_OK)
+                       /* nothing */;
+
+               /* Then the data itself.. */
+               stream.next_in = unpacked;
+               stream.avail_in = len;
+               while (deflate(&stream, Z_FINISH) == Z_OK)
+                       /* nothing */;
+               deflateEnd(&stream);
+               
+               objsize = stream.total_out;
+       }
+
+       do {
+               size = write(fd, buf + posn, objsize - posn);
+               if (size <= 0) {
+                       if (!size) {
+                               fprintf(stderr, "write closed");
+                       } else {
+                               perror("write ");
+                       }
+                       return -1;
+               }
+               posn += size;
+       } while (posn < objsize);
+       return 0;
+}
+
 int write_sha1_from_fd(const unsigned char *sha1, int fd)
 {
        char *filename = sha1_file_name(sha1);
@@ -1299,11 +1358,13 @@ int has_sha1_file(const unsigned char *sha1)
        return find_pack_entry(sha1, &e);
 }
 
-int index_fd(unsigned char *sha1, int fd, struct stat *st)
+int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type)
 {
        unsigned long size = st->st_size;
        void *buf;
        int ret;
+       unsigned char hdr[50];
+       int hdrlen;
 
        buf = "";
        if (size)
@@ -1312,7 +1373,14 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st)
        if ((int)(long)buf == -1)
                return -1;
 
-       ret = write_sha1_file(buf, size, "blob", sha1);
+       if (!type)
+               type = "blob";
+       if (write_object)
+               ret = write_sha1_file(buf, size, type, sha1);
+       else {
+               write_sha1_file_prepare(buf, size, type, sha1, hdr, &hdrlen);
+               ret = 0;
+       }
        if (size)
                munmap(buf, size);
        return ret;