{"thread":{"id":"5673","subject":"[PATCH 2/2] git-tar-tree: Move code for git-archive --format=tar to archive-tar.c","startedAt":"2006-09-24T15:31:10Z","lastAt":"2006-09-24T22:19:59Z","messageCount":3,"participants":["Rene Scharfe","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"27554","messageId":"4516A4BE.9090406@lsrfire.ath.cx","threadId":"5673","inReplyTo":null,"subject":"[PATCH 2/2] git-tar-tree: Move code for git-archive --format=tar to archive-tar.c","fromName":"Rene Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2006-09-24T15:31:10Z","receivedAt":"2006-09-24T15:31:10Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"This patch doesn't change any functionality, it only moves code around.  It\nmakes seeing the few remaining lines of git-tar-tree code easier. ;-)\n\nSigned-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n---\n\n Makefile           |    2 \n archive-tar.c      |  325 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n builtin-tar-tree.c |  313 --------------------------------------------------\n 3 files changed, 326 insertions(+), 314 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 739d7e3..d4f6e01 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -254,7 +254,7 @@ LIB_OBJS = \\\n \tfetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \\\n \twrite_or_die.o trace.o list-objects.o \\\n \talloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \\\n-\tcolor.o wt-status.o archive-zip.o\n+\tcolor.o wt-status.o archive-zip.o archive-tar.o\n \n BUILTIN_OBJS = \\\n \tbuiltin-add.o \\\ndiff --git a/archive-tar.c b/archive-tar.c\nnew file mode 100644\nindex 0000000..ff0f6e2\n--- /dev/null\n+++ b/archive-tar.c\n@@ -0,0 +1,325 @@\n+/*\n+ * Copyright (c) 2005, 2006 Rene Scharfe\n+ */\n+#include <time.h>\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"strbuf.h\"\n+#include \"tar.h\"\n+#include \"builtin.h\"\n+#include \"archive.h\"\n+\n+#define RECORDSIZE\t(512)\n+#define BLOCKSIZE\t(RECORDSIZE * 20)\n+\n+static char block[BLOCKSIZE];\n+static unsigned long offset;\n+\n+static time_t archive_time;\n+static int tar_umask;\n+static int verbose;\n+\n+/* writes out the whole block, but only if it is full */\n+static void write_if_needed(void)\n+{\n+\tif (offset == BLOCKSIZE) {\n+\t\twrite_or_die(1, block, BLOCKSIZE);\n+\t\toffset = 0;\n+\t}\n+}\n+\n+/*\n+ * queues up writes, so that all our write(2) calls write exactly one\n+ * full block; pads writes to RECORDSIZE\n+ */\n+static void write_blocked(const void *data, unsigned long size)\n+{\n+\tconst char *buf = data;\n+\tunsigned long tail;\n+\n+\tif (offset) {\n+\t\tunsigned long chunk = BLOCKSIZE - offset;\n+\t\tif (size < chunk)\n+\t\t\tchunk = size;\n+\t\tmemcpy(block + offset, buf, chunk);\n+\t\tsize -= chunk;\n+\t\toffset += chunk;\n+\t\tbuf += chunk;\n+\t\twrite_if_needed();\n+\t}\n+\twhile (size >= BLOCKSIZE) {\n+\t\twrite_or_die(1, buf, BLOCKSIZE);\n+\t\tsize -= BLOCKSIZE;\n+\t\tbuf += BLOCKSIZE;\n+\t}\n+\tif (size) {\n+\t\tmemcpy(block + offset, buf, size);\n+\t\toffset += size;\n+\t}\n+\ttail = offset % RECORDSIZE;\n+\tif (tail)  {\n+\t\tmemset(block + offset, 0, RECORDSIZE - tail);\n+\t\toffset += RECORDSIZE - tail;\n+\t}\n+\twrite_if_needed();\n+}\n+\n+/*\n+ * The end of tar archives is marked by 2*512 nul bytes and after that\n+ * follows the rest of the block (if any).\n+ */\n+static void write_trailer(void)\n+{\n+\tint tail = BLOCKSIZE - offset;\n+\tmemset(block + offset, 0, tail);\n+\twrite_or_die(1, block, BLOCKSIZE);\n+\tif (tail < 2 * RECORDSIZE) {\n+\t\tmemset(block, 0, offset);\n+\t\twrite_or_die(1, block, BLOCKSIZE);\n+\t}\n+}\n+\n+static void strbuf_append_string(struct strbuf *sb, const char *s)\n+{\n+\tint slen = strlen(s);\n+\tint total = sb->len + slen;\n+\tif (total > sb->alloc) {\n+\t\tsb->buf = xrealloc(sb->buf, total);\n+\t\tsb->alloc = total;\n+\t}\n+\tmemcpy(sb->buf + sb->len, s, slen);\n+\tsb->len = total;\n+}\n+\n+/*\n+ * pax extended header records have the format \"%u %s=%s\\n\".  %u contains\n+ * the size of the whole string (including the %u), the first %s is the\n+ * keyword, the second one is the value.  This function constructs such a\n+ * string and appends it to a struct strbuf.\n+ */\n+static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,\n+                                     const char *value, unsigned int valuelen)\n+{\n+\tchar *p;\n+\tint len, total, tmp;\n+\n+\t/* \"%u %s=%s\\n\" */\n+\tlen = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;\n+\tfor (tmp = len; tmp > 9; tmp /= 10)\n+\t\tlen++;\n+\n+\ttotal = sb->len + len;\n+\tif (total > sb->alloc) {\n+\t\tsb->buf = xrealloc(sb->buf, total);\n+\t\tsb->alloc = total;\n+\t}\n+\n+\tp = sb->buf;\n+\tp += sprintf(p, \"%u %s=\", len, keyword);\n+\tmemcpy(p, value, valuelen);\n+\tp += valuelen;\n+\t*p = '\\n';\n+\tsb->len = total;\n+}\n+\n+static unsigned int ustar_header_chksum(const struct ustar_header *header)\n+{\n+\tchar *p = (char *)header;\n+\tunsigned int chksum = 0;\n+\twhile (p < header->chksum)\n+\t\tchksum += *p++;\n+\tchksum += sizeof(header->chksum) * ' ';\n+\tp += sizeof(header->chksum);\n+\twhile (p < (char *)header + sizeof(struct ustar_header))\n+\t\tchksum += *p++;\n+\treturn chksum;\n+}\n+\n+static int get_path_prefix(const struct strbuf *path, int maxlen)\n+{\n+\tint i = path->len;\n+\tif (i > maxlen)\n+\t\ti = maxlen;\n+\tdo {\n+\t\ti--;\n+\t} while (i > 0 && path->buf[i] != '/');\n+\treturn i;\n+}\n+\n+static void write_entry(const unsigned char *sha1, struct strbuf *path,\n+                        unsigned int mode, void *buffer, unsigned long size)\n+{\n+\tstruct ustar_header header;\n+\tstruct strbuf ext_header;\n+\n+\tmemset(&header, 0, sizeof(header));\n+\text_header.buf = NULL;\n+\text_header.len = ext_header.alloc = 0;\n+\n+\tif (!sha1) {\n+\t\t*header.typeflag = TYPEFLAG_GLOBAL_HEADER;\n+\t\tmode = 0100666;\n+\t\tstrcpy(header.name, \"pax_global_header\");\n+\t} else if (!path) {\n+\t\t*header.typeflag = TYPEFLAG_EXT_HEADER;\n+\t\tmode = 0100666;\n+\t\tsprintf(header.name, \"%s.paxheader\", sha1_to_hex(sha1));\n+\t} else {\n+\t\tif (verbose)\n+\t\t\tfprintf(stderr, \"%.*s\\n\", path->len, path->buf);\n+\t\tif (S_ISDIR(mode)) {\n+\t\t\t*header.typeflag = TYPEFLAG_DIR;\n+\t\t\tmode = (mode | 0777) & ~tar_umask;\n+\t\t} else if (S_ISLNK(mode)) {\n+\t\t\t*header.typeflag = TYPEFLAG_LNK;\n+\t\t\tmode |= 0777;\n+\t\t} else if (S_ISREG(mode)) {\n+\t\t\t*header.typeflag = TYPEFLAG_REG;\n+\t\t\tmode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;\n+\t\t} else {\n+\t\t\terror(\"unsupported file mode: 0%o (SHA1: %s)\",\n+\t\t\t      mode, sha1_to_hex(sha1));\n+\t\t\treturn;\n+\t\t}\n+\t\tif (path->len > sizeof(header.name)) {\n+\t\t\tint plen = get_path_prefix(path, sizeof(header.prefix));\n+\t\t\tint rest = path->len - plen - 1;\n+\t\t\tif (plen > 0 && rest <= sizeof(header.name)) {\n+\t\t\t\tmemcpy(header.prefix, path->buf, plen);\n+\t\t\t\tmemcpy(header.name, path->buf + plen + 1, rest);\n+\t\t\t} else {\n+\t\t\t\tsprintf(header.name, \"%s.data\",\n+\t\t\t\t        sha1_to_hex(sha1));\n+\t\t\t\tstrbuf_append_ext_header(&ext_header, \"path\",\n+\t\t\t\t                         path->buf, path->len);\n+\t\t\t}\n+\t\t} else\n+\t\t\tmemcpy(header.name, path->buf, path->len);\n+\t}\n+\n+\tif (S_ISLNK(mode) && buffer) {\n+\t\tif (size > sizeof(header.linkname)) {\n+\t\t\tsprintf(header.linkname, \"see %s.paxheader\",\n+\t\t\t        sha1_to_hex(sha1));\n+\t\t\tstrbuf_append_ext_header(&ext_header, \"linkpath\",\n+\t\t\t                         buffer, size);\n+\t\t} else\n+\t\t\tmemcpy(header.linkname, buffer, size);\n+\t}\n+\n+\tsprintf(header.mode, \"%07o\", mode & 07777);\n+\tsprintf(header.size, \"%011lo\", S_ISREG(mode) ? size : 0);\n+\tsprintf(header.mtime, \"%011lo\", archive_time);\n+\n+\t/* XXX: should we provide more meaningful info here? */\n+\tsprintf(header.uid, \"%07o\", 0);\n+\tsprintf(header.gid, \"%07o\", 0);\n+\tstrlcpy(header.uname, \"git\", sizeof(header.uname));\n+\tstrlcpy(header.gname, \"git\", sizeof(header.gname));\n+\tsprintf(header.devmajor, \"%07o\", 0);\n+\tsprintf(header.devminor, \"%07o\", 0);\n+\n+\tmemcpy(header.magic, \"ustar\", 6);\n+\tmemcpy(header.version, \"00\", 2);\n+\n+\tsprintf(header.chksum, \"%07o\", ustar_header_chksum(&header));\n+\n+\tif (ext_header.len > 0) {\n+\t\twrite_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);\n+\t\tfree(ext_header.buf);\n+\t}\n+\twrite_blocked(&header, sizeof(header));\n+\tif (S_ISREG(mode) && buffer && size > 0)\n+\t\twrite_blocked(buffer, size);\n+}\n+\n+static void write_global_extended_header(const unsigned char *sha1)\n+{\n+\tstruct strbuf ext_header;\n+\text_header.buf = NULL;\n+\text_header.len = ext_header.alloc = 0;\n+\tstrbuf_append_ext_header(&ext_header, \"comment\", sha1_to_hex(sha1), 40);\n+\twrite_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);\n+\tfree(ext_header.buf);\n+}\n+\n+static int git_tar_config(const char *var, const char *value)\n+{\n+\tif (!strcmp(var, \"tar.umask\")) {\n+\t\tif (!strcmp(value, \"user\")) {\n+\t\t\ttar_umask = umask(0);\n+\t\t\tumask(tar_umask);\n+\t\t} else {\n+\t\t\ttar_umask = git_config_int(var, value);\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\treturn git_default_config(var, value);\n+}\n+\n+static int write_tar_entry(const unsigned char *sha1,\n+                           const char *base, int baselen,\n+                           const char *filename, unsigned mode, int stage)\n+{\n+\tstatic struct strbuf path;\n+\tint filenamelen = strlen(filename);\n+\tvoid *buffer;\n+\tchar type[20];\n+\tunsigned long size;\n+\n+\tif (!path.alloc) {\n+\t\tpath.buf = xmalloc(PATH_MAX);\n+\t\tpath.alloc = PATH_MAX;\n+\t\tpath.len = path.eof = 0;\n+\t}\n+\tif (path.alloc < baselen + filenamelen) {\n+\t\tfree(path.buf);\n+\t\tpath.buf = xmalloc(baselen + filenamelen);\n+\t\tpath.alloc = baselen + filenamelen;\n+\t}\n+\tmemcpy(path.buf, base, baselen);\n+\tmemcpy(path.buf + baselen, filename, filenamelen);\n+\tpath.len = baselen + filenamelen;\n+\tif (S_ISDIR(mode)) {\n+\t\tstrbuf_append_string(&path, \"/\");\n+\t\tbuffer = NULL;\n+\t\tsize = 0;\n+\t} else {\n+\t\tbuffer = read_sha1_file(sha1, type, &size);\n+\t\tif (!buffer)\n+\t\t\tdie(\"cannot read %s\", sha1_to_hex(sha1));\n+\t}\n+\n+\twrite_entry(sha1, &path, mode, buffer, size);\n+\tfree(buffer);\n+\n+\treturn READ_TREE_RECURSIVE;\n+}\n+\n+int write_tar_archive(struct archiver_args *args)\n+{\n+\tint plen = args->base ? strlen(args->base) : 0;\n+\n+\tgit_config(git_tar_config);\n+\n+\tarchive_time = args->time;\n+\tverbose = args->verbose;\n+\n+\tif (args->commit_sha1)\n+\t\twrite_global_extended_header(args->commit_sha1);\n+\n+\tif (args->base && plen > 0 && args->base[plen - 1] == '/') {\n+\t\tchar *base = xstrdup(args->base);\n+\t\tint baselen = strlen(base);\n+\n+\t\twhile (baselen > 0 && base[baselen - 1] == '/')\n+\t\t\tbase[--baselen] = '\\0';\n+\t\twrite_tar_entry(args->tree->object.sha1, \"\", 0, base, 040777, 0);\n+\t\tfree(base);\n+\t}\n+\tread_tree_recursive(args->tree, args->base, plen, 0,\n+\t\t\t    args->pathspec, write_tar_entry);\n+\twrite_trailer();\n+\n+\treturn 0;\n+}\ndiff --git a/builtin-tar-tree.c b/builtin-tar-tree.c\nindex 82b4951..aa370e3 100644\n--- a/builtin-tar-tree.c\n+++ b/builtin-tar-tree.c\n@@ -4,7 +4,6 @@\n #include <time.h>\n #include \"cache.h\"\n #include \"commit.h\"\n-#include \"strbuf.h\"\n #include \"tar.h\"\n #include \"builtin.h\"\n #include \"pkt-line.h\"\n@@ -16,251 +15,6 @@ #define BLOCKSIZE\t(RECORDSIZE * 20)\n static const char tar_tree_usage[] =\n \"git-tar-tree [--remote=<repo>] <tree-ish> [basedir]\";\n \n-static char block[BLOCKSIZE];\n-static unsigned long offset;\n-\n-static time_t archive_time;\n-static int tar_umask;\n-static int verbose;\n-\n-/* writes out the whole block, but only if it is full */\n-static void write_if_needed(void)\n-{\n-\tif (offset == BLOCKSIZE) {\n-\t\twrite_or_die(1, block, BLOCKSIZE);\n-\t\toffset = 0;\n-\t}\n-}\n-\n-/*\n- * queues up writes, so that all our write(2) calls write exactly one\n- * full block; pads writes to RECORDSIZE\n- */\n-static void write_blocked(const void *data, unsigned long size)\n-{\n-\tconst char *buf = data;\n-\tunsigned long tail;\n-\n-\tif (offset) {\n-\t\tunsigned long chunk = BLOCKSIZE - offset;\n-\t\tif (size < chunk)\n-\t\t\tchunk = size;\n-\t\tmemcpy(block + offset, buf, chunk);\n-\t\tsize -= chunk;\n-\t\toffset += chunk;\n-\t\tbuf += chunk;\n-\t\twrite_if_needed();\n-\t}\n-\twhile (size >= BLOCKSIZE) {\n-\t\twrite_or_die(1, buf, BLOCKSIZE);\n-\t\tsize -= BLOCKSIZE;\n-\t\tbuf += BLOCKSIZE;\n-\t}\n-\tif (size) {\n-\t\tmemcpy(block + offset, buf, size);\n-\t\toffset += size;\n-\t}\n-\ttail = offset % RECORDSIZE;\n-\tif (tail)  {\n-\t\tmemset(block + offset, 0, RECORDSIZE - tail);\n-\t\toffset += RECORDSIZE - tail;\n-\t}\n-\twrite_if_needed();\n-}\n-\n-/*\n- * The end of tar archives is marked by 2*512 nul bytes and after that\n- * follows the rest of the block (if any).\n- */\n-static void write_trailer(void)\n-{\n-\tint tail = BLOCKSIZE - offset;\n-\tmemset(block + offset, 0, tail);\n-\twrite_or_die(1, block, BLOCKSIZE);\n-\tif (tail < 2 * RECORDSIZE) {\n-\t\tmemset(block, 0, offset);\n-\t\twrite_or_die(1, block, BLOCKSIZE);\n-\t}\n-}\n-\n-static void strbuf_append_string(struct strbuf *sb, const char *s)\n-{\n-\tint slen = strlen(s);\n-\tint total = sb->len + slen;\n-\tif (total > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total);\n-\t\tsb->alloc = total;\n-\t}\n-\tmemcpy(sb->buf + sb->len, s, slen);\n-\tsb->len = total;\n-}\n-\n-/*\n- * pax extended header records have the format \"%u %s=%s\\n\".  %u contains\n- * the size of the whole string (including the %u), the first %s is the\n- * keyword, the second one is the value.  This function constructs such a\n- * string and appends it to a struct strbuf.\n- */\n-static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,\n-                                     const char *value, unsigned int valuelen)\n-{\n-\tchar *p;\n-\tint len, total, tmp;\n-\n-\t/* \"%u %s=%s\\n\" */\n-\tlen = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;\n-\tfor (tmp = len; tmp > 9; tmp /= 10)\n-\t\tlen++;\n-\n-\ttotal = sb->len + len;\n-\tif (total > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total);\n-\t\tsb->alloc = total;\n-\t}\n-\n-\tp = sb->buf;\n-\tp += sprintf(p, \"%u %s=\", len, keyword);\n-\tmemcpy(p, value, valuelen);\n-\tp += valuelen;\n-\t*p = '\\n';\n-\tsb->len = total;\n-}\n-\n-static unsigned int ustar_header_chksum(const struct ustar_header *header)\n-{\n-\tchar *p = (char *)header;\n-\tunsigned int chksum = 0;\n-\twhile (p < header->chksum)\n-\t\tchksum += *p++;\n-\tchksum += sizeof(header->chksum) * ' ';\n-\tp += sizeof(header->chksum);\n-\twhile (p < (char *)header + sizeof(struct ustar_header))\n-\t\tchksum += *p++;\n-\treturn chksum;\n-}\n-\n-static int get_path_prefix(const struct strbuf *path, int maxlen)\n-{\n-\tint i = path->len;\n-\tif (i > maxlen)\n-\t\ti = maxlen;\n-\tdo {\n-\t\ti--;\n-\t} while (i > 0 && path->buf[i] != '/');\n-\treturn i;\n-}\n-\n-static void write_entry(const unsigned char *sha1, struct strbuf *path,\n-                        unsigned int mode, void *buffer, unsigned long size)\n-{\n-\tstruct ustar_header header;\n-\tstruct strbuf ext_header;\n-\n-\tmemset(&header, 0, sizeof(header));\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n-\n-\tif (!sha1) {\n-\t\t*header.typeflag = TYPEFLAG_GLOBAL_HEADER;\n-\t\tmode = 0100666;\n-\t\tstrcpy(header.name, \"pax_global_header\");\n-\t} else if (!path) {\n-\t\t*header.typeflag = TYPEFLAG_EXT_HEADER;\n-\t\tmode = 0100666;\n-\t\tsprintf(header.name, \"%s.paxheader\", sha1_to_hex(sha1));\n-\t} else {\n-\t\tif (verbose)\n-\t\t\tfprintf(stderr, \"%.*s\\n\", path->len, path->buf);\n-\t\tif (S_ISDIR(mode)) {\n-\t\t\t*header.typeflag = TYPEFLAG_DIR;\n-\t\t\tmode = (mode | 0777) & ~tar_umask;\n-\t\t} else if (S_ISLNK(mode)) {\n-\t\t\t*header.typeflag = TYPEFLAG_LNK;\n-\t\t\tmode |= 0777;\n-\t\t} else if (S_ISREG(mode)) {\n-\t\t\t*header.typeflag = TYPEFLAG_REG;\n-\t\t\tmode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;\n-\t\t} else {\n-\t\t\terror(\"unsupported file mode: 0%o (SHA1: %s)\",\n-\t\t\t      mode, sha1_to_hex(sha1));\n-\t\t\treturn;\n-\t\t}\n-\t\tif (path->len > sizeof(header.name)) {\n-\t\t\tint plen = get_path_prefix(path, sizeof(header.prefix));\n-\t\t\tint rest = path->len - plen - 1;\n-\t\t\tif (plen > 0 && rest <= sizeof(header.name)) {\n-\t\t\t\tmemcpy(header.prefix, path->buf, plen);\n-\t\t\t\tmemcpy(header.name, path->buf + plen + 1, rest);\n-\t\t\t} else {\n-\t\t\t\tsprintf(header.name, \"%s.data\",\n-\t\t\t\t        sha1_to_hex(sha1));\n-\t\t\t\tstrbuf_append_ext_header(&ext_header, \"path\",\n-\t\t\t\t                         path->buf, path->len);\n-\t\t\t}\n-\t\t} else\n-\t\t\tmemcpy(header.name, path->buf, path->len);\n-\t}\n-\n-\tif (S_ISLNK(mode) && buffer) {\n-\t\tif (size > sizeof(header.linkname)) {\n-\t\t\tsprintf(header.linkname, \"see %s.paxheader\",\n-\t\t\t        sha1_to_hex(sha1));\n-\t\t\tstrbuf_append_ext_header(&ext_header, \"linkpath\",\n-\t\t\t                         buffer, size);\n-\t\t} else\n-\t\t\tmemcpy(header.linkname, buffer, size);\n-\t}\n-\n-\tsprintf(header.mode, \"%07o\", mode & 07777);\n-\tsprintf(header.size, \"%011lo\", S_ISREG(mode) ? size : 0);\n-\tsprintf(header.mtime, \"%011lo\", archive_time);\n-\n-\t/* XXX: should we provide more meaningful info here? */\n-\tsprintf(header.uid, \"%07o\", 0);\n-\tsprintf(header.gid, \"%07o\", 0);\n-\tstrlcpy(header.uname, \"git\", sizeof(header.uname));\n-\tstrlcpy(header.gname, \"git\", sizeof(header.gname));\n-\tsprintf(header.devmajor, \"%07o\", 0);\n-\tsprintf(header.devminor, \"%07o\", 0);\n-\n-\tmemcpy(header.magic, \"ustar\", 6);\n-\tmemcpy(header.version, \"00\", 2);\n-\n-\tsprintf(header.chksum, \"%07o\", ustar_header_chksum(&header));\n-\n-\tif (ext_header.len > 0) {\n-\t\twrite_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);\n-\t\tfree(ext_header.buf);\n-\t}\n-\twrite_blocked(&header, sizeof(header));\n-\tif (S_ISREG(mode) && buffer && size > 0)\n-\t\twrite_blocked(buffer, size);\n-}\n-\n-static void write_global_extended_header(const unsigned char *sha1)\n-{\n-\tstruct strbuf ext_header;\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n-\tstrbuf_append_ext_header(&ext_header, \"comment\", sha1_to_hex(sha1), 40);\n-\twrite_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);\n-\tfree(ext_header.buf);\n-}\n-\n-static int git_tar_config(const char *var, const char *value)\n-{\n-\tif (!strcmp(var, \"tar.umask\")) {\n-\t\tif (!strcmp(value, \"user\")) {\n-\t\t\ttar_umask = umask(0);\n-\t\t\tumask(tar_umask);\n-\t\t} else {\n-\t\t\ttar_umask = git_config_int(var, value);\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\treturn git_default_config(var, value);\n-}\n-\n static int generate_tar(int argc, const char **argv, const char *prefix)\n {\n \tstruct archiver_args args;\n@@ -286,73 +40,6 @@ static int generate_tar(int argc, const \n \treturn result;\n }\n \n-static int write_tar_entry(const unsigned char *sha1,\n-                           const char *base, int baselen,\n-                           const char *filename, unsigned mode, int stage)\n-{\n-\tstatic struct strbuf path;\n-\tint filenamelen = strlen(filename);\n-\tvoid *buffer;\n-\tchar type[20];\n-\tunsigned long size;\n-\n-\tif (!path.alloc) {\n-\t\tpath.buf = xmalloc(PATH_MAX);\n-\t\tpath.alloc = PATH_MAX;\n-\t\tpath.len = path.eof = 0;\n-\t}\n-\tif (path.alloc < baselen + filenamelen) {\n-\t\tfree(path.buf);\n-\t\tpath.buf = xmalloc(baselen + filenamelen);\n-\t\tpath.alloc = baselen + filenamelen;\n-\t}\n-\tmemcpy(path.buf, base, baselen);\n-\tmemcpy(path.buf + baselen, filename, filenamelen);\n-\tpath.len = baselen + filenamelen;\n-\tif (S_ISDIR(mode)) {\n-\t\tstrbuf_append_string(&path, \"/\");\n-\t\tbuffer = NULL;\n-\t\tsize = 0;\n-\t} else {\n-\t\tbuffer = read_sha1_file(sha1, type, &size);\n-\t\tif (!buffer)\n-\t\t\tdie(\"cannot read %s\", sha1_to_hex(sha1));\n-\t}\n-\n-\twrite_entry(sha1, &path, mode, buffer, size);\n-\tfree(buffer);\n-\n-\treturn READ_TREE_RECURSIVE;\n-}\n-\n-int write_tar_archive(struct archiver_args *args)\n-{\n-\tint plen = args->base ? strlen(args->base) : 0;\n-\n-\tgit_config(git_tar_config);\n-\n-\tarchive_time = args->time;\n-\tverbose = args->verbose;\n-\n-\tif (args->commit_sha1)\n-\t\twrite_global_extended_header(args->commit_sha1);\n-\n-\tif (args->base && plen > 0 && args->base[plen - 1] == '/') {\n-\t\tchar *base = xstrdup(args->base);\n-\t\tint baselen = strlen(base);\n-\n-\t\twhile (baselen > 0 && base[baselen - 1] == '/')\n-\t\t\tbase[--baselen] = '\\0';\n-\t\twrite_tar_entry(args->tree->object.sha1, \"\", 0, base, 040777, 0);\n-\t\tfree(base);\n-\t}\n-\tread_tree_recursive(args->tree, args->base, plen, 0,\n-\t\t\t    args->pathspec, write_tar_entry);\n-\twrite_trailer();\n-\n-\treturn 0;\n-}\n-\n static const char *exec = \"git-upload-tar\";\n \n static int remote_tar(int argc, const char **argv)\n"},{"id":"27583","messageId":"7vr6y16iyk.fsf@assigned-by-dhcp.cox.net","threadId":"5673","inReplyTo":"4516A4BE.9090406@lsrfire.ath.cx","subject":"Re: [PATCH 2/2] git-tar-tree: Move code for git-archive --format=tar to archive-tar.c","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-09-24T21:41:23Z","receivedAt":"2006-09-24T21:41:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Rene Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n\n> This patch doesn't change any functionality, it only moves code around.  It\n> makes seeing the few remaining lines of git-tar-tree code easier. ;-)\n>\n> Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n\nThanks.  And here is an obvious follow-up to it.\n\n-- >8 --\n[PATCH] Remove upload-tar and make git-tar-tree a thin wrapper to git-archive\n\n---\ndiff --git a/.gitignore b/.gitignore\nindex 3ca66e4..284db5d 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -122,7 +122,6 @@ git-update-ref\n git-update-server-info\n git-upload-archive\n git-upload-pack\n-git-upload-tar\n git-var\n git-verify-pack\n git-verify-tag\ndiff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt\nindex 1e1c7fa..74a6fdd 100644\n--- a/Documentation/git-tar-tree.txt\n+++ b/Documentation/git-tar-tree.txt\n@@ -12,6 +12,9 @@ SYNOPSIS\n \n DESCRIPTION\n -----------\n+THIS COMMAND IS DEPRECATED.  Use `git-archive` with `--format=tar`\n+option instead.\n+\n Creates a tar archive containing the tree structure for the named tree.\n When <base> is specified it is added as a leading path to the files in the\n generated tar archive.\ndiff --git a/Documentation/git-upload-tar.txt b/Documentation/git-upload-tar.txt\ndeleted file mode 100644\nindex 394af62..0000000\n--- a/Documentation/git-upload-tar.txt\n+++ /dev/null\n@@ -1,39 +0,0 @@\n-git-upload-tar(1)\n-=================\n-\n-NAME\n-----\n-git-upload-tar - Send tar archive\n-\n-\n-SYNOPSIS\n---------\n-'git-upload-tar' <directory>\n-\n-DESCRIPTION\n------------\n-Invoked by 'git-tar-tree --remote' and sends a generated tar archive\n-to the other end over the git protocol.\n-\n-This command is usually not invoked directly by the end user.\n-The UI for the protocol is on the 'git-tar-tree' side, and the\n-program pair is meant to be used to get a tar archive from a\n-remote repository.\n-\n-\n-OPTIONS\n--------\n-<directory>::\n-\tThe repository to get a tar archive from.\n-\n-Author\n-------\n-Written by Junio C Hamano <junio@kernel.org>\n-\n-Documentation\n---------------\n-Documentation by Junio C Hamano.\n-\n-GIT\n----\n-Part of the gitlink:git[7] suite\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 744c38d..1bf5ef5 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -247,10 +247,6 @@ gitlink:git-upload-pack[1]::\n \tInvoked by 'git-fetch-pack' to push\n \twhat are asked for.\n \n-gitlink:git-upload-tar[1]::\n-\tInvoked by 'git-tar-tree --remote' to return the tar\n-\tarchive the other end asked for.\n-\n \n High-level commands (porcelain)\n -------------------------------\ndiff --git a/Makefile b/Makefile\nindex d4f6e01..35de011 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -298,7 +298,6 @@ BUILTIN_OBJS = \\\n \tbuiltin-update-index.o \\\n \tbuiltin-update-ref.o \\\n \tbuiltin-upload-archive.o \\\n-\tbuiltin-upload-tar.o \\\n \tbuiltin-verify-pack.o \\\n \tbuiltin-write-tree.o\n \ndiff --git a/builtin-tar-tree.c b/builtin-tar-tree.c\nindex aa370e3..5d2bec0 100644\n--- a/builtin-tar-tree.c\n+++ b/builtin-tar-tree.c\n@@ -8,94 +8,66 @@ #include \"tar.h\"\n #include \"builtin.h\"\n #include \"pkt-line.h\"\n #include \"archive.h\"\n-\n-#define RECORDSIZE\t(512)\n-#define BLOCKSIZE\t(RECORDSIZE * 20)\n+#include \"quote.h\"\n \n static const char tar_tree_usage[] =\n-\"git-tar-tree [--remote=<repo>] <tree-ish> [basedir]\";\n+\"git-tar-tree [--remote=<repo>] <tree-ish> [basedir]\\n\"\n+\"*** Note that this command is now deprecated; use git-archive instead.\";\n \n-static int generate_tar(int argc, const char **argv, const char *prefix)\n+int cmd_tar_tree(int argc, const char **argv, const char *prefix)\n {\n-\tstruct archiver_args args;\n-\tint result;\n-\tchar *base = NULL;\n-\n-\tmemset(&args, 0, sizeof(args));\n-\tif (argc != 2 && argc != 3)\n-\t\tusage(tar_tree_usage);\n-\tif (argc == 3) {\n-\t\tint baselen = strlen(argv[2]);\n-\t\tbase = xmalloc(baselen + 2);\n-\t\tmemcpy(base, argv[2], baselen);\n-\t\tbase[baselen] = '/';\n-\t\tbase[baselen + 1] = '\\0';\n+\t/*\n+\t * git-tar-tree is now a wrapper around git-archive --format=tar\n+\t *\n+\t * $0 --remote=<repo> arg... ==>\n+\t *\tgit-archive --format=tar --remote=<repo> arg...\n+\t * $0 tree-ish ==>\n+\t *\tgit-archive --format=tar tree-ish\n+\t * $0 tree-ish basedir ==>\n+\t * \tgit-archive --format-tar --prefix=basedir tree-ish\n+\t */ \n+\tint i;\n+\tconst char **nargv = xcalloc(sizeof(*nargv), argc + 2);\n+\tchar *basedir_arg;\n+\tint nargc = 0;\n+\n+\tnargv[nargc++] = \"git-archive\";\n+\tnargv[nargc++] = \"--format=tar\";\n+\n+\tif (2 <= argc && !strncmp(\"--remote=\", argv[1], 9)) {\n+\t\tnargv[nargc++] = argv[1];\n+\t\targv++;\n+\t\targc--;\n \t}\n-\targs.base = base;\n-\tparse_treeish_arg(argv + 1, &args, NULL);\n-\n-\tresult = write_tar_archive(&args);\n-\tfree(base);\n-\n-\treturn result;\n-}\n-\n-static const char *exec = \"git-upload-tar\";\n-\n-static int remote_tar(int argc, const char **argv)\n-{\n-\tint fd[2], ret, len;\n-\tpid_t pid;\n-\tchar buf[1024];\n-\tchar *url;\n-\n-\tif (argc < 3 || 4 < argc)\n+\tswitch (argc) {\n+\tdefault:\n \t\tusage(tar_tree_usage);\n-\n-\t/* --remote=<repo> */\n-\turl = xstrdup(argv[1]+9);\n-\tpid = git_connect(fd, url, exec);\n-\tif (pid < 0)\n-\t\treturn 1;\n-\n-\tpacket_write(fd[1], \"want %s\\n\", argv[2]);\n-\tif (argv[3])\n-\t\tpacket_write(fd[1], \"base %s\\n\", argv[3]);\n-\tpacket_flush(fd[1]);\n-\n-\tlen = packet_read_line(fd[0], buf, sizeof(buf));\n-\tif (!len)\n-\t\tdie(\"git-tar-tree: expected ACK/NAK, got EOF\");\n-\tif (buf[len-1] == '\\n')\n-\t\tbuf[--len] = 0;\n-\tif (strcmp(buf, \"ACK\")) {\n-\t\tif (5 < len && !strncmp(buf, \"NACK \", 5))\n-\t\t\tdie(\"git-tar-tree: NACK %s\", buf + 5);\n-\t\tdie(\"git-tar-tree: protocol error\");\n+\t\tbreak;\n+\tcase 3:\n+\t\t/* base-path */ \n+\t\tbasedir_arg = xmalloc(strlen(argv[2]) + 10);\n+\t\tsprintf(basedir_arg, \"--prefix=%s\", argv[2]);\n+\t\tnargv[nargc++] = basedir_arg;\n+\t\t/* fallthru */\n+\tcase 2:\n+\t\t/* tree-ish */\n+\t\tnargv[nargc++] = argv[1];\n \t}\n-\t/* expect a flush */\n-\tlen = packet_read_line(fd[0], buf, sizeof(buf));\n-\tif (len)\n-\t\tdie(\"git-tar-tree: expected a flush\");\n-\n-\t/* Now, start reading from fd[0] and spit it out to stdout */\n-\tret = copy_fd(fd[0], 1);\n-\tclose(fd[0]);\n-\n-\tret |= finish_connect(pid);\n-\treturn !!ret;\n-}\n-\n-int cmd_tar_tree(int argc, const char **argv, const char *prefix)\n-{\n-\tif (argc < 2)\n-\t\tusage(tar_tree_usage);\n-\tif (!strncmp(\"--remote=\", argv[1], 9))\n-\t\treturn remote_tar(argc, argv);\n-\treturn generate_tar(argc, argv, prefix);\n+\tnargv[nargc] = NULL;\n+\t\n+\tfprintf(stderr,\n+\t\t\"*** git-tar-tree is now deprecated.\\n\"\n+\t\t\"*** Running git-archive instead.\\n***\");\n+\tfor (i = 0; i < nargc; i++) {\n+\t\tfputc(' ', stderr);\n+\t\tsq_quote_print(stderr, nargv[i]);\n+\t}\n+\tfputc('\\n', stderr);\n+\treturn cmd_archive(nargc, nargv, prefix);\n }\n \n /* ustar header + extended global header content */\n+#define RECORDSIZE\t(512)\n #define HEADERSIZE (2 * RECORDSIZE)\n \n int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)\ndiff --git a/builtin-upload-tar.c b/builtin-upload-tar.c\ndeleted file mode 100644\nindex 06a945a..0000000\n--- a/builtin-upload-tar.c\n+++ /dev/null\n@@ -1,74 +0,0 @@\n-/*\n- * Copyright (c) 2006 Junio C Hamano\n- */\n-#include \"cache.h\"\n-#include \"pkt-line.h\"\n-#include \"exec_cmd.h\"\n-#include \"builtin.h\"\n-\n-static const char upload_tar_usage[] = \"git-upload-tar <repo>\";\n-\n-static int nak(const char *reason)\n-{\n-\tpacket_write(1, \"NACK %s\\n\", reason);\n-\tpacket_flush(1);\n-\treturn 1;\n-}\n-\n-int cmd_upload_tar(int argc, const char **argv, const char *prefix)\n-{\n-\tint len;\n-\tconst char *dir = argv[1];\n-\tchar buf[8192];\n-\tunsigned char sha1[20];\n-\tchar *base = NULL;\n-\tchar hex[41];\n-\tint ac;\n-\tconst char *av[4];\n-\n-\tif (argc != 2)\n-\t\tusage(upload_tar_usage);\n-\tif (strlen(dir) < sizeof(buf)-1)\n-\t\tstrcpy(buf, dir); /* enter-repo smudges its argument */\n-\telse\n-\t\tpacket_write(1, \"NACK insanely long repository name %s\\n\", dir);\n-\tif (!enter_repo(buf, 0)) {\n-\t\tpacket_write(1, \"NACK not a git archive %s\\n\", dir);\n-\t\tpacket_flush(1);\n-\t\treturn 1;\n-\t}\n-\n-\tlen = packet_read_line(0, buf, sizeof(buf));\n-\tif (len < 5 || strncmp(\"want \", buf, 5))\n-\t\treturn nak(\"expected want\");\n-\tif (buf[len-1] == '\\n')\n-\t\tbuf[--len] = 0;\n-\tif (get_sha1(buf + 5, sha1))\n-\t\treturn nak(\"expected sha1\");\n-        strcpy(hex, sha1_to_hex(sha1));\n-\n-\tlen = packet_read_line(0, buf, sizeof(buf));\n-\tif (len) {\n-\t\tif (len < 5 || strncmp(\"base \", buf, 5))\n-\t\t\treturn nak(\"expected (optional) base\");\n-\t\tif (buf[len-1] == '\\n')\n-\t\t\tbuf[--len] = 0;\n-\t\tbase = xstrdup(buf + 5);\n-\t\tlen = packet_read_line(0, buf, sizeof(buf));\n-\t}\n-\tif (len)\n-\t\treturn nak(\"expected flush\");\n-\n-\tpacket_write(1, \"ACK\\n\");\n-\tpacket_flush(1);\n-\n-\tac = 0;\n-\tav[ac++] = \"tar-tree\";\n-\tav[ac++] = hex;\n-\tif (base)\n-\t\tav[ac++] = base;\n-\tav[ac++] = NULL;\n-\texecv_git_cmd(av);\n-\t/* should it return that is an error */\n-\treturn 1;\n-}\ndiff --git a/git.c b/git.c\nindex 1686220..ae80e78 100644\n--- a/git.c\n+++ b/git.c\n@@ -263,7 +263,6 @@ static void handle_internal_command(int \n \t\t{ \"update-index\", cmd_update_index, RUN_SETUP },\n \t\t{ \"update-ref\", cmd_update_ref, RUN_SETUP },\n \t\t{ \"upload-archive\", cmd_upload_archive },\n-\t\t{ \"upload-tar\", cmd_upload_tar },\n \t\t{ \"version\", cmd_version },\n \t\t{ \"whatchanged\", cmd_whatchanged, RUN_SETUP | USE_PAGER },\n \t\t{ \"write-tree\", cmd_write_tree, RUN_SETUP },\n"},{"id":"27588","messageId":"4517048F.9040007@lsrfire.ath.cx","threadId":"5673","inReplyTo":"7vr6y16iyk.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] git-tar-tree: Move code for git-archive --format=tar to archive-tar.c","fromName":"Rene Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2006-09-24T22:19:59Z","receivedAt":"2006-09-24T22:19:59Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Junio C Hamano schrieb:\n> Rene Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n> \n>> This patch doesn't change any functionality, it only moves code around.  It\n>> makes seeing the few remaining lines of git-tar-tree code easier. ;-)\n>>\n>> Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n> \n> Thanks.  And here is an obvious follow-up to it.\n> \n> -- >8 --\n> [PATCH] Remove upload-tar and make git-tar-tree a thin wrapper to git-archive\n\nOK.\n\n> diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c\n> index aa370e3..5d2bec0 100644\n> --- a/builtin-tar-tree.c\n> +++ b/builtin-tar-tree.c\n> @@ -8,94 +8,66 @@ #include \"tar.h\"\n>  #include \"builtin.h\"\n>  #include \"pkt-line.h\"\n>  #include \"archive.h\"\n\nAt least the last two header references aren't needed any more.\n\n> -\tif (argc == 3) {\n> -\t\tint baselen = strlen(argv[2]);\n> -\t\tbase = xmalloc(baselen + 2);\n> -\t\tmemcpy(base, argv[2], baselen);\n> -\t\tbase[baselen] = '/';\n> -\t\tbase[baselen + 1] = '\\0';\n[...]\n> +\tcase 3:\n> +\t\t/* base-path */ \n> +\t\tbasedir_arg = xmalloc(strlen(argv[2]) + 10);\n> +\t\tsprintf(basedir_arg, \"--prefix=%s\", argv[2]);\n> +\t\tnargv[nargc++] = basedir_arg;\n\nTraditionally we always added a slash to the git-tar-tree base\nparameter, forcing it to always be a base _directory_.  git-archive\nin contrast to that simply adds the prefix to the paths; users have\nto provide their own slash.  This is consistent with how we handle\n--prefix parameters elsewhere.  It also means that the sprintf\nformat string here should be \"--prefix=%s/\" (and allocate one more\nbyte the line before).\n\n> +\tfprintf(stderr,\n> +\t\t\"*** git-tar-tree is now deprecated.\\n\"\n> +\t\t\"*** Running git-archive instead.\\n***\");\n> +\tfor (i = 0; i < nargc; i++) {\n> +\t\tfputc(' ', stderr);\n> +\t\tsq_quote_print(stderr, nargv[i]);\n> +\t}\n> +\tfputc('\\n', stderr);\n\nHey, scary message. ;-)  It certainly will aid the re-education of\nour users, so I think it's OK.\n\nThanks,\nRené\n"}]}