aboutsummaryrefslogtreecommitdiff
path: root/archive.c
diff options
context:
space:
mode:
authorRené Scharfe <rene.scharfe@lsrfire.ath.cx>2008-07-14 21:22:24 +0200
committerJunio C Hamano <gitster@pobox.com>2008-07-15 07:18:04 -0700
commit562e25abea9f1f2d443053279c009a88d81a592b (patch)
treed9c85fad9ac3f441f39a1644182b8711da63047e /archive.c
parentd53fe8187c38a5a160ef2199a899d9c47ec881b9 (diff)
downloadgit-562e25abea9f1f2d443053279c009a88d81a592b.tar.gz
git-562e25abea9f1f2d443053279c009a88d81a592b.tar.xz
archive: centralize archive entry writing
Add the exported function write_archive_entries() to archive.c, which uses the new ability of read_tree_recursive() to pass a context pointer to its callback in order to centralize previously duplicated code. The new callback function write_archive_entry() does the work that every archiver backend needs to do: loading file contents, entering subdirectories, handling file attributes, constructing the full path of the entry. All that done, it calls the backend specific write_archive_entry_fn_t function. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'archive.c')
-rw-r--r--archive.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/archive.c b/archive.c
index 6502b76ef..58de55e15 100644
--- a/archive.c
+++ b/archive.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "commit.h"
#include "attr.h"
+#include "archive.h"
static void format_subst(const struct commit *commit,
const char *src, size_t len,
@@ -95,3 +96,79 @@ int is_archive_path_ignored(const char *path)
return 0;
return ATTR_TRUE(check[0].value);
}
+
+struct archiver_context {
+ struct archiver_args *args;
+ write_archive_entry_fn_t write_entry;
+};
+
+static int write_archive_entry(const unsigned char *sha1, const char *base,
+ int baselen, const char *filename, unsigned mode, int stage,
+ void *context)
+{
+ static struct strbuf path = STRBUF_INIT;
+ struct archiver_context *c = context;
+ struct archiver_args *args = c->args;
+ write_archive_entry_fn_t write_entry = c->write_entry;
+ int err;
+ enum object_type type;
+ unsigned long size;
+ void *buffer;
+
+ strbuf_reset(&path);
+ strbuf_grow(&path, PATH_MAX);
+ strbuf_add(&path, base, baselen);
+ strbuf_addstr(&path, filename);
+
+ if (is_archive_path_ignored(path.buf + args->baselen))
+ return 0;
+
+ 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);
+ if (err)
+ return err;
+ return READ_TREE_RECURSIVE;
+ }
+
+ buffer = sha1_file_to_archive(path.buf + args->baselen, sha1, mode,
+ &type, &size, args->commit);
+ 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;
+}
+
+int write_archive_entries(struct archiver_args *args,
+ write_archive_entry_fn_t write_entry)
+{
+ struct archiver_context context;
+ int err;
+
+ if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
+ size_t len = args->baselen;
+
+ while (len > 1 && args->base[len - 2] == '/')
+ len--;
+ 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);
+ if (err)
+ return err;
+ }
+
+ context.args = args;
+ context.write_entry = write_entry;
+
+ err = read_tree_recursive(args->tree, args->base, args->baselen, 0,
+ args->pathspec, write_archive_entry, &context);
+ if (err == READ_TREE_RECURSIVE)
+ err = 0;
+ return err;
+}