archive: delegate blob reading to backend
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Thu, 3 May 2012 01:51:03 +0000 (08:51 +0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 3 May 2012 17:22:56 +0000 (10:22 -0700)
archive-tar.c and archive-zip.c now perform conversion check, with
help of sha1_file_to_archive() from archive.c

This gives backends more freedom in dealing with (streaming) large
blobs.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
archive-tar.c
archive-zip.c
archive.c
archive.h

index 6c8a0bd3bf524a962d18395e710a67e0358451b2..3be0cdf35069c6e810ca61ad9faf3f0917ad2ee0 100644 (file)
@@ -161,11 +161,15 @@ static int write_extended_header(struct archiver_args *args,
 }
 
 static int write_tar_entry(struct archiver_args *args,
-               const unsigned char *sha1, const char *path, size_t pathlen,
-               unsigned int mode, void *buffer, unsigned long size)
+                          const unsigned char *sha1,
+                          const char *path, size_t pathlen,
+                          unsigned int mode)
 {
        struct ustar_header header;
        struct strbuf ext_header = STRBUF_INIT;
+       unsigned int old_mode = mode;
+       unsigned long size;
+       void *buffer;
        int err = 0;
 
        memset(&header, 0, sizeof(header));
@@ -199,7 +203,17 @@ static int write_tar_entry(struct archiver_args *args,
        } else
                memcpy(header.name, path, pathlen);
 
-       if (S_ISLNK(mode) && buffer) {
+       if (S_ISLNK(mode) || S_ISREG(mode)) {
+               enum object_type type;
+               buffer = sha1_file_to_archive(args, path, sha1, old_mode, &type, &size);
+               if (!buffer)
+                       return error("cannot read %s", sha1_to_hex(sha1));
+       } else {
+               buffer = NULL;
+               size = 0;
+       }
+
+       if (S_ISLNK(mode)) {
                if (size > sizeof(header.linkname)) {
                        sprintf(header.linkname, "see %s.paxheader",
                                sha1_to_hex(sha1));
@@ -214,13 +228,16 @@ static int write_tar_entry(struct archiver_args *args,
        if (ext_header.len > 0) {
                err = write_extended_header(args, sha1, ext_header.buf,
                                            ext_header.len);
-               if (err)
+               if (err) {
+                       free(buffer);
                        return err;
+               }
        }
        strbuf_release(&ext_header);
        write_blocked(&header, sizeof(header));
        if (S_ISREG(mode) && buffer && size > 0)
                write_blocked(buffer, size);
+       free(buffer);
        return err;
 }
 
index 02d1f3787acd8d6583073458ab7c8946684f9371..716cc42710ddc9f6f599c2330671ac31912bcb4e 100644 (file)
@@ -121,8 +121,9 @@ static void *zlib_deflate(void *data, unsigned long size,
 }
 
 static int write_zip_entry(struct archiver_args *args,
-               const unsigned char *sha1, const char *path, size_t pathlen,
-               unsigned int mode, void *buffer, unsigned long size)
+                          const unsigned char *sha1,
+                          const char *path, size_t pathlen,
+                          unsigned int mode)
 {
        struct zip_local_header header;
        struct zip_dir_header dirent;
@@ -134,6 +135,8 @@ static int write_zip_entry(struct archiver_args *args,
        int method;
        unsigned char *out;
        void *deflated = NULL;
+       void *buffer;
+       unsigned long size;
 
        crc = crc32(0, NULL, 0);
 
@@ -148,7 +151,14 @@ static int write_zip_entry(struct archiver_args *args,
                out = NULL;
                uncompressed_size = 0;
                compressed_size = 0;
+               buffer = NULL;
+               size = 0;
        } else if (S_ISREG(mode) || S_ISLNK(mode)) {
+               enum object_type type;
+               buffer = sha1_file_to_archive(args, path, sha1, mode, &type, &size);
+               if (!buffer)
+                       return error("cannot read %s", sha1_to_hex(sha1));
+
                method = 0;
                attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
                        (mode & 0111) ? ((mode) << 16) : 0;
@@ -229,6 +239,7 @@ static int write_zip_entry(struct archiver_args *args,
        }
 
        free(deflated);
+       free(buffer);
 
        return 0;
 }
index 1ee837d7170cfa52da6725cfe7c5ae0d6d67462e..cd083eaf9aa2f1ae4cfc57d90fb11b8f808fbfe7 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -59,12 +59,15 @@ static void format_subst(const struct commit *commit,
        free(to_free);
 }
 
-static void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
-               unsigned int mode, enum object_type *type,
-               unsigned long *sizep, const struct commit *commit)
+void *sha1_file_to_archive(const struct archiver_args *args,
+                          const char *path, const unsigned char *sha1,
+                          unsigned int mode, enum object_type *type,
+                          unsigned long *sizep)
 {
        void *buffer;
+       const struct commit *commit = args->convert ? args->commit : NULL;
 
+       path += args->baselen;
        buffer = read_sha1_file(sha1, type, sizep);
        if (buffer && S_ISREG(mode)) {
                struct strbuf buf = STRBUF_INIT;
@@ -109,12 +112,9 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
        write_archive_entry_fn_t write_entry = c->write_entry;
        struct git_attr_check check[2];
        const char *path_without_prefix;
-       int convert = 0;
        int err;
-       enum object_type type;
-       unsigned long size;
-       void *buffer;
 
+       args->convert = 0;
        strbuf_reset(&path);
        strbuf_grow(&path, PATH_MAX);
        strbuf_add(&path, args->base, args->baselen);
@@ -126,28 +126,22 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
        if (!git_check_attr(path_without_prefix, ARRAY_SIZE(check), check)) {
                if (ATTR_TRUE(check[0].value))
                        return 0;
-               convert = ATTR_TRUE(check[1].value);
+               args->convert = ATTR_TRUE(check[1].value);
        }
 
        if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
                strbuf_addch(&path, '/');
                if (args->verbose)
                        fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
-               err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0);
+               err = write_entry(args, sha1, path.buf, path.len, mode);
                if (err)
                        return err;
                return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
        }
 
-       buffer = sha1_file_to_archive(path_without_prefix, sha1, mode,
-                       &type, &size, convert ? args->commit : NULL);
-       if (!buffer)
-               return error("cannot read %s", sha1_to_hex(sha1));
        if (args->verbose)
                fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
-       err = write_entry(args, sha1, path.buf, path.len, mode, buffer, size);
-       free(buffer);
-       return err;
+       return write_entry(args, sha1, path.buf, path.len, mode);
 }
 
 int write_archive_entries(struct archiver_args *args,
@@ -167,7 +161,7 @@ int write_archive_entries(struct archiver_args *args,
                if (args->verbose)
                        fprintf(stderr, "%.*s\n", (int)len, args->base);
                err = write_entry(args, args->tree->object.sha1, args->base,
-                               len, 040777, NULL, 0);
+                                 len, 040777);
                if (err)
                        return err;
        }
index 2b0884f1ef3123f26d9a7b3ba03e3d14ae1ccd57..895afcdc7a00c5f9f16a21f2c9fe361a3e218d37 100644 (file)
--- a/archive.h
+++ b/archive.h
@@ -11,6 +11,7 @@ struct archiver_args {
        const char **pathspec;
        unsigned int verbose : 1;
        unsigned int worktree_attributes : 1;
+       unsigned int convert : 1;
        int compression_level;
 };
 
@@ -27,11 +28,18 @@ extern void register_archiver(struct archiver *);
 extern void init_tar_archiver(void);
 extern void init_zip_archiver(void);
 
-typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode, void *buffer, unsigned long size);
+typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
+                                       const unsigned char *sha1,
+                                       const char *path, size_t pathlen,
+                                       unsigned int mode);
 
 extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
 extern int write_archive(int argc, const char **argv, const char *prefix, int setup_prefix, const char *name_hint, int remote);
 
 const char *archive_format_from_filename(const char *filename);
+extern void *sha1_file_to_archive(const struct archiver_args *args,
+                                 const char *path, const unsigned char *sha1,
+                                 unsigned int mode, enum object_type *type,
+                                 unsigned long *sizep);
 
 #endif /* ARCHIVE_H */