From 562e25abea9f1f2d443053279c009a88d81a592b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Mon, 14 Jul 2008 21:22:24 +0200 Subject: 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 Signed-off-by: Junio C Hamano --- archive.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) (limited to 'archive.c') 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; +} -- cgit v1.2.1