{"thread":{"id":"26784","subject":"vcs-svn: purge obsolete data structures and code","startedAt":"2011-03-19T07:03:42Z","lastAt":"2011-03-28T20:44:03Z","messageCount":72,"participants":["David Barr","Jonathan Nieder","Junio C Hamano","tb","Torsten Bögershausen"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"163701","messageId":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":null,"subject":"vcs-svn: purge obsolete data structures and code","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:42Z","receivedAt":"2011-03-19T07:03:42Z","isPatch":false,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Patches 1-8:\nNow that vcs-svn delegates tracking the repository structure to\nfast-import, reorganise the code and drop the internal data\nstructures and supporting code.\n\nPatch 9:\nOne final optimisation jumps out after the clean up, apply it.\n\n .gitignore              |    3 -\n Makefile                |   13 +--\n t/t0080-vcs-svn.sh      |  117 ---------------------\n test-obj-pool.c         |  116 ---------------------\n test-string-pool.c      |   31 ------\n test-treap.c            |   70 -------------\n vcs-svn/LICENSE         |    3 -\n vcs-svn/fast_export.c   |   64 ++++++------\n vcs-svn/fast_export.h   |   14 ++--\n vcs-svn/obj_pool.h      |   61 -----------\n vcs-svn/repo_tree.c     |   36 ++-----\n vcs-svn/repo_tree.h     |   12 +--\n vcs-svn/string_pool.c   |  113 --------------------\n vcs-svn/string_pool.h   |   12 --\n vcs-svn/string_pool.txt |   43 --------\n vcs-svn/svndump.c       |  260 ++++++++++++++++++++++++++---------------------\n vcs-svn/trp.h           |  237 ------------------------------------------\n vcs-svn/trp.txt         |  109 --------------------\n 18 files changed, 197 insertions(+), 1117 deletions(-)\n"},{"id":"163710","messageId":"1300518231-20008-2-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 1/9] vcs-svn: pass paths through to fast-import","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:43Z","receivedAt":"2011-03-19T07:03:43Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Now that there is no internal representation of the repo,\nit is not necessary to tokenise paths.\n\nUse strbuf instead and bypass string_pool.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/fast_export.c |   47 ++++++++++++++++++------------------\n vcs-svn/fast_export.h |    9 +++----\n vcs-svn/repo_tree.c   |   20 +++++++-------\n vcs-svn/repo_tree.h   |   13 ++++------\n vcs-svn/svndump.c     |   63 +++++++++++++++++++++----------------------------\n 5 files changed, 70 insertions(+), 82 deletions(-)\n\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex f19db9a..bb5e9aa 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -4,6 +4,8 @@\n  */\n \n #include \"git-compat-util.h\"\n+#include \"strbuf.h\"\n+#include \"quote.h\"\n #include \"fast_export.h\"\n #include \"line_buffer.h\"\n #include \"repo_tree.h\"\n@@ -32,30 +34,30 @@ void fast_export_reset(void)\n \tbuffer_reset(&report_buffer);\n }\n \n-void fast_export_delete(uint32_t depth, const uint32_t *path)\n+void fast_export_delete(const char *path)\n {\n-\tprintf(\"D \\\"\");\n-\tpool_print_seq_q(depth, path, '/', stdout);\n-\tprintf(\"\\\"\\n\");\n+\tputchar('D');\n+\tputchar(' ');\n+\tquote_c_style(path, NULL, stdout, 0);\n+\tputchar('\\n');\n }\n \n-static void fast_export_truncate(uint32_t depth, const uint32_t *path, uint32_t mode)\n+static void fast_export_truncate(const char *path, uint32_t mode)\n {\n-\tfast_export_modify(depth, path, mode, \"inline\");\n+\tfast_export_modify(path, mode, \"inline\");\n \tprintf(\"data 0\\n\\n\");\n }\n \n-void fast_export_modify(uint32_t depth, const uint32_t *path, uint32_t mode,\n-\t\t\tconst char *dataref)\n+void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n {\n \t/* Mode must be 100644, 100755, 120000, or 160000. */\n \tif (!dataref) {\n-\t\tfast_export_truncate(depth, path, mode);\n+\t\tfast_export_truncate(path, mode);\n \t\treturn;\n \t}\n-\tprintf(\"M %06\"PRIo32\" %s \\\"\", mode, dataref);\n-\tpool_print_seq_q(depth, path, '/', stdout);\n-\tprintf(\"\\\"\\n\");\n+\tprintf(\"M %06\"PRIo32\" %s \", mode, dataref);\n+\tquote_c_style(path, NULL, stdout, 0);\n+\tputchar('\\n');\n }\n \n static char gitsvnline[MAX_GITSVN_LINE_LEN];\n@@ -93,20 +95,20 @@ void fast_export_end_commit(uint32_t revision)\n \tprintf(\"progress Imported commit %\"PRIu32\".\\n\\n\", revision);\n }\n \n-static void ls_from_rev(uint32_t rev, uint32_t depth, const uint32_t *path)\n+static void ls_from_rev(uint32_t rev, const char *path)\n {\n \t/* ls :5 path/to/old/file */\n-\tprintf(\"ls :%\"PRIu32\" \\\"\", rev);\n-\tpool_print_seq_q(depth, path, '/', stdout);\n-\tprintf(\"\\\"\\n\");\n+\tprintf(\"ls :%\"PRIu32\" \", rev);\n+\tquote_c_style(path, NULL, stdout, 0);\n+\tputchar('\\n');\n \tfflush(stdout);\n }\n \n-static void ls_from_active_commit(uint32_t depth, const uint32_t *path)\n+static void ls_from_active_commit(const char *path)\n {\n \t/* ls \"path/to/file\" */\n \tprintf(\"ls \\\"\");\n-\tpool_print_seq_q(depth, path, '/', stdout);\n+\tquote_c_style(path, NULL, stdout, 1);\n \tprintf(\"\\\"\\n\");\n \tfflush(stdout);\n }\n@@ -174,16 +176,15 @@ static int parse_ls_response(const char *response, uint32_t *mode,\n \treturn 0;\n }\n \n-int fast_export_ls_rev(uint32_t rev, uint32_t depth, const uint32_t *path,\n+int fast_export_ls_rev(uint32_t rev, const char *path,\n \t\t\t\tuint32_t *mode, struct strbuf *dataref)\n {\n-\tls_from_rev(rev, depth, path);\n+\tls_from_rev(rev, path);\n \treturn parse_ls_response(get_response_line(), mode, dataref);\n }\n \n-int fast_export_ls(uint32_t depth, const uint32_t *path,\n-\t\t\t\tuint32_t *mode, struct strbuf *dataref)\n+int fast_export_ls(const char *path, uint32_t *mode, struct strbuf *dataref)\n {\n-\tls_from_active_commit(depth, path);\n+\tls_from_active_commit(path);\n \treturn parse_ls_response(get_response_line(), mode, dataref);\n }\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex 633d219..a47c609 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -8,18 +8,17 @@ void fast_export_init(int fd);\n void fast_export_deinit(void);\n void fast_export_reset(void);\n \n-void fast_export_delete(uint32_t depth, const uint32_t *path);\n-void fast_export_modify(uint32_t depth, const uint32_t *path,\n-\t\t\tuint32_t mode, const char *dataref);\n+void fast_export_delete(const char *path);\n+void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,\n \t\t\tuint32_t uuid, uint32_t url, unsigned long timestamp);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input);\n \n /* If there is no such file at that rev, returns -1, errno == ENOENT. */\n-int fast_export_ls_rev(uint32_t rev, uint32_t depth, const uint32_t *path,\n+int fast_export_ls_rev(uint32_t rev, const char *path,\n \t\t\tuint32_t *mode_out, struct strbuf *dataref_out);\n-int fast_export_ls(uint32_t depth, const uint32_t *path,\n+int fast_export_ls(const char *path,\n \t\t\tuint32_t *mode_out, struct strbuf *dataref_out);\n \n #endif\ndiff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c\nindex e75f580..f2466bc 100644\n--- a/vcs-svn/repo_tree.c\n+++ b/vcs-svn/repo_tree.c\n@@ -8,14 +8,14 @@\n #include \"repo_tree.h\"\n #include \"fast_export.h\"\n \n-const char *repo_read_path(const uint32_t *path)\n+const char *repo_read_path(const char *path)\n {\n \tint err;\n \tuint32_t dummy;\n \tstatic struct strbuf buf = STRBUF_INIT;\n \n \tstrbuf_reset(&buf);\n-\terr = fast_export_ls(REPO_MAX_PATH_DEPTH, path, &dummy, &buf);\n+\terr = fast_export_ls(path, &dummy, &buf);\n \tif (err) {\n \t\tif (errno != ENOENT)\n \t\t\tdie_errno(\"BUG: unexpected fast_export_ls error\");\n@@ -24,14 +24,14 @@ const char *repo_read_path(const uint32_t *path)\n \treturn buf.buf;\n }\n \n-uint32_t repo_read_mode(const uint32_t *path)\n+uint32_t repo_read_mode(const char *path)\n {\n \tint err;\n \tuint32_t result;\n \tstatic struct strbuf dummy = STRBUF_INIT;\n \n \tstrbuf_reset(&dummy);\n-\terr = fast_export_ls(REPO_MAX_PATH_DEPTH, path, &result, &dummy);\n+\terr = fast_export_ls(path, &result, &dummy);\n \tif (err) {\n \t\tif (errno != ENOENT)\n \t\t\tdie_errno(\"BUG: unexpected fast_export_ls error\");\n@@ -41,24 +41,24 @@ uint32_t repo_read_mode(const uint32_t *path)\n \treturn result;\n }\n \n-void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst)\n+void repo_copy(uint32_t revision, const char *src, const char *dst)\n {\n \tint err;\n \tuint32_t mode;\n \tstatic struct strbuf data = STRBUF_INIT;\n \n \tstrbuf_reset(&data);\n-\terr = fast_export_ls_rev(revision, REPO_MAX_PATH_DEPTH, src, &mode, &data);\n+\terr = fast_export_ls_rev(revision, src, &mode, &data);\n \tif (err) {\n \t\tif (errno != ENOENT)\n \t\t\tdie_errno(\"BUG: unexpected fast_export_ls_rev error\");\n-\t\tfast_export_delete(REPO_MAX_PATH_DEPTH, dst);\n+\t\tfast_export_delete(dst);\n \t\treturn;\n \t}\n-\tfast_export_modify(REPO_MAX_PATH_DEPTH, dst, mode, data.buf);\n+\tfast_export_modify(dst, mode, data.buf);\n }\n \n-void repo_delete(uint32_t *path)\n+void repo_delete(const char *path)\n {\n-\tfast_export_delete(REPO_MAX_PATH_DEPTH, path);\n+\tfast_export_delete(path);\n }\ndiff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h\nindex d690784..af2415c 100644\n--- a/vcs-svn/repo_tree.h\n+++ b/vcs-svn/repo_tree.h\n@@ -8,15 +8,12 @@\n #define REPO_MODE_EXE 0100755\n #define REPO_MODE_LNK 0120000\n \n-#define REPO_MAX_PATH_LEN 4096\n-#define REPO_MAX_PATH_DEPTH 1000\n-\n uint32_t next_blob_mark(void);\n-void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst);\n-void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark);\n-const char *repo_read_path(const uint32_t *path);\n-uint32_t repo_read_mode(const uint32_t *path);\n-void repo_delete(uint32_t *path);\n+void repo_copy(uint32_t revision, const char *src, const char *dst);\n+void repo_add(const char *path, uint32_t mode, uint32_t blob_mark);\n+const char *repo_read_path(const char *path);\n+uint32_t repo_read_mode(const char *path);\n+void repo_delete(const char *path);\n void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,\n \t\t uint32_t url, long unsigned timestamp);\n void repo_diff(uint32_t r1, uint32_t r2);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 7ecb227..afdfc63 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -11,8 +11,8 @@\n #include \"repo_tree.h\"\n #include \"fast_export.h\"\n #include \"line_buffer.h\"\n-#include \"obj_pool.h\"\n #include \"string_pool.h\"\n+#include \"strbuf.h\"\n \n #define REPORT_FILENO 3\n \n@@ -31,32 +31,20 @@\n #define LENGTH_UNKNOWN (~0)\n #define DATE_RFC2822_LEN 31\n \n-/* Create memory pool for log messages */\n-obj_pool_gen(log, char, 4096)\n-\n static struct line_buffer input = LINE_BUFFER_INIT;\n \n #define REPORT_FILENO 3\n \n-static char *log_copy(uint32_t length, const char *log)\n-{\n-\tchar *buffer;\n-\tlog_free(log_pool.size);\n-\tbuffer = log_pointer(log_alloc(length));\n-\tstrncpy(buffer, log, length);\n-\treturn buffer;\n-}\n-\n static struct {\n \tuint32_t action, propLength, textLength, srcRev, type;\n-\tuint32_t src[REPO_MAX_PATH_DEPTH], dst[REPO_MAX_PATH_DEPTH];\n+\tstruct strbuf src, dst;\n \tuint32_t text_delta, prop_delta;\n } node_ctx;\n \n static struct {\n \tuint32_t revision, author;\n \tunsigned long timestamp;\n-\tchar *log;\n+\tstruct strbuf log;\n } rev_ctx;\n \n static struct {\n@@ -78,9 +66,11 @@ static void reset_node_ctx(char *fname)\n \tnode_ctx.action = NODEACT_UNKNOWN;\n \tnode_ctx.propLength = LENGTH_UNKNOWN;\n \tnode_ctx.textLength = LENGTH_UNKNOWN;\n-\tnode_ctx.src[0] = ~0;\n+\tstrbuf_reset(&node_ctx.src);\n \tnode_ctx.srcRev = 0;\n-\tpool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.dst, \"/\", fname);\n+\tstrbuf_reset(&node_ctx.dst);\n+\tif (fname)\n+\t\tstrbuf_addstr(&node_ctx.dst, fname);\n \tnode_ctx.text_delta = 0;\n \tnode_ctx.prop_delta = 0;\n }\n@@ -89,7 +79,7 @@ static void reset_rev_ctx(uint32_t revision)\n {\n \trev_ctx.revision = revision;\n \trev_ctx.timestamp = 0;\n-\trev_ctx.log = NULL;\n+\tstrbuf_reset(&rev_ctx.log);\n \trev_ctx.author = ~0;\n }\n \n@@ -130,7 +120,7 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:log\");\n \t\t/* Value length excludes terminating nul. */\n-\t\trev_ctx.log = log_copy(len + 1, val);\n+\t\tstrbuf_add(&rev_ctx.log, val, len + 1);\n \t} else if (key == keys.svn_author) {\n \t\trev_ctx.author = pool_intern(val);\n \t} else if (key == keys.svn_date) {\n@@ -223,14 +213,14 @@ static void handle_node(void)\n \t\tif (have_text || have_props || node_ctx.srcRev)\n \t\t\tdie(\"invalid dump: deletion node has \"\n \t\t\t\t\"copyfrom info, text, or properties\");\n-\t\treturn repo_delete(node_ctx.dst);\n+\t\treturn repo_delete(node_ctx.dst.buf);\n \t}\n \tif (node_ctx.action == NODEACT_REPLACE) {\n-\t\trepo_delete(node_ctx.dst);\n+\t\trepo_delete(node_ctx.dst.buf);\n \t\tnode_ctx.action = NODEACT_ADD;\n \t}\n \tif (node_ctx.srcRev) {\n-\t\trepo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst);\n+\t\trepo_copy(node_ctx.srcRev, node_ctx.src.buf, node_ctx.dst.buf);\n \t\tif (node_ctx.action == NODEACT_ADD)\n \t\t\tnode_ctx.action = NODEACT_CHANGE;\n \t}\n@@ -240,14 +230,14 @@ static void handle_node(void)\n \t/*\n \t * Find old content (old_data) and decide on the new mode.\n \t */\n-\tif (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) {\n+\tif (node_ctx.action == NODEACT_CHANGE && !*node_ctx.dst.buf) {\n \t\tif (type != REPO_MODE_DIR)\n \t\t\tdie(\"invalid dump: root of tree is not a regular file\");\n \t\told_data = NULL;\n \t} else if (node_ctx.action == NODEACT_CHANGE) {\n \t\tuint32_t mode;\n-\t\told_data = repo_read_path(node_ctx.dst);\n-\t\tmode = repo_read_mode(node_ctx.dst);\n+\t\told_data = repo_read_path(node_ctx.dst.buf);\n+\t\tmode = repo_read_mode(node_ctx.dst.buf);\n \t\tif (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)\n \t\t\tdie(\"invalid dump: cannot modify a directory into a file\");\n \t\tif (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)\n@@ -284,12 +274,10 @@ static void handle_node(void)\n \t\t/* For the fast_export_* functions, NULL means empty. */\n \t\told_data = NULL;\n \tif (!have_text) {\n-\t\tfast_export_modify(REPO_MAX_PATH_DEPTH, node_ctx.dst,\n-\t\t\t\t\tnode_ctx.type, old_data);\n+\t\tfast_export_modify(node_ctx.dst.buf, node_ctx.type, old_data);\n \t\treturn;\n \t}\n-\tfast_export_modify(REPO_MAX_PATH_DEPTH, node_ctx.dst,\n-\t\t\t\tnode_ctx.type, \"inline\");\n+\tfast_export_modify(node_ctx.dst.buf, node_ctx.type, \"inline\");\n \tfast_export_data(node_ctx.type, node_ctx.textLength, &input);\n }\n \n@@ -297,7 +285,7 @@ static void begin_revision(void)\n {\n \tif (!rev_ctx.revision)\t/* revision 0 gets no git commit. */\n \t\treturn;\n-\tfast_export_begin_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log,\n+\tfast_export_begin_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log.buf,\n \t\tdump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);\n }\n \n@@ -368,7 +356,8 @@ void svndump_read(const char *url)\n \t\t\t\tnode_ctx.action = NODEACT_UNKNOWN;\n \t\t\t}\n \t\t} else if (key == keys.node_copyfrom_path) {\n-\t\t\tpool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.src, \"/\", val);\n+\t\t\tstrbuf_reset(&node_ctx.src);\n+\t\t\tstrbuf_addstr(&node_ctx.src, val);\n \t\t} else if (key == keys.node_copyfrom_rev) {\n \t\t\tnode_ctx.srcRev = atoi(val);\n \t\t} else if (key == keys.text_content_length) {\n@@ -406,6 +395,9 @@ int svndump_init(const char *filename)\n \tif (buffer_init(&input, filename))\n \t\treturn error(\"cannot open %s: %s\", filename, strerror(errno));\n \tfast_export_init(REPORT_FILENO);\n+\tstrbuf_init(&rev_ctx.log, 4096);\n+\tstrbuf_init(&node_ctx.src, 4096);\n+\tstrbuf_init(&node_ctx.dst, 4096);\n \treset_dump_ctx(~0);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n@@ -415,11 +407,13 @@ int svndump_init(const char *filename)\n \n void svndump_deinit(void)\n {\n-\tlog_reset();\n \tfast_export_deinit();\n \treset_dump_ctx(~0);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n+\tstrbuf_release(&rev_ctx.log);\n+\tstrbuf_release(&node_ctx.src);\n+\tstrbuf_release(&node_ctx.dst);\n \tif (buffer_deinit(&input))\n \t\tfprintf(stderr, \"Input error\\n\");\n \tif (ferror(stdout))\n@@ -428,10 +422,7 @@ void svndump_deinit(void)\n \n void svndump_reset(void)\n {\n-\tlog_reset();\n \tfast_export_reset();\n \tbuffer_reset(&input);\n-\treset_dump_ctx(~0);\n-\treset_rev_ctx(0);\n-\treset_node_ctx(NULL);\n+\tpool_reset();\n }\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163703","messageId":"1300518231-20008-3-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 2/9] vcs-svn: avoid using ls command twice","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:44Z","receivedAt":"2011-03-19T07:03:44Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Signed-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/repo_tree.c |   24 ++++--------------------\n vcs-svn/repo_tree.h |    3 +--\n vcs-svn/svndump.c   |    3 +--\n 3 files changed, 6 insertions(+), 24 deletions(-)\n\ndiff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c\nindex f2466bc..67d27f0 100644\n--- a/vcs-svn/repo_tree.c\n+++ b/vcs-svn/repo_tree.c\n@@ -8,39 +8,23 @@\n #include \"repo_tree.h\"\n #include \"fast_export.h\"\n \n-const char *repo_read_path(const char *path)\n+const char *repo_read_path(const char *path, uint32_t *mode_out)\n {\n \tint err;\n-\tuint32_t dummy;\n \tstatic struct strbuf buf = STRBUF_INIT;\n \n \tstrbuf_reset(&buf);\n-\terr = fast_export_ls(path, &dummy, &buf);\n+\terr = fast_export_ls(path, mode_out, &buf);\n \tif (err) {\n \t\tif (errno != ENOENT)\n \t\t\tdie_errno(\"BUG: unexpected fast_export_ls error\");\n+\t\t/* Treat missing paths as directories. */\n+\t\t*mode_out = REPO_MODE_DIR;\n \t\treturn NULL;\n \t}\n \treturn buf.buf;\n }\n \n-uint32_t repo_read_mode(const char *path)\n-{\n-\tint err;\n-\tuint32_t result;\n-\tstatic struct strbuf dummy = STRBUF_INIT;\n-\n-\tstrbuf_reset(&dummy);\n-\terr = fast_export_ls(path, &result, &dummy);\n-\tif (err) {\n-\t\tif (errno != ENOENT)\n-\t\t\tdie_errno(\"BUG: unexpected fast_export_ls error\");\n-\t\t/* Treat missing paths as directories. */\n-\t\treturn REPO_MODE_DIR;\n-\t}\n-\treturn result;\n-}\n-\n void repo_copy(uint32_t revision, const char *src, const char *dst)\n {\n \tint err;\ndiff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h\nindex af2415c..eb003e6 100644\n--- a/vcs-svn/repo_tree.h\n+++ b/vcs-svn/repo_tree.h\n@@ -11,8 +11,7 @@\n uint32_t next_blob_mark(void);\n void repo_copy(uint32_t revision, const char *src, const char *dst);\n void repo_add(const char *path, uint32_t mode, uint32_t blob_mark);\n-const char *repo_read_path(const char *path);\n-uint32_t repo_read_mode(const char *path);\n+const char *repo_read_path(const char *path, uint32_t *mode_out);\n void repo_delete(const char *path);\n void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,\n \t\t uint32_t url, long unsigned timestamp);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex afdfc63..15b173e 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -236,8 +236,7 @@ static void handle_node(void)\n \t\told_data = NULL;\n \t} else if (node_ctx.action == NODEACT_CHANGE) {\n \t\tuint32_t mode;\n-\t\told_data = repo_read_path(node_ctx.dst.buf);\n-\t\tmode = repo_read_mode(node_ctx.dst.buf);\n+\t\told_data = repo_read_path(node_ctx.dst.buf, &mode);\n \t\tif (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)\n \t\t\tdie(\"invalid dump: cannot modify a directory into a file\");\n \t\tif (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163702","messageId":"1300518231-20008-4-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 3/9] vcs-svn: implement perfect hash for node-prop keys","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:45Z","receivedAt":"2011-03-19T07:03:45Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This eliminates one more dependency on string_pool.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndump.c |   50 ++++++++++++++++++++++++++++++++------------------\n 1 files changed, 32 insertions(+), 18 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 15b173e..49fb6db 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -52,8 +52,7 @@ static struct {\n } dump_ctx;\n \n static struct {\n-\tuint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid,\n-\t\trevision_number, node_path, node_kind, node_action,\n+\tuint32_t uuid, revision_number, node_path, node_kind, node_action,\n \t\tnode_copyfrom_path, node_copyfrom_rev, text_content_length,\n \t\tprop_content_length, content_length, svn_fs_dump_format_version,\n \t\t/* version 3 format */\n@@ -92,11 +91,6 @@ static void reset_dump_ctx(uint32_t url)\n \n static void init_keys(void)\n {\n-\tkeys.svn_log = pool_intern(\"svn:log\");\n-\tkeys.svn_author = pool_intern(\"svn:author\");\n-\tkeys.svn_date = pool_intern(\"svn:date\");\n-\tkeys.svn_executable = pool_intern(\"svn:executable\");\n-\tkeys.svn_special = pool_intern(\"svn:special\");\n \tkeys.uuid = pool_intern(\"UUID\");\n \tkeys.revision_number = pool_intern(\"Revision-number\");\n \tkeys.node_path = pool_intern(\"Node-path\");\n@@ -113,22 +107,38 @@ static void init_keys(void)\n \tkeys.prop_delta = pool_intern(\"Prop-delta\");\n }\n \n-static void handle_property(uint32_t key, const char *val, uint32_t len,\n+static void handle_property(const char *key, const char *val, uint32_t len,\n \t\t\t\tuint32_t *type_set)\n {\n-\tif (key == keys.svn_log) {\n+\tconst int key_len = strlen(key);\n+\tswitch (key_len) {\n+\tcase 7:\n+\t\tif (memcmp(key, \"svn:log\", 7))\n+\t\t\tbreak;\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:log\");\n \t\t/* Value length excludes terminating nul. */\n \t\tstrbuf_add(&rev_ctx.log, val, len + 1);\n-\t} else if (key == keys.svn_author) {\n+\t\tbreak;\n+\tcase 10:\n+\t\tif (memcmp(key, \"svn:author\", 10))\n+\t\t\tbreak;\n \t\trev_ctx.author = pool_intern(val);\n-\t} else if (key == keys.svn_date) {\n+\t\tbreak;\n+\tcase 8:\n+\t\tif (memcmp(key, \"svn:date\", 8))\n+\t\t\tbreak;\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:date\");\n \t\tif (parse_date_basic(val, &rev_ctx.timestamp, NULL))\n \t\t\twarning(\"invalid timestamp: %s\", val);\n-\t} else if (key == keys.svn_executable || key == keys.svn_special) {\n+\t\tbreak;\n+\tcase 14:\n+\t\tif (memcmp(key, \"svn:executable\", 14))\n+\t\t\tbreak;\n+\tcase 11:\n+\t\tif (key_len == 11 && memcmp(key, \"svn:special\", 11))\n+\t\t\tbreak;\n \t\tif (*type_set) {\n \t\t\tif (!val)\n \t\t\t\treturn;\n@@ -139,7 +149,7 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,\n \t\t\treturn;\n \t\t}\n \t\t*type_set = 1;\n-\t\tnode_ctx.type = key == keys.svn_executable ?\n+\t\tnode_ctx.type = key_len == strlen(\"svn:executable\") ?\n \t\t\t\tREPO_MODE_EXE :\n \t\t\t\tREPO_MODE_LNK;\n \t}\n@@ -147,7 +157,7 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,\n \n static void read_props(void)\n {\n-\tuint32_t key = ~0;\n+\tchar key[16] = {0};\n \tconst char *t;\n \t/*\n \t * NEEDSWORK: to support simple mode changes like\n@@ -175,16 +185,20 @@ static void read_props(void)\n \n \t\tswitch (type) {\n \t\tcase 'K':\n-\t\t\tkey = pool_intern(val);\n-\t\t\tcontinue;\n \t\tcase 'D':\n-\t\t\tkey = pool_intern(val);\n+\t\t\tif (len < sizeof(key))\n+\t\t\t\tmemcpy(key, val, len + 1);\n+\t\t\telse\t/* nonstandard key. */\n+\t\t\t\t*key = '\\0';\n+\t\t\tif (type == 'K')\n+\t\t\t\tcontinue;\n+\t\t\tassert(type == 'D');\n \t\t\tval = NULL;\n \t\t\tlen = 0;\n \t\t\t/* fall through */\n \t\tcase 'V':\n \t\t\thandle_property(key, val, len, &type_set);\n-\t\t\tkey = ~0;\n+\t\t\t*key = '\\0';\n \t\t\tcontinue;\n \t\tdefault:\n \t\t\tdie(\"invalid property line: %s\\n\", t);\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163706","messageId":"1300518231-20008-5-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 4/9] vcs-svn: implement perfect hash for top-level keys","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:46Z","receivedAt":"2011-03-19T07:03:46Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This eliminates one more dependency on string_pool.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndump.c |  110 +++++++++++++++++++++++++++++------------------------\n 1 files changed, 60 insertions(+), 50 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 49fb6db..03f916d 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -51,14 +51,6 @@ static struct {\n \tuint32_t version, uuid, url;\n } dump_ctx;\n \n-static struct {\n-\tuint32_t uuid, revision_number, node_path, node_kind, node_action,\n-\t\tnode_copyfrom_path, node_copyfrom_rev, text_content_length,\n-\t\tprop_content_length, content_length, svn_fs_dump_format_version,\n-\t\t/* version 3 format */\n-\t\ttext_delta, prop_delta;\n-} keys;\n-\n static void reset_node_ctx(char *fname)\n {\n \tnode_ctx.type = 0;\n@@ -89,24 +81,6 @@ static void reset_dump_ctx(uint32_t url)\n \tdump_ctx.uuid = ~0;\n }\n \n-static void init_keys(void)\n-{\n-\tkeys.uuid = pool_intern(\"UUID\");\n-\tkeys.revision_number = pool_intern(\"Revision-number\");\n-\tkeys.node_path = pool_intern(\"Node-path\");\n-\tkeys.node_kind = pool_intern(\"Node-kind\");\n-\tkeys.node_action = pool_intern(\"Node-action\");\n-\tkeys.node_copyfrom_path = pool_intern(\"Node-copyfrom-path\");\n-\tkeys.node_copyfrom_rev = pool_intern(\"Node-copyfrom-rev\");\n-\tkeys.text_content_length = pool_intern(\"Text-content-length\");\n-\tkeys.prop_content_length = pool_intern(\"Prop-content-length\");\n-\tkeys.content_length = pool_intern(\"Content-length\");\n-\tkeys.svn_fs_dump_format_version = pool_intern(\"SVN-fs-dump-format-version\");\n-\t/* version 3 format (Subversion 1.1.0) */\n-\tkeys.text_delta = pool_intern(\"Text-delta\");\n-\tkeys.prop_delta = pool_intern(\"Prop-delta\");\n-}\n-\n static void handle_property(const char *key, const char *val, uint32_t len,\n \t\t\t\tuint32_t *type_set)\n {\n@@ -314,7 +288,6 @@ void svndump_read(const char *url)\n \tchar *t;\n \tuint32_t active_ctx = DUMP_CTX;\n \tuint32_t len;\n-\tuint32_t key;\n \n \treset_dump_ctx(pool_intern(url));\n \twhile ((t = buffer_read_line(&input))) {\n@@ -323,16 +296,25 @@ void svndump_read(const char *url)\n \t\t\tcontinue;\n \t\t*val++ = '\\0';\n \t\t*val++ = '\\0';\n-\t\tkey = pool_intern(t);\n \n-\t\tif (key == keys.svn_fs_dump_format_version) {\n+\t\t/* strlen(key) */\n+\t\tswitch (val - t - 2) { \n+\t\tcase 26:\n+\t\t\tif (memcmp(t, \"SVN-fs-dump-format-version\", 26))\n+\t\t\t\tcontinue;\n \t\t\tdump_ctx.version = atoi(val);\n \t\t\tif (dump_ctx.version > 3)\n \t\t\t\tdie(\"expected svn dump format version <= 3, found %\"PRIu32,\n \t\t\t\t    dump_ctx.version);\n-\t\t} else if (key == keys.uuid) {\n+\t\t\tbreak;\n+\t\tcase 4:\n+\t\t\tif (memcmp(t, \"UUID\", 4))\n+\t\t\t\tcontinue;\n \t\t\tdump_ctx.uuid = pool_intern(val);\n-\t\t} else if (key == keys.revision_number) {\n+\t\t\tbreak;\n+\t\tcase 15:\n+\t\t\tif (memcmp(t, \"Revision-number\", 15))\n+\t\t\t\tcontinue;\n \t\t\tif (active_ctx == NODE_CTX)\n \t\t\t\thandle_node();\n \t\t\tif (active_ctx == REV_CTX)\n@@ -341,21 +323,31 @@ void svndump_read(const char *url)\n \t\t\t\tend_revision();\n \t\t\tactive_ctx = REV_CTX;\n \t\t\treset_rev_ctx(atoi(val));\n-\t\t} else if (key == keys.node_path) {\n-\t\t\tif (active_ctx == NODE_CTX)\n-\t\t\t\thandle_node();\n-\t\t\tif (active_ctx == REV_CTX)\n-\t\t\t\tbegin_revision();\n-\t\t\tactive_ctx = NODE_CTX;\n-\t\t\treset_node_ctx(val);\n-\t\t} else if (key == keys.node_kind) {\n+\t\t\tbreak;\n+\t\tcase 9:\n+\t\t\tif (prefixcmp(t, \"Node-\"))\n+\t\t\t\tcontinue;\n+\t\t\tif (!memcmp(t + strlen(\"Node-\"), \"path\", 4)) {\n+\t\t\t\tif (active_ctx == NODE_CTX)\n+\t\t\t\t\thandle_node();\n+\t\t\t\tif (active_ctx == REV_CTX)\n+\t\t\t\t\tbegin_revision();\n+\t\t\t\tactive_ctx = NODE_CTX;\n+\t\t\t\treset_node_ctx(val);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (memcmp(t + strlen(\"Node-\"), \"kind\", 4))\n+\t\t\t\tcontinue;\n \t\t\tif (!strcmp(val, \"dir\"))\n \t\t\t\tnode_ctx.type = REPO_MODE_DIR;\n \t\t\telse if (!strcmp(val, \"file\"))\n \t\t\t\tnode_ctx.type = REPO_MODE_BLB;\n \t\t\telse\n \t\t\t\tfprintf(stderr, \"Unknown node-kind: %s\\n\", val);\n-\t\t} else if (key == keys.node_action) {\n+\t\t\tbreak;\n+\t\tcase 11:\n+\t\t\tif (memcmp(t, \"Node-action\", 11))\n+\t\t\t\tcontinue;\n \t\t\tif (!strcmp(val, \"delete\")) {\n \t\t\t\tnode_ctx.action = NODEACT_DELETE;\n \t\t\t} else if (!strcmp(val, \"add\")) {\n@@ -368,20 +360,39 @@ void svndump_read(const char *url)\n \t\t\t\tfprintf(stderr, \"Unknown node-action: %s\\n\", val);\n \t\t\t\tnode_ctx.action = NODEACT_UNKNOWN;\n \t\t\t}\n-\t\t} else if (key == keys.node_copyfrom_path) {\n+\t\t\tbreak;\n+\t\tcase 18:\n+\t\t\tif (memcmp(t, \"Node-copyfrom-path\", 18))\n+\t\t\t\tcontinue;\n \t\t\tstrbuf_reset(&node_ctx.src);\n \t\t\tstrbuf_addstr(&node_ctx.src, val);\n-\t\t} else if (key == keys.node_copyfrom_rev) {\n+\t\t\tbreak;\n+\t\tcase 17:\n+\t\t\tif (memcmp(t, \"Node-copyfrom-rev\", 17))\n+\t\t\t\tcontinue;\n \t\t\tnode_ctx.srcRev = atoi(val);\n-\t\t} else if (key == keys.text_content_length) {\n-\t\t\tnode_ctx.textLength = atoi(val);\n-\t\t} else if (key == keys.prop_content_length) {\n+\t\t\tbreak;\n+\t\tcase 19:\n+\t\t\tif (!memcmp(t, \"Text-content-length\", 19)) {\n+\t\t\t\tnode_ctx.textLength = atoi(val);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (memcmp(t, \"Prop-content-length\", 19))\n+\t\t\t\tcontinue;\n \t\t\tnode_ctx.propLength = atoi(val);\n-\t\t} else if (key == keys.text_delta) {\n-\t\t\tnode_ctx.text_delta = !strcmp(val, \"true\");\n-\t\t} else if (key == keys.prop_delta) {\n+\t\t\tbreak;\n+\t\tcase 10:\n+\t\t\tif (!memcmp(t, \"Text-delta\", 10)) {\n+\t\t\t\tnode_ctx.text_delta = !strcmp(val, \"true\");\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (memcmp(t, \"Prop-delta\", 10))\n+\t\t\t\tcontinue;\n \t\t\tnode_ctx.prop_delta = !strcmp(val, \"true\");\n-\t\t} else if (key == keys.content_length) {\n+\t\t\tbreak;\n+\t\tcase 14:\n+\t\t\tif (memcmp(t, \"Content-length\", 14))\n+\t\t\t\tcontinue;\n \t\t\tlen = atoi(val);\n \t\t\tbuffer_read_line(&input);\n \t\t\tif (active_ctx == REV_CTX) {\n@@ -414,7 +425,6 @@ int svndump_init(const char *filename)\n \treset_dump_ctx(~0);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n-\tinit_keys();\n \treturn 0;\n }\n \n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163708","messageId":"1300518231-20008-6-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 5/9] vcs-svn: factor out usage of string_pool","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:47Z","receivedAt":"2011-03-19T07:03:47Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Signed-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/fast_export.c |   17 +++++++----------\n vcs-svn/fast_export.h |    5 +++--\n vcs-svn/svndump.c     |   44 ++++++++++++++++++++++++++------------------\n 3 files changed, 36 insertions(+), 30 deletions(-)\n\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex bb5e9aa..1d50512 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -9,7 +9,6 @@\n #include \"fast_export.h\"\n #include \"line_buffer.h\"\n #include \"repo_tree.h\"\n-#include \"string_pool.h\"\n #include \"strbuf.h\"\n \n #define MAX_GITSVN_LINE_LEN 4096\n@@ -61,25 +60,23 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n }\n \n static char gitsvnline[MAX_GITSVN_LINE_LEN];\n-void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,\n-\t\t\tuint32_t uuid, uint32_t url,\n+void fast_export_begin_commit(uint32_t revision, const char *author,\n+\t\t\tconst char *log, const char *uuid, const char *url,\n \t\t\tunsigned long timestamp)\n {\n-\tif (!log)\n-\t\tlog = \"\";\n-\tif (~uuid && ~url) {\n+\tif (*uuid && *url) {\n \t\tsnprintf(gitsvnline, MAX_GITSVN_LINE_LEN,\n \t\t\t\t\"\\n\\ngit-svn-id: %s@%\"PRIu32\" %s\\n\",\n-\t\t\t\t pool_fetch(url), revision, pool_fetch(uuid));\n+\t\t\t\t url, revision, uuid);\n \t} else {\n \t\t*gitsvnline = '\\0';\n \t}\n \tprintf(\"commit refs/heads/master\\n\");\n \tprintf(\"mark :%\"PRIu32\"\\n\", revision);\n \tprintf(\"committer %s <%s@%s> %ld +0000\\n\",\n-\t\t   ~author ? pool_fetch(author) : \"nobody\",\n-\t\t   ~author ? pool_fetch(author) : \"nobody\",\n-\t\t   ~uuid ? pool_fetch(uuid) : \"local\", timestamp);\n+\t\t   *author ? author : \"nobody\",\n+\t\t   *author ? author : \"nobody\",\n+\t\t   *uuid ? uuid : \"local\", timestamp);\n \tprintf(\"data %\"PRIu32\"\\n%s%s\\n\",\n \t\t   (uint32_t) (strlen(log) + strlen(gitsvnline)),\n \t\t   log, gitsvnline);\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex a47c609..bc5bddf 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -10,8 +10,9 @@ void fast_export_reset(void);\n \n void fast_export_delete(const char *path);\n void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n-void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,\n-\t\t\tuint32_t uuid, uint32_t url, unsigned long timestamp);\n+void fast_export_begin_commit(uint32_t revision, const char *author,\n+\t\t\tconst char *log, const char *uuid, const char *url,\n+\t\t\tunsigned long timestamp);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input);\n \ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 03f916d..fd67db8 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -11,7 +11,6 @@\n #include \"repo_tree.h\"\n #include \"fast_export.h\"\n #include \"line_buffer.h\"\n-#include \"string_pool.h\"\n #include \"strbuf.h\"\n \n #define REPORT_FILENO 3\n@@ -42,13 +41,14 @@ static struct {\n } node_ctx;\n \n static struct {\n-\tuint32_t revision, author;\n+\tuint32_t revision;\n \tunsigned long timestamp;\n-\tstruct strbuf log;\n+\tstruct strbuf log, author;\n } rev_ctx;\n \n static struct {\n-\tuint32_t version, uuid, url;\n+\tuint32_t version;\n+\tstruct strbuf uuid, url;\n } dump_ctx;\n \n static void reset_node_ctx(char *fname)\n@@ -71,14 +71,16 @@ static void reset_rev_ctx(uint32_t revision)\n \trev_ctx.revision = revision;\n \trev_ctx.timestamp = 0;\n \tstrbuf_reset(&rev_ctx.log);\n-\trev_ctx.author = ~0;\n+\tstrbuf_reset(&rev_ctx.author);\n }\n \n-static void reset_dump_ctx(uint32_t url)\n+static void reset_dump_ctx(const char *url)\n {\n-\tdump_ctx.url = url;\n+\tstrbuf_reset(&dump_ctx.url);\n+\tif (url)\n+\t\tstrbuf_addstr(&dump_ctx.url, url);\n \tdump_ctx.version = 1;\n-\tdump_ctx.uuid = ~0;\n+\tstrbuf_reset(&dump_ctx.uuid);\n }\n \n static void handle_property(const char *key, const char *val, uint32_t len,\n@@ -91,13 +93,15 @@ static void handle_property(const char *key, const char *val, uint32_t len,\n \t\t\tbreak;\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:log\");\n-\t\t/* Value length excludes terminating nul. */\n-\t\tstrbuf_add(&rev_ctx.log, val, len + 1);\n+\t\tstrbuf_reset(&rev_ctx.log);\n+\t\tstrbuf_add(&rev_ctx.log, val, len);\n \t\tbreak;\n \tcase 10:\n \t\tif (memcmp(key, \"svn:author\", 10))\n \t\t\tbreak;\n-\t\trev_ctx.author = pool_intern(val);\n+\t\tstrbuf_reset(&rev_ctx.author);\n+\t\tif (val)\n+\t\t\tstrbuf_add(&rev_ctx.author, val, len);\n \t\tbreak;\n \tcase 8:\n \t\tif (memcmp(key, \"svn:date\", 8))\n@@ -272,8 +276,9 @@ static void begin_revision(void)\n {\n \tif (!rev_ctx.revision)\t/* revision 0 gets no git commit. */\n \t\treturn;\n-\tfast_export_begin_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log.buf,\n-\t\tdump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);\n+\tfast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,\n+\t\trev_ctx.log.buf, dump_ctx.uuid.buf, dump_ctx.url.buf,\n+\t\trev_ctx.timestamp);\n }\n \n static void end_revision(void)\n@@ -289,7 +294,7 @@ void svndump_read(const char *url)\n \tuint32_t active_ctx = DUMP_CTX;\n \tuint32_t len;\n \n-\treset_dump_ctx(pool_intern(url));\n+\treset_dump_ctx(url);\n \twhile ((t = buffer_read_line(&input))) {\n \t\tval = strstr(t, \": \");\n \t\tif (!val)\n@@ -310,7 +315,8 @@ void svndump_read(const char *url)\n \t\tcase 4:\n \t\t\tif (memcmp(t, \"UUID\", 4))\n \t\t\t\tcontinue;\n-\t\t\tdump_ctx.uuid = pool_intern(val);\n+\t\t\tstrbuf_reset(&dump_ctx.uuid);\n+\t\t\tstrbuf_addstr(&dump_ctx.uuid, val);\n \t\t\tbreak;\n \t\tcase 15:\n \t\t\tif (memcmp(t, \"Revision-number\", 15))\n@@ -419,10 +425,13 @@ int svndump_init(const char *filename)\n \tif (buffer_init(&input, filename))\n \t\treturn error(\"cannot open %s: %s\", filename, strerror(errno));\n \tfast_export_init(REPORT_FILENO);\n+\tstrbuf_init(&dump_ctx.uuid, 4096);\n+\tstrbuf_init(&dump_ctx.url, 4096);\n \tstrbuf_init(&rev_ctx.log, 4096);\n+\tstrbuf_init(&rev_ctx.author, 4096);\n \tstrbuf_init(&node_ctx.src, 4096);\n \tstrbuf_init(&node_ctx.dst, 4096);\n-\treset_dump_ctx(~0);\n+\treset_dump_ctx(NULL);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n \treturn 0;\n@@ -431,7 +440,7 @@ int svndump_init(const char *filename)\n void svndump_deinit(void)\n {\n \tfast_export_deinit();\n-\treset_dump_ctx(~0);\n+\treset_dump_ctx(NULL);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n \tstrbuf_release(&rev_ctx.log);\n@@ -447,5 +456,4 @@ void svndump_reset(void)\n {\n \tfast_export_reset();\n \tbuffer_reset(&input);\n-\tpool_reset();\n }\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163704","messageId":"1300518231-20008-7-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 6/9] vcs-svn: drop string_pool","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:48Z","receivedAt":"2011-03-19T07:03:48Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Signed-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n .gitignore              |    1 -\n Makefile                |   12 ++---\n t/t0080-vcs-svn.sh      |   16 -------\n test-string-pool.c      |   31 -------------\n vcs-svn/string_pool.c   |  113 -----------------------------------------------\n vcs-svn/string_pool.h   |   12 -----\n vcs-svn/string_pool.txt |   43 ------------------\n 7 files changed, 4 insertions(+), 224 deletions(-)\n delete mode 100644 test-string-pool.c\n delete mode 100644 vcs-svn/string_pool.c\n delete mode 100644 vcs-svn/string_pool.h\n delete mode 100644 vcs-svn/string_pool.txt\n\ndiff --git a/.gitignore b/.gitignore\nindex c460c66..215e842 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -177,7 +177,6 @@\n /test-run-command\n /test-sha1\n /test-sigchain\n-/test-string-pool\n /test-subprocess\n /test-svn-fe\n /test-treap\ndiff --git a/Makefile b/Makefile\nindex ade7923..f8182e5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -430,7 +430,6 @@ TEST_PROGRAMS_NEED_X += test-path-utils\n TEST_PROGRAMS_NEED_X += test-run-command\n TEST_PROGRAMS_NEED_X += test-sha1\n TEST_PROGRAMS_NEED_X += test-sigchain\n-TEST_PROGRAMS_NEED_X += test-string-pool\n TEST_PROGRAMS_NEED_X += test-subprocess\n TEST_PROGRAMS_NEED_X += test-svn-fe\n TEST_PROGRAMS_NEED_X += test-treap\n@@ -1838,10 +1837,9 @@ ifndef NO_CURL\n endif\n XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \\\n \txdiff/xmerge.o xdiff/xpatience.o\n-VCSSVN_OBJS = vcs-svn/string_pool.o vcs-svn/line_buffer.o \\\n-\tvcs-svn/repo_tree.o vcs-svn/fast_export.o vcs-svn/svndump.o\n-VCSSVN_TEST_OBJS = test-obj-pool.o test-string-pool.o \\\n-\ttest-line-buffer.o test-treap.o\n+VCSSVN_OBJS = vcs-svn/line_buffer.o vcs-svn/repo_tree.o \\\n+\tvcs-svn/fast_export.o vcs-svn/svndump.o\n+VCSSVN_TEST_OBJS = test-obj-pool.o test-line-buffer.o test-treap.o\n OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)\n \n dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)\n@@ -1965,7 +1963,7 @@ xdiff-interface.o $(XDIFF_OBJS): \\\n \txdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h\n \n $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \\\n-\tvcs-svn/obj_pool.h vcs-svn/trp.h vcs-svn/string_pool.h \\\n+\tvcs-svn/obj_pool.h vcs-svn/trp.h \\\n \tvcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \\\n \tvcs-svn/svndump.h\n \n@@ -2133,8 +2131,6 @@ test-line-buffer$X: vcs-svn/lib.a\n \n test-parse-options$X: parse-options.o\n \n-test-string-pool$X: vcs-svn/lib.a\n-\n test-svn-fe$X: vcs-svn/lib.a\n \n .PRECIOUS: $(TEST_OBJS)\ndiff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh\nindex 99a314b..ce02c58 100755\n--- a/t/t0080-vcs-svn.sh\n+++ b/t/t0080-vcs-svn.sh\n@@ -76,22 +76,6 @@ test_expect_success 'obj pool: high-water mark' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'string pool' '\n-\techo a does not equal b >expected.differ &&\n-\techo a equals a >expected.match &&\n-\techo equals equals equals >expected.matchmore &&\n-\n-\ttest-string-pool \"a,--b\" >actual.differ &&\n-\ttest-string-pool \"a,a\" >actual.match &&\n-\ttest-string-pool \"equals-equals\" >actual.matchmore &&\n-\ttest_must_fail test-string-pool a,a,a &&\n-\ttest_must_fail test-string-pool a &&\n-\n-\ttest_cmp expected.differ actual.differ &&\n-\ttest_cmp expected.match actual.match &&\n-\ttest_cmp expected.matchmore actual.matchmore\n-'\n-\n test_expect_success 'treap sort' '\n \tcat <<-\\EOF >unsorted &&\n \t68\ndiff --git a/test-string-pool.c b/test-string-pool.c\ndeleted file mode 100644\nindex c5782e6..0000000\n--- a/test-string-pool.c\n+++ /dev/null\n@@ -1,31 +0,0 @@\n-/*\n- * test-string-pool.c: code to exercise the svn importer's string pool\n- */\n-\n-#include \"git-compat-util.h\"\n-#include \"vcs-svn/string_pool.h\"\n-\n-int main(int argc, char *argv[])\n-{\n-\tconst uint32_t unequal = pool_intern(\"does not equal\");\n-\tconst uint32_t equal = pool_intern(\"equals\");\n-\tuint32_t buf[3];\n-\tuint32_t n;\n-\n-\tif (argc != 2)\n-\t\tusage(\"test-string-pool <string>,<string>\");\n-\n-\tn = pool_tok_seq(3, buf, \",-\", argv[1]);\n-\tif (n >= 3)\n-\t\tdie(\"too many strings\");\n-\tif (n <= 1)\n-\t\tdie(\"too few strings\");\n-\n-\tbuf[2] = buf[1];\n-\tbuf[1] = (buf[0] == buf[2]) ? equal : unequal;\n-\tpool_print_seq(3, buf, ' ', stdout);\n-\tfputc('\\n', stdout);\n-\n-\tpool_reset();\n-\treturn 0;\n-}\ndiff --git a/vcs-svn/string_pool.c b/vcs-svn/string_pool.c\ndeleted file mode 100644\nindex be43598..0000000\n--- a/vcs-svn/string_pool.c\n+++ /dev/null\n@@ -1,113 +0,0 @@\n-/*\n- * Licensed under a two-clause BSD-style license.\n- * See LICENSE for details.\n- */\n-\n-#include \"git-compat-util.h\"\n-#include \"quote.h\"\n-#include \"trp.h\"\n-#include \"obj_pool.h\"\n-#include \"string_pool.h\"\n-\n-static struct trp_root tree = { ~0 };\n-\n-struct node {\n-\tuint32_t offset;\n-\tstruct trp_node children;\n-};\n-\n-/* Two memory pools: one for struct node, and another for strings */\n-obj_pool_gen(node, struct node, 4096)\n-obj_pool_gen(string, char, 4096)\n-\n-static char *node_value(struct node *node)\n-{\n-\treturn node ? string_pointer(node->offset) : NULL;\n-}\n-\n-static int node_cmp(struct node *a, struct node *b)\n-{\n-\treturn strcmp(node_value(a), node_value(b));\n-}\n-\n-/* Build a Treap from the node structure (a trp_node w/ offset) */\n-trp_gen(static, tree_, struct node, children, node, node_cmp);\n-\n-const char *pool_fetch(uint32_t entry)\n-{\n-\treturn node_value(node_pointer(entry));\n-}\n-\n-uint32_t pool_intern(const char *key)\n-{\n-\t/* Canonicalize key */\n-\tstruct node *match = NULL, *node;\n-\tuint32_t key_len;\n-\tif (key == NULL)\n-\t\treturn ~0;\n-\tkey_len = strlen(key) + 1;\n-\tnode = node_pointer(node_alloc(1));\n-\tnode->offset = string_alloc(key_len);\n-\tstrcpy(node_value(node), key);\n-\tmatch = tree_search(&tree, node);\n-\tif (!match) {\n-\t\ttree_insert(&tree, node);\n-\t} else {\n-\t\tnode_free(1);\n-\t\tstring_free(key_len);\n-\t\tnode = match;\n-\t}\n-\treturn node_offset(node);\n-}\n-\n-uint32_t pool_tok_r(char *str, const char *delim, char **saveptr)\n-{\n-\tchar *token = strtok_r(str, delim, saveptr);\n-\treturn token ? pool_intern(token) : ~0;\n-}\n-\n-void pool_print_seq(uint32_t len, const uint32_t *seq, char delim, FILE *stream)\n-{\n-\tuint32_t i;\n-\tfor (i = 0; i < len && ~seq[i]; i++) {\n-\t\tfputs(pool_fetch(seq[i]), stream);\n-\t\tif (i < len - 1 && ~seq[i + 1])\n-\t\t\tfputc(delim, stream);\n-\t}\n-}\n-\n-void pool_print_seq_q(uint32_t len, const uint32_t *seq, char delim, FILE *stream)\n-{\n-\tuint32_t i;\n-\tfor (i = 0; i < len && ~seq[i]; i++) {\n-\t\tquote_c_style(pool_fetch(seq[i]), NULL, stream, 1);\n-\t\tif (i < len - 1 && ~seq[i + 1])\n-\t\t\tfputc(delim, stream);\n-\t}\n-}\n-\n-uint32_t pool_tok_seq(uint32_t sz, uint32_t *seq, const char *delim, char *str)\n-{\n-\tchar *context = NULL;\n-\tuint32_t token = ~0;\n-\tuint32_t length;\n-\n-\tif (sz == 0)\n-\t\treturn ~0;\n-\tif (str)\n-\t\ttoken = pool_tok_r(str, delim, &context);\n-\tfor (length = 0; length < sz; length++) {\n-\t\tseq[length] = token;\n-\t\tif (token == ~0)\n-\t\t\treturn length;\n-\t\ttoken = pool_tok_r(NULL, delim, &context);\n-\t}\n-\tseq[sz - 1] = ~0;\n-\treturn sz;\n-}\n-\n-void pool_reset(void)\n-{\n-\tnode_reset();\n-\tstring_reset();\n-}\ndiff --git a/vcs-svn/string_pool.h b/vcs-svn/string_pool.h\ndeleted file mode 100644\nindex 96e501d..0000000\n--- a/vcs-svn/string_pool.h\n+++ /dev/null\n@@ -1,12 +0,0 @@\n-#ifndef STRING_POOL_H_\n-#define STRING_POOL_H_\n-\n-uint32_t pool_intern(const char *key);\n-const char *pool_fetch(uint32_t entry);\n-uint32_t pool_tok_r(char *str, const char *delim, char **saveptr);\n-void pool_print_seq(uint32_t len, const uint32_t *seq, char delim, FILE *stream);\n-void pool_print_seq_q(uint32_t len, const uint32_t *seq, char delim, FILE *stream);\n-uint32_t pool_tok_seq(uint32_t sz, uint32_t *seq, const char *delim, char *str);\n-void pool_reset(void);\n-\n-#endif\ndiff --git a/vcs-svn/string_pool.txt b/vcs-svn/string_pool.txt\ndeleted file mode 100644\nindex 1b41f15..0000000\n--- a/vcs-svn/string_pool.txt\n+++ /dev/null\n@@ -1,43 +0,0 @@\n-string_pool API\n-===============\n-\n-The string_pool API provides facilities for replacing strings\n-with integer keys that can be more easily compared and stored.\n-The facilities are designed so that one could teach Git without\n-too much trouble to store the information needed for these keys to\n-remain valid over multiple executions.\n-\n-Functions\n----------\n-\n-pool_intern::\n-\tInclude a string in the string pool and get its key.\n-\tIf that string is already in the pool, retrieves its\n-\texisting key.\n-\n-pool_fetch::\n-\tRetrieve the string associated to a given key.\n-\n-pool_tok_r::\n-\tExtract the key of the next token from a string.\n-\tInterface mimics strtok_r.\n-\n-pool_print_seq::\n-\tPrint a sequence of strings named by key to a file, using the\n-\tspecified delimiter to separate them.\n-\n-\tIf NULL (key ~0) appears in the sequence, the sequence ends\n-\tearly.\n-\n-pool_tok_seq::\n-\tSplit a string into tokens, storing the keys of segments\n-\tinto a caller-provided array.\n-\n-\tUnless sz is 0, the array will always be ~0-terminated.\n-\tIf there is not enough room for all the tokens, the\n-\tarray holds as many tokens as fit in the entries before\n-\tthe terminating ~0.  Return value is the index after the\n-\tlast token, or sz if the tokens did not fit.\n-\n-pool_reset::\n-\tDeallocate storage for the string pool.\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163707","messageId":"1300518231-20008-8-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 7/9] vcs-svn: drop trp.h","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:49Z","receivedAt":"2011-03-19T07:03:49Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Signed-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n .gitignore         |    1 -\n Makefile           |    3 +-\n t/t0080-vcs-svn.sh |   22 -----\n test-treap.c       |   70 ---------------\n vcs-svn/LICENSE    |    3 -\n vcs-svn/trp.h      |  237 ----------------------------------------------------\n vcs-svn/trp.txt    |  109 ------------------------\n 7 files changed, 1 insertions(+), 444 deletions(-)\n delete mode 100644 test-treap.c\n delete mode 100644 vcs-svn/trp.h\n delete mode 100644 vcs-svn/trp.txt\n\ndiff --git a/.gitignore b/.gitignore\nindex 215e842..aa94ff1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -179,7 +179,6 @@\n /test-sigchain\n /test-subprocess\n /test-svn-fe\n-/test-treap\n /common-cmds.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex f8182e5..2d56ab9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -432,7 +432,6 @@ TEST_PROGRAMS_NEED_X += test-sha1\n TEST_PROGRAMS_NEED_X += test-sigchain\n TEST_PROGRAMS_NEED_X += test-subprocess\n TEST_PROGRAMS_NEED_X += test-svn-fe\n-TEST_PROGRAMS_NEED_X += test-treap\n TEST_PROGRAMS_NEED_X += test-index-version\n TEST_PROGRAMS_NEED_X += test-mktemp\n \n@@ -1963,7 +1962,7 @@ xdiff-interface.o $(XDIFF_OBJS): \\\n \txdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h\n \n $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \\\n-\tvcs-svn/obj_pool.h vcs-svn/trp.h \\\n+\tvcs-svn/obj_pool.h \\\n \tvcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \\\n \tvcs-svn/svndump.h\n \ndiff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh\nindex ce02c58..3f29496 100755\n--- a/t/t0080-vcs-svn.sh\n+++ b/t/t0080-vcs-svn.sh\n@@ -76,26 +76,4 @@ test_expect_success 'obj pool: high-water mark' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'treap sort' '\n-\tcat <<-\\EOF >unsorted &&\n-\t68\n-\t12\n-\t13\n-\t13\n-\t68\n-\t13\n-\t13\n-\t21\n-\t10\n-\t11\n-\t12\n-\t13\n-\t13\n-\tEOF\n-\tsort unsorted >expected &&\n-\n-\ttest-treap <unsorted >actual &&\n-\ttest_cmp expected actual\n-'\n-\n test_done\ndiff --git a/test-treap.c b/test-treap.c\ndeleted file mode 100644\nindex ab8c951..0000000\n--- a/test-treap.c\n+++ /dev/null\n@@ -1,70 +0,0 @@\n-/*\n- * test-treap.c: code to exercise the svn importer's treap structure\n- */\n-\n-#include \"cache.h\"\n-#include \"vcs-svn/obj_pool.h\"\n-#include \"vcs-svn/trp.h\"\n-\n-struct int_node {\n-\tuintmax_t n;\n-\tstruct trp_node children;\n-};\n-\n-obj_pool_gen(node, struct int_node, 3)\n-\n-static int node_cmp(struct int_node *a, struct int_node *b)\n-{\n-\treturn (a->n > b->n) - (a->n < b->n);\n-}\n-\n-trp_gen(static, treap_, struct int_node, children, node, node_cmp)\n-\n-static void strtonode(struct int_node *item, const char *s)\n-{\n-\tchar *end;\n-\titem->n = strtoumax(s, &end, 10);\n-\tif (*s == '\\0' || (*end != '\\n' && *end != '\\0'))\n-\t\tdie(\"invalid integer: %s\", s);\n-}\n-\n-int main(int argc, char *argv[])\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tstruct trp_root root = { ~0 };\n-\tuint32_t item;\n-\n-\tif (argc != 1)\n-\t\tusage(\"test-treap < ints\");\n-\n-\twhile (strbuf_getline(&sb, stdin, '\\n') != EOF) {\n-\t\tstruct int_node *node = node_pointer(node_alloc(1));\n-\n-\t\titem = node_offset(node);\n-\t\tstrtonode(node, sb.buf);\n-\t\tnode = treap_insert(&root, node_pointer(item));\n-\t\tif (node_offset(node) != item)\n-\t\t\tdie(\"inserted %\"PRIu32\" in place of %\"PRIu32\"\",\n-\t\t\t\tnode_offset(node), item);\n-\t}\n-\n-\titem = node_offset(treap_first(&root));\n-\twhile (~item) {\n-\t\tuint32_t next;\n-\t\tstruct int_node *tmp = node_pointer(node_alloc(1));\n-\n-\t\ttmp->n = node_pointer(item)->n;\n-\t\tnext = node_offset(treap_next(&root, node_pointer(item)));\n-\n-\t\ttreap_remove(&root, node_pointer(item));\n-\t\titem = node_offset(treap_nsearch(&root, tmp));\n-\n-\t\tif (item != next && (!~item || node_pointer(item)->n != tmp->n))\n-\t\t\tdie(\"found %\"PRIuMAX\" in place of %\"PRIuMAX\"\",\n-\t\t\t\t~item ? node_pointer(item)->n : ~(uintmax_t) 0,\n-\t\t\t\t~next ? node_pointer(next)->n : ~(uintmax_t) 0);\n-\t\tprintf(\"%\"PRIuMAX\"\\n\", tmp->n);\n-\t}\n-\tnode_reset();\n-\treturn 0;\n-}\ndiff --git a/vcs-svn/LICENSE b/vcs-svn/LICENSE\nindex 0a5e3c4..533f585 100644\n--- a/vcs-svn/LICENSE\n+++ b/vcs-svn/LICENSE\n@@ -1,9 +1,6 @@\n Copyright (C) 2010 David Barr <david.barr@cordelta.com>.\n All rights reserved.\n \n-Copyright (C) 2008 Jason Evans <jasone@canonware.com>.\n-All rights reserved.\n-\n Copyright (C) 2005 Stefan Hegny, hydrografix Consulting GmbH,\n Frankfurt/Main, Germany\n and others, see http://svn2cc.sarovar.org\ndiff --git a/vcs-svn/trp.h b/vcs-svn/trp.h\ndeleted file mode 100644\nindex c32b918..0000000\n--- a/vcs-svn/trp.h\n+++ /dev/null\n@@ -1,237 +0,0 @@\n-/*\n- * C macro implementation of treaps.\n- *\n- * Usage:\n- *   #include <stdint.h>\n- *   #include \"trp.h\"\n- *   trp_gen(...)\n- *\n- * Licensed under a two-clause BSD-style license.\n- * See LICENSE for details.\n- */\n-\n-#ifndef TRP_H_\n-#define TRP_H_\n-\n-#define MAYBE_UNUSED __attribute__((__unused__))\n-\n-/* Node structure. */\n-struct trp_node {\n-\tuint32_t trpn_left;\n-\tuint32_t trpn_right;\n-};\n-\n-/* Root structure. */\n-struct trp_root {\n-\tuint32_t trp_root;\n-};\n-\n-/* Pointer/Offset conversion. */\n-#define trpn_pointer(a_base, a_offset) (a_base##_pointer(a_offset))\n-#define trpn_offset(a_base, a_pointer) (a_base##_offset(a_pointer))\n-#define trpn_modify(a_base, a_offset) \\\n-\tdo { \\\n-\t\tif ((a_offset) < a_base##_pool.committed) { \\\n-\t\t\tuint32_t old_offset = (a_offset);\\\n-\t\t\t(a_offset) = a_base##_alloc(1); \\\n-\t\t\t*trpn_pointer(a_base, a_offset) = \\\n-\t\t\t\t*trpn_pointer(a_base, old_offset); \\\n-\t\t} \\\n-\t} while (0)\n-\n-/* Left accessors. */\n-#define trp_left_get(a_base, a_field, a_node) \\\n-\t(trpn_pointer(a_base, a_node)->a_field.trpn_left)\n-#define trp_left_set(a_base, a_field, a_node, a_left) \\\n-\tdo { \\\n-\t\ttrpn_modify(a_base, a_node); \\\n-\t\ttrp_left_get(a_base, a_field, a_node) = (a_left); \\\n-\t} while (0)\n-\n-/* Right accessors. */\n-#define trp_right_get(a_base, a_field, a_node) \\\n-\t(trpn_pointer(a_base, a_node)->a_field.trpn_right)\n-#define trp_right_set(a_base, a_field, a_node, a_right) \\\n-\tdo { \\\n-\t\ttrpn_modify(a_base, a_node); \\\n-\t\ttrp_right_get(a_base, a_field, a_node) = (a_right); \\\n-\t} while (0)\n-\n-/*\n- * Fibonacci hash function.\n- * The multiplier is the nearest prime to (2^32 times (√5 - 1)/2).\n- * See Knuth §6.4: volume 3, 3rd ed, p518.\n- */\n-#define trpn_hash(a_node) (uint32_t) (2654435761u * (a_node))\n-\n-/* Priority accessors. */\n-#define trp_prio_get(a_node) trpn_hash(a_node)\n-\n-/* Node initializer. */\n-#define trp_node_new(a_base, a_field, a_node) \\\n-\tdo { \\\n-\t\ttrp_left_set(a_base, a_field, (a_node), ~0); \\\n-\t\ttrp_right_set(a_base, a_field, (a_node), ~0); \\\n-\t} while (0)\n-\n-/* Internal utility macros. */\n-#define trpn_first(a_base, a_field, a_root, r_node) \\\n-\tdo { \\\n-\t\t(r_node) = (a_root); \\\n-\t\tif ((r_node) == ~0) \\\n-\t\t\treturn NULL; \\\n-\t\twhile (~trp_left_get(a_base, a_field, (r_node))) \\\n-\t\t\t(r_node) = trp_left_get(a_base, a_field, (r_node)); \\\n-\t} while (0)\n-\n-#define trpn_rotate_left(a_base, a_field, a_node, r_node) \\\n-\tdo { \\\n-\t\t(r_node) = trp_right_get(a_base, a_field, (a_node)); \\\n-\t\ttrp_right_set(a_base, a_field, (a_node), \\\n-\t\t\ttrp_left_get(a_base, a_field, (r_node))); \\\n-\t\ttrp_left_set(a_base, a_field, (r_node), (a_node)); \\\n-\t} while (0)\n-\n-#define trpn_rotate_right(a_base, a_field, a_node, r_node) \\\n-\tdo { \\\n-\t\t(r_node) = trp_left_get(a_base, a_field, (a_node)); \\\n-\t\ttrp_left_set(a_base, a_field, (a_node), \\\n-\t\t\ttrp_right_get(a_base, a_field, (r_node))); \\\n-\t\ttrp_right_set(a_base, a_field, (r_node), (a_node)); \\\n-\t} while (0)\n-\n-#define trp_gen(a_attr, a_pre, a_type, a_field, a_base, a_cmp) \\\n-a_attr a_type MAYBE_UNUSED *a_pre##first(struct trp_root *treap) \\\n-{ \\\n-\tuint32_t ret; \\\n-\ttrpn_first(a_base, a_field, treap->trp_root, ret); \\\n-\treturn trpn_pointer(a_base, ret); \\\n-} \\\n-a_attr a_type MAYBE_UNUSED *a_pre##next(struct trp_root *treap, a_type *node) \\\n-{ \\\n-\tuint32_t ret; \\\n-\tuint32_t offset = trpn_offset(a_base, node); \\\n-\tif (~trp_right_get(a_base, a_field, offset)) { \\\n-\t\ttrpn_first(a_base, a_field, \\\n-\t\t\ttrp_right_get(a_base, a_field, offset), ret); \\\n-\t} else { \\\n-\t\tuint32_t tnode = treap->trp_root; \\\n-\t\tret = ~0; \\\n-\t\twhile (1) { \\\n-\t\t\tint cmp = (a_cmp)(trpn_pointer(a_base, offset), \\\n-\t\t\t\ttrpn_pointer(a_base, tnode)); \\\n-\t\t\tif (cmp < 0) { \\\n-\t\t\t\tret = tnode; \\\n-\t\t\t\ttnode = trp_left_get(a_base, a_field, tnode); \\\n-\t\t\t} else if (cmp > 0) { \\\n-\t\t\t\ttnode = trp_right_get(a_base, a_field, tnode); \\\n-\t\t\t} else { \\\n-\t\t\t\tbreak; \\\n-\t\t\t} \\\n-\t\t} \\\n-\t} \\\n-\treturn trpn_pointer(a_base, ret); \\\n-} \\\n-a_attr a_type MAYBE_UNUSED *a_pre##search(struct trp_root *treap, a_type *key) \\\n-{ \\\n-\tint cmp; \\\n-\tuint32_t ret = treap->trp_root; \\\n-\twhile (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base, ret)))) { \\\n-\t\tif (cmp < 0) { \\\n-\t\t\tret = trp_left_get(a_base, a_field, ret); \\\n-\t\t} else { \\\n-\t\t\tret = trp_right_get(a_base, a_field, ret); \\\n-\t\t} \\\n-\t} \\\n-\treturn trpn_pointer(a_base, ret); \\\n-} \\\n-a_attr a_type MAYBE_UNUSED *a_pre##nsearch(struct trp_root *treap, a_type *key) \\\n-{ \\\n-\tint cmp; \\\n-\tuint32_t ret = treap->trp_root; \\\n-\twhile (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base, ret)))) { \\\n-\t\tif (cmp < 0) { \\\n-\t\t\tif (!~trp_left_get(a_base, a_field, ret)) \\\n-\t\t\t\tbreak; \\\n-\t\t\tret = trp_left_get(a_base, a_field, ret); \\\n-\t\t} else { \\\n-\t\t\tret = trp_right_get(a_base, a_field, ret); \\\n-\t\t} \\\n-\t} \\\n-\treturn trpn_pointer(a_base, ret); \\\n-} \\\n-a_attr uint32_t MAYBE_UNUSED a_pre##insert_recurse(uint32_t cur_node, uint32_t ins_node) \\\n-{ \\\n-\tif (cur_node == ~0) { \\\n-\t\treturn ins_node; \\\n-\t} else { \\\n-\t\tuint32_t ret; \\\n-\t\tint cmp = (a_cmp)(trpn_pointer(a_base, ins_node), \\\n-\t\t\t\t\ttrpn_pointer(a_base, cur_node)); \\\n-\t\tif (cmp < 0) { \\\n-\t\t\tuint32_t left = a_pre##insert_recurse( \\\n-\t\t\t\ttrp_left_get(a_base, a_field, cur_node), ins_node); \\\n-\t\t\ttrp_left_set(a_base, a_field, cur_node, left); \\\n-\t\t\tif (trp_prio_get(left) < trp_prio_get(cur_node)) \\\n-\t\t\t\ttrpn_rotate_right(a_base, a_field, cur_node, ret); \\\n-\t\t\telse \\\n-\t\t\t\tret = cur_node; \\\n-\t\t} else { \\\n-\t\t\tuint32_t right = a_pre##insert_recurse( \\\n-\t\t\t\ttrp_right_get(a_base, a_field, cur_node), ins_node); \\\n-\t\t\ttrp_right_set(a_base, a_field, cur_node, right); \\\n-\t\t\tif (trp_prio_get(right) < trp_prio_get(cur_node)) \\\n-\t\t\t\ttrpn_rotate_left(a_base, a_field, cur_node, ret); \\\n-\t\t\telse \\\n-\t\t\t\tret = cur_node; \\\n-\t\t} \\\n-\t\treturn ret; \\\n-\t} \\\n-} \\\n-a_attr a_type *MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \\\n-{ \\\n-\tuint32_t offset = trpn_offset(a_base, node); \\\n-\ttrp_node_new(a_base, a_field, offset); \\\n-\ttreap->trp_root = a_pre##insert_recurse(treap->trp_root, offset); \\\n-\treturn trpn_pointer(a_base, offset); \\\n-} \\\n-a_attr uint32_t MAYBE_UNUSED a_pre##remove_recurse(uint32_t cur_node, uint32_t rem_node) \\\n-{ \\\n-\tint cmp = a_cmp(trpn_pointer(a_base, rem_node), \\\n-\t\t\ttrpn_pointer(a_base, cur_node)); \\\n-\tif (cmp == 0) { \\\n-\t\tuint32_t ret; \\\n-\t\tuint32_t left = trp_left_get(a_base, a_field, cur_node); \\\n-\t\tuint32_t right = trp_right_get(a_base, a_field, cur_node); \\\n-\t\tif (left == ~0) { \\\n-\t\t\tif (right == ~0) \\\n-\t\t\t\treturn ~0; \\\n-\t\t} else if (right == ~0 || trp_prio_get(left) < trp_prio_get(right)) { \\\n-\t\t\ttrpn_rotate_right(a_base, a_field, cur_node, ret); \\\n-\t\t\tright = a_pre##remove_recurse(cur_node, rem_node); \\\n-\t\t\ttrp_right_set(a_base, a_field, ret, right); \\\n-\t\t\treturn ret; \\\n-\t\t} \\\n-\t\ttrpn_rotate_left(a_base, a_field, cur_node, ret); \\\n-\t\tleft = a_pre##remove_recurse(cur_node, rem_node); \\\n-\t\ttrp_left_set(a_base, a_field, ret, left); \\\n-\t\treturn ret; \\\n-\t} else if (cmp < 0) { \\\n-\t\tuint32_t left = a_pre##remove_recurse( \\\n-\t\t\ttrp_left_get(a_base, a_field, cur_node), rem_node); \\\n-\t\ttrp_left_set(a_base, a_field, cur_node, left); \\\n-\t\treturn cur_node; \\\n-\t} else { \\\n-\t\tuint32_t right = a_pre##remove_recurse( \\\n-\t\t\ttrp_right_get(a_base, a_field, cur_node), rem_node); \\\n-\t\ttrp_right_set(a_base, a_field, cur_node, right); \\\n-\t\treturn cur_node; \\\n-\t} \\\n-} \\\n-a_attr void MAYBE_UNUSED a_pre##remove(struct trp_root *treap, a_type *node) \\\n-{ \\\n-\ttreap->trp_root = a_pre##remove_recurse(treap->trp_root, \\\n-\t\ttrpn_offset(a_base, node)); \\\n-} \\\n-\n-#endif\ndiff --git a/vcs-svn/trp.txt b/vcs-svn/trp.txt\ndeleted file mode 100644\nindex 5ca6b42..0000000\n--- a/vcs-svn/trp.txt\n+++ /dev/null\n@@ -1,109 +0,0 @@\n-Motivation\n-==========\n-\n-Treaps provide a memory-efficient binary search tree structure.\n-Insertion/deletion/search are about as about as fast in the average\n-case as red-black trees and the chances of worst-case behavior are\n-vanishingly small, thanks to (pseudo-)randomness.  The bad worst-case\n-behavior is a small price to pay, given that treaps are much simpler\n-to implement.\n-\n-API\n-===\n-\n-The trp API generates a data structure and functions to handle a\n-large growing set of objects stored in a pool.\n-\n-The caller:\n-\n-. Specifies parameters for the generated functions with the\n-  trp_gen(static, foo_, ...) macro.\n-\n-. Allocates a `struct trp_root` variable and sets it to {~0}.\n-\n-. Adds new nodes to the set using `foo_insert`.  Any pointers\n-  to existing nodes cannot be relied upon any more, so the caller\n-  might retrieve them anew with `foo_pointer`.\n-\n-. Can find a specific item in the set using `foo_search`.\n-\n-. Can iterate over items in the set using `foo_first` and `foo_next`.\n-\n-. Can remove an item from the set using `foo_remove`.\n-\n-Example:\n-\n-----\n-struct ex_node {\n-\tconst char *s;\n-\tstruct trp_node ex_link;\n-};\n-static struct trp_root ex_base = {~0};\n-obj_pool_gen(ex, struct ex_node, 4096);\n-trp_gen(static, ex_, struct ex_node, ex_link, ex, strcmp)\n-struct ex_node *item;\n-\n-item = ex_pointer(ex_alloc(1));\n-item->s = \"hello\";\n-ex_insert(&ex_base, item);\n-item = ex_pointer(ex_alloc(1));\n-item->s = \"goodbye\";\n-ex_insert(&ex_base, item);\n-for (item = ex_first(&ex_base); item; item = ex_next(&ex_base, item))\n-\tprintf(\"%s\\n\", item->s);\n-----\n-\n-Functions\n----------\n-\n-trp_gen(attr, foo_, node_type, link_field, pool, cmp)::\n-\n-\tGenerate a type-specific treap implementation.\n-+\n-. The storage class for generated functions will be 'attr' (e.g., `static`).\n-. Generated function names are prefixed with 'foo_' (e.g., `treap_`).\n-. Treap nodes will be of type 'node_type' (e.g., `struct treap_node`).\n-  This type must be a struct with at least one `struct trp_node` field\n-  to point to its children.\n-. The field used to access child nodes will be 'link_field'.\n-. All treap nodes must lie in the 'pool' object pool.\n-. Treap nodes must be totally ordered by the 'cmp' relation, with the\n-  following prototype:\n-+\n-int (*cmp)(node_type \\*a, node_type \\*b)\n-+\n-and returning a value less than, equal to, or greater than zero\n-according to the result of comparison.\n-\n-node_type {asterisk}foo_insert(struct trp_root *treap, node_type \\*node)::\n-\n-\tInsert node into treap.  If inserted multiple times,\n-\ta node will appear in the treap multiple times.\n-+\n-The return value is the address of the node within the treap,\n-which might differ from `node` if `pool_alloc` had to call\n-`realloc` to expand the pool.\n-\n-void foo_remove(struct trp_root *treap, node_type \\*node)::\n-\n-\tRemove node from treap.  Caller must ensure node is\n-\tpresent in treap before using this function.\n-\n-node_type *foo_search(struct trp_root \\*treap, node_type \\*key)::\n-\n-\tSearch for a node that matches key.  If no match is found,\n-\tresult is NULL.\n-\n-node_type *foo_nsearch(struct trp_root \\*treap, node_type \\*key)::\n-\n-\tLike `foo_search`, but if if the key is missing return what\n-\twould be key's successor, were key in treap (NULL if no\n-\tsuccessor).\n-\n-node_type *foo_first(struct trp_root \\*treap)::\n-\n-\tFind the first item from the treap, in sorted order.\n-\n-node_type *foo_next(struct trp_root \\*treap, node_type \\*node)::\n-\n-\tFind the next item.\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163705","messageId":"1300518231-20008-9-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 8/9] vcs-svn: drop obj_pool.h","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:50Z","receivedAt":"2011-03-19T07:03:50Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Signed-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n .gitignore         |    1 -\n Makefile           |    2 -\n t/t0080-vcs-svn.sh |   79 -----------------------------------\n test-obj-pool.c    |  116 ----------------------------------------------------\n vcs-svn/obj_pool.h |   61 ---------------------------\n 5 files changed, 0 insertions(+), 259 deletions(-)\n delete mode 100755 t/t0080-vcs-svn.sh\n delete mode 100644 test-obj-pool.c\n delete mode 100644 vcs-svn/obj_pool.h\n\ndiff --git a/.gitignore b/.gitignore\nindex aa94ff1..789f922 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -171,7 +171,6 @@\n /test-line-buffer\n /test-match-trees\n /test-mktemp\n-/test-obj-pool\n /test-parse-options\n /test-path-utils\n /test-run-command\ndiff --git a/Makefile b/Makefile\nindex 2d56ab9..6165609 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -424,7 +424,6 @@ TEST_PROGRAMS_NEED_X += test-dump-cache-tree\n TEST_PROGRAMS_NEED_X += test-genrandom\n TEST_PROGRAMS_NEED_X += test-line-buffer\n TEST_PROGRAMS_NEED_X += test-match-trees\n-TEST_PROGRAMS_NEED_X += test-obj-pool\n TEST_PROGRAMS_NEED_X += test-parse-options\n TEST_PROGRAMS_NEED_X += test-path-utils\n TEST_PROGRAMS_NEED_X += test-run-command\n@@ -1962,7 +1961,6 @@ xdiff-interface.o $(XDIFF_OBJS): \\\n \txdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h\n \n $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \\\n-\tvcs-svn/obj_pool.h \\\n \tvcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \\\n \tvcs-svn/svndump.h\n \ndiff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh\ndeleted file mode 100755\nindex 3f29496..0000000\n--- a/t/t0080-vcs-svn.sh\n+++ /dev/null\n@@ -1,79 +0,0 @@\n-#!/bin/sh\n-\n-test_description='check infrastructure for svn importer'\n-\n-. ./test-lib.sh\n-uint32_max=4294967295\n-\n-test_expect_success 'obj pool: store data' '\n-\tcat <<-\\EOF >expected &&\n-\t0\n-\t1\n-\tEOF\n-\n-\ttest-obj-pool <<-\\EOF >actual &&\n-\talloc one 16\n-\tset one 13\n-\ttest one 13\n-\treset one\n-\tEOF\n-\ttest_cmp expected actual\n-'\n-\n-test_expect_success 'obj pool: NULL is offset ~0' '\n-\techo \"$uint32_max\" >expected &&\n-\techo null one | test-obj-pool >actual &&\n-\ttest_cmp expected actual\n-'\n-\n-test_expect_success 'obj pool: out-of-bounds access' '\n-\tcat <<-EOF >expected &&\n-\t0\n-\t0\n-\t$uint32_max\n-\t$uint32_max\n-\t16\n-\t20\n-\t$uint32_max\n-\tEOF\n-\n-\ttest-obj-pool <<-\\EOF >actual &&\n-\talloc one 16\n-\talloc two 16\n-\toffset one 20\n-\toffset two 20\n-\talloc one 5\n-\toffset one 20\n-\tfree one 1\n-\toffset one 20\n-\treset one\n-\treset two\n-\tEOF\n-\ttest_cmp expected actual\n-'\n-\n-test_expect_success 'obj pool: high-water mark' '\n-\tcat <<-\\EOF >expected &&\n-\t0\n-\t0\n-\t10\n-\t20\n-\t20\n-\t20\n-\tEOF\n-\n-\ttest-obj-pool <<-\\EOF >actual &&\n-\talloc one 10\n-\tcommitted one\n-\talloc one 10\n-\tcommit one\n-\tcommitted one\n-\talloc one 10\n-\tfree one 20\n-\tcommitted one\n-\treset one\n-\tEOF\n-\ttest_cmp expected actual\n-'\n-\n-test_done\ndiff --git a/test-obj-pool.c b/test-obj-pool.c\ndeleted file mode 100644\nindex 5018863..0000000\n--- a/test-obj-pool.c\n+++ /dev/null\n@@ -1,116 +0,0 @@\n-/*\n- * test-obj-pool.c: code to exercise the svn importer's object pool\n- */\n-\n-#include \"cache.h\"\n-#include \"vcs-svn/obj_pool.h\"\n-\n-enum pool { POOL_ONE, POOL_TWO };\n-obj_pool_gen(one, int, 1)\n-obj_pool_gen(two, int, 4096)\n-\n-static uint32_t strtouint32(const char *s)\n-{\n-\tchar *end;\n-\tuintmax_t n = strtoumax(s, &end, 10);\n-\tif (*s == '\\0' || (*end != '\\n' && *end != '\\0'))\n-\t\tdie(\"invalid offset: %s\", s);\n-\treturn (uint32_t) n;\n-}\n-\n-static void handle_command(const char *command, enum pool pool, const char *arg)\n-{\n-\tswitch (*command) {\n-\tcase 'a':\n-\t\tif (!prefixcmp(command, \"alloc \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tprintf(\"%\"PRIu32\"\\n\",\n-\t\t\t\tpool == POOL_ONE ?\n-\t\t\t\tone_alloc(n) : two_alloc(n));\n-\t\t\treturn;\n-\t\t}\n-\tcase 'c':\n-\t\tif (!prefixcmp(command, \"commit \")) {\n-\t\t\tpool == POOL_ONE ? one_commit() : two_commit();\n-\t\t\treturn;\n-\t\t}\n-\t\tif (!prefixcmp(command, \"committed \")) {\n-\t\t\tprintf(\"%\"PRIu32\"\\n\",\n-\t\t\t\tpool == POOL_ONE ?\n-\t\t\t\tone_pool.committed : two_pool.committed);\n-\t\t\treturn;\n-\t\t}\n-\tcase 'f':\n-\t\tif (!prefixcmp(command, \"free \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tpool == POOL_ONE ? one_free(n) : two_free(n);\n-\t\t\treturn;\n-\t\t}\n-\tcase 'n':\n-\t\tif (!prefixcmp(command, \"null \")) {\n-\t\t\tprintf(\"%\"PRIu32\"\\n\",\n-\t\t\t\tpool == POOL_ONE ?\n-\t\t\t\tone_offset(NULL) : two_offset(NULL));\n-\t\t\treturn;\n-\t\t}\n-\tcase 'o':\n-\t\tif (!prefixcmp(command, \"offset \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tprintf(\"%\"PRIu32\"\\n\",\n-\t\t\t\tpool == POOL_ONE ?\n-\t\t\t\tone_offset(one_pointer(n)) :\n-\t\t\t\ttwo_offset(two_pointer(n)));\n-\t\t\treturn;\n-\t\t}\n-\tcase 'r':\n-\t\tif (!prefixcmp(command, \"reset \")) {\n-\t\t\tpool == POOL_ONE ? one_reset() : two_reset();\n-\t\t\treturn;\n-\t\t}\n-\tcase 's':\n-\t\tif (!prefixcmp(command, \"set \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tif (pool == POOL_ONE)\n-\t\t\t\t*one_pointer(n) = 1;\n-\t\t\telse\n-\t\t\t\t*two_pointer(n) = 1;\n-\t\t\treturn;\n-\t\t}\n-\tcase 't':\n-\t\tif (!prefixcmp(command, \"test \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tprintf(\"%d\\n\", pool == POOL_ONE ?\n-\t\t\t\t*one_pointer(n) : *two_pointer(n));\n-\t\t\treturn;\n-\t\t}\n-\tdefault:\n-\t\tdie(\"unrecognized command: %s\", command);\n-\t}\n-}\n-\n-static void handle_line(const char *line)\n-{\n-\tconst char *arg = strchr(line, ' ');\n-\tenum pool pool;\n-\n-\tif (arg && !prefixcmp(arg + 1, \"one\"))\n-\t\tpool = POOL_ONE;\n-\telse if (arg && !prefixcmp(arg + 1, \"two\"))\n-\t\tpool = POOL_TWO;\n-\telse\n-\t\tdie(\"no pool specified: %s\", line);\n-\n-\thandle_command(line, pool, arg + strlen(\"one \"));\n-}\n-\n-int main(int argc, char *argv[])\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 1)\n-\t\tusage(\"test-obj-str < script\");\n-\n-\twhile (strbuf_getline(&sb, stdin, '\\n') != EOF)\n-\t\thandle_line(sb.buf);\n-\tstrbuf_release(&sb);\n-\treturn 0;\n-}\ndiff --git a/vcs-svn/obj_pool.h b/vcs-svn/obj_pool.h\ndeleted file mode 100644\nindex deb6eb8..0000000\n--- a/vcs-svn/obj_pool.h\n+++ /dev/null\n@@ -1,61 +0,0 @@\n-/*\n- * Licensed under a two-clause BSD-style license.\n- * See LICENSE for details.\n- */\n-\n-#ifndef OBJ_POOL_H_\n-#define OBJ_POOL_H_\n-\n-#include \"git-compat-util.h\"\n-\n-#define MAYBE_UNUSED __attribute__((__unused__))\n-\n-#define obj_pool_gen(pre, obj_t, initial_capacity) \\\n-static struct { \\\n-\tuint32_t committed; \\\n-\tuint32_t size; \\\n-\tuint32_t capacity; \\\n-\tobj_t *base; \\\n-} pre##_pool = {0, 0, 0, NULL}; \\\n-static MAYBE_UNUSED uint32_t pre##_alloc(uint32_t count) \\\n-{ \\\n-\tuint32_t offset; \\\n-\tif (pre##_pool.size + count > pre##_pool.capacity) { \\\n-\t\twhile (pre##_pool.size + count > pre##_pool.capacity) \\\n-\t\t\tif (pre##_pool.capacity) \\\n-\t\t\t\tpre##_pool.capacity *= 2; \\\n-\t\t\telse \\\n-\t\t\t\tpre##_pool.capacity = initial_capacity; \\\n-\t\tpre##_pool.base = realloc(pre##_pool.base, \\\n-\t\t\t\t\tpre##_pool.capacity * sizeof(obj_t)); \\\n-\t} \\\n-\toffset = pre##_pool.size; \\\n-\tpre##_pool.size += count; \\\n-\treturn offset; \\\n-} \\\n-static MAYBE_UNUSED void pre##_free(uint32_t count) \\\n-{ \\\n-\tpre##_pool.size -= count; \\\n-} \\\n-static MAYBE_UNUSED uint32_t pre##_offset(obj_t *obj) \\\n-{ \\\n-\treturn obj == NULL ? ~0 : obj - pre##_pool.base; \\\n-} \\\n-static MAYBE_UNUSED obj_t *pre##_pointer(uint32_t offset) \\\n-{ \\\n-\treturn offset >= pre##_pool.size ? NULL : &pre##_pool.base[offset]; \\\n-} \\\n-static MAYBE_UNUSED void pre##_commit(void) \\\n-{ \\\n-\tpre##_pool.committed = pre##_pool.size; \\\n-} \\\n-static MAYBE_UNUSED void pre##_reset(void) \\\n-{ \\\n-\tfree(pre##_pool.base); \\\n-\tpre##_pool.base = NULL; \\\n-\tpre##_pool.size = 0; \\\n-\tpre##_pool.capacity = 0; \\\n-\tpre##_pool.committed = 0; \\\n-}\n-\n-#endif\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163709","messageId":"1300518231-20008-10-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 9/9] vcs-svn: use strchr to find RFC822 delimiter","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:03:51Z","receivedAt":"2011-03-19T07:03:51Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This is a small optimisation (4% reduction in user time) but is the largest\nartifact within the parsing portion of svndump.c\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndump.c |    4 +++-\n 1 files changed, 3 insertions(+), 1 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex fd67db8..7bc2d3d 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -296,10 +296,12 @@ void svndump_read(const char *url)\n \n \treset_dump_ctx(url);\n \twhile ((t = buffer_read_line(&input))) {\n-\t\tval = strstr(t, \": \");\n+\t\tval = strchr(t, ':');\n \t\tif (!val)\n \t\t\tcontinue;\n \t\t*val++ = '\\0';\n+\t\tif (*val != ' ')\n+\t\t\tcontinue;\n \t\t*val++ = '\\0';\n \n \t\t/* strlen(key) */\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163711","messageId":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"vcs-svn: integrate support for text deltas","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:38Z","receivedAt":"2011-03-19T07:20:38Z","isPatch":false,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This series is largely the work of Jonathan Nieder.\nI have painstakingly ported it from the old development branch to the\nlatest series to hit the list. As previously, I have tested against\nthe ASF subversion repository to increase confidence in the series.\nHopefully, this brings us a little closer to having full support for\nversion 3 of the subversion dump format in master.\n\n\n Makefile                  |    5 +-\n contrib/svn-fe/svn-fe.txt |    5 +-\n t/t9010-svn-fe.sh         |  108 ++++++++++++++++-\n t/t9011-svn-da.sh         |  250 ++++++++++++++++++++++++++++++++++++\n test-svn-fe.c             |   42 +++++--\n vcs-svn/LICENSE           |    2 +\n vcs-svn/fast_export.c     |  122 +++++++++++++++++-\n vcs-svn/fast_export.h     |    3 +\n vcs-svn/line_buffer.c     |   37 +++---\n vcs-svn/line_buffer.h     |    7 +-\n vcs-svn/line_buffer.txt   |    3 +-\n vcs-svn/sliding_window.c  |   74 +++++++++++\n vcs-svn/sliding_window.h  |   17 +++\n vcs-svn/svndiff.c         |  308 +++++++++++++++++++++++++++++++++++++++++++++\n vcs-svn/svndiff.h         |   10 ++\n vcs-svn/svndump.c         |   35 ++++-\n 16 files changed, 980 insertions(+), 48 deletions(-)\n"},{"id":"163716","messageId":"1300519254-20201-2-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 01/16] vcs-svn: improve support for reading large files","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:39Z","receivedAt":"2011-03-19T07:20:39Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nMove from uint32_t to off_t as the fundamental unit of length used by\nthe line_buffer library.  Performance would get worse if anything but\nI think it's worth it for support of deltas that need to skip large\npieces (> 4 GiB).\n\nException: buffer_read_string still takes a uint32_t, since it keeps\nits result in an in-core obj_pool.\n\nCallers still have to be updated to take advantage of this.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/line_buffer.c |    8 ++++----\n vcs-svn/line_buffer.h |    4 ++--\n 2 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c\nindex eb8a6a7..6930aac 100644\n--- a/vcs-svn/line_buffer.c\n+++ b/vcs-svn/line_buffer.c\n@@ -104,10 +104,10 @@ void buffer_read_binary(struct line_buffer *buf,\n \tstrbuf_fread(sb, size, buf->infile);\n }\n \n-void buffer_copy_bytes(struct line_buffer *buf, uint32_t len)\n+void buffer_copy_bytes(struct line_buffer *buf, off_t len)\n {\n \tchar byte_buffer[COPY_BUFFER_LEN];\n-\tuint32_t in;\n+\toff_t in;\n \twhile (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {\n \t\tin = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;\n \t\tin = fread(byte_buffer, 1, in, buf->infile);\n@@ -120,10 +120,10 @@ void buffer_copy_bytes(struct line_buffer *buf, uint32_t len)\n \t}\n }\n \n-void buffer_skip_bytes(struct line_buffer *buf, uint32_t len)\n+void buffer_skip_bytes(struct line_buffer *buf, off_t len)\n {\n \tchar byte_buffer[COPY_BUFFER_LEN];\n-\tuint32_t in;\n+\toff_t in;\n \twhile (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {\n \t\tin = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;\n \t\tin = fread(byte_buffer, 1, in, buf->infile);\ndiff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h\nindex 3c9629e..a090dd6 100644\n--- a/vcs-svn/line_buffer.h\n+++ b/vcs-svn/line_buffer.h\n@@ -26,7 +26,7 @@ char *buffer_read_line(struct line_buffer *buf);\n char *buffer_read_string(struct line_buffer *buf, uint32_t len);\n int buffer_read_char(struct line_buffer *buf);\n void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);\n-void buffer_copy_bytes(struct line_buffer *buf, uint32_t len);\n-void buffer_skip_bytes(struct line_buffer *buf, uint32_t len);\n+void buffer_copy_bytes(struct line_buffer *buf, off_t len);\n+void buffer_skip_bytes(struct line_buffer *buf, off_t len);\n \n #endif\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163712","messageId":"1300519254-20201-3-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 02/16] vcs-svn: make buffer_skip_bytes return length read","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:40Z","receivedAt":"2011-03-19T07:20:40Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nCurrently there is no way to detect when input ended if it ended\nearly during buffer_skip_bytes.  Tell the calling program how many\nbytes were actually skipped for easier debugging.\n\nExisting callers will still ignore early EOF.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/line_buffer.c   |   13 +++++++------\n vcs-svn/line_buffer.h   |    2 +-\n vcs-svn/line_buffer.txt |    3 ++-\n 3 files changed, 10 insertions(+), 8 deletions(-)\n\ndiff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c\nindex 6930aac..a78c5d8 100644\n--- a/vcs-svn/line_buffer.c\n+++ b/vcs-svn/line_buffer.c\n@@ -120,15 +120,16 @@ void buffer_copy_bytes(struct line_buffer *buf, off_t len)\n \t}\n }\n \n-void buffer_skip_bytes(struct line_buffer *buf, off_t len)\n+off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)\n {\n \tchar byte_buffer[COPY_BUFFER_LEN];\n-\toff_t in;\n-\twhile (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {\n-\t\tin = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;\n-\t\tin = fread(byte_buffer, 1, in, buf->infile);\n-\t\tlen -= in;\n+\toff_t done = 0;\n+\twhile (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {\n+\t\toff_t len = nbytes - done;\n+\t\toff_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;\n+\t\tdone += fread(byte_buffer, 1, in, buf->infile);\n \t}\n+\treturn done;\n }\n \n void buffer_reset(struct line_buffer *buf)\ndiff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h\nindex a090dd6..7d10f9c 100644\n--- a/vcs-svn/line_buffer.h\n+++ b/vcs-svn/line_buffer.h\n@@ -27,6 +27,6 @@ char *buffer_read_string(struct line_buffer *buf, uint32_t len);\n int buffer_read_char(struct line_buffer *buf);\n void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);\n void buffer_copy_bytes(struct line_buffer *buf, off_t len);\n-void buffer_skip_bytes(struct line_buffer *buf, off_t len);\n+off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);\n \n #endif\ndiff --git a/vcs-svn/line_buffer.txt b/vcs-svn/line_buffer.txt\nindex e89cc41..4ef0755 100644\n--- a/vcs-svn/line_buffer.txt\n+++ b/vcs-svn/line_buffer.txt\n@@ -76,7 +76,8 @@ Functions\n \n `buffer_skip_bytes`::\n \tDiscards `len` bytes from the input stream (stopping early\n-\tif necessary because of an error or eof).\n+\tif necessary because of an error or eof).  Return value is\n+\tthe number of bytes successfully read.\n \n `buffer_reset`::\n \tDeallocates non-static buffers.\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163714","messageId":"1300519254-20201-4-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 03/16] vcs-svn: make buffer_copy_bytes return length read","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:41Z","receivedAt":"2011-03-19T07:20:41Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nCurrently buffer_copy_bytes does not report to its caller whether\nit encountered an early end of file.\n\nAdd a return value representing the number of bytes read (but not\nthe number of bytes copied).  This way all three unusual conditions\ncan be distinguished: input error with buffer_ferror, output error\nwith ferror(outfile), early end of input by checking the return\nvalue.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/line_buffer.c |   18 +++++++++---------\n vcs-svn/line_buffer.h |    3 ++-\n 2 files changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c\nindex a78c5d8..08d7cae 100644\n--- a/vcs-svn/line_buffer.c\n+++ b/vcs-svn/line_buffer.c\n@@ -104,20 +104,20 @@ void buffer_read_binary(struct line_buffer *buf,\n \tstrbuf_fread(sb, size, buf->infile);\n }\n \n-void buffer_copy_bytes(struct line_buffer *buf, off_t len)\n+off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)\n {\n \tchar byte_buffer[COPY_BUFFER_LEN];\n-\toff_t in;\n-\twhile (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {\n-\t\tin = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;\n+\toff_t done = 0;\n+\twhile (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {\n+\t\toff_t len = nbytes - done;\n+\t\toff_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;\n \t\tin = fread(byte_buffer, 1, in, buf->infile);\n-\t\tlen -= in;\n+\t\tdone += in;\n \t\tfwrite(byte_buffer, 1, in, stdout);\n-\t\tif (ferror(stdout)) {\n-\t\t\tbuffer_skip_bytes(buf, len);\n-\t\t\treturn;\n-\t\t}\n+\t\tif (ferror(stdout))\n+\t\t\treturn done + buffer_skip_bytes(buf, nbytes - done);\n \t}\n+\treturn done;\n }\n \n off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)\ndiff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h\nindex 7d10f9c..f5c468a 100644\n--- a/vcs-svn/line_buffer.h\n+++ b/vcs-svn/line_buffer.h\n@@ -26,7 +26,8 @@ char *buffer_read_line(struct line_buffer *buf);\n char *buffer_read_string(struct line_buffer *buf, uint32_t len);\n int buffer_read_char(struct line_buffer *buf);\n void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);\n-void buffer_copy_bytes(struct line_buffer *buf, off_t len);\n+/* Returns number of bytes read (not necessarily written). */\n+off_t buffer_copy_bytes(struct line_buffer *buf, off_t len);\n off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);\n \n #endif\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163715","messageId":"1300519254-20201-5-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 04/16] vcs-svn: improve reporting of input errors","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:42Z","receivedAt":"2011-03-19T07:20:42Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nCatch input errors and exit early enough to print a reasonable\ndiagnosis based on errno.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/fast_export.c |   13 +++++++++++--\n vcs-svn/svndump.c     |   22 +++++++++++++++++++---\n 2 files changed, 30 insertions(+), 5 deletions(-)\n\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 1d50512..4748253 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -120,15 +120,24 @@ static const char *get_response_line(void)\n \tdie(\"unexpected end of fast-import feedback\");\n }\n \n+static void die_short_read(struct line_buffer *input)\n+{\n+\tif (buffer_ferror(input))\n+\t\tdie_errno(\"error reading dump file\");\n+\tdie(\"invalid dump: unexpected end of file\");\n+}\n+\n void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input)\n {\n \tif (mode == REPO_MODE_LNK) {\n \t\t/* svn symlink blobs start with \"link \" */\n-\t\tbuffer_skip_bytes(input, 5);\n \t\tlen -= 5;\n+\t\tif (buffer_skip_bytes(input, 5) != 5)\n+\t\t\tdie_short_read(input);\n \t}\n \tprintf(\"data %\"PRIu32\"\\n\", len);\n-\tbuffer_copy_bytes(input, len);\n+\tif (buffer_copy_bytes(input, len) != len)\n+\t\tdie_short_read(input);\n \tfputc('\\n', stdout);\n }\n \ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 7bc2d3d..dbb9c16 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -133,6 +133,13 @@ static void handle_property(const char *key, const char *val, uint32_t len,\n \t}\n }\n \n+static void die_short_read(void)\n+{\n+\tif (buffer_ferror(&input))\n+\t\tdie_errno(\"error reading dump file\");\n+\tdie(\"invalid dump: unexpected end of file\");\n+}\n+\n static void read_props(void)\n {\n \tchar key[16] = {0};\n@@ -159,7 +166,9 @@ static void read_props(void)\n \t\t\tdie(\"invalid property line: %s\\n\", t);\n \t\tlen = atoi(&t[2]);\n \t\tval = buffer_read_string(&input, len);\n-\t\tbuffer_skip_bytes(&input, 1);\t/* Discard trailing newline. */\n+\t\t/* Discard trailing newline. */\n+\t\tif (buffer_skip_bytes(&input, 1) != 1)\n+\t\t\tdie_short_read();\n \n \t\tswitch (type) {\n \t\tcase 'K':\n@@ -402,7 +411,11 @@ void svndump_read(const char *url)\n \t\t\tif (memcmp(t, \"Content-length\", 14))\n \t\t\t\tcontinue;\n \t\t\tlen = atoi(val);\n-\t\t\tbuffer_read_line(&input);\n+\t\t\tt = buffer_read_line(&input);\n+\t\t\tif (!t)\n+\t\t\t\tdie_short_read();\n+\t\t\tif (*t)\n+\t\t\t\tdie(\"invalid dump: expected blank line after content length header\");\n \t\t\tif (active_ctx == REV_CTX) {\n \t\t\t\tread_props();\n \t\t\t} else if (active_ctx == NODE_CTX) {\n@@ -410,10 +423,13 @@ void svndump_read(const char *url)\n \t\t\t\tactive_ctx = INTERNODE_CTX;\n \t\t\t} else {\n \t\t\t\tfprintf(stderr, \"Unexpected content length header: %\"PRIu32\"\\n\", len);\n-\t\t\t\tbuffer_skip_bytes(&input, len);\n+\t\t\t\tif (buffer_skip_bytes(&input, len) != len)\n+\t\t\t\t\tdie_short_read();\n \t\t\t}\n \t\t}\n \t}\n+\tif (buffer_ferror(&input))\n+\t\tdie_short_read();\n \tif (active_ctx == NODE_CTX)\n \t\thandle_node();\n \tif (active_ctx == REV_CTX)\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163713","messageId":"1300519254-20201-6-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 05/16] vcs-svn: learn to maintain a sliding view of a file","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:43Z","receivedAt":"2011-03-19T07:20:43Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nEach section of a Subversion-format delta only requires examining (and\nkeeping in random-access memory) a small portion of the preimage.  At\nany moment, this portion is starts at a certain file offset and has a\nwell-defined length, and as the delta is applied, the portion moves\nfrom the beginning to the end of the preimage.  Add a move_window\nfunction to keep track of this view into the preimage.\n\nYou can use it like this:\n\n\tbuffer_init(f, NULL);\n\tstruct sliding_view window = SLIDING_VIEW_INIT(f);\n\tmove_window(&window, 3, 7);\t/* (1) */\n\tmove_window(&window, 5, 5);\t/* (2) */\n\tmove_window(&window, 12, 2);\t/* (3) */\n\tstrbuf_release(&window.buf);\n\tbuffer_deinit(f);\n\nThe data structure is called sliding_view instead of _window to\nprevent confusion with svndiff0 Windows.\n\nIn this example, (1) reads 10 bytes and discards the first 3;\n(2) discards the first 2, which are not needed any more; and (3) skips\n2 bytes and reads 2 new bytes to work with.\n\nWhen move_window returns, the file position indicator is at position\nwindow->off + window->width and the data from positions window->off to\nthe current file position are stored in window->buf.\n\nThis function performs only sequential access from the input file and\nnever seeks, so it can be safely used on pipes and sockets.\n\nOn end-of-file, move_window silently reads less than the caller\nrequested.  On other errors, it prints a message and returns -1.\n\nHelped-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n Makefile                 |    5 ++-\n vcs-svn/LICENSE          |    2 +\n vcs-svn/sliding_window.c |   74 ++++++++++++++++++++++++++++++++++++++++++++++\n vcs-svn/sliding_window.h |   17 ++++++++++\n 4 files changed, 96 insertions(+), 2 deletions(-)\n create mode 100644 vcs-svn/sliding_window.c\n create mode 100644 vcs-svn/sliding_window.h\n\ndiff --git a/Makefile b/Makefile\nindex 6165609..bac415d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1836,7 +1836,8 @@ endif\n XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \\\n \txdiff/xmerge.o xdiff/xpatience.o\n VCSSVN_OBJS = vcs-svn/line_buffer.o vcs-svn/repo_tree.o \\\n-\tvcs-svn/fast_export.o vcs-svn/svndump.o\n+\tvcs-svn/fast_export.o vcs-svn/svndump.o \\\n+\tvcs-svn/sliding_window.o\n VCSSVN_TEST_OBJS = test-obj-pool.o test-line-buffer.o test-treap.o\n OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)\n \n@@ -1962,7 +1963,7 @@ xdiff-interface.o $(XDIFF_OBJS): \\\n \n $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \\\n \tvcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \\\n-\tvcs-svn/svndump.h\n+\tvcs-svn/svndump.h vcs-svn/sliding_window.h\n \n test-svn-fe.o: vcs-svn/svndump.h\n endif\ndiff --git a/vcs-svn/LICENSE b/vcs-svn/LICENSE\nindex 533f585..eb91858 100644\n--- a/vcs-svn/LICENSE\n+++ b/vcs-svn/LICENSE\n@@ -1,6 +1,8 @@\n Copyright (C) 2010 David Barr <david.barr@cordelta.com>.\n All rights reserved.\n \n+Copyright (C) 2010 Jonathan Nieder <jrnieder@gmail.com>.\n+\n Copyright (C) 2005 Stefan Hegny, hydrografix Consulting GmbH,\n Frankfurt/Main, Germany\n and others, see http://svn2cc.sarovar.org\ndiff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c\nnew file mode 100644\nindex 0000000..9ce399c\n--- /dev/null\n+++ b/vcs-svn/sliding_window.c\n@@ -0,0 +1,74 @@\n+/*\n+ * Licensed under a two-clause BSD-style license.\n+ * See LICENSE for details.\n+ */\n+\n+#include \"git-compat-util.h\"\n+#include \"sliding_window.h\"\n+#include \"line_buffer.h\"\n+#include \"strbuf.h\"\n+\n+static int input_error(struct line_buffer *file)\n+{\n+\tif (!buffer_ferror(file))\n+\t\treturn error(\"delta preimage ends early\");\n+\treturn error(\"cannot read delta preimage: %s\", strerror(errno));\n+}\n+\n+static int skip_or_whine(struct line_buffer *file, off_t gap)\n+{\n+\tconst off_t nread = buffer_skip_bytes(file, gap);\n+\treturn nread == gap ? 0 : input_error(file);\n+}\n+\n+static int read_to_fill_or_whine(struct line_buffer *file,\n+\t\t\t\tstruct strbuf *buf, size_t width)\n+{\n+\tbuffer_read_binary(file, buf, width - buf->len);\n+\treturn buf->len == width ? 0 : input_error(file);\n+}\n+\n+static int check_overflow(off_t a, size_t b)\n+{\n+\tif (b > maximum_signed_value_of_type(off_t))\n+\t\treturn error(\"unrepresentable length in delta: \"\n+\t\t\t\t\"%\"PRIuMAX\" > OFF_MAX\", (uintmax_t) b);\n+\tif (signed_add_overflows(a, (off_t) b))\n+\t\treturn error(\"unrepresentable offset in delta: \"\n+\t\t\t\t\"%\"PRIuMAX\" + %\"PRIuMAX\" > OFF_MAX\",\n+\t\t\t\t(uintmax_t) a, (uintmax_t) b);\n+\treturn 0;\n+}\n+\n+int move_window(struct sliding_view *view, off_t off, size_t width)\n+{\n+\toff_t file_offset;\n+\tassert(view);\n+\tassert(view->width <= view->buf.len);\n+\tassert(!check_overflow(view->off, view->buf.len));\n+\n+\tif (check_overflow(off, width))\n+\t\treturn -1;\n+\tif (off < view->off || off + width < view->off + view->width)\n+\t\treturn error(\"invalid delta: window slides left\");\n+\n+\tfile_offset = view->off + view->buf.len;\n+\tif (off < file_offset) {\n+\t\t/* Move the overlapping region into place. */\n+\t\tstrbuf_remove(&view->buf, 0, off - view->off);\n+\t} else {\n+\t\t/* Seek ahead to skip the gap. */\n+\t\tif (skip_or_whine(view->file, off - file_offset))\n+\t\t\treturn -1;\n+\t\tstrbuf_setlen(&view->buf, 0);\n+\t}\n+\n+\tif (view->buf.len > width)\n+\t\t; /* Already read. */\n+\telse if (read_to_fill_or_whine(view->file, &view->buf, width))\n+\t\treturn -1;\n+\n+\tview->off = off;\n+\tview->width = width;\n+\treturn 0;\n+}\ndiff --git a/vcs-svn/sliding_window.h b/vcs-svn/sliding_window.h\nnew file mode 100644\nindex 0000000..ed0bfdd\n--- /dev/null\n+++ b/vcs-svn/sliding_window.h\n@@ -0,0 +1,17 @@\n+#ifndef SLIDING_WINDOW_H_\n+#define SLIDING_WINDOW_H_\n+\n+#include \"strbuf.h\"\n+\n+struct sliding_view {\n+\tstruct line_buffer *file;\n+\toff_t off;\n+\tsize_t width;\n+\tstruct strbuf buf;\n+};\n+\n+#define SLIDING_VIEW_INIT(input)\t{ (input), 0, 0, STRBUF_INIT }\n+\n+extern int move_window(struct sliding_view *view, off_t off, size_t width);\n+\n+#endif\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163718","messageId":"1300519254-20201-7-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 06/16] vcs-svn: skeleton of an svn delta parser","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:44Z","receivedAt":"2011-03-19T07:20:44Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nA delta in the subversion delta (svndiff0) format consists of the\nmagic bytes SVN\\0 followed by a sequence of windows of a certain\nwell specified format (starting with five integers).\n\nAdd an svndiff0_apply function and test-svn-fe -d commandline tool to\nparse such a delta in the special case of not including any windows.\n\nLater patches will add features to turn this into a fully functional\ndelta applier for use by svn-fe in parsing the streams produced by\n\"svnrdump dump\" and \"svnadmin dump --deltas\".\n\nThe content of symlinks starts with the word \"link \" in Subversion's\nworldview, so we will need to prepend that text for the sake of\ndelta application.  Initialization of the input state of the\ndelta preimage is left to the calling program, which gives callers\na chance to seed the sliding window with text of their choice.\n\nImproved-by: Ramkumar Ramachandra <artagnon@gmail.com>\nImproved-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n Makefile              |    4 +-\n t/t9011-svn-da.sh     |   37 ++++++++++++++++++++++++++++++++++\n test-svn-fe.c         |   42 ++++++++++++++++++++++++++++++++-------\n vcs-svn/line_buffer.c |    6 ++--\n vcs-svn/line_buffer.h |    2 +-\n vcs-svn/svndiff.c     |   52 +++++++++++++++++++++++++++++++++++++++++++++++++\n vcs-svn/svndiff.h     |   10 +++++++++\n 7 files changed, 139 insertions(+), 14 deletions(-)\n create mode 100755 t/t9011-svn-da.sh\n create mode 100644 vcs-svn/svndiff.c\n create mode 100644 vcs-svn/svndiff.h\n\ndiff --git a/Makefile b/Makefile\nindex bac415d..bc6690a 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1837,7 +1837,7 @@ XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \\\n \txdiff/xmerge.o xdiff/xpatience.o\n VCSSVN_OBJS = vcs-svn/line_buffer.o vcs-svn/repo_tree.o \\\n \tvcs-svn/fast_export.o vcs-svn/svndump.o \\\n-\tvcs-svn/sliding_window.o\n+\tvcs-svn/sliding_window.o vcs-svn/svndiff.o\n VCSSVN_TEST_OBJS = test-obj-pool.o test-line-buffer.o test-treap.o\n OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)\n \n@@ -1963,7 +1963,7 @@ xdiff-interface.o $(XDIFF_OBJS): \\\n \n $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \\\n \tvcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \\\n-\tvcs-svn/svndump.h vcs-svn/sliding_window.h\n+\tvcs-svn/sliding_window.h vcs-svn/svndiff.h vcs-svn/svndump.h\n \n test-svn-fe.o: vcs-svn/svndump.h\n endif\ndiff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh\nnew file mode 100755\nindex 0000000..6d6a406\n--- /dev/null\n+++ b/t/t9011-svn-da.sh\n@@ -0,0 +1,37 @@\n+#!/bin/sh\n+\n+test_description='test parsing of svndiff0 files\n+\n+Using the \"test-svn-fe -d\" helper, check that svn-fe correctly\n+interprets deltas using various facilities (some from the spec,\n+some only learned from practice).\n+'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\t>empty &&\n+\tprintf foo >preimage\n+'\n+\n+test_expect_success 'reject empty delta' '\n+\ttest_must_fail test-svn-fe -d preimage empty 0\n+'\n+\n+test_expect_success 'delta can empty file' '\n+\tprintf \"SVNQ\" | q_to_nul >clear.delta &&\n+\ttest-svn-fe -d preimage clear.delta 4 >actual &&\n+\ttest_cmp empty actual\n+'\n+\n+test_expect_success 'reject svndiff2' '\n+\tprintf \"SVN\\002\" >bad.filetype &&\n+\ttest_must_fail test-svn-fe -d preimage bad.filetype 4\n+'\n+\n+test_expect_failure 'one-window empty delta' '\n+\tprintf \"SVNQ%s\" \"QQQQQ\" | q_to_nul >clear.onewindow &&\n+\ttest-svn-fe -d preimage clear.onewindow 9 >actual &&\n+\ttest_cmp empty actual\n+'\n+\n+test_done\ndiff --git a/test-svn-fe.c b/test-svn-fe.c\nindex b42ba78..6558b52 100644\n--- a/test-svn-fe.c\n+++ b/test-svn-fe.c\n@@ -4,15 +4,41 @@\n \n #include \"git-compat-util.h\"\n #include \"vcs-svn/svndump.h\"\n+#include \"vcs-svn/svndiff.h\"\n+#include \"vcs-svn/sliding_window.h\"\n+#include \"vcs-svn/line_buffer.h\"\n \n int main(int argc, char *argv[])\n {\n-\tif (argc != 2)\n-\t\tusage(\"test-svn-fe <file>\");\n-\tif (svndump_init(argv[1]))\n-\t\treturn 1;\n-\tsvndump_read(NULL);\n-\tsvndump_deinit();\n-\tsvndump_reset();\n-\treturn 0;\n+\tstatic const char test_svnfe_usage[] =\n+\t\t\"test-svn-fe (<dumpfile> | [-d] <preimage> <delta> <len>)\";\n+\tif (argc == 2) {\n+\t\tif (svndump_init(argv[1]))\n+\t\t\treturn 1;\n+\t\tsvndump_read(NULL);\n+\t\tsvndump_deinit();\n+\t\tsvndump_reset();\n+\t\treturn 0;\n+\t}\n+\tif (argc == 5 && !strcmp(argv[1], \"-d\")) {\n+\t\tstruct line_buffer preimage = LINE_BUFFER_INIT;\n+\t\tstruct line_buffer delta = LINE_BUFFER_INIT;\n+\t\tstruct sliding_view preimage_view = SLIDING_VIEW_INIT(&preimage);\n+\t\tif (buffer_init(&preimage, argv[2]))\n+\t\t\tdie_errno(\"cannot open preimage\");\n+\t\tif (buffer_init(&delta, argv[3]))\n+\t\t\tdie_errno(\"cannot open delta\");\n+\t\tif (svndiff0_apply(&delta, (off_t) strtoull(argv[4], NULL, 0),\n+\t\t\t\t   &preimage_view, stdout))\n+\t\t\treturn 1;\n+\t\tif (buffer_deinit(&preimage))\n+\t\t\tdie_errno(\"cannot close preimage\");\n+\t\tif (buffer_deinit(&delta))\n+\t\t\tdie_errno(\"cannot close delta\");\n+\t\tbuffer_reset(&preimage);\n+\t\tstrbuf_release(&preimage_view.buf);\n+\t\tbuffer_reset(&delta);\n+\t\treturn 0;\n+\t}\n+\tusage(test_svnfe_usage);\n }\ndiff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c\nindex 08d7cae..2f59670 100644\n--- a/vcs-svn/line_buffer.c\n+++ b/vcs-svn/line_buffer.c\n@@ -98,10 +98,10 @@ char *buffer_read_string(struct line_buffer *buf, uint32_t len)\n \treturn ferror(buf->infile) ? NULL : buf->blob_buffer.buf;\n }\n \n-void buffer_read_binary(struct line_buffer *buf,\n-\t\t\t\tstruct strbuf *sb, uint32_t size)\n+off_t buffer_read_binary(struct line_buffer *buf,\n+\t\t\t\tstruct strbuf *sb, off_t size)\n {\n-\tstrbuf_fread(sb, size, buf->infile);\n+\treturn strbuf_fread(sb, size, buf->infile);\n }\n \n off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)\ndiff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h\nindex f5c468a..a253070 100644\n--- a/vcs-svn/line_buffer.h\n+++ b/vcs-svn/line_buffer.h\n@@ -25,7 +25,7 @@ int buffer_ferror(struct line_buffer *buf);\n char *buffer_read_line(struct line_buffer *buf);\n char *buffer_read_string(struct line_buffer *buf, uint32_t len);\n int buffer_read_char(struct line_buffer *buf);\n-void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);\n+off_t buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, off_t len);\n /* Returns number of bytes read (not necessarily written). */\n off_t buffer_copy_bytes(struct line_buffer *buf, off_t len);\n off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nnew file mode 100644\nindex 0000000..5916036\n--- /dev/null\n+++ b/vcs-svn/svndiff.c\n@@ -0,0 +1,52 @@\n+/*\n+ * Licensed under a two-clause BSD-style license.\n+ * See LICENSE for details.\n+ */\n+\n+#include \"git-compat-util.h\"\n+#include \"line_buffer.h\"\n+#include \"svndiff.h\"\n+\n+/*\n+ * svndiff0 applier\n+ *\n+ * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff.\n+ *\n+ * svndiff0 ::= 'SVN\\0' window*\n+ */\n+\n+static int error_short_read(struct line_buffer *input)\n+{\n+\tif (buffer_ferror(input))\n+\t\treturn error(\"error reading delta: %s\", strerror(errno));\n+\treturn error(\"invalid delta: unexpected end of file\");\n+}\n+\n+static int read_magic(struct line_buffer *in, off_t *len)\n+{\n+\tstatic const char magic[] = {'S', 'V', 'N', '\\0'};\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tif (*len < sizeof(magic) ||\n+\t    buffer_read_binary(in, &sb, sizeof(magic)) != sizeof(magic))\n+\t\treturn error_short_read(in);\n+\n+\tif (memcmp(sb.buf, magic, sizeof(magic)))\n+\t\treturn error(\"invalid delta: unrecognized file type\");\n+\n+\t*len -= sizeof(magic);\n+\tstrbuf_release(&sb);\n+\treturn 0;\n+}\n+\n+int svndiff0_apply(struct line_buffer *delta, off_t delta_len,\n+\t\t\tstruct sliding_view *preimage, FILE *postimage)\n+{\n+\tassert(delta && preimage && postimage);\n+\n+\tif (read_magic(delta, &delta_len))\n+\t\treturn -1;\n+\tif (delta_len)\n+\t\treturn error(\"What do you think I am?  A delta applier?\");\n+\treturn 0;\n+}\ndiff --git a/vcs-svn/svndiff.h b/vcs-svn/svndiff.h\nnew file mode 100644\nindex 0000000..74eb464\n--- /dev/null\n+++ b/vcs-svn/svndiff.h\n@@ -0,0 +1,10 @@\n+#ifndef SVNDIFF_H_\n+#define SVNDIFF_H_\n+\n+struct line_buffer;\n+struct sliding_view;\n+\n+extern int svndiff0_apply(struct line_buffer *delta, off_t delta_len,\n+\t\tstruct sliding_view *preimage, FILE *postimage);\n+\n+#endif\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163725","messageId":"1300519254-20201-8-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 07/16] vcs-svn: parse svndiff0 window header","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:45Z","receivedAt":"2011-03-19T07:20:45Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nEach window in a subversion delta (svndiff0-format file) starts with a\nwindow header, consisting of five integers with variable-length\nrepresentation:\n\n\tsource view offset\n\tsource view length\n\toutput length\n\tinstructions length\n\tauxiliary data length\n\nParse it.  The result is not usable for deltas with nonempty postimage\nyet; in fact, this only adds support for deltas without any\ninstructions or auxiliary data.  This is a good place to stop, though,\nsince that little support lets us add some simple passing tests\nconcerning error handling to the test suite.\n\nImproved-by: Ramkumar Ramachandra <artagnon@gmail.com>\nImproved-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n t/t9011-svn-da.sh |   56 +++++++++++++++++++++++++++++++-\n vcs-svn/svndiff.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++++---\n 2 files changed, 142 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh\nindex 6d6a406..2ab580a 100755\n--- a/t/t9011-svn-da.sh\n+++ b/t/t9011-svn-da.sh\n@@ -28,10 +28,64 @@ test_expect_success 'reject svndiff2' '\n \ttest_must_fail test-svn-fe -d preimage bad.filetype 4\n '\n \n-test_expect_failure 'one-window empty delta' '\n+test_expect_success 'one-window empty delta' '\n \tprintf \"SVNQ%s\" \"QQQQQ\" | q_to_nul >clear.onewindow &&\n \ttest-svn-fe -d preimage clear.onewindow 9 >actual &&\n \ttest_cmp empty actual\n '\n \n+test_expect_success 'reject incomplete window header' '\n+\tprintf \"SVNQ%s\" \"QQQQQ\" | q_to_nul >clear.onewindow &&\n+\tprintf \"SVNQ%s\" \"QQ\" | q_to_nul >clear.partialwindow &&\n+\ttest_must_fail test-svn-fe -d preimage clear.onewindow 6 &&\n+\ttest_must_fail test-svn-fe -d preimage clear.partialwindow 6\n+'\n+\n+test_expect_success 'reject declared delta longer than actual delta' '\n+\tprintf \"SVNQ%s\" \"QQQQQ\" | q_to_nul >clear.onewindow &&\n+\tprintf \"SVNQ%s\" \"QQ\" | q_to_nul >clear.partialwindow &&\n+\ttest_must_fail test-svn-fe -d preimage clear.onewindow 14 &&\n+\ttest_must_fail test-svn-fe -d preimage clear.partialwindow 9\n+'\n+\n+test_expect_success 'two-window empty delta' '\n+\tprintf \"SVNQ%s%s\" \"QQQQQ\" \"QQQQQ\" | q_to_nul >clear.twowindow &&\n+\ttest-svn-fe -d preimage clear.twowindow 14 >actual &&\n+\ttest_must_fail test-svn-fe -d preimage clear.twowindow 13 &&\n+\ttest_cmp empty actual\n+'\n+\n+test_expect_success 'noisy zeroes' '\n+\tprintf \"SVNQ%s\" \\\n+\t\t\"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQ\" |\n+\t\ttr R \"\\200\" |\n+\t\tq_to_nul >clear.noisy &&\n+\tlen=$(wc -c <clear.noisy) &&\n+\ttest-svn-fe -d preimage clear.noisy $len &&\n+\ttest_cmp empty actual\n+'\n+\n+test_expect_success 'reject variable-length int in magic' '\n+\tprintf \"SVNRQ\" | tr R \"\\200\" | q_to_nul >clear.badmagic &&\n+\ttest_must_fail test-svn-fe -d preimage clear.badmagic 5\n+'\n+\n+test_expect_success 'reject truncated integer' '\n+\tprintf \"SVNQ%s%s\" \"QQQQQ\" \"QQQQRRQ\" |\n+\t\ttr R \"\\200\" |\n+\t\tq_to_nul >clear.fullint &&\n+\tprintf \"SVNQ%s%s\" \"QQQQQ\" \"QQQQRR\" |\n+\t\ttr RT \"\\201\" |\n+\t\tq_to_nul >clear.partialint &&\n+\ttest_must_fail test-svn-fe -d preimage clear.fullint 15 &&\n+\ttest-svn-fe -d preimage clear.fullint 16 &&\n+\ttest_must_fail test-svn-fe -d preimage clear.partialint 15\n+'\n+\n+test_expect_success 'nonempty (but unused) preimage view' '\n+\tprintf \"SVNQ%b\" \"Q\\003QQQ\" | q_to_nul >clear.readpreimage &&\n+\ttest-svn-fe -d preimage clear.readpreimage 9 >actual &&\n+\ttest_cmp empty actual\n+'\n+\n test_done\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nindex 5916036..249efb6 100644\n--- a/vcs-svn/svndiff.c\n+++ b/vcs-svn/svndiff.c\n@@ -13,8 +13,16 @@\n  * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff.\n  *\n  * svndiff0 ::= 'SVN\\0' window*\n+ * window ::= int int int int int instructions inline_data;\n+ * int ::= highdigit* lowdigit;\n+ * highdigit ::= # binary 1000 0000 OR-ed with 7 bit value;\n+ * lowdigit ::= # 7 bit value;\n  */\n \n+#define VLI_CONTINUE\t0x80\n+#define VLI_DIGIT_MASK\t0x7f\n+#define VLI_BITS_PER_DIGIT 7\n+\n static int error_short_read(struct line_buffer *input)\n {\n \tif (buffer_ferror(input))\n@@ -28,17 +36,84 @@ static int read_magic(struct line_buffer *in, off_t *len)\n \tstruct strbuf sb = STRBUF_INIT;\n \n \tif (*len < sizeof(magic) ||\n-\t    buffer_read_binary(in, &sb, sizeof(magic)) != sizeof(magic))\n-\t\treturn error_short_read(in);\n+\t    buffer_read_binary(in, &sb, sizeof(magic)) != sizeof(magic)) {\n+\t\terror_short_read(in);\n+\t\tstrbuf_release(&sb);\n+\t\treturn -1;\n+\t}\n \n-\tif (memcmp(sb.buf, magic, sizeof(magic)))\n+\tif (memcmp(sb.buf, magic, sizeof(magic))) {\n+\t\tstrbuf_release(&sb);\n \t\treturn error(\"invalid delta: unrecognized file type\");\n+\t}\n \n \t*len -= sizeof(magic);\n \tstrbuf_release(&sb);\n \treturn 0;\n }\n \n+static int read_int(struct line_buffer *in, uintmax_t *result, off_t *len)\n+{\n+\tuintmax_t rv = 0;\n+\toff_t sz;\n+\tfor (sz = *len; sz; sz--) {\n+\t\tconst int ch = buffer_read_char(in);\n+\t\tif (ch == EOF)\n+\t\t\tbreak;\n+\n+\t\trv <<= VLI_BITS_PER_DIGIT;\n+\t\trv += (ch & VLI_DIGIT_MASK);\n+\t\tif (ch & VLI_CONTINUE)\n+\t\t\tcontinue;\n+\n+\t\t*result = rv;\n+\t\t*len = sz - 1;\n+\t\treturn 0;\n+\t}\n+\treturn error_short_read(in);\n+}\n+\n+static int read_offset(struct line_buffer *in, off_t *result, off_t *len)\n+{\n+\tuintmax_t val;\n+\tif (read_int(in, &val, len))\n+\t\treturn -1;\n+\tif (val > maximum_signed_value_of_type(off_t))\n+\t\treturn error(\"unrepresentable offset in delta: %\"PRIuMAX\"\", val);\n+\t*result = val;\n+\treturn 0;\n+}\n+\n+static int read_length(struct line_buffer *in, size_t *result, off_t *len)\n+{\n+\tuintmax_t val;\n+\tif (read_int(in, &val, len))\n+\t\treturn -1;\n+\tif (val > SIZE_MAX)\n+\t\treturn error(\"unrepresentable length in delta: %\"PRIuMAX\"\", val);\n+\t*result = val;\n+\treturn 0;\n+}\n+\n+static int apply_one_window(struct line_buffer *delta, off_t *delta_len)\n+{\n+\tsize_t out_len;\n+\tsize_t instructions_len;\n+\tsize_t data_len;\n+\tassert(delta_len);\n+\n+\t/* \"source view\" offset and length already handled; */\n+\tif (read_length(delta, &out_len, delta_len) ||\n+\t    read_length(delta, &instructions_len, delta_len) ||\n+\t    read_length(delta, &data_len, delta_len))\n+\t\treturn -1;\n+\tif (instructions_len)\n+\t\treturn error(\"What do you think I am?  A delta applier?\");\n+\tif (data_len)\n+\t\treturn error(\"No support for inline data yet\");\n+\treturn 0;\n+}\n+\n int svndiff0_apply(struct line_buffer *delta, off_t delta_len,\n \t\t\tstruct sliding_view *preimage, FILE *postimage)\n {\n@@ -46,7 +121,14 @@ int svndiff0_apply(struct line_buffer *delta, off_t delta_len,\n \n \tif (read_magic(delta, &delta_len))\n \t\treturn -1;\n-\tif (delta_len)\n-\t\treturn error(\"What do you think I am?  A delta applier?\");\n+\twhile (delta_len) {\t/* For each window: */\n+\t\toff_t pre_off;\n+\t\tsize_t pre_len;\n+\n+\t\tif (read_offset(delta, &pre_off, &delta_len) ||\n+\t\t    read_length(delta, &pre_len, &delta_len) ||\n+\t\t    apply_one_window(delta, &delta_len))\n+\t\t\treturn -1;\n+\t}\n \treturn 0;\n }\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163720","messageId":"1300519254-20201-9-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 08/16] vcs-svn: read the preimage when applying deltas","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:46Z","receivedAt":"2011-03-19T07:20:46Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nThe source view offset heading each svndiff0 window represents a\nnumber of bytes past the beginning of the preimage.  Together with the\nsource view length, it dictates to the delta applier what portion of\nthe preimage instructions will refer to.  Read that portion right away\nusing the sliding window code.\n\nMaybe some day we will use mmap to read data more lazily.\n\nSubversion's implementation tolerates source view offsets pointing\npast the end of the preimage file but we do not, for simplicity.\n\nThis does not teach the delta applier to read instructions or copy\ndata from the source view.  Deltas that could produce nonempty output\nwill still be rejected.\n\nImproved-by: Ramkumar Ramachandra <artagnon@gmail.com>\nImproved-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nAcked-by: Ramkumar Ramachandra <artagnon@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n t/t9011-svn-da.sh |   35 +++++++++++++++++++++++++++++++++++\n vcs-svn/svndiff.c |    6 ++++--\n 2 files changed, 39 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh\nindex 2ab580a..986dce6 100755\n--- a/t/t9011-svn-da.sh\n+++ b/t/t9011-svn-da.sh\n@@ -88,4 +88,39 @@ test_expect_success 'nonempty (but unused) preimage view' '\n \ttest_cmp empty actual\n '\n \n+test_expect_success 'preimage view: right endpoint cannot backtrack' '\n+\tprintf \"SVNQ%b%b\" \"Q\\003QQQ\" \"Q\\002QQQ\" |\n+\t\tq_to_nul >clear.backtrack &&\n+\ttest_must_fail test-svn-fe -d preimage clear.backtrack 14\n+'\n+\n+test_expect_success 'preimage view: left endpoint can advance' '\n+\tprintf \"SVNQ%b%b\" \"Q\\003QQQ\" \"\\001\\002QQQ\" |\n+\t\tq_to_nul >clear.preshrink &&\n+\tprintf \"SVNQ%b%b\" \"Q\\003QQQ\" \"\\001\\001QQQ\" |\n+\t\tq_to_nul >clear.shrinkbacktrack &&\n+\ttest-svn-fe -d preimage clear.preshrink 14 >actual &&\n+\ttest_must_fail test-svn-fe -d preimage clear.shrinkbacktrack 14 &&\n+\ttest_cmp empty actual\n+'\n+\n+test_expect_success 'preimage view: offsets compared by value' '\n+\tprintf \"SVNQ%b%b\" \"\\001\\001QQQ\" \"\\0200Q\\003QQQ\" |\n+\t\tq_to_nul >clear.noisybacktrack &&\n+\tprintf \"SVNQ%b%b\" \"\\001\\001QQQ\" \"\\0200\\001\\002QQQ\" |\n+\t\tq_to_nul >clear.noisyadvance &&\n+\ttest_must_fail test-svn-fe -d preimage clear.noisybacktrack 15\n+\ttest-svn-fe -d preimage clear.noisyadvance 15 &&\n+\ttest_cmp empty actual\n+'\n+\n+test_expect_success 'preimage view: reject truncated preimage' '\n+\tprintf \"SVNQ%b\" \"\\010QQQQ\" | q_to_nul >clear.lateemptyread &&\n+\tprintf \"SVNQ%b\" \"\\010\\001QQQ\" | q_to_nul >clear.latenonemptyread &&\n+\tprintf \"SVNQ%b\" \"\\001\\010QQQ\" | q_to_nul >clear.longread &&\n+\ttest_must_fail test-svn-fe -d preimage clear.lateemptyread 9 &&\n+\ttest_must_fail test-svn-fe -d preimage clear.latenonemptyread 9 &&\n+\ttest_must_fail test-svn-fe -d preimage clear.longread 9\n+'\n+\n test_done\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nindex 249efb6..1020275 100644\n--- a/vcs-svn/svndiff.c\n+++ b/vcs-svn/svndiff.c\n@@ -4,6 +4,7 @@\n  */\n \n #include \"git-compat-util.h\"\n+#include \"sliding_window.h\"\n #include \"line_buffer.h\"\n #include \"svndiff.h\"\n \n@@ -122,11 +123,12 @@ int svndiff0_apply(struct line_buffer *delta, off_t delta_len,\n \tif (read_magic(delta, &delta_len))\n \t\treturn -1;\n \twhile (delta_len) {\t/* For each window: */\n-\t\toff_t pre_off;\n-\t\tsize_t pre_len;\n+\t\toff_t pre_off = pre_off;\n+\t\tsize_t pre_len = pre_len;\n \n \t\tif (read_offset(delta, &pre_off, &delta_len) ||\n \t\t    read_length(delta, &pre_len, &delta_len) ||\n+\t\t    move_window(preimage, pre_off, pre_len) ||\n \t\t    apply_one_window(delta, &delta_len))\n \t\t\treturn -1;\n \t}\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163719","messageId":"1300519254-20201-10-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 09/16] vcs-svn: read inline data from deltas","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:47Z","receivedAt":"2011-03-19T07:20:47Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nEach window of an svndiff0-format delta includes a section for new\ndata that will be copied into the preimage (in the order it appears in\nthe window, possibly interspersed with other data).\n\nRead this data when encountering it.  It is not actually necessary to\ndo so --- it would be just as easy to copy straight from the delta\nto output when interpreting the relevant instructions --- but this\nway, the code that interprets svndiff0 instructions can proceed more\nquickly because it does not require any I/O.\n\nSubversion's implementation rejects deltas that do not consume all\nthe auxiliary data that is available.  Do not check that for now,\nbecause it would make it impossible to test the function of this\npatch until the instructions to consume data are implemented.\n\nDo check for truncated data sections.  Since Subversion's applier\nrejects deltas that end before the new-data section is declared to\nend, it should be safe for this applier to reject such deltas, too.\n\nImproved-by: Ramkumar Ramachandra <artagnon@gmail.com>\nImproved-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nAcked-by: Ramkumar Ramachandra <artagnon@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n t/t9011-svn-da.sh |   12 ++++++++++++\n vcs-svn/svndiff.c |   46 +++++++++++++++++++++++++++++++++++-----------\n 2 files changed, 47 insertions(+), 11 deletions(-)\n\ndiff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh\nindex 986dce6..4919fae 100755\n--- a/t/t9011-svn-da.sh\n+++ b/t/t9011-svn-da.sh\n@@ -123,4 +123,16 @@ test_expect_success 'preimage view: reject truncated preimage' '\n \ttest_must_fail test-svn-fe -d preimage clear.longread 9\n '\n \n+test_expect_success 'inline data' '\n+\tprintf \"SVNQ%b%s%b%s\" \"QQQQ\\003\" \"bar\" \"QQQQ\\001\" \"x\" |\n+\t\tq_to_nul >inline.clear &&\n+\ttest-svn-fe -d preimage inline.clear 18 >actual &&\n+\ttest_cmp empty actual\n+'\n+\n+test_expect_success 'reject truncated inline data' '\n+\tprintf \"SVNQ%b%s\" \"QQQQ\\003\" \"b\" | q_to_nul >inline.trunc &&\n+\ttest_must_fail test-svn-fe -d preimage inline.trunc 10\n+'\n+\n test_done\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nindex 1020275..74e0401 100644\n--- a/vcs-svn/svndiff.c\n+++ b/vcs-svn/svndiff.c\n@@ -24,6 +24,17 @@\n #define VLI_DIGIT_MASK\t0x7f\n #define VLI_BITS_PER_DIGIT 7\n \n+struct window {\n+\tstruct strbuf data;\n+};\n+\n+#define WINDOW_INIT\t{ STRBUF_INIT }\n+\n+static void window_release(struct window *ctx)\n+{\n+\tstrbuf_release(&ctx->data);\n+}\n+\n static int error_short_read(struct line_buffer *input)\n {\n \tif (buffer_ferror(input))\n@@ -31,24 +42,30 @@ static int error_short_read(struct line_buffer *input)\n \treturn error(\"invalid delta: unexpected end of file\");\n }\n \n+static int read_chunk(struct line_buffer *delta, off_t *delta_len,\n+\t\t      struct strbuf *buf, size_t len)\n+{\n+\tstrbuf_reset(buf);\n+\tif (len > *delta_len ||\n+\t    buffer_read_binary(delta, buf, len) != len)\n+\t\treturn error_short_read(delta);\n+\t*delta_len -= buf->len;\n+\treturn 0;\n+}\n+\n static int read_magic(struct line_buffer *in, off_t *len)\n {\n \tstatic const char magic[] = {'S', 'V', 'N', '\\0'};\n \tstruct strbuf sb = STRBUF_INIT;\n \n-\tif (*len < sizeof(magic) ||\n-\t    buffer_read_binary(in, &sb, sizeof(magic)) != sizeof(magic)) {\n-\t\terror_short_read(in);\n+\tif (read_chunk(in, len, &sb, sizeof(magic))) {\n \t\tstrbuf_release(&sb);\n \t\treturn -1;\n \t}\n-\n \tif (memcmp(sb.buf, magic, sizeof(magic))) {\n \t\tstrbuf_release(&sb);\n \t\treturn error(\"invalid delta: unrecognized file type\");\n \t}\n-\n-\t*len -= sizeof(magic);\n \tstrbuf_release(&sb);\n \treturn 0;\n }\n@@ -98,6 +115,7 @@ static int read_length(struct line_buffer *in, size_t *result, off_t *len)\n \n static int apply_one_window(struct line_buffer *delta, off_t *delta_len)\n {\n+\tstruct window ctx = WINDOW_INIT;\n \tsize_t out_len;\n \tsize_t instructions_len;\n \tsize_t data_len;\n@@ -107,12 +125,18 @@ static int apply_one_window(struct line_buffer *delta, off_t *delta_len)\n \tif (read_length(delta, &out_len, delta_len) ||\n \t    read_length(delta, &instructions_len, delta_len) ||\n \t    read_length(delta, &data_len, delta_len))\n-\t\treturn -1;\n-\tif (instructions_len)\n-\t\treturn error(\"What do you think I am?  A delta applier?\");\n-\tif (data_len)\n-\t\treturn error(\"No support for inline data yet\");\n+\t\tgoto error_out;\n+\tif (instructions_len) {\n+\t\terror(\"What do you think I am?  A delta applier?\");\n+\t\tgoto error_out;\n+\t}\n+\tif (read_chunk(delta, delta_len, &ctx.data, data_len))\n+\t\tgoto error_out;\n+\twindow_release(&ctx);\n \treturn 0;\n+error_out:\n+\twindow_release(&ctx);\n+\treturn -1;\n }\n \n int svndiff0_apply(struct line_buffer *delta, off_t delta_len,\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163717","messageId":"1300519254-20201-11-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 10/16] vcs-svn: read instructions from deltas","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:48Z","receivedAt":"2011-03-19T07:20:48Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nBuffer the instruction section upon encountering it for later\ninterpretation.\n\nAn alternative design would involve parsing the instructions\nat this point and buffering them in some processed form.  Using\nthe unprocessed form is simpler.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nAcked-by: Ramkumar Ramachandra <artagnon@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n t/t9011-svn-da.sh |    5 +++++\n vcs-svn/svndiff.c |    6 +++++-\n 2 files changed, 10 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh\nindex 4919fae..e909d92 100755\n--- a/t/t9011-svn-da.sh\n+++ b/t/t9011-svn-da.sh\n@@ -135,4 +135,9 @@ test_expect_success 'reject truncated inline data' '\n \ttest_must_fail test-svn-fe -d preimage inline.trunc 10\n '\n \n+test_expect_success 'reject truncated inline data (after instruction section)' '\n+\tprintf \"SVNQ%b%b%s\" \"QQ\\001\\001\\003\" \"\\0201\" \"b\" | q_to_nul >insn.trunc &&\n+\ttest_must_fail test-svn-fe -d preimage insn.trunc 11\n+'\n+\n test_done\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nindex 74e0401..a2dd9b6 100644\n--- a/vcs-svn/svndiff.c\n+++ b/vcs-svn/svndiff.c\n@@ -25,13 +25,15 @@\n #define VLI_BITS_PER_DIGIT 7\n \n struct window {\n+\tstruct strbuf instructions;\n \tstruct strbuf data;\n };\n \n-#define WINDOW_INIT\t{ STRBUF_INIT }\n+#define WINDOW_INIT\t{ STRBUF_INIT, STRBUF_INIT }\n \n static void window_release(struct window *ctx)\n {\n+\tstrbuf_release(&ctx->instructions);\n \tstrbuf_release(&ctx->data);\n }\n \n@@ -126,6 +128,8 @@ static int apply_one_window(struct line_buffer *delta, off_t *delta_len)\n \t    read_length(delta, &instructions_len, delta_len) ||\n \t    read_length(delta, &data_len, delta_len))\n \t\tgoto error_out;\n+\tif (read_chunk(delta, delta_len, &ctx.instructions, instructions_len))\n+\t\tgoto error_out;\n \tif (instructions_len) {\n \t\terror(\"What do you think I am?  A delta applier?\");\n \t\tgoto error_out;\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163724","messageId":"1300519254-20201-12-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 11/16] vcs-svn: implement copyfrom_data delta instruction","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:49Z","receivedAt":"2011-03-19T07:20:49Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nThe copyfrom_data instruction copies a few bytes verbatim from the\nauxiliary data section of a window to the postimage.\n\n[jn: with memory leak fix from David]\n\nImproved-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nAcked-by: Ramkumar Ramachandra <artagnon@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n t/t9011-svn-da.sh |   31 ++++++++++++++\n vcs-svn/svndiff.c |  114 ++++++++++++++++++++++++++++++++++++++++++++++++++---\n 2 files changed, 139 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh\nindex e909d92..c6dbb21 100755\n--- a/t/t9011-svn-da.sh\n+++ b/t/t9011-svn-da.sh\n@@ -140,4 +140,35 @@ test_expect_success 'reject truncated inline data (after instruction section)' '\n \ttest_must_fail test-svn-fe -d preimage insn.trunc 11\n '\n \n+test_expect_success 'copyfrom_data' '\n+\techo hi >expect &&\n+\tprintf \"SVNQ%b%b%b\" \"QQ\\003\\001\\003\" \"\\0203\" \"hi\\n\" | q_to_nul >copydat &&\n+\ttest-svn-fe -d preimage copydat 13 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'multiple copyfrom_data' '\n+\techo hi >expect &&\n+\tprintf \"SVNQ%b%b%b%b%b\" \"QQ\\003\\002\\003\" \"\\0201\\0202\" \"hi\\n\" \\\n+\t\t\"QQQ\\002Q\" \"\\0200Q\" | q_to_nul >copy.multi &&\n+\tlen=$(wc -c <copy.multi) &&\n+\ttest-svn-fe -d preimage copy.multi $len >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'incomplete multiple insn' '\n+\tprintf \"SVNQ%b%b%b\" \"QQ\\003\\002\\003\" \"\\0203\\0200\" \"hi\\n\" |\n+\t\tq_to_nul >copy.partial &&\n+\tlen=$(wc -c <copy.partial) &&\n+\ttest_must_fail test-svn-fe -d preimage copy.partial $len\n+'\n+\n+test_expect_success 'catch attempt to copy missing data' '\n+\tprintf \"SVNQ%b%b%s%b%s\" \"QQ\\002\\002\\001\" \"\\0201\\0201\" \"X\" \\\n+\t\t\t\"QQQQ\\002\" \"YZ\" |\n+\t\tq_to_nul >copy.incomplete &&\n+\tlen=$(wc -c <copy.incomplete) &&\n+\ttest_must_fail test-svn-fe -d preimage copy.incomplete $len\n+'\n+\n test_done\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nindex a2dd9b6..118e8c6 100644\n--- a/vcs-svn/svndiff.c\n+++ b/vcs-svn/svndiff.c\n@@ -15,28 +15,49 @@\n  *\n  * svndiff0 ::= 'SVN\\0' window*\n  * window ::= int int int int int instructions inline_data;\n+ * instructions ::= instruction*;\n+ * instruction ::= view_selector int int\n+ *   | copyfrom_data int\n+ *   | packed_view_selector int\n+ *   | packed_copyfrom_data\n+ *   ;\n+ * copyfrom_data ::= # binary 10 000000;\n+ * packed_copyfrom_data ::= # copyfrom_data OR-ed with 6 bit value;\n  * int ::= highdigit* lowdigit;\n  * highdigit ::= # binary 1000 0000 OR-ed with 7 bit value;\n  * lowdigit ::= # 7 bit value;\n  */\n \n+#define INSN_MASK\t0xc0\n+#define INSN_COPYFROM_DATA\t0x80\n+#define OPERAND_MASK\t0x3f\n+\n #define VLI_CONTINUE\t0x80\n #define VLI_DIGIT_MASK\t0x7f\n #define VLI_BITS_PER_DIGIT 7\n \n struct window {\n+\tstruct strbuf out;\n \tstruct strbuf instructions;\n \tstruct strbuf data;\n };\n \n-#define WINDOW_INIT\t{ STRBUF_INIT, STRBUF_INIT }\n+#define WINDOW_INIT\t{ STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }\n \n static void window_release(struct window *ctx)\n {\n+\tstrbuf_release(&ctx->out);\n \tstrbuf_release(&ctx->instructions);\n \tstrbuf_release(&ctx->data);\n }\n \n+static int write_strbuf(struct strbuf *sb, FILE *out)\n+{\n+\tif (fwrite(sb->buf, 1, sb->len, out) == sb->len)\t/* Success. */\n+\t\treturn 0;\n+\treturn error(\"cannot write delta postimage: %s\", strerror(errno));\n+}\n+\n static int error_short_read(struct line_buffer *input)\n {\n \tif (buffer_ferror(input))\n@@ -93,6 +114,25 @@ static int read_int(struct line_buffer *in, uintmax_t *result, off_t *len)\n \treturn error_short_read(in);\n }\n \n+static int parse_int(const char **buf, size_t *result, const char *end)\n+{\n+\tsize_t rv = 0;\n+\tconst char *pos;\n+\tfor (pos = *buf; pos != end; pos++) {\n+\t\tunsigned char ch = *pos;\n+\n+\t\trv <<= VLI_BITS_PER_DIGIT;\n+\t\trv += (ch & VLI_DIGIT_MASK);\n+\t\tif (ch & VLI_CONTINUE)\n+\t\t\tcontinue;\n+\n+\t\t*result = rv;\n+\t\t*buf = pos + 1;\n+\t\treturn 0;\n+\t}\n+\treturn error(\"invalid delta: unexpected end of instructions section\");\n+}\n+\n static int read_offset(struct line_buffer *in, off_t *result, off_t *len)\n {\n \tuintmax_t val;\n@@ -115,7 +155,64 @@ static int read_length(struct line_buffer *in, size_t *result, off_t *len)\n \treturn 0;\n }\n \n-static int apply_one_window(struct line_buffer *delta, off_t *delta_len)\n+static int copyfrom_data(struct window *ctx, size_t *data_pos, size_t nbytes)\n+{\n+\tconst size_t pos = *data_pos;\n+\tif (unsigned_add_overflows(pos, nbytes) ||\n+\t    pos + nbytes > ctx->data.len)\n+\t\treturn error(\"invalid delta: copies unavailable inline data.\");\n+\tstrbuf_add(&ctx->out, ctx->data.buf + pos, nbytes);\n+\t*data_pos += nbytes;\n+\treturn 0;\n+}\n+\n+static int parse_first_operand(const char **buf, size_t *out, const char *end)\n+{\n+\tsize_t result = (unsigned char) *(*buf)++ & OPERAND_MASK;\n+\tif (result) {\t/* immediate operand */\n+\t\t*out = result;\n+\t\treturn 0;\n+\t}\n+\treturn parse_int(buf, out, end);\n+}\n+\n+static int execute_one_instruction(struct window *ctx,\n+\t\t\t\tconst char **instructions, size_t *data_pos)\n+{\n+\tunsigned int instruction;\n+\tconst char *insns_end = ctx->instructions.buf + ctx->instructions.len;\n+\tsize_t nbytes;\n+\tassert(ctx);\n+\tassert(instructions && *instructions);\n+\tassert(data_pos);\n+\n+\tinstruction = (unsigned char) **instructions;\n+\tif (parse_first_operand(instructions, &nbytes, insns_end))\n+\t\treturn -1;\n+\tif ((instruction & INSN_MASK) != INSN_COPYFROM_DATA)\n+\t\treturn error(\"Unknown instruction %x\", instruction);\n+\treturn copyfrom_data(ctx, data_pos, nbytes);\n+}\n+\n+static int apply_window_in_core(struct window *ctx)\n+{\n+\tconst char *instructions;\n+\tsize_t data_pos = 0;\n+\n+\t/*\n+\t * Fill ctx->out.buf using data from the source, target,\n+\t * and inline data views.\n+\t */\n+\tfor (instructions = ctx->instructions.buf;\n+\t     instructions != ctx->instructions.buf + ctx->instructions.len;\n+\t     )\n+\t\tif (execute_one_instruction(ctx, &instructions, &data_pos))\n+\t\t\treturn -1;\n+\treturn 0;\n+}\n+\n+static int apply_one_window(struct line_buffer *delta, off_t *delta_len,\n+\t\t\t    FILE *out)\n {\n \tstruct window ctx = WINDOW_INIT;\n \tsize_t out_len;\n@@ -130,11 +227,16 @@ static int apply_one_window(struct line_buffer *delta, off_t *delta_len)\n \t\tgoto error_out;\n \tif (read_chunk(delta, delta_len, &ctx.instructions, instructions_len))\n \t\tgoto error_out;\n-\tif (instructions_len) {\n-\t\terror(\"What do you think I am?  A delta applier?\");\n+\tif (read_chunk(delta, delta_len, &ctx.data, data_len))\n+\t\tgoto error_out;\n+\tstrbuf_grow(&ctx.out, out_len);\n+\tif (apply_window_in_core(&ctx))\n+\t\tgoto error_out;\n+\tif (ctx.out.len != out_len) {\n+\t\terror(\"invalid delta: incorrect postimage length\");\n \t\tgoto error_out;\n \t}\n-\tif (read_chunk(delta, delta_len, &ctx.data, data_len))\n+\tif (write_strbuf(&ctx.out, out))\n \t\tgoto error_out;\n \twindow_release(&ctx);\n \treturn 0;\n@@ -157,7 +259,7 @@ int svndiff0_apply(struct line_buffer *delta, off_t delta_len,\n \t\tif (read_offset(delta, &pre_off, &delta_len) ||\n \t\t    read_length(delta, &pre_len, &delta_len) ||\n \t\t    move_window(preimage, pre_off, pre_len) ||\n-\t\t    apply_one_window(delta, &delta_len))\n+\t\t    apply_one_window(delta, &delta_len, postimage))\n \t\t\treturn -1;\n \t}\n \treturn 0;\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163723","messageId":"1300519254-20201-13-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 12/16] vcs-svn: verify that deltas consume all inline data","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:50Z","receivedAt":"2011-03-19T07:20:50Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nBy constraining the format of deltas, we can more easily detect\ncorruption and other breakage.\n\nRequiring deltas not to provide unconsumed data also opens the\npossibility of ignoring the declared amount of new data and simply\nstreaming the data as needed to fulfill copyfrom_data requests.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nAcked-by: Ramkumar Ramachandra <artagnon@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n t/t9011-svn-da.sh |    5 ++---\n vcs-svn/svndiff.c |    2 ++\n 2 files changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh\nindex c6dbb21..7f422ca 100755\n--- a/t/t9011-svn-da.sh\n+++ b/t/t9011-svn-da.sh\n@@ -123,11 +123,10 @@ test_expect_success 'preimage view: reject truncated preimage' '\n \ttest_must_fail test-svn-fe -d preimage clear.longread 9\n '\n \n-test_expect_success 'inline data' '\n+test_expect_success 'forbid unconsumed inline data' '\n \tprintf \"SVNQ%b%s%b%s\" \"QQQQ\\003\" \"bar\" \"QQQQ\\001\" \"x\" |\n \t\tq_to_nul >inline.clear &&\n-\ttest-svn-fe -d preimage inline.clear 18 >actual &&\n-\ttest_cmp empty actual\n+\ttest_must_fail test-svn-fe -d preimage inline.clear 18 >actual\n '\n \n test_expect_success 'reject truncated inline data' '\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nindex 118e8c6..6b505dc 100644\n--- a/vcs-svn/svndiff.c\n+++ b/vcs-svn/svndiff.c\n@@ -208,6 +208,8 @@ static int apply_window_in_core(struct window *ctx)\n \t     )\n \t\tif (execute_one_instruction(ctx, &instructions, &data_pos))\n \t\t\treturn -1;\n+\tif (data_pos != ctx->data.len)\n+\t\treturn error(\"invalid delta: does not copy all inline data\");\n \treturn 0;\n }\n \n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163727","messageId":"1300519254-20201-14-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 13/16] vcs-svn: let deltas use data from postimage","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:51Z","receivedAt":"2011-03-19T07:20:51Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nThe copyfrom_target instruction copies appends data that is already\npresent in the current output view to the end of output.  (The offset\nargument is relative to the beginning of output produced in the\ncurrent window.)\n\nThe region copied is allowed to run past the end of the existing\noutput.  To support that case, copy one character at a time rather\nthan calling memcpy or memmove.  This allows copyfrom_target to be\nused once to repeat a string many times.  For example:\n\n\tCOPYFROM_DATA 2\n\tCOPYFROM_OUTPUT 10, 0\n\tDATA \"ab\"\n\nwould produce the output \"ababababababababababab\".\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nAcked-by: Ramkumar Ramachandra <artagnon@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n t/t9011-svn-da.sh |   42 ++++++++++++++++++++++++++++++++++++++++++\n vcs-svn/svndiff.c |   28 ++++++++++++++++++++++++++--\n 2 files changed, 68 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh\nindex 7f422ca..d13115a 100755\n--- a/t/t9011-svn-da.sh\n+++ b/t/t9011-svn-da.sh\n@@ -170,4 +170,46 @@ test_expect_success 'catch attempt to copy missing data' '\n \ttest_must_fail test-svn-fe -d preimage copy.incomplete $len\n '\n \n+test_expect_success 'copyfrom target to repeat data' '\n+\tprintf foofoo >expect &&\n+\tprintf \"SVNQ%b%b%s\" \"QQ\\006\\004\\003\" \"\\0203\\0100\\003Q\" \"foo\" |\n+\t\tq_to_nul >copytarget.repeat &&\n+\tlen=$(wc -c <copytarget.repeat) &&\n+\ttest-svn-fe -d preimage copytarget.repeat $len >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'copyfrom target out of order' '\n+\tprintf foooof >expect &&\n+\tprintf \"SVNQ%b%b%s\" \\\n+\t\t\"QQ\\006\\007\\003\" \"\\0203\\0101\\002\\0101\\001\\0101Q\" \"foo\" |\n+\t\tq_to_nul >copytarget.reverse &&\n+\tlen=$(wc -c <copytarget.reverse) &&\n+\ttest-svn-fe -d preimage copytarget.reverse $len >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'catch copyfrom future' '\n+\tprintf \"SVNQ%b%b%s\" \"QQ\\004\\004\\003\" \"\\0202\\0101\\002\\0201\" \"XYZ\" |\n+\t\tq_to_nul >copytarget.infuture &&\n+\tlen=$(wc -c <copytarget.infuture) &&\n+\ttest_must_fail test-svn-fe -d preimage copytarget.infuture $len\n+'\n+\n+test_expect_success 'copy to sustain' '\n+\tprintf XYXYXYXYXYXZ >expect &&\n+\tprintf \"SVNQ%b%b%s\" \"QQ\\014\\004\\003\" \"\\0202\\0111Q\\0201\" \"XYZ\" |\n+\t\tq_to_nul >copytarget.sustain &&\n+\tlen=$(wc -c <copytarget.sustain) &&\n+\ttest-svn-fe -d preimage copytarget.sustain $len >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'catch copy that overflows' '\n+\tprintf \"SVNQ%b%b%s\" \"QQ\\003\\003\\001\" \"\\0201\\0177Q\" X |\n+\t\tq_to_nul >copytarget.overflow &&\n+\tlen=$(wc -c <copytarget.overflow) &&\n+\ttest_must_fail test-svn-fe -d preimage copytarget.overflow $len\n+'\n+\n test_done\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nindex 6b505dc..f4c5dae 100644\n--- a/vcs-svn/svndiff.c\n+++ b/vcs-svn/svndiff.c\n@@ -21,7 +21,12 @@\n  *   | packed_view_selector int\n  *   | packed_copyfrom_data\n  *   ;\n+ * view_selector ::= copyfrom_source\n+ *   | copyfrom_target\n+ *   ;\n+ * copyfrom_target ::= # binary 01 000000;\n  * copyfrom_data ::= # binary 10 000000;\n+ * packed_view_selector ::= # view_selector OR-ed with 6 bit value;\n  * packed_copyfrom_data ::= # copyfrom_data OR-ed with 6 bit value;\n  * int ::= highdigit* lowdigit;\n  * highdigit ::= # binary 1000 0000 OR-ed with 7 bit value;\n@@ -29,6 +34,7 @@\n  */\n \n #define INSN_MASK\t0xc0\n+#define INSN_COPYFROM_TARGET\t0x40\n #define INSN_COPYFROM_DATA\t0x80\n #define OPERAND_MASK\t0x3f\n \n@@ -155,6 +161,19 @@ static int read_length(struct line_buffer *in, size_t *result, off_t *len)\n \treturn 0;\n }\n \n+static int copyfrom_target(struct window *ctx, const char **instructions,\n+\t\t\t   size_t nbytes, const char *instructions_end)\n+{\n+\tsize_t offset;\n+\tif (parse_int(instructions, &offset, instructions_end))\n+\t\treturn -1;\n+\tif (offset >= ctx->out.len)\n+\t\treturn error(\"invalid delta: copies from the future.\");\n+\tfor (; nbytes > 0; nbytes--)\n+\t\tstrbuf_addch(&ctx->out, ctx->out.buf[offset++]);\n+\treturn 0;\n+}\n+\n static int copyfrom_data(struct window *ctx, size_t *data_pos, size_t nbytes)\n {\n \tconst size_t pos = *data_pos;\n@@ -189,9 +208,14 @@ static int execute_one_instruction(struct window *ctx,\n \tinstruction = (unsigned char) **instructions;\n \tif (parse_first_operand(instructions, &nbytes, insns_end))\n \t\treturn -1;\n-\tif ((instruction & INSN_MASK) != INSN_COPYFROM_DATA)\n+\tswitch (instruction & INSN_MASK) {\n+\tcase INSN_COPYFROM_TARGET:\n+\t\treturn copyfrom_target(ctx, instructions, nbytes, insns_end);\n+\tcase INSN_COPYFROM_DATA:\n+\t\treturn copyfrom_data(ctx, data_pos, nbytes);\n+\tdefault:\n \t\treturn error(\"Unknown instruction %x\", instruction);\n-\treturn copyfrom_data(ctx, data_pos, nbytes);\n+\t}\n }\n \n static int apply_window_in_core(struct window *ctx)\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163722","messageId":"1300519254-20201-15-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 14/16] vcs-svn: let deltas use data from preimage","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:52Z","receivedAt":"2011-03-19T07:20:52Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nThe copyfrom_source instruction appends data from the preimage buffer\nto the end of output.  Its arguments are a length and an offset\nrelative to the beginning of the source view.\n\nWith this change, the delta applier is able to reproduce all 5,636,613\nblobs in the early history of the ASF repository.  Tested with\n\n\tmkfifo backflow\n\tsvn-fe <svn-asf-public-r0:940166 3<backflow |\n\tgit fast-import --cat-blob-fd=3 3>backflow\n\nwith svn-asf-public-r0:940166 produced by whatever version of\nSubversion the dumps in /dump/ on svn.apache.org use (presumably\n1.6.something).\n\nImproved-by: Ramkumar Ramachandra <artagnon@gmail.com>\nImproved-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nAcked-by: Ramkumar Ramachandra <artagnon@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n t/t9011-svn-da.sh |   35 +++++++++++++++++++++++++++++++++++\n vcs-svn/svndiff.c |   28 +++++++++++++++++++++++-----\n 2 files changed, 58 insertions(+), 5 deletions(-)\n\ndiff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh\nindex d13115a..45e396f 100755\n--- a/t/t9011-svn-da.sh\n+++ b/t/t9011-svn-da.sh\n@@ -212,4 +212,39 @@ test_expect_success 'catch copy that overflows' '\n \ttest_must_fail test-svn-fe -d preimage copytarget.overflow $len\n '\n \n+test_expect_success 'copyfrom source' '\n+\tprintf foo >expect &&\n+\tprintf \"SVNQ%b%b\" \"Q\\003\\003\\002Q\" \"\\003Q\" | q_to_nul >copysource.all &&\n+\ttest-svn-fe -d preimage copysource.all 11 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'copy backwards' '\n+\tprintf oof >expect &&\n+\tprintf \"SVNQ%b%b\" \"Q\\003\\003\\006Q\" \"\\001\\002\\001\\001\\001Q\" |\n+\t\tq_to_nul >copysource.rev &&\n+\ttest-svn-fe -d preimage copysource.rev 15 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'offsets are relative to window' '\n+\tprintf fo >expect &&\n+\tprintf \"SVNQ%b%b%b%b\" \"Q\\003\\001\\002Q\" \"\\001Q\" \\\n+\t\t\"\\002\\001\\001\\002Q\" \"\\001Q\" |\n+\t\tq_to_nul >copysource.two &&\n+\ttest-svn-fe -d preimage copysource.two 18 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'example from notes/svndiff' '\n+\tprintf aaaaccccdddddddd >expect &&\n+\tprintf aaaabbbbcccc >source &&\n+\tprintf \"SVNQ%b%b%s\" \"Q\\014\\020\\007\\001\" \\\n+\t\t\"\\004Q\\004\\010\\0201\\0107\\010\" d |\n+\t\tq_to_nul >delta.example &&\n+\tlen=$(wc -c <delta.example) &&\n+\ttest-svn-fe -d source delta.example $len >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nindex f4c5dae..b7d40c8 100644\n--- a/vcs-svn/svndiff.c\n+++ b/vcs-svn/svndiff.c\n@@ -24,6 +24,7 @@\n  * view_selector ::= copyfrom_source\n  *   | copyfrom_target\n  *   ;\n+ * copyfrom_source ::= # binary 00 000000;\n  * copyfrom_target ::= # binary 01 000000;\n  * copyfrom_data ::= # binary 10 000000;\n  * packed_view_selector ::= # view_selector OR-ed with 6 bit value;\n@@ -34,6 +35,7 @@\n  */\n \n #define INSN_MASK\t0xc0\n+#define INSN_COPYFROM_SOURCE\t0x00\n #define INSN_COPYFROM_TARGET\t0x40\n #define INSN_COPYFROM_DATA\t0x80\n #define OPERAND_MASK\t0x3f\n@@ -43,12 +45,13 @@\n #define VLI_BITS_PER_DIGIT 7\n \n struct window {\n+\tstruct sliding_view *in;\n \tstruct strbuf out;\n \tstruct strbuf instructions;\n \tstruct strbuf data;\n };\n \n-#define WINDOW_INIT\t{ STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }\n+#define WINDOW_INIT(w)\t{ w, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }\n \n static void window_release(struct window *ctx)\n {\n@@ -161,6 +164,19 @@ static int read_length(struct line_buffer *in, size_t *result, off_t *len)\n \treturn 0;\n }\n \n+static int copyfrom_source(struct window *ctx, const char **instructions,\n+\t\t\t   size_t nbytes, const char *insns_end)\n+{\n+\tsize_t offset;\n+\tif (parse_int(instructions, &offset, insns_end))\n+\t\treturn -1;\n+\tif (unsigned_add_overflows(offset, nbytes) ||\n+\t    offset + nbytes > ctx->in->width)\n+\t\treturn error(\"invalid delta: copies source data outside view\");\n+\tstrbuf_add(&ctx->out, ctx->in->buf.buf + offset, nbytes);\n+\treturn 0;\n+}\n+\n static int copyfrom_target(struct window *ctx, const char **instructions,\n \t\t\t   size_t nbytes, const char *instructions_end)\n {\n@@ -209,12 +225,14 @@ static int execute_one_instruction(struct window *ctx,\n \tif (parse_first_operand(instructions, &nbytes, insns_end))\n \t\treturn -1;\n \tswitch (instruction & INSN_MASK) {\n+\tcase INSN_COPYFROM_SOURCE:\n+\t\treturn copyfrom_source(ctx, instructions, nbytes, insns_end);\n \tcase INSN_COPYFROM_TARGET:\n \t\treturn copyfrom_target(ctx, instructions, nbytes, insns_end);\n \tcase INSN_COPYFROM_DATA:\n \t\treturn copyfrom_data(ctx, data_pos, nbytes);\n \tdefault:\n-\t\treturn error(\"Unknown instruction %x\", instruction);\n+\t\treturn error(\"invalid delta: unrecognized instruction\");\n \t}\n }\n \n@@ -238,9 +256,9 @@ static int apply_window_in_core(struct window *ctx)\n }\n \n static int apply_one_window(struct line_buffer *delta, off_t *delta_len,\n-\t\t\t    FILE *out)\n+\t\t\t    struct sliding_view *preimage, FILE *out)\n {\n-\tstruct window ctx = WINDOW_INIT;\n+\tstruct window ctx = WINDOW_INIT(preimage);\n \tsize_t out_len;\n \tsize_t instructions_len;\n \tsize_t data_len;\n@@ -285,7 +303,7 @@ int svndiff0_apply(struct line_buffer *delta, off_t delta_len,\n \t\tif (read_offset(delta, &pre_off, &delta_len) ||\n \t\t    read_length(delta, &pre_len, &delta_len) ||\n \t\t    move_window(preimage, pre_off, pre_len) ||\n-\t\t    apply_one_window(delta, &delta_len, postimage))\n+\t\t    apply_one_window(delta, &delta_len, preimage, postimage))\n \t\t\treturn -1;\n \t}\n \treturn 0;\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163721","messageId":"1300519254-20201-16-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 15/16] vcs-svn: microcleanup in svndiff0 window-reading code","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:53Z","receivedAt":"2011-03-19T07:20:53Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\nCombine some ifs.  No functional change intended.\n\nMissed this in \"vcs-svn: let deltas use data from preimage\"\n(2010-10-13).\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndiff.c |    8 +++-----\n 1 files changed, 3 insertions(+), 5 deletions(-)\n\ndiff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c\nindex b7d40c8..ea727ee 100644\n--- a/vcs-svn/svndiff.c\n+++ b/vcs-svn/svndiff.c\n@@ -267,11 +267,9 @@ static int apply_one_window(struct line_buffer *delta, off_t *delta_len,\n \t/* \"source view\" offset and length already handled; */\n \tif (read_length(delta, &out_len, delta_len) ||\n \t    read_length(delta, &instructions_len, delta_len) ||\n-\t    read_length(delta, &data_len, delta_len))\n-\t\tgoto error_out;\n-\tif (read_chunk(delta, delta_len, &ctx.instructions, instructions_len))\n-\t\tgoto error_out;\n-\tif (read_chunk(delta, delta_len, &ctx.data, data_len))\n+\t    read_length(delta, &data_len, delta_len) ||\n+\t    read_chunk(delta, delta_len, &ctx.instructions, instructions_len) ||\n+\t    read_chunk(delta, delta_len, &ctx.data, data_len))\n \t\tgoto error_out;\n \tstrbuf_grow(&ctx.out, out_len);\n \tif (apply_window_in_core(&ctx))\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163726","messageId":"1300519254-20201-17-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 16/16] vcs-svn: implement text-delta handling","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-19T07:20:54Z","receivedAt":"2011-03-19T07:20:54Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Handle input in Subversion's dumpfile format, version 3.  This is the\nformat produced by \"svnrdump dump\" and \"svnadmin dump --deltas\", and\nthe main difference between v3 dumpfiles and the dumpfiles already\nhandled is that these can include nodes whose properties and text are\nexpressed relative to some other node.\n\nTo handle such nodes, we find which node the text and properties are\nbased on, handle its property changes, use the cat-blob command to\nrequest the basis blob from the fast-import backend, use the\nsvndiff0_apply() helper to apply the text delta on the fly, writing\noutput to a temporary file, and then measure that postimage file's\nlength and write its content to the fast-import stream.\n\nThe temporary postimage file is shared between delta-using nodes to\navoid some file system overhead.\n\nThe svn-fe interface needs to be more complicated to accomodate the\nbackward flow of information from the fast-import backend to svn-fe.\nThe backflow fd is not needed when parsing streams without deltas,\nthough, so existing scripts using svn-fe on v2 dumps should\ncontinue to work.\n\nNEEDSWORK: generalize interface so caller sets the backflow fd, close\ntemporary file before exiting\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n contrib/svn-fe/svn-fe.txt |    5 +--\n t/t9010-svn-fe.sh         |  108 +++++++++++++++++++++++++++++++++++++++++++-\n vcs-svn/fast_export.c     |  109 ++++++++++++++++++++++++++++++++++++++++++++-\n vcs-svn/fast_export.h     |    3 +\n vcs-svn/svndump.c         |   13 ++++--\n 5 files changed, 227 insertions(+), 11 deletions(-)\n\ndiff --git a/contrib/svn-fe/svn-fe.txt b/contrib/svn-fe/svn-fe.txt\nindex 85f7b83..2dd27ce 100644\n--- a/contrib/svn-fe/svn-fe.txt\n+++ b/contrib/svn-fe/svn-fe.txt\n@@ -9,7 +9,7 @@ SYNOPSIS\n --------\n [verse]\n mkfifo backchannel &&\n-svnadmin dump --incremental REPO |\n+svnadmin dump --deltas REPO |\n \tsvn-fe [url] 3<backchannel |\n \tgit fast-import --cat-blob-fd=3 3>backchannel\n \n@@ -32,9 +32,6 @@ Subversion's repository dump format is documented in full in\n Files in this format can be generated using the 'svnadmin dump' or\n 'svk admin dump' command.\n \n-Dumps produced with 'svnadmin dump --deltas' (dumpfile format v3)\n-are not supported.\n-\n OUTPUT FORMAT\n -------------\n The fast-import format is documented by the git-fast-import(1)\ndiff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh\nindex 720fd6b..cd7a215 100755\n--- a/t/t9010-svn-fe.sh\n+++ b/t/t9010-svn-fe.sh\n@@ -568,7 +568,7 @@ test_expect_success PIPE 'change file mode and reiterate content' '\n \ttest_cmp hello actual.target\n '\n \n-test_expect_success PIPE 'deltas not supported' '\n+test_expect_success PIPE 'deltas supported' '\n \treinit_git &&\n \t{\n \t\t# (old) h + (inline) ello + (old) \\n\n@@ -629,7 +629,7 @@ test_expect_success PIPE 'deltas not supported' '\n \t\techo PROPS-END &&\n \t\tcat delta\n \t} >delta.dump &&\n-\ttest_must_fail try_dump delta.dump\n+\ttry_dump delta.dump\n '\n \n test_expect_success PIPE 'property deltas supported' '\n@@ -836,6 +836,110 @@ test_expect_success PIPE 'deltas for typechange' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success PIPE 'deltas need not consume the whole preimage' '\n+\treinit_git &&\n+\tcat >expect <<-\\EOF &&\n+\tOBJID\n+\t:120000 100644 OBJID OBJID T\tpostimage\n+\tOBJID\n+\t:100644 120000 OBJID OBJID T\tpostimage\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tpostimage\n+\tEOF\n+\techo \"first preimage\" >expect.1 &&\n+\tprintf target >expect.2 &&\n+\tprintf lnk >expect.3 &&\n+\t{\n+\t\tprintf \"SVNQ%b%b%b\" \"QQ\\017\\001\\017\" \"\\0217\" \"first preimage\\n\" |\n+\t\tq_to_nul\n+\t} >delta.1 &&\n+\t{\n+\t\tproperties svn:special \"*\" &&\n+\t\techo PROPS-END\n+\t} >symlink.props &&\n+\t{\n+\t\tprintf \"SVNQ%b%b%b\" \"Q\\002\\013\\004\\012\" \"\\0201\\001\\001\\0211\" \"lnk target\" |\n+\t\tq_to_nul\n+\t} >delta.2 &&\n+\t{\n+\t\tprintf \"SVNQ%b%b\" \"Q\\004\\003\\004Q\" \"\\001Q\\002\\002\" |\n+\t\tq_to_nul\n+\t} >delta.3 &&\n+\t{\n+\t\tcat <<-\\EOF &&\n+\t\tSVN-fs-dump-format-version: 3\n+\n+\t\tRevision-number: 1\n+\t\tProp-content-length: 10\n+\t\tContent-length: 10\n+\n+\t\tPROPS-END\n+\n+\t\tNode-path: postimage\n+\t\tNode-kind: file\n+\t\tNode-action: add\n+\t\tText-delta: true\n+\t\tProp-content-length: 10\n+\t\tEOF\n+\t\techo Text-content-length: $(wc -c <delta.1) &&\n+\t\techo Content-length: $((10 + $(wc -c <delta.1))) &&\n+\t\techo &&\n+\t\techo PROPS-END &&\n+\t\tcat delta.1 &&\n+\t\tcat <<-\\EOF &&\n+\n+\t\tRevision-number: 2\n+\t\tProp-content-length: 10\n+\t\tContent-length: 10\n+\n+\t\tPROPS-END\n+\n+\t\tNode-path: postimage\n+\t\tNode-kind: file\n+\t\tNode-action: change\n+\t\tText-delta: true\n+\t\tEOF\n+\t\techo Prop-content-length: $(wc -c <symlink.props) &&\n+\t\techo Text-content-length: $(wc -c <delta.2) &&\n+\t\techo Content-length: $(($(wc -c <symlink.props) + $(wc -c <delta.2))) &&\n+\t\techo &&\n+\t\tcat symlink.props &&\n+\t\tcat delta.2 &&\n+\t\tcat <<-\\EOF &&\n+\n+\t\tRevision-number: 3\n+\t\tProp-content-length: 10\n+\t\tContent-length: 10\n+\n+\t\tPROPS-END\n+\n+\t\tNode-path: postimage\n+\t\tNode-kind: file\n+\t\tNode-action: change\n+\t\tText-delta: true\n+\t\tProp-content-length: 10\n+\t\tEOF\n+\t\techo Text-content-length: $(wc -c <delta.3) &&\n+\t\techo Content-length: $((10 + $(wc -c <delta.3))) &&\n+\t\techo &&\n+\t\techo PROPS-END &&\n+\t\tcat delta.3 &&\n+\t\techo\n+\t} >deltapartial.dump &&\n+\ttry_dump deltapartial.dump &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$_x40/OBJID/g\"\n+\t} >actual &&\n+\ttest_cmp expect actual &&\n+\tgit show HEAD:postimage >actual.3 &&\n+\tgit show HEAD^:postimage >actual.2 &&\n+\tgit show HEAD^^:postimage >actual.1 &&\n+\ttest_cmp expect.1 actual.1 &&\n+\ttest_cmp expect.2 actual.2 &&\n+\ttest_cmp expect.3 actual.3\n+'\n \n test_expect_success 'set up svn repo' '\n \tsvnconf=$PWD/svnconf &&\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 4748253..94f12dc 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -7,15 +7,38 @@\n #include \"strbuf.h\"\n #include \"quote.h\"\n #include \"fast_export.h\"\n-#include \"line_buffer.h\"\n #include \"repo_tree.h\"\n #include \"strbuf.h\"\n+#include \"svndiff.h\"\n+#include \"sliding_window.h\"\n+#include \"line_buffer.h\"\n \n #define MAX_GITSVN_LINE_LEN 4096\n+#define REPORT_FILENO 3\n \n static uint32_t first_commit_done;\n+static struct line_buffer postimage = LINE_BUFFER_INIT;\n static struct line_buffer report_buffer = LINE_BUFFER_INIT;\n \n+/* NEEDSWORK: move to fast_export_init() */\n+static int init_postimage(void)\n+{\n+\tstatic int postimage_initialized;\n+\tif (postimage_initialized)\n+\t\treturn 0;\n+\tpostimage_initialized = 1;\n+\treturn buffer_tmpfile_init(&postimage);\n+}\n+\n+static int init_report_buffer(int fd)\n+{\n+\tstatic int report_buffer_initialized;\n+\tif (report_buffer_initialized)\n+\t\treturn 0;\n+\treport_buffer_initialized = 1;\n+\treturn buffer_fdinit(&report_buffer, fd);\n+}\n+\n void fast_export_init(int fd)\n {\n \tif (buffer_fdinit(&report_buffer, fd))\n@@ -127,6 +150,73 @@ static void die_short_read(struct line_buffer *input)\n \tdie(\"invalid dump: unexpected end of file\");\n }\n \n+static int ends_with(const char *s, size_t len, const char *suffix)\n+{\n+\tconst size_t suffixlen = strlen(suffix);\n+\tif (len < suffixlen)\n+\t\treturn 0;\n+\treturn !memcmp(s + len - suffixlen, suffix, suffixlen);\n+}\n+\n+static int parse_cat_response_line(const char *header, off_t *len)\n+{\n+\tsize_t headerlen = strlen(header);\n+\tconst char *type;\n+\tconst char *end;\n+\n+\tif (ends_with(header, headerlen, \" missing\"))\n+\t\treturn error(\"cat-blob reports missing blob: %s\", header);\n+\ttype = memmem(header, headerlen, \" blob \", strlen(\" blob \"));\n+\tif (!type)\n+\t\treturn error(\"cat-blob header has wrong object type: %s\", header);\n+\t*len = strtoumax(type + strlen(\" blob \"), (char **) &end, 10);\n+\tif (end == type + strlen(\" blob \"))\n+\t\treturn error(\"cat-blob header does not contain length: %s\", header);\n+\tif (*end)\n+\t\treturn error(\"cat-blob header contains garbage after length: %s\", header);\n+\treturn 0;\n+}\n+\n+static long apply_delta(off_t len, struct line_buffer *input,\n+\t\t\tconst char *old_data, uint32_t old_mode)\n+{\n+\tlong ret;\n+\toff_t preimage_len = 0;\n+\tstruct sliding_view preimage = SLIDING_VIEW_INIT(&report_buffer);\n+\tFILE *out;\n+\n+\tif (init_postimage() || !(out = buffer_tmpfile_rewind(&postimage)))\n+\t\tdie(\"cannot open temporary file for blob retrieval\");\n+\tif (init_report_buffer(REPORT_FILENO))\n+\t\tdie(\"cannot open fd 3 for feedback from fast-import\");\n+\tif (old_data) {\n+\t\tconst char *response;\n+\t\tprintf(\"cat-blob %s\\n\", old_data);\n+\t\tfflush(stdout);\n+\t\tresponse = get_response_line();\n+\t\tif (parse_cat_response_line(response, &preimage_len))\n+\t\t\tdie(\"invalid cat-blob response: %s\", response);\n+\t}\n+\tif (old_mode == REPO_MODE_LNK) {\n+\t\tstrbuf_addstr(&preimage.buf, \"link \");\n+\t\tpreimage_len += strlen(\"link \");\n+\t}\n+\tif (svndiff0_apply(input, len, &preimage, out))\n+\t\tdie(\"cannot apply delta\");\n+\tif (old_data) {\n+\t\t/* Read the remainder of preimage and trailing newline. */\n+\t\tif (move_window(&preimage, preimage_len, 1))\n+\t\t\tdie(\"cannot seek to end of input\");\n+\t\tif (preimage.buf.buf[0] != '\\n')\n+\t\t\tdie(\"missing newline after cat-blob response\");\n+\t}\n+\tret = buffer_tmpfile_prepare_to_read(&postimage);\n+\tif (ret < 0)\n+\t\tdie(\"cannot read temporary file for blob retrieval\");\n+\tstrbuf_release(&preimage.buf);\n+\treturn ret;\n+}\n+\n void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input)\n {\n \tif (mode == REPO_MODE_LNK) {\n@@ -194,3 +284,20 @@ int fast_export_ls(const char *path, uint32_t *mode, struct strbuf *dataref)\n \tls_from_active_commit(path);\n \treturn parse_ls_response(get_response_line(), mode, dataref);\n }\n+\n+void fast_export_blob_delta(uint32_t mode,\n+\t\t\t\tuint32_t old_mode, const char *old_data,\n+\t\t\t\tuint32_t len, struct line_buffer *input)\n+{\n+\tlong postimage_len;\n+\tif (len > maximum_signed_value_of_type(off_t))\n+\t\tdie(\"enormous delta\");\n+\tpostimage_len = apply_delta((off_t) len, input, old_data, old_mode);\n+\tif (mode == REPO_MODE_LNK) {\n+\t\tbuffer_skip_bytes(&postimage, strlen(\"link \"));\n+\t\tpostimage_len -= strlen(\"link \");\n+\t}\n+\tprintf(\"data %ld\\n\", postimage_len);\n+\tbuffer_copy_bytes(&postimage, postimage_len);\n+\tfputc('\\n', stdout);\n+}\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex bc5bddf..a01774c 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -15,6 +15,9 @@ void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tunsigned long timestamp);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input);\n+void fast_export_blob_delta(uint32_t mode,\n+\t\t\tuint32_t old_mode, const char *old_data,\n+\t\t\tuint32_t len, struct line_buffer *input);\n \n /* If there is no such file at that rev, returns -1, errno == ENOENT. */\n int fast_export_ls_rev(uint32_t rev, const char *path,\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex dbb9c16..0c7ac64 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -206,9 +206,7 @@ static void handle_node(void)\n \t */\n \tstatic const char *const empty_blob = \"::empty::\";\n \tconst char *old_data = NULL;\n-\n-\tif (node_ctx.text_delta)\n-\t\tdie(\"text deltas not supported\");\n+\tuint32_t old_mode = REPO_MODE_BLB;\n \n \tif (node_ctx.action == NODEACT_DELETE) {\n \t\tif (have_text || have_props || node_ctx.srcRev)\n@@ -243,6 +241,7 @@ static void handle_node(void)\n \t\tif (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)\n \t\t\tdie(\"invalid dump: cannot modify a file into a directory\");\n \t\tnode_ctx.type = mode;\n+\t\told_mode = mode;\n \t} else if (node_ctx.action == NODEACT_ADD) {\n \t\tif (type == REPO_MODE_DIR)\n \t\t\told_data = NULL;\n@@ -277,8 +276,14 @@ static void handle_node(void)\n \t\tfast_export_modify(node_ctx.dst.buf, node_ctx.type, old_data);\n \t\treturn;\n \t}\n+\tif (!node_ctx.text_delta) {\n+\t\tfast_export_modify(node_ctx.dst.buf, node_ctx.type, \"inline\");\n+\t\tfast_export_data(node_ctx.type, node_ctx.textLength, &input);\n+\t\treturn;\n+\t}\n \tfast_export_modify(node_ctx.dst.buf, node_ctx.type, \"inline\");\n-\tfast_export_data(node_ctx.type, node_ctx.textLength, &input);\n+\tfast_export_blob_delta(node_ctx.type, old_mode, old_data,\n+\t\t\t\tnode_ctx.textLength, &input);\n }\n \n static void begin_revision(void)\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163728","messageId":"20110319075028.GB4063@elie","threadId":"26784","inReplyTo":"1300518231-20008-2-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH 1/9] vcs-svn: pass paths through to fast-import","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-19T07:50:28Z","receivedAt":"2011-03-19T07:50:28Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nDavid Barr wrote:\n\n>  vcs-svn/fast_export.c |   47 ++++++++++++++++++------------------\n>  vcs-svn/fast_export.h |    9 +++----\n>  vcs-svn/repo_tree.c   |   20 +++++++-------\n>  vcs-svn/repo_tree.h   |   13 ++++------\n>  vcs-svn/svndump.c     |   63 +++++++++++++++++++++----------------------------\n>  5 files changed, 70 insertions(+), 82 deletions(-)\n\nHoorah!  Simpler and more idiomatic.\n\n> +++ b/vcs-svn/fast_export.c\n> @@ -32,30 +34,30 @@ void fast_export_reset(void)\n[...]\n>  \tbuffer_reset(&report_buffer);\n>  }\n>  \n> -void fast_export_delete(uint32_t depth, const uint32_t *path)\n> +void fast_export_delete(const char *path)\n>  {\n> -\tprintf(\"D \\\"\");\n> -\tpool_print_seq_q(depth, path, '/', stdout);\n> -\tprintf(\"\\\"\\n\");\n> +\tputchar('D');\n> +\tputchar(' ');\n> +\tquote_c_style(path, NULL, stdout, 0);\n> +\tputchar('\\n');\n>  }\n\nFunctional change: if the path doesn't need quoting, this won't\nsurround it with quotation marks.  Luckily fast-import doesn't\nmind.\n\n[...]\n> -\tprintf(\"M %06\"PRIo32\" %s \\\"\", mode, dataref);\n> -\tpool_print_seq_q(depth, path, '/', stdout);\n> -\tprintf(\"\\\"\\n\");\n> +\tprintf(\"M %06\"PRIo32\" %s \", mode, dataref);\n> +\tquote_c_style(path, NULL, stdout, 0);\n> +\tputchar('\\n');\n[...]\n> -\tprintf(\"ls :%\"PRIu32\" \\\"\", rev);\n> -\tpool_print_seq_q(depth, path, '/', stdout);\n> -\tprintf(\"\\\"\\n\");\n> +\tprintf(\"ls :%\"PRIu32\" \", rev);\n> +\tquote_c_style(path, NULL, stdout, 0);\n> +\tputchar('\\n');\n\nLikewise.\n\n[...]\n> -static void ls_from_active_commit(uint32_t depth, const uint32_t *path)\n> +static void ls_from_active_commit(const char *path)\n>  {\n>  \t/* ls \"path/to/file\" */\n>  \tprintf(\"ls \\\"\");\n> -\tpool_print_seq_q(depth, path, '/', stdout);\n> +\tquote_c_style(path, NULL, stdout, 1);\n>  \tprintf(\"\\\"\\n\");\n\nSingle-argument 'ls': quotes always present.  Phew.\n\n[...]\n> --- a/vcs-svn/repo_tree.h\n> +++ b/vcs-svn/repo_tree.h\n> @@ -8,15 +8,12 @@\n>  #define REPO_MODE_EXE 0100755\n>  #define REPO_MODE_LNK 0120000\n>  \n> -#define REPO_MAX_PATH_LEN 4096\n> -#define REPO_MAX_PATH_DEPTH 1000\n\nYes.\n\n> --- a/vcs-svn/svndump.c\n> +++ b/vcs-svn/svndump.c\n> @@ -11,8 +11,8 @@\n>  #include \"repo_tree.h\"\n>  #include \"fast_export.h\"\n>  #include \"line_buffer.h\"\n> -#include \"obj_pool.h\"\n>  #include \"string_pool.h\"\n> +#include \"strbuf.h\"\n>  \n>  #define REPORT_FILENO 3\n>  \n> @@ -31,32 +31,20 @@\n>  #define LENGTH_UNKNOWN (~0)\n>  #define DATE_RFC2822_LEN 31\n>  \n> -/* Create memory pool for log messages */\n> -obj_pool_gen(log, char, 4096)\n> -\n\nNot a path. :)  Snuck in from a separate patch?\n\n>  static struct line_buffer input = LINE_BUFFER_INIT;\n>  \n>  #define REPORT_FILENO 3\n>  \n> -static char *log_copy(uint32_t length, const char *log)\n> -{\n[...]\n> -}\n\nLikewise.\n\n[...]\n>  static struct {\n>  \tuint32_t revision, author;\n>  \tunsigned long timestamp;\n> -\tchar *log;\n> +\tstruct strbuf log;\n>  } rev_ctx;\n\nLikewise.\n\n[... etc ...]\n> @@ -406,6 +395,9 @@ int svndump_init(const char *filename)\n>  \tif (buffer_init(&input, filename))\n>  \t\treturn error(\"cannot open %s: %s\", filename, strerror(errno));\n>  \tfast_export_init(REPORT_FILENO);\n> +\tstrbuf_init(&rev_ctx.log, 4096);\n> +\tstrbuf_init(&node_ctx.src, 4096);\n> +\tstrbuf_init(&node_ctx.dst, 4096);\n\n4096 because PATH_MAX or some other reason?\n\n> @@ -415,11 +407,13 @@ int svndump_init(const char *filename)\n>\n>  void svndump_deinit(void)\n>  {\n> -\tlog_reset();\n>  \tfast_export_deinit();\n>  \treset_dump_ctx(~0);\n>  \treset_rev_ctx(0);\n>  \treset_node_ctx(NULL);\n> +\tstrbuf_release(&rev_ctx.log);\n> +\tstrbuf_release(&node_ctx.src);\n> +\tstrbuf_release(&node_ctx.dst);\n\nSide note: it's often not clear what should go in the \"prepare for next\nuser\" routine and what should go in the \"shutting down for good\".  I\nsuppose these should use strbuf_reset and the memory would be finally\nfreed in svndump_reset?  Does it make sense to have two distinct\nroutines like this without a user to demonstrate the trade-offs?\n\nExcept as noted above,\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n\nThanks; I like where this is going.\n"},{"id":"163729","messageId":"20110319080129.GA6706@elie","threadId":"26784","inReplyTo":"1300518231-20008-3-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH 2/9] vcs-svn: avoid using ls command twice","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-19T08:01:29Z","receivedAt":"2011-03-19T08:01:29Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"David Barr wrote:\n\n>  3 files changed, 6 insertions(+), 24 deletions(-)\n\n:)\n\n> --- a/vcs-svn/repo_tree.c\n> +++ b/vcs-svn/repo_tree.c\n> @@ -8,39 +8,23 @@\n>  #include \"repo_tree.h\"\n>  #include \"fast_export.h\"\n>  \n> -const char *repo_read_path(const char *path)\n> +const char *repo_read_path(const char *path, uint32_t *mode_out)\n\nObviously good, both because it means we can use one round-trip\nto get the same information that  previously took two and because\nthe API just makes more sense.  Thanks.\n"},{"id":"163731","messageId":"20110319085138.GB6706@elie","threadId":"26784","inReplyTo":"1300518231-20008-4-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH 3/9] vcs-svn: implement perfect hash for node-prop keys","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-19T08:51:38Z","receivedAt":"2011-03-19T08:51:38Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"David Barr wrote:\n\n>  vcs-svn/svndump.c |   50 ++++++++++++++++++++++++++++++++------------------\n>  1 files changed, 32 insertions(+), 18 deletions(-)\n\nAlas.  But it's probably worth it for the chance to get rid of\nknowledge of how to intern strings.\n\n> --- a/vcs-svn/svndump.c\n> +++ b/vcs-svn/svndump.c\n[...]\n> @@ -113,22 +107,38 @@ static void init_keys(void)\n>  \tkeys.prop_delta = pool_intern(\"Prop-delta\");\n>  }\n>  \n> -static void handle_property(uint32_t key, const char *val, uint32_t len,\n> +static void handle_property(const char *key, const char *val, uint32_t len,\n>  \t\t\t\tuint32_t *type_set)\n>  {\n> -\tif (key == keys.svn_log) {\n> +\tconst int key_len = strlen(key);\n> +\tswitch (key_len) {\n> +\tcase 7:\n> +\t\tif (memcmp(key, \"svn:log\", 7))\n> +\t\t\tbreak;\n\nCrazy idea: to make it visible at a glance when the numbers are wrong,\none can do:\n\n\tswitch (key_len + 1) {\n\tcase sizeof(\"svn:log\"):\n\t\tif (memcmp(key, \"svn:log\", strlen(\"svn:log\")))\n\t\t\tbreak;\n\nThis only makes the redundancy more obvious, of course.  It could\nbe reduced a little with something like\n\n static int prefixcmp_len(const char *str, size_t str_len,\n\t\t\t  const char *prefix, size_t prefix_len)\n {\n\tif (prefix_len > str_len)\n\t\treturn 1;\n\treturn memcmp(str, prefix, prefix_len);\n }\n\nbut that's probably not worth the cognitive load.\n\n[...]\n> -\t} else if (key == keys.svn_executable || key == keys.svn_special) {\n> +\t\tbreak;\n> +\tcase 14:\n> +\t\tif (memcmp(key, \"svn:executable\", 14))\n> +\t\t\tbreak;\n> +\tcase 11:\n> +\t\tif (key_len == 11 && memcmp(key, \"svn:special\", 11))\n> +\t\t\tbreak;\n\nMaybe, to avoid an unnecessary /* fall through */:\n\n\tcase sizeof(\"svn:executable\"):\n\tcase sizeof(\"svn:special\"):\n\t\tif (key_len == strlen(\"svn:executable\") &&\n\t\t    memcmp(key, \"svn:executable\", strlen(...)))\n\t\t\tbreak;\n\t\tif (key_len == strlen(\"svn:special\") &&\n\t\t    memcmp(key, \"svn:special\", strlen(\"svn:special\")))\n\t\t\tbreak;\n\n>  \t\tif (*type_set) {\n[...]\n> @@ -147,7 +157,7 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,\n>  \n>  static void read_props(void)\n>  {\n> -\tuint32_t key = ~0;\n> +\tchar key[16] = {0};\n\nProbably warrants a comment:\n\n\t/* the longest key we pay attention to is \"<whatever>\" */\n\n>  \tconst char *t;\n>  \t/*\n>  \t * NEEDSWORK: to support simple mode changes like\n> @@ -175,16 +185,20 @@ static void read_props(void)\n>  \n>  \t\tswitch (type) {\n>  \t\tcase 'K':\n> -\t\t\tkey = pool_intern(val);\n> -\t\t\tcontinue;\n>  \t\tcase 'D':\n> -\t\t\tkey = pool_intern(val);\n> +\t\t\tif (len < sizeof(key))\n> +\t\t\t\tmemcpy(key, val, len + 1);\n\nWhat happens on I/O error, when val is NULL?  How about early EOF\nor malformed input, when strlen(val) < len?\n\nSome tests would also be a comfort.\n\nI'm not so happy with the table of (at first glance) magic-seeming\nnumbers and the error handling looks a little tricky but aside from\nthose details this seems like a reasonable way to avoid some\ncomplication without sacrificing speed.\n\nSpeaking of which, any hints for people who want to time this patch\n(and other patches in the series)?\n\nThanks.\nJonathan\n"},{"id":"163733","messageId":"20110319085737.GC6706@elie","threadId":"26784","inReplyTo":"1300518231-20008-5-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH 4/9] vcs-svn: implement perfect hash for top-level keys","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-19T08:57:37Z","receivedAt":"2011-03-19T08:57:37Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"David Barr wrote:\n\n> --- a/vcs-svn/svndump.c\n> +++ b/vcs-svn/svndump.c\n> @@ -323,16 +296,25 @@ void svndump_read(const char *url)\n>  \t\t\tcontinue;\n>  \t\t*val++ = '\\0';\n>  \t\t*val++ = '\\0';\n> -\t\tkey = pool_intern(t);\n>  \n> -\t\tif (key == keys.svn_fs_dump_format_version) {\n> +\t\t/* strlen(key) */\n> +\t\tswitch (val - t - 2) { \n> +\t\tcase 26:\n> +\t\t\tif (memcmp(t, \"SVN-fs-dump-format-version\", 26))\n> +\t\t\t\tcontinue;\n\nSame comments as the previous patch apply here.\n\nMight make sense to split out the loop body (or at least the giant\nswitch statement) as a separate function for easier contemplation.\n\n[...]\n> -\t\t} else if (key == keys.content_length) {\n> +\t\t\tbreak;\n> +\t\tcase 14:\n> +\t\t\tif (memcmp(t, \"Content-length\", 14))\n> +\t\t\t\tcontinue;\n>  \t\t\tlen = atoi(val);\n\nThanks for a very clean patch.\n"},{"id":"163734","messageId":"20110319090821.GD6706@elie","threadId":"26784","inReplyTo":"1300518231-20008-6-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH 5/9] vcs-svn: factor out usage of string_pool","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-19T09:08:21Z","receivedAt":"2011-03-19T09:08:21Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"David Barr wrote:\n\n> [Subject: vcs-svn: factor out usage of string_pool]\n\nThis actually means something like: use strbufs and strings instead of\ninterned strings for values of rev, dump, and node fields that happen\nto be strings.  After this change, there are no more users of the\nstring-pool library left.\n\n> @@ -71,14 +71,16 @@ static void reset_rev_ctx(uint32_t revision)\n>  \trev_ctx.revision = revision;\n>  \trev_ctx.timestamp = 0;\n>  \tstrbuf_reset(&rev_ctx.log);\n> -\trev_ctx.author = ~0;\n> +\tstrbuf_reset(&rev_ctx.author);\n\nSide note: should the default timestamp really be the epoch?  I'd\nrather the default timestamp be the timestamp of the parent revision,\nto make out-of-order dates a little less likely.\n\n>  }\n>  \n> -static void reset_dump_ctx(uint32_t url)\n> +static void reset_dump_ctx(const char *url)\n>  {\n> -\tdump_ctx.url = url;\n> +\tstrbuf_reset(&dump_ctx.url);\n> +\tif (url)\n> +\t\tstrbuf_addstr(&dump_ctx.url, url);\n\nGood, we keep our own copy of the url still.\n\n> @@ -91,13 +93,15 @@ static void handle_property(const char *key, const char *val, uint32_t len,\n>  \t\t\tbreak;\n>  \t\tif (!val)\n>  \t\t\tdie(\"invalid dump: unsets svn:log\");\n> -\t\t/* Value length excludes terminating nul. */\n> -\t\tstrbuf_add(&rev_ctx.log, val, len + 1);\n> +\t\tstrbuf_reset(&rev_ctx.log);\n> +\t\tstrbuf_add(&rev_ctx.log, val, len);\n\nWhat is this change about?\n\n> @@ -447,5 +456,4 @@ void svndump_reset(void)\n>  {\n>  \tfast_export_reset();\n>  \tbuffer_reset(&input);\n> -\tpool_reset();\n\nstrbuf_release(&dump_ctx.url)?\n\nLikewise for dump_ctx.uuid and the other one.\n\nThanks; except as noted above this looks good.\n"},{"id":"163735","messageId":"20110319091003.GE6706@elie","threadId":"26784","inReplyTo":"1300518231-20008-10-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH 9/9] vcs-svn: use strchr to find RFC822 delimiter","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-19T09:10:03Z","receivedAt":"2011-03-19T09:10:03Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"David Barr wrote:\n\n> --- a/vcs-svn/svndump.c\n> +++ b/vcs-svn/svndump.c\n> @@ -296,10 +296,12 @@ void svndump_read(const char *url)\n>  \n>  \treset_dump_ctx(url);\n>  \twhile ((t = buffer_read_line(&input))) {\n> -\t\tval = strstr(t, \": \");\n> +\t\tval = strchr(t, ':');\n>  \t\tif (!val)\n>  \t\t\tcontinue;\n>  \t\t*val++ = '\\0';\n> +\t\tif (*val != ' ')\n> +\t\t\tcontinue;\n\nThis one and the three preceding it (removing sublibraries)\nmake sense.  Thanks for a pleasant read.\n\nGood night,\nJonathan\n"},{"id":"163861","messageId":"1300670777-17197-1-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"20110319085138.GB6706@elie","subject":"[PATCH 1/3] vcs-svn: implement perfect hash for node-prop keys","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T01:26:15Z","receivedAt":"2011-03-21T01:26:15Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This eliminates one more dependency on string_pool.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndump.c |   64 +++++++++++++++++++++++++++++++++++++---------------\n 1 files changed, 45 insertions(+), 19 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 15b173e..48848ff 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -52,8 +52,7 @@ static struct {\n } dump_ctx;\n \n static struct {\n-\tuint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid,\n-\t\trevision_number, node_path, node_kind, node_action,\n+\tuint32_t uuid, revision_number, node_path, node_kind, node_action,\n \t\tnode_copyfrom_path, node_copyfrom_rev, text_content_length,\n \t\tprop_content_length, content_length, svn_fs_dump_format_version,\n \t\t/* version 3 format */\n@@ -92,11 +91,6 @@ static void reset_dump_ctx(uint32_t url)\n \n static void init_keys(void)\n {\n-\tkeys.svn_log = pool_intern(\"svn:log\");\n-\tkeys.svn_author = pool_intern(\"svn:author\");\n-\tkeys.svn_date = pool_intern(\"svn:date\");\n-\tkeys.svn_executable = pool_intern(\"svn:executable\");\n-\tkeys.svn_special = pool_intern(\"svn:special\");\n \tkeys.uuid = pool_intern(\"UUID\");\n \tkeys.revision_number = pool_intern(\"Revision-number\");\n \tkeys.node_path = pool_intern(\"Node-path\");\n@@ -113,22 +107,43 @@ static void init_keys(void)\n \tkeys.prop_delta = pool_intern(\"Prop-delta\");\n }\n \n-static void handle_property(uint32_t key, const char *val, uint32_t len,\n+/* Compare string to literal of equal length; must be guarded by length test. */\n+#define constcmp(s, ref) memcmp((s), (ref), sizeof(ref) - 1)\n+\n+static void handle_property(const char *key, const int sizeof_key,\n+\t\t\t\tconst char *val, uint32_t len,\n \t\t\t\tuint32_t *type_set)\n {\n-\tif (key == keys.svn_log) {\n+\tswitch (sizeof_key) {\n+\tcase sizeof(\"svn:log\"):\n+\t\tif (constcmp(key, \"svn:log\"))\n+\t\t\tbreak;\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:log\");\n \t\t/* Value length excludes terminating nul. */\n \t\tstrbuf_add(&rev_ctx.log, val, len + 1);\n-\t} else if (key == keys.svn_author) {\n+\t\tbreak;\n+\tcase sizeof(\"svn:author\"):\n+\t\tif (constcmp(key, \"svn:author\"))\n+\t\t\tbreak;\n \t\trev_ctx.author = pool_intern(val);\n-\t} else if (key == keys.svn_date) {\n+\t\tbreak;\n+\tcase sizeof(\"svn:date\"):\n+\t\tif (constcmp(key, \"svn:date\"))\n+\t\t\tbreak;\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:date\");\n \t\tif (parse_date_basic(val, &rev_ctx.timestamp, NULL))\n \t\t\twarning(\"invalid timestamp: %s\", val);\n-\t} else if (key == keys.svn_executable || key == keys.svn_special) {\n+\t\tbreak;\n+\tcase sizeof(\"svn:executable\"):\n+\tcase sizeof(\"svn:special\"):\n+\t\tif (sizeof_key == sizeof(\"svn:executable\") &&\n+\t\t    constcmp(key, \"svn:executable\"))\n+\t\t\tbreak;\n+\t\tif (sizeof_key == sizeof(\"svn:special\") &&\n+\t\t    constcmp(key, \"svn:special\"))\n+\t\t\tbreak;\n \t\tif (*type_set) {\n \t\t\tif (!val)\n \t\t\t\treturn;\n@@ -139,7 +154,7 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,\n \t\t\treturn;\n \t\t}\n \t\t*type_set = 1;\n-\t\tnode_ctx.type = key == keys.svn_executable ?\n+\t\tnode_ctx.type = sizeof_key == sizeof(\"svn:executable\") ?\n \t\t\t\tREPO_MODE_EXE :\n \t\t\t\tREPO_MODE_LNK;\n \t}\n@@ -147,7 +162,9 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,\n \n static void read_props(void)\n {\n-\tuint32_t key = ~0;\n+\t/* Reserve enough space for the longest standard key. */\n+\tchar key[sizeof(\"svn:executable\")] = {0};\n+\tint sizeof_key = 1;\n \tconst char *t;\n \t/*\n \t * NEEDSWORK: to support simple mode changes like\n@@ -175,16 +192,25 @@ static void read_props(void)\n \n \t\tswitch (type) {\n \t\tcase 'K':\n-\t\t\tkey = pool_intern(val);\n-\t\t\tcontinue;\n \t\tcase 'D':\n-\t\t\tkey = pool_intern(val);\n+\t\t\tif (len < sizeof(key) && val) {\n+\t\t\t\tmemcpy(key, val, len + 1);\n+\t\t\t\tsizeof_key = len + 1;\n+\t\t\t} else {\n+\t\t\t\t/* nonstandard key. */\n+\t\t\t\t*key = '\\0';\n+\t\t\t\tsizeof_key = 1;\n+\t\t\t}\n+\t\t\tif (type == 'K')\n+\t\t\t\tcontinue;\n+\t\t\tassert(type == 'D');\n \t\t\tval = NULL;\n \t\t\tlen = 0;\n \t\t\t/* fall through */\n \t\tcase 'V':\n-\t\t\thandle_property(key, val, len, &type_set);\n-\t\t\tkey = ~0;\n+\t\t\thandle_property(key, sizeof_key, val, len, &type_set);\n+\t\t\t*key = '\\0';\n+\t\t\tsizeof_key = 1;\n \t\t\tcontinue;\n \t\tdefault:\n \t\t\tdie(\"invalid property line: %s\\n\", t);\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163859","messageId":"1300670777-17197-2-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300670777-17197-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 2/3] vcs-svn: implement perfect hash for top-level keys","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T01:26:16Z","receivedAt":"2011-03-21T01:26:16Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This eliminates one more dependency on string_pool.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndump.c |  110 +++++++++++++++++++++++++++++------------------------\n 1 files changed, 60 insertions(+), 50 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 48848ff..f03e8cf 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -51,14 +51,6 @@ static struct {\n \tuint32_t version, uuid, url;\n } dump_ctx;\n \n-static struct {\n-\tuint32_t uuid, revision_number, node_path, node_kind, node_action,\n-\t\tnode_copyfrom_path, node_copyfrom_rev, text_content_length,\n-\t\tprop_content_length, content_length, svn_fs_dump_format_version,\n-\t\t/* version 3 format */\n-\t\ttext_delta, prop_delta;\n-} keys;\n-\n static void reset_node_ctx(char *fname)\n {\n \tnode_ctx.type = 0;\n@@ -89,24 +81,6 @@ static void reset_dump_ctx(uint32_t url)\n \tdump_ctx.uuid = ~0;\n }\n \n-static void init_keys(void)\n-{\n-\tkeys.uuid = pool_intern(\"UUID\");\n-\tkeys.revision_number = pool_intern(\"Revision-number\");\n-\tkeys.node_path = pool_intern(\"Node-path\");\n-\tkeys.node_kind = pool_intern(\"Node-kind\");\n-\tkeys.node_action = pool_intern(\"Node-action\");\n-\tkeys.node_copyfrom_path = pool_intern(\"Node-copyfrom-path\");\n-\tkeys.node_copyfrom_rev = pool_intern(\"Node-copyfrom-rev\");\n-\tkeys.text_content_length = pool_intern(\"Text-content-length\");\n-\tkeys.prop_content_length = pool_intern(\"Prop-content-length\");\n-\tkeys.content_length = pool_intern(\"Content-length\");\n-\tkeys.svn_fs_dump_format_version = pool_intern(\"SVN-fs-dump-format-version\");\n-\t/* version 3 format (Subversion 1.1.0) */\n-\tkeys.text_delta = pool_intern(\"Text-delta\");\n-\tkeys.prop_delta = pool_intern(\"Prop-delta\");\n-}\n-\n /* Compare string to literal of equal length; must be guarded by length test. */\n #define constcmp(s, ref) memcmp((s), (ref), sizeof(ref) - 1)\n \n@@ -326,7 +300,6 @@ void svndump_read(const char *url)\n \tchar *t;\n \tuint32_t active_ctx = DUMP_CTX;\n \tuint32_t len;\n-\tuint32_t key;\n \n \treset_dump_ctx(pool_intern(url));\n \twhile ((t = buffer_read_line(&input))) {\n@@ -335,16 +308,25 @@ void svndump_read(const char *url)\n \t\t\tcontinue;\n \t\t*val++ = '\\0';\n \t\t*val++ = '\\0';\n-\t\tkey = pool_intern(t);\n \n-\t\tif (key == keys.svn_fs_dump_format_version) {\n+\t\t/* strlen(key) + 1 */\n+\t\tswitch (val - t - 1) {\n+\t\tcase sizeof(\"SVN-fs-dump-format-version\"):\n+\t\t\tif (constcmp(t, \"SVN-fs-dump-format-version\"))\n+\t\t\t\tcontinue;\n \t\t\tdump_ctx.version = atoi(val);\n \t\t\tif (dump_ctx.version > 3)\n \t\t\t\tdie(\"expected svn dump format version <= 3, found %\"PRIu32,\n \t\t\t\t    dump_ctx.version);\n-\t\t} else if (key == keys.uuid) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"UUID\"):\n+\t\t\tif (constcmp(t, \"UUID\"))\n+\t\t\t\tcontinue;\n \t\t\tdump_ctx.uuid = pool_intern(val);\n-\t\t} else if (key == keys.revision_number) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Revision-number\"):\n+\t\t\tif (constcmp(t, \"Revision-number\"))\n+\t\t\t\tcontinue;\n \t\t\tif (active_ctx == NODE_CTX)\n \t\t\t\thandle_node();\n \t\t\tif (active_ctx == REV_CTX)\n@@ -353,21 +335,31 @@ void svndump_read(const char *url)\n \t\t\t\tend_revision();\n \t\t\tactive_ctx = REV_CTX;\n \t\t\treset_rev_ctx(atoi(val));\n-\t\t} else if (key == keys.node_path) {\n-\t\t\tif (active_ctx == NODE_CTX)\n-\t\t\t\thandle_node();\n-\t\t\tif (active_ctx == REV_CTX)\n-\t\t\t\tbegin_revision();\n-\t\t\tactive_ctx = NODE_CTX;\n-\t\t\treset_node_ctx(val);\n-\t\t} else if (key == keys.node_kind) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Node-path\"):\n+\t\t\tif (prefixcmp(t, \"Node-\"))\n+\t\t\t\tcontinue;\n+\t\t\tif (!constcmp(t + strlen(\"Node-\"), \"path\")) {\n+\t\t\t\tif (active_ctx == NODE_CTX)\n+\t\t\t\t\thandle_node();\n+\t\t\t\tif (active_ctx == REV_CTX)\n+\t\t\t\t\tbegin_revision();\n+\t\t\t\tactive_ctx = NODE_CTX;\n+\t\t\t\treset_node_ctx(val);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (constcmp(t + strlen(\"Node-\"), \"kind\"))\n+\t\t\t\tcontinue;\n \t\t\tif (!strcmp(val, \"dir\"))\n \t\t\t\tnode_ctx.type = REPO_MODE_DIR;\n \t\t\telse if (!strcmp(val, \"file\"))\n \t\t\t\tnode_ctx.type = REPO_MODE_BLB;\n \t\t\telse\n \t\t\t\tfprintf(stderr, \"Unknown node-kind: %s\\n\", val);\n-\t\t} else if (key == keys.node_action) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Node-action\"):\n+\t\t\tif (constcmp(t, \"Node-action\"))\n+\t\t\t\tcontinue;\n \t\t\tif (!strcmp(val, \"delete\")) {\n \t\t\t\tnode_ctx.action = NODEACT_DELETE;\n \t\t\t} else if (!strcmp(val, \"add\")) {\n@@ -380,20 +372,39 @@ void svndump_read(const char *url)\n \t\t\t\tfprintf(stderr, \"Unknown node-action: %s\\n\", val);\n \t\t\t\tnode_ctx.action = NODEACT_UNKNOWN;\n \t\t\t}\n-\t\t} else if (key == keys.node_copyfrom_path) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Node-copyfrom-path\"):\n+\t\t\tif (constcmp(t, \"Node-copyfrom-path\"))\n+\t\t\t\tcontinue;\n \t\t\tstrbuf_reset(&node_ctx.src);\n \t\t\tstrbuf_addstr(&node_ctx.src, val);\n-\t\t} else if (key == keys.node_copyfrom_rev) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Node-copyfrom-rev\"):\n+\t\t\tif (constcmp(t, \"Node-copyfrom-rev\"))\n+\t\t\t\tcontinue;\n \t\t\tnode_ctx.srcRev = atoi(val);\n-\t\t} else if (key == keys.text_content_length) {\n-\t\t\tnode_ctx.textLength = atoi(val);\n-\t\t} else if (key == keys.prop_content_length) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Text-content-length\"):\n+\t\t\tif (!constcmp(t, \"Text-content-length\")) {\n+\t\t\t\tnode_ctx.textLength = atoi(val);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (constcmp(t, \"Prop-content-length\"))\n+\t\t\t\tcontinue;\n \t\t\tnode_ctx.propLength = atoi(val);\n-\t\t} else if (key == keys.text_delta) {\n-\t\t\tnode_ctx.text_delta = !strcmp(val, \"true\");\n-\t\t} else if (key == keys.prop_delta) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Text-delta\"):\n+\t\t\tif (!constcmp(t, \"Text-delta\")) {\n+\t\t\t\tnode_ctx.text_delta = !strcmp(val, \"true\");\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (constcmp(t, \"Prop-delta\"))\n+\t\t\t\tcontinue;\n \t\t\tnode_ctx.prop_delta = !strcmp(val, \"true\");\n-\t\t} else if (key == keys.content_length) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Content-length\"):\n+\t\t\tif (constcmp(t, \"Content-length\"))\n+\t\t\t\tcontinue;\n \t\t\tlen = atoi(val);\n \t\t\tbuffer_read_line(&input);\n \t\t\tif (active_ctx == REV_CTX) {\n@@ -426,7 +437,6 @@ int svndump_init(const char *filename)\n \treset_dump_ctx(~0);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n-\tinit_keys();\n \treturn 0;\n }\n \n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163860","messageId":"1300670777-17197-3-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300670777-17197-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 3/3] vcs-svn: use switch rather than cascading ifs","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T01:26:17Z","receivedAt":"2011-03-21T01:26:17Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"In the spirit of the last two changes:\nSwitch on length and use constcmp for parsing headers with restricted values.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndump.c |   38 +++++++++++++++++++++++++++++---------\n 1 files changed, 29 insertions(+), 9 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex f03e8cf..fe14ce2 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -350,25 +350,45 @@ void svndump_read(const char *url)\n \t\t\t}\n \t\t\tif (constcmp(t + strlen(\"Node-\"), \"kind\"))\n \t\t\t\tcontinue;\n-\t\t\tif (!strcmp(val, \"dir\"))\n+\t\t\tswitch (strlen(val) + 1) {\n+\t\t\tcase sizeof(\"dir\"):\n+\t\t\t\tif (constcmp(val, \"dir\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.type = REPO_MODE_DIR;\n-\t\t\telse if (!strcmp(val, \"file\"))\n+\t\t\t\tbreak;\n+\t\t\tcase sizeof(\"file\"):\n+\t\t\t\tif (constcmp(val, \"file\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.type = REPO_MODE_BLB;\n-\t\t\telse\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n \t\t\t\tfprintf(stderr, \"Unknown node-kind: %s\\n\", val);\n+\t\t\t}\n \t\t\tbreak;\n \t\tcase sizeof(\"Node-action\"):\n \t\t\tif (constcmp(t, \"Node-action\"))\n \t\t\t\tcontinue;\n-\t\t\tif (!strcmp(val, \"delete\")) {\n-\t\t\t\tnode_ctx.action = NODEACT_DELETE;\n-\t\t\t} else if (!strcmp(val, \"add\")) {\n+\t\t\tswitch (strlen(val) + 1) {\n+\t\t\tcase sizeof(\"add\"):\n+\t\t\t\tif (constcmp(val, \"add\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.action = NODEACT_ADD;\n-\t\t\t} else if (!strcmp(val, \"change\")) {\n+\t\t\t\tbreak;\n+\t\t\tcase sizeof(\"change\"):\n+\t\t\t\tif (constcmp(val, \"change\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.action = NODEACT_CHANGE;\n-\t\t\t} else if (!strcmp(val, \"replace\")) {\n+\t\t\t\tbreak;\n+\t\t\tcase sizeof(\"delete\"):\n+\t\t\t\tif (!constcmp(val, \"delete\")) {\n+\t\t\t\t\tnode_ctx.action = NODEACT_DELETE;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\tif (constcmp(val, \"replace\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.action = NODEACT_REPLACE;\n-\t\t\t} else {\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n \t\t\t\tfprintf(stderr, \"Unknown node-action: %s\\n\", val);\n \t\t\t\tnode_ctx.action = NODEACT_UNKNOWN;\n \t\t\t}\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163863","messageId":"1300671507-18911-1-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300670777-17197-3-git-send-email-david.barr@cordelta.com","subject":"[PATCHv2] vcs-svn: use switch rather than cascading ifs","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T01:38:27Z","receivedAt":"2011-03-21T01:38:27Z","isPatch":false,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"In the spirit of the last two changes:\nSwitch on length and use constcmp for parsing headers with restricted values.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n\n Silly me, the last version didn't even compile.\n\n vcs-svn/svndump.c |   39 +++++++++++++++++++++++++++++----------\n 1 files changed, 29 insertions(+), 10 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex f03e8cf..ccf2520 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -350,25 +350,44 @@ void svndump_read(const char *url)\n \t\t\t}\n \t\t\tif (constcmp(t + strlen(\"Node-\"), \"kind\"))\n \t\t\t\tcontinue;\n-\t\t\tif (!strcmp(val, \"dir\"))\n+\t\t\tswitch (strlen(val) + 1) {\n+\t\t\tcase sizeof(\"dir\"):\n+\t\t\t\tif (constcmp(val, \"dir\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.type = REPO_MODE_DIR;\n-\t\t\telse if (!strcmp(val, \"file\"))\n+\t\t\t\tbreak;\n+\t\t\tcase sizeof(\"file\"):\n+\t\t\t\tif (constcmp(val, \"file\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.type = REPO_MODE_BLB;\n-\t\t\telse\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n \t\t\t\tfprintf(stderr, \"Unknown node-kind: %s\\n\", val);\n+\t\t\t}\n \t\t\tbreak;\n \t\tcase sizeof(\"Node-action\"):\n \t\t\tif (constcmp(t, \"Node-action\"))\n \t\t\t\tcontinue;\n-\t\t\tif (!strcmp(val, \"delete\")) {\n-\t\t\t\tnode_ctx.action = NODEACT_DELETE;\n-\t\t\t} else if (!strcmp(val, \"add\")) {\n+\t\t\tswitch (strlen(val) + 1) {\n+\t\t\tcase sizeof(\"add\"):\n+\t\t\t\tif (constcmp(val, \"add\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.action = NODEACT_ADD;\n-\t\t\t} else if (!strcmp(val, \"change\")) {\n-\t\t\t\tnode_ctx.action = NODEACT_CHANGE;\n-\t\t\t} else if (!strcmp(val, \"replace\")) {\n+\t\t\t\tbreak;\n+\t\t\tcase sizeof(\"change\"):\n+\t\t\t\tif (!constcmp(val, \"change\")) {\n+\t\t\t\t\tnode_ctx.action = NODEACT_CHANGE;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\tif (!constcmp(val, \"delete\")) {\n+\t\t\t\t\tnode_ctx.action = NODEACT_DELETE;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\tif (constcmp(val, \"replace\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.action = NODEACT_REPLACE;\n-\t\t\t} else {\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n \t\t\t\tfprintf(stderr, \"Unknown node-action: %s\\n\", val);\n \t\t\t\tnode_ctx.action = NODEACT_UNKNOWN;\n \t\t\t}\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164004","messageId":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300518231-20008-1-git-send-email-david.barr@cordelta.com","subject":"[PATCHv2 00/11] vcs-svn: purge obsolete data structures and code","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:49Z","receivedAt":"2011-03-21T23:49:49Z","isPatch":false,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Thanks Jonathan for reviewing the series and for suggesting\na good compromise between readability and performance.\n\nThe first patch of the last version has been split into two.\nPatch 6 follows the spirit of patches 4 and 5, for a consistent\napproach to switching on constant strings.\n\n .gitignore              |    3 -\n Makefile                |   13 +--\n t/t0080-vcs-svn.sh      |  117 ------------------\n test-obj-pool.c         |  116 ------------------\n test-string-pool.c      |   31 -----\n test-treap.c            |   70 -----------\n vcs-svn/LICENSE         |    3 -\n vcs-svn/fast_export.c   |   64 +++++-----\n vcs-svn/fast_export.h   |   14 +-\n vcs-svn/obj_pool.h      |   61 ---------\n vcs-svn/repo_tree.c     |   36 ++----\n vcs-svn/repo_tree.h     |   12 +--\n vcs-svn/string_pool.c   |  113 -----------------\n vcs-svn/string_pool.h   |   12 --\n vcs-svn/string_pool.txt |   43 -------\n vcs-svn/svndump.c       |  309 ++++++++++++++++++++++++++++-------------------\n vcs-svn/trp.h           |  237 ------------------------------------\n vcs-svn/trp.txt         |  109 -----------------\n 18 files changed, 237 insertions(+), 1126 deletions(-)\n"},{"id":"163998","messageId":"1300751400-7427-2-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 01/11] vcs-svn: use strbuf for revision log","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:50Z","receivedAt":"2011-03-21T23:49:50Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This is a small step towards removing dependence on obj_pool.h\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n vcs-svn/svndump.c |   26 +++++++-------------------\n 1 files changed, 7 insertions(+), 19 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 7ecb227..da154ad 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -11,8 +11,8 @@\n #include \"repo_tree.h\"\n #include \"fast_export.h\"\n #include \"line_buffer.h\"\n-#include \"obj_pool.h\"\n #include \"string_pool.h\"\n+#include \"strbuf.h\"\n \n #define REPORT_FILENO 3\n \n@@ -31,22 +31,10 @@\n #define LENGTH_UNKNOWN (~0)\n #define DATE_RFC2822_LEN 31\n \n-/* Create memory pool for log messages */\n-obj_pool_gen(log, char, 4096)\n-\n static struct line_buffer input = LINE_BUFFER_INIT;\n \n #define REPORT_FILENO 3\n \n-static char *log_copy(uint32_t length, const char *log)\n-{\n-\tchar *buffer;\n-\tlog_free(log_pool.size);\n-\tbuffer = log_pointer(log_alloc(length));\n-\tstrncpy(buffer, log, length);\n-\treturn buffer;\n-}\n-\n static struct {\n \tuint32_t action, propLength, textLength, srcRev, type;\n \tuint32_t src[REPO_MAX_PATH_DEPTH], dst[REPO_MAX_PATH_DEPTH];\n@@ -56,7 +44,7 @@ static struct {\n static struct {\n \tuint32_t revision, author;\n \tunsigned long timestamp;\n-\tchar *log;\n+\tstruct strbuf log;\n } rev_ctx;\n \n static struct {\n@@ -89,7 +77,7 @@ static void reset_rev_ctx(uint32_t revision)\n {\n \trev_ctx.revision = revision;\n \trev_ctx.timestamp = 0;\n-\trev_ctx.log = NULL;\n+\tstrbuf_reset(&rev_ctx.log);\n \trev_ctx.author = ~0;\n }\n \n@@ -130,7 +118,7 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:log\");\n \t\t/* Value length excludes terminating nul. */\n-\t\trev_ctx.log = log_copy(len + 1, val);\n+\t\tstrbuf_add(&rev_ctx.log, val, len + 1);\n \t} else if (key == keys.svn_author) {\n \t\trev_ctx.author = pool_intern(val);\n \t} else if (key == keys.svn_date) {\n@@ -297,7 +285,7 @@ static void begin_revision(void)\n {\n \tif (!rev_ctx.revision)\t/* revision 0 gets no git commit. */\n \t\treturn;\n-\tfast_export_begin_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log,\n+\tfast_export_begin_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log.buf,\n \t\tdump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);\n }\n \n@@ -406,6 +394,7 @@ int svndump_init(const char *filename)\n \tif (buffer_init(&input, filename))\n \t\treturn error(\"cannot open %s: %s\", filename, strerror(errno));\n \tfast_export_init(REPORT_FILENO);\n+\tstrbuf_init(&rev_ctx.log, 4096);\n \treset_dump_ctx(~0);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n@@ -415,11 +404,11 @@ int svndump_init(const char *filename)\n \n void svndump_deinit(void)\n {\n-\tlog_reset();\n \tfast_export_deinit();\n \treset_dump_ctx(~0);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n+\tstrbuf_release(&rev_ctx.log);\n \tif (buffer_deinit(&input))\n \t\tfprintf(stderr, \"Input error\\n\");\n \tif (ferror(stdout))\n@@ -428,7 +417,6 @@ void svndump_deinit(void)\n \n void svndump_reset(void)\n {\n-\tlog_reset();\n \tfast_export_reset();\n \tbuffer_reset(&input);\n \treset_dump_ctx(~0);\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164000","messageId":"1300751400-7427-3-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 02/11] vcs-svn: pass paths through to fast-import","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:51Z","receivedAt":"2011-03-21T23:49:51Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Now that there is no internal representation of the repo,\nit is not necessary to tokenise paths.\n\nUse strbuf instead and bypass string_pool.\n\nAlso, since we now treat paths in their entirety,\nonly quote when necessary.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/fast_export.c |   47 ++++++++++++++++++++++++-----------------------\n vcs-svn/fast_export.h |    9 ++++-----\n vcs-svn/repo_tree.c   |   20 ++++++++++----------\n vcs-svn/repo_tree.h   |   13 +++++--------\n vcs-svn/svndump.c     |   37 ++++++++++++++++++++-----------------\n 5 files changed, 63 insertions(+), 63 deletions(-)\n\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex f19db9a..bb5e9aa 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -4,6 +4,8 @@\n  */\n \n #include \"git-compat-util.h\"\n+#include \"strbuf.h\"\n+#include \"quote.h\"\n #include \"fast_export.h\"\n #include \"line_buffer.h\"\n #include \"repo_tree.h\"\n@@ -32,30 +34,30 @@ void fast_export_reset(void)\n \tbuffer_reset(&report_buffer);\n }\n \n-void fast_export_delete(uint32_t depth, const uint32_t *path)\n+void fast_export_delete(const char *path)\n {\n-\tprintf(\"D \\\"\");\n-\tpool_print_seq_q(depth, path, '/', stdout);\n-\tprintf(\"\\\"\\n\");\n+\tputchar('D');\n+\tputchar(' ');\n+\tquote_c_style(path, NULL, stdout, 0);\n+\tputchar('\\n');\n }\n \n-static void fast_export_truncate(uint32_t depth, const uint32_t *path, uint32_t mode)\n+static void fast_export_truncate(const char *path, uint32_t mode)\n {\n-\tfast_export_modify(depth, path, mode, \"inline\");\n+\tfast_export_modify(path, mode, \"inline\");\n \tprintf(\"data 0\\n\\n\");\n }\n \n-void fast_export_modify(uint32_t depth, const uint32_t *path, uint32_t mode,\n-\t\t\tconst char *dataref)\n+void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n {\n \t/* Mode must be 100644, 100755, 120000, or 160000. */\n \tif (!dataref) {\n-\t\tfast_export_truncate(depth, path, mode);\n+\t\tfast_export_truncate(path, mode);\n \t\treturn;\n \t}\n-\tprintf(\"M %06\"PRIo32\" %s \\\"\", mode, dataref);\n-\tpool_print_seq_q(depth, path, '/', stdout);\n-\tprintf(\"\\\"\\n\");\n+\tprintf(\"M %06\"PRIo32\" %s \", mode, dataref);\n+\tquote_c_style(path, NULL, stdout, 0);\n+\tputchar('\\n');\n }\n \n static char gitsvnline[MAX_GITSVN_LINE_LEN];\n@@ -93,20 +95,20 @@ void fast_export_end_commit(uint32_t revision)\n \tprintf(\"progress Imported commit %\"PRIu32\".\\n\\n\", revision);\n }\n \n-static void ls_from_rev(uint32_t rev, uint32_t depth, const uint32_t *path)\n+static void ls_from_rev(uint32_t rev, const char *path)\n {\n \t/* ls :5 path/to/old/file */\n-\tprintf(\"ls :%\"PRIu32\" \\\"\", rev);\n-\tpool_print_seq_q(depth, path, '/', stdout);\n-\tprintf(\"\\\"\\n\");\n+\tprintf(\"ls :%\"PRIu32\" \", rev);\n+\tquote_c_style(path, NULL, stdout, 0);\n+\tputchar('\\n');\n \tfflush(stdout);\n }\n \n-static void ls_from_active_commit(uint32_t depth, const uint32_t *path)\n+static void ls_from_active_commit(const char *path)\n {\n \t/* ls \"path/to/file\" */\n \tprintf(\"ls \\\"\");\n-\tpool_print_seq_q(depth, path, '/', stdout);\n+\tquote_c_style(path, NULL, stdout, 1);\n \tprintf(\"\\\"\\n\");\n \tfflush(stdout);\n }\n@@ -174,16 +176,15 @@ static int parse_ls_response(const char *response, uint32_t *mode,\n \treturn 0;\n }\n \n-int fast_export_ls_rev(uint32_t rev, uint32_t depth, const uint32_t *path,\n+int fast_export_ls_rev(uint32_t rev, const char *path,\n \t\t\t\tuint32_t *mode, struct strbuf *dataref)\n {\n-\tls_from_rev(rev, depth, path);\n+\tls_from_rev(rev, path);\n \treturn parse_ls_response(get_response_line(), mode, dataref);\n }\n \n-int fast_export_ls(uint32_t depth, const uint32_t *path,\n-\t\t\t\tuint32_t *mode, struct strbuf *dataref)\n+int fast_export_ls(const char *path, uint32_t *mode, struct strbuf *dataref)\n {\n-\tls_from_active_commit(depth, path);\n+\tls_from_active_commit(path);\n \treturn parse_ls_response(get_response_line(), mode, dataref);\n }\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex 633d219..a47c609 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -8,18 +8,17 @@ void fast_export_init(int fd);\n void fast_export_deinit(void);\n void fast_export_reset(void);\n \n-void fast_export_delete(uint32_t depth, const uint32_t *path);\n-void fast_export_modify(uint32_t depth, const uint32_t *path,\n-\t\t\tuint32_t mode, const char *dataref);\n+void fast_export_delete(const char *path);\n+void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,\n \t\t\tuint32_t uuid, uint32_t url, unsigned long timestamp);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input);\n \n /* If there is no such file at that rev, returns -1, errno == ENOENT. */\n-int fast_export_ls_rev(uint32_t rev, uint32_t depth, const uint32_t *path,\n+int fast_export_ls_rev(uint32_t rev, const char *path,\n \t\t\tuint32_t *mode_out, struct strbuf *dataref_out);\n-int fast_export_ls(uint32_t depth, const uint32_t *path,\n+int fast_export_ls(const char *path,\n \t\t\tuint32_t *mode_out, struct strbuf *dataref_out);\n \n #endif\ndiff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c\nindex e75f580..f2466bc 100644\n--- a/vcs-svn/repo_tree.c\n+++ b/vcs-svn/repo_tree.c\n@@ -8,14 +8,14 @@\n #include \"repo_tree.h\"\n #include \"fast_export.h\"\n \n-const char *repo_read_path(const uint32_t *path)\n+const char *repo_read_path(const char *path)\n {\n \tint err;\n \tuint32_t dummy;\n \tstatic struct strbuf buf = STRBUF_INIT;\n \n \tstrbuf_reset(&buf);\n-\terr = fast_export_ls(REPO_MAX_PATH_DEPTH, path, &dummy, &buf);\n+\terr = fast_export_ls(path, &dummy, &buf);\n \tif (err) {\n \t\tif (errno != ENOENT)\n \t\t\tdie_errno(\"BUG: unexpected fast_export_ls error\");\n@@ -24,14 +24,14 @@ const char *repo_read_path(const uint32_t *path)\n \treturn buf.buf;\n }\n \n-uint32_t repo_read_mode(const uint32_t *path)\n+uint32_t repo_read_mode(const char *path)\n {\n \tint err;\n \tuint32_t result;\n \tstatic struct strbuf dummy = STRBUF_INIT;\n \n \tstrbuf_reset(&dummy);\n-\terr = fast_export_ls(REPO_MAX_PATH_DEPTH, path, &result, &dummy);\n+\terr = fast_export_ls(path, &result, &dummy);\n \tif (err) {\n \t\tif (errno != ENOENT)\n \t\t\tdie_errno(\"BUG: unexpected fast_export_ls error\");\n@@ -41,24 +41,24 @@ uint32_t repo_read_mode(const uint32_t *path)\n \treturn result;\n }\n \n-void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst)\n+void repo_copy(uint32_t revision, const char *src, const char *dst)\n {\n \tint err;\n \tuint32_t mode;\n \tstatic struct strbuf data = STRBUF_INIT;\n \n \tstrbuf_reset(&data);\n-\terr = fast_export_ls_rev(revision, REPO_MAX_PATH_DEPTH, src, &mode, &data);\n+\terr = fast_export_ls_rev(revision, src, &mode, &data);\n \tif (err) {\n \t\tif (errno != ENOENT)\n \t\t\tdie_errno(\"BUG: unexpected fast_export_ls_rev error\");\n-\t\tfast_export_delete(REPO_MAX_PATH_DEPTH, dst);\n+\t\tfast_export_delete(dst);\n \t\treturn;\n \t}\n-\tfast_export_modify(REPO_MAX_PATH_DEPTH, dst, mode, data.buf);\n+\tfast_export_modify(dst, mode, data.buf);\n }\n \n-void repo_delete(uint32_t *path)\n+void repo_delete(const char *path)\n {\n-\tfast_export_delete(REPO_MAX_PATH_DEPTH, path);\n+\tfast_export_delete(path);\n }\ndiff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h\nindex d690784..af2415c 100644\n--- a/vcs-svn/repo_tree.h\n+++ b/vcs-svn/repo_tree.h\n@@ -8,15 +8,12 @@\n #define REPO_MODE_EXE 0100755\n #define REPO_MODE_LNK 0120000\n \n-#define REPO_MAX_PATH_LEN 4096\n-#define REPO_MAX_PATH_DEPTH 1000\n-\n uint32_t next_blob_mark(void);\n-void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst);\n-void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark);\n-const char *repo_read_path(const uint32_t *path);\n-uint32_t repo_read_mode(const uint32_t *path);\n-void repo_delete(uint32_t *path);\n+void repo_copy(uint32_t revision, const char *src, const char *dst);\n+void repo_add(const char *path, uint32_t mode, uint32_t blob_mark);\n+const char *repo_read_path(const char *path);\n+uint32_t repo_read_mode(const char *path);\n+void repo_delete(const char *path);\n void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,\n \t\t uint32_t url, long unsigned timestamp);\n void repo_diff(uint32_t r1, uint32_t r2);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex da154ad..afdfc63 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -37,7 +37,7 @@ static struct line_buffer input = LINE_BUFFER_INIT;\n \n static struct {\n \tuint32_t action, propLength, textLength, srcRev, type;\n-\tuint32_t src[REPO_MAX_PATH_DEPTH], dst[REPO_MAX_PATH_DEPTH];\n+\tstruct strbuf src, dst;\n \tuint32_t text_delta, prop_delta;\n } node_ctx;\n \n@@ -66,9 +66,11 @@ static void reset_node_ctx(char *fname)\n \tnode_ctx.action = NODEACT_UNKNOWN;\n \tnode_ctx.propLength = LENGTH_UNKNOWN;\n \tnode_ctx.textLength = LENGTH_UNKNOWN;\n-\tnode_ctx.src[0] = ~0;\n+\tstrbuf_reset(&node_ctx.src);\n \tnode_ctx.srcRev = 0;\n-\tpool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.dst, \"/\", fname);\n+\tstrbuf_reset(&node_ctx.dst);\n+\tif (fname)\n+\t\tstrbuf_addstr(&node_ctx.dst, fname);\n \tnode_ctx.text_delta = 0;\n \tnode_ctx.prop_delta = 0;\n }\n@@ -211,14 +213,14 @@ static void handle_node(void)\n \t\tif (have_text || have_props || node_ctx.srcRev)\n \t\t\tdie(\"invalid dump: deletion node has \"\n \t\t\t\t\"copyfrom info, text, or properties\");\n-\t\treturn repo_delete(node_ctx.dst);\n+\t\treturn repo_delete(node_ctx.dst.buf);\n \t}\n \tif (node_ctx.action == NODEACT_REPLACE) {\n-\t\trepo_delete(node_ctx.dst);\n+\t\trepo_delete(node_ctx.dst.buf);\n \t\tnode_ctx.action = NODEACT_ADD;\n \t}\n \tif (node_ctx.srcRev) {\n-\t\trepo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst);\n+\t\trepo_copy(node_ctx.srcRev, node_ctx.src.buf, node_ctx.dst.buf);\n \t\tif (node_ctx.action == NODEACT_ADD)\n \t\t\tnode_ctx.action = NODEACT_CHANGE;\n \t}\n@@ -228,14 +230,14 @@ static void handle_node(void)\n \t/*\n \t * Find old content (old_data) and decide on the new mode.\n \t */\n-\tif (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) {\n+\tif (node_ctx.action == NODEACT_CHANGE && !*node_ctx.dst.buf) {\n \t\tif (type != REPO_MODE_DIR)\n \t\t\tdie(\"invalid dump: root of tree is not a regular file\");\n \t\told_data = NULL;\n \t} else if (node_ctx.action == NODEACT_CHANGE) {\n \t\tuint32_t mode;\n-\t\told_data = repo_read_path(node_ctx.dst);\n-\t\tmode = repo_read_mode(node_ctx.dst);\n+\t\told_data = repo_read_path(node_ctx.dst.buf);\n+\t\tmode = repo_read_mode(node_ctx.dst.buf);\n \t\tif (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)\n \t\t\tdie(\"invalid dump: cannot modify a directory into a file\");\n \t\tif (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)\n@@ -272,12 +274,10 @@ static void handle_node(void)\n \t\t/* For the fast_export_* functions, NULL means empty. */\n \t\told_data = NULL;\n \tif (!have_text) {\n-\t\tfast_export_modify(REPO_MAX_PATH_DEPTH, node_ctx.dst,\n-\t\t\t\t\tnode_ctx.type, old_data);\n+\t\tfast_export_modify(node_ctx.dst.buf, node_ctx.type, old_data);\n \t\treturn;\n \t}\n-\tfast_export_modify(REPO_MAX_PATH_DEPTH, node_ctx.dst,\n-\t\t\t\tnode_ctx.type, \"inline\");\n+\tfast_export_modify(node_ctx.dst.buf, node_ctx.type, \"inline\");\n \tfast_export_data(node_ctx.type, node_ctx.textLength, &input);\n }\n \n@@ -356,7 +356,8 @@ void svndump_read(const char *url)\n \t\t\t\tnode_ctx.action = NODEACT_UNKNOWN;\n \t\t\t}\n \t\t} else if (key == keys.node_copyfrom_path) {\n-\t\t\tpool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.src, \"/\", val);\n+\t\t\tstrbuf_reset(&node_ctx.src);\n+\t\t\tstrbuf_addstr(&node_ctx.src, val);\n \t\t} else if (key == keys.node_copyfrom_rev) {\n \t\t\tnode_ctx.srcRev = atoi(val);\n \t\t} else if (key == keys.text_content_length) {\n@@ -395,6 +396,8 @@ int svndump_init(const char *filename)\n \t\treturn error(\"cannot open %s: %s\", filename, strerror(errno));\n \tfast_export_init(REPORT_FILENO);\n \tstrbuf_init(&rev_ctx.log, 4096);\n+\tstrbuf_init(&node_ctx.src, 4096);\n+\tstrbuf_init(&node_ctx.dst, 4096);\n \treset_dump_ctx(~0);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n@@ -409,6 +412,8 @@ void svndump_deinit(void)\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n \tstrbuf_release(&rev_ctx.log);\n+\tstrbuf_release(&node_ctx.src);\n+\tstrbuf_release(&node_ctx.dst);\n \tif (buffer_deinit(&input))\n \t\tfprintf(stderr, \"Input error\\n\");\n \tif (ferror(stdout))\n@@ -419,7 +424,5 @@ void svndump_reset(void)\n {\n \tfast_export_reset();\n \tbuffer_reset(&input);\n-\treset_dump_ctx(~0);\n-\treset_rev_ctx(0);\n-\treset_node_ctx(NULL);\n+\tpool_reset();\n }\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163997","messageId":"1300751400-7427-4-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 03/11] vcs-svn: avoid using ls command twice","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:52Z","receivedAt":"2011-03-21T23:49:52Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Signed-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/repo_tree.c |   24 ++++--------------------\n vcs-svn/repo_tree.h |    3 +--\n vcs-svn/svndump.c   |    3 +--\n 3 files changed, 6 insertions(+), 24 deletions(-)\n\ndiff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c\nindex f2466bc..67d27f0 100644\n--- a/vcs-svn/repo_tree.c\n+++ b/vcs-svn/repo_tree.c\n@@ -8,39 +8,23 @@\n #include \"repo_tree.h\"\n #include \"fast_export.h\"\n \n-const char *repo_read_path(const char *path)\n+const char *repo_read_path(const char *path, uint32_t *mode_out)\n {\n \tint err;\n-\tuint32_t dummy;\n \tstatic struct strbuf buf = STRBUF_INIT;\n \n \tstrbuf_reset(&buf);\n-\terr = fast_export_ls(path, &dummy, &buf);\n+\terr = fast_export_ls(path, mode_out, &buf);\n \tif (err) {\n \t\tif (errno != ENOENT)\n \t\t\tdie_errno(\"BUG: unexpected fast_export_ls error\");\n+\t\t/* Treat missing paths as directories. */\n+\t\t*mode_out = REPO_MODE_DIR;\n \t\treturn NULL;\n \t}\n \treturn buf.buf;\n }\n \n-uint32_t repo_read_mode(const char *path)\n-{\n-\tint err;\n-\tuint32_t result;\n-\tstatic struct strbuf dummy = STRBUF_INIT;\n-\n-\tstrbuf_reset(&dummy);\n-\terr = fast_export_ls(path, &result, &dummy);\n-\tif (err) {\n-\t\tif (errno != ENOENT)\n-\t\t\tdie_errno(\"BUG: unexpected fast_export_ls error\");\n-\t\t/* Treat missing paths as directories. */\n-\t\treturn REPO_MODE_DIR;\n-\t}\n-\treturn result;\n-}\n-\n void repo_copy(uint32_t revision, const char *src, const char *dst)\n {\n \tint err;\ndiff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h\nindex af2415c..eb003e6 100644\n--- a/vcs-svn/repo_tree.h\n+++ b/vcs-svn/repo_tree.h\n@@ -11,8 +11,7 @@\n uint32_t next_blob_mark(void);\n void repo_copy(uint32_t revision, const char *src, const char *dst);\n void repo_add(const char *path, uint32_t mode, uint32_t blob_mark);\n-const char *repo_read_path(const char *path);\n-uint32_t repo_read_mode(const char *path);\n+const char *repo_read_path(const char *path, uint32_t *mode_out);\n void repo_delete(const char *path);\n void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,\n \t\t uint32_t url, long unsigned timestamp);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex afdfc63..15b173e 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -236,8 +236,7 @@ static void handle_node(void)\n \t\told_data = NULL;\n \t} else if (node_ctx.action == NODEACT_CHANGE) {\n \t\tuint32_t mode;\n-\t\told_data = repo_read_path(node_ctx.dst.buf);\n-\t\tmode = repo_read_mode(node_ctx.dst.buf);\n+\t\told_data = repo_read_path(node_ctx.dst.buf, &mode);\n \t\tif (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)\n \t\t\tdie(\"invalid dump: cannot modify a directory into a file\");\n \t\tif (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163999","messageId":"1300751400-7427-5-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 04/11] vcs-svn: implement perfect hash for node-prop keys","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:53Z","receivedAt":"2011-03-21T23:49:53Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This eliminates one more dependency on string_pool.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndump.c |   57 +++++++++++++++++++++++++++++++++++-----------------\n 1 files changed, 38 insertions(+), 19 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 15b173e..46ae5fa 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -52,8 +52,7 @@ static struct {\n } dump_ctx;\n \n static struct {\n-\tuint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid,\n-\t\trevision_number, node_path, node_kind, node_action,\n+\tuint32_t uuid, revision_number, node_path, node_kind, node_action,\n \t\tnode_copyfrom_path, node_copyfrom_rev, text_content_length,\n \t\tprop_content_length, content_length, svn_fs_dump_format_version,\n \t\t/* version 3 format */\n@@ -92,11 +91,6 @@ static void reset_dump_ctx(uint32_t url)\n \n static void init_keys(void)\n {\n-\tkeys.svn_log = pool_intern(\"svn:log\");\n-\tkeys.svn_author = pool_intern(\"svn:author\");\n-\tkeys.svn_date = pool_intern(\"svn:date\");\n-\tkeys.svn_executable = pool_intern(\"svn:executable\");\n-\tkeys.svn_special = pool_intern(\"svn:special\");\n \tkeys.uuid = pool_intern(\"UUID\");\n \tkeys.revision_number = pool_intern(\"Revision-number\");\n \tkeys.node_path = pool_intern(\"Node-path\");\n@@ -113,22 +107,44 @@ static void init_keys(void)\n \tkeys.prop_delta = pool_intern(\"Prop-delta\");\n }\n \n-static void handle_property(uint32_t key, const char *val, uint32_t len,\n+/* Compare string to literal of equal length; must be guarded by length test. */\n+#define constcmp(s, ref) memcmp((s), (ref), sizeof(ref) - 1)\n+\n+static void handle_property(struct strbuf *key_buf, const char *val, uint32_t len,\n \t\t\t\tuint32_t *type_set)\n {\n-\tif (key == keys.svn_log) {\n+\tconst int sizeof_key = key_buf->len + 1;\n+\tconst char *key = key_buf->buf;\n+\tswitch (sizeof_key) {\n+\tcase sizeof(\"svn:log\"):\n+\t\tif (constcmp(key, \"svn:log\"))\n+\t\t\tbreak;\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:log\");\n \t\t/* Value length excludes terminating nul. */\n \t\tstrbuf_add(&rev_ctx.log, val, len + 1);\n-\t} else if (key == keys.svn_author) {\n+\t\tbreak;\n+\tcase sizeof(\"svn:author\"):\n+\t\tif (constcmp(key, \"svn:author\"))\n+\t\t\tbreak;\n \t\trev_ctx.author = pool_intern(val);\n-\t} else if (key == keys.svn_date) {\n+\t\tbreak;\n+\tcase sizeof(\"svn:date\"):\n+\t\tif (constcmp(key, \"svn:date\"))\n+\t\t\tbreak;\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:date\");\n \t\tif (parse_date_basic(val, &rev_ctx.timestamp, NULL))\n \t\t\twarning(\"invalid timestamp: %s\", val);\n-\t} else if (key == keys.svn_executable || key == keys.svn_special) {\n+\t\tbreak;\n+\tcase sizeof(\"svn:executable\"):\n+\tcase sizeof(\"svn:special\"):\n+\t\tif (sizeof_key == sizeof(\"svn:executable\") &&\n+\t\t    constcmp(key, \"svn:executable\"))\n+\t\t\tbreak;\n+\t\tif (sizeof_key == sizeof(\"svn:special\") &&\n+\t\t    constcmp(key, \"svn:special\"))\n+\t\t\tbreak;\n \t\tif (*type_set) {\n \t\t\tif (!val)\n \t\t\t\treturn;\n@@ -139,7 +155,7 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,\n \t\t\treturn;\n \t\t}\n \t\t*type_set = 1;\n-\t\tnode_ctx.type = key == keys.svn_executable ?\n+\t\tnode_ctx.type = sizeof_key == sizeof(\"svn:executable\") ?\n \t\t\t\tREPO_MODE_EXE :\n \t\t\t\tREPO_MODE_LNK;\n \t}\n@@ -147,7 +163,7 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,\n \n static void read_props(void)\n {\n-\tuint32_t key = ~0;\n+\tstatic struct strbuf key = STRBUF_INIT;\n \tconst char *t;\n \t/*\n \t * NEEDSWORK: to support simple mode changes like\n@@ -175,16 +191,19 @@ static void read_props(void)\n \n \t\tswitch (type) {\n \t\tcase 'K':\n-\t\t\tkey = pool_intern(val);\n-\t\t\tcontinue;\n \t\tcase 'D':\n-\t\t\tkey = pool_intern(val);\n+\t\t\tstrbuf_reset(&key);\n+\t\t\tif (val)\n+\t\t\t\tstrbuf_add(&key, val, len);\n+\t\t\tif (type == 'K')\n+\t\t\t\tcontinue;\n+\t\t\tassert(type == 'D');\n \t\t\tval = NULL;\n \t\t\tlen = 0;\n \t\t\t/* fall through */\n \t\tcase 'V':\n-\t\t\thandle_property(key, val, len, &type_set);\n-\t\t\tkey = ~0;\n+\t\t\thandle_property(&key, val, len, &type_set);\n+\t\t\tstrbuf_reset(&key);\n \t\t\tcontinue;\n \t\tdefault:\n \t\t\tdie(\"invalid property line: %s\\n\", t);\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164001","messageId":"1300751400-7427-6-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 05/11] vcs-svn: implement perfect hash for top-level keys","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:54Z","receivedAt":"2011-03-21T23:49:54Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This eliminates one more dependency on string_pool.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndump.c |  110 +++++++++++++++++++++++++++++------------------------\n 1 files changed, 60 insertions(+), 50 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 46ae5fa..3ad48e5 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -51,14 +51,6 @@ static struct {\n \tuint32_t version, uuid, url;\n } dump_ctx;\n \n-static struct {\n-\tuint32_t uuid, revision_number, node_path, node_kind, node_action,\n-\t\tnode_copyfrom_path, node_copyfrom_rev, text_content_length,\n-\t\tprop_content_length, content_length, svn_fs_dump_format_version,\n-\t\t/* version 3 format */\n-\t\ttext_delta, prop_delta;\n-} keys;\n-\n static void reset_node_ctx(char *fname)\n {\n \tnode_ctx.type = 0;\n@@ -89,24 +81,6 @@ static void reset_dump_ctx(uint32_t url)\n \tdump_ctx.uuid = ~0;\n }\n \n-static void init_keys(void)\n-{\n-\tkeys.uuid = pool_intern(\"UUID\");\n-\tkeys.revision_number = pool_intern(\"Revision-number\");\n-\tkeys.node_path = pool_intern(\"Node-path\");\n-\tkeys.node_kind = pool_intern(\"Node-kind\");\n-\tkeys.node_action = pool_intern(\"Node-action\");\n-\tkeys.node_copyfrom_path = pool_intern(\"Node-copyfrom-path\");\n-\tkeys.node_copyfrom_rev = pool_intern(\"Node-copyfrom-rev\");\n-\tkeys.text_content_length = pool_intern(\"Text-content-length\");\n-\tkeys.prop_content_length = pool_intern(\"Prop-content-length\");\n-\tkeys.content_length = pool_intern(\"Content-length\");\n-\tkeys.svn_fs_dump_format_version = pool_intern(\"SVN-fs-dump-format-version\");\n-\t/* version 3 format (Subversion 1.1.0) */\n-\tkeys.text_delta = pool_intern(\"Text-delta\");\n-\tkeys.prop_delta = pool_intern(\"Prop-delta\");\n-}\n-\n /* Compare string to literal of equal length; must be guarded by length test. */\n #define constcmp(s, ref) memcmp((s), (ref), sizeof(ref) - 1)\n \n@@ -319,7 +293,6 @@ void svndump_read(const char *url)\n \tchar *t;\n \tuint32_t active_ctx = DUMP_CTX;\n \tuint32_t len;\n-\tuint32_t key;\n \n \treset_dump_ctx(pool_intern(url));\n \twhile ((t = buffer_read_line(&input))) {\n@@ -328,16 +301,25 @@ void svndump_read(const char *url)\n \t\t\tcontinue;\n \t\t*val++ = '\\0';\n \t\t*val++ = '\\0';\n-\t\tkey = pool_intern(t);\n \n-\t\tif (key == keys.svn_fs_dump_format_version) {\n+\t\t/* strlen(key) + 1 */\n+\t\tswitch (val - t - 1) {\n+\t\tcase sizeof(\"SVN-fs-dump-format-version\"):\n+\t\t\tif (constcmp(t, \"SVN-fs-dump-format-version\"))\n+\t\t\t\tcontinue;\n \t\t\tdump_ctx.version = atoi(val);\n \t\t\tif (dump_ctx.version > 3)\n \t\t\t\tdie(\"expected svn dump format version <= 3, found %\"PRIu32,\n \t\t\t\t    dump_ctx.version);\n-\t\t} else if (key == keys.uuid) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"UUID\"):\n+\t\t\tif (constcmp(t, \"UUID\"))\n+\t\t\t\tcontinue;\n \t\t\tdump_ctx.uuid = pool_intern(val);\n-\t\t} else if (key == keys.revision_number) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Revision-number\"):\n+\t\t\tif (constcmp(t, \"Revision-number\"))\n+\t\t\t\tcontinue;\n \t\t\tif (active_ctx == NODE_CTX)\n \t\t\t\thandle_node();\n \t\t\tif (active_ctx == REV_CTX)\n@@ -346,21 +328,31 @@ void svndump_read(const char *url)\n \t\t\t\tend_revision();\n \t\t\tactive_ctx = REV_CTX;\n \t\t\treset_rev_ctx(atoi(val));\n-\t\t} else if (key == keys.node_path) {\n-\t\t\tif (active_ctx == NODE_CTX)\n-\t\t\t\thandle_node();\n-\t\t\tif (active_ctx == REV_CTX)\n-\t\t\t\tbegin_revision();\n-\t\t\tactive_ctx = NODE_CTX;\n-\t\t\treset_node_ctx(val);\n-\t\t} else if (key == keys.node_kind) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Node-path\"):\n+\t\t\tif (prefixcmp(t, \"Node-\"))\n+\t\t\t\tcontinue;\n+\t\t\tif (!constcmp(t + strlen(\"Node-\"), \"path\")) {\n+\t\t\t\tif (active_ctx == NODE_CTX)\n+\t\t\t\t\thandle_node();\n+\t\t\t\tif (active_ctx == REV_CTX)\n+\t\t\t\t\tbegin_revision();\n+\t\t\t\tactive_ctx = NODE_CTX;\n+\t\t\t\treset_node_ctx(val);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (constcmp(t + strlen(\"Node-\"), \"kind\"))\n+\t\t\t\tcontinue;\n \t\t\tif (!strcmp(val, \"dir\"))\n \t\t\t\tnode_ctx.type = REPO_MODE_DIR;\n \t\t\telse if (!strcmp(val, \"file\"))\n \t\t\t\tnode_ctx.type = REPO_MODE_BLB;\n \t\t\telse\n \t\t\t\tfprintf(stderr, \"Unknown node-kind: %s\\n\", val);\n-\t\t} else if (key == keys.node_action) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Node-action\"):\n+\t\t\tif (constcmp(t, \"Node-action\"))\n+\t\t\t\tcontinue;\n \t\t\tif (!strcmp(val, \"delete\")) {\n \t\t\t\tnode_ctx.action = NODEACT_DELETE;\n \t\t\t} else if (!strcmp(val, \"add\")) {\n@@ -373,20 +365,39 @@ void svndump_read(const char *url)\n \t\t\t\tfprintf(stderr, \"Unknown node-action: %s\\n\", val);\n \t\t\t\tnode_ctx.action = NODEACT_UNKNOWN;\n \t\t\t}\n-\t\t} else if (key == keys.node_copyfrom_path) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Node-copyfrom-path\"):\n+\t\t\tif (constcmp(t, \"Node-copyfrom-path\"))\n+\t\t\t\tcontinue;\n \t\t\tstrbuf_reset(&node_ctx.src);\n \t\t\tstrbuf_addstr(&node_ctx.src, val);\n-\t\t} else if (key == keys.node_copyfrom_rev) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Node-copyfrom-rev\"):\n+\t\t\tif (constcmp(t, \"Node-copyfrom-rev\"))\n+\t\t\t\tcontinue;\n \t\t\tnode_ctx.srcRev = atoi(val);\n-\t\t} else if (key == keys.text_content_length) {\n-\t\t\tnode_ctx.textLength = atoi(val);\n-\t\t} else if (key == keys.prop_content_length) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Text-content-length\"):\n+\t\t\tif (!constcmp(t, \"Text-content-length\")) {\n+\t\t\t\tnode_ctx.textLength = atoi(val);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (constcmp(t, \"Prop-content-length\"))\n+\t\t\t\tcontinue;\n \t\t\tnode_ctx.propLength = atoi(val);\n-\t\t} else if (key == keys.text_delta) {\n-\t\t\tnode_ctx.text_delta = !strcmp(val, \"true\");\n-\t\t} else if (key == keys.prop_delta) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Text-delta\"):\n+\t\t\tif (!constcmp(t, \"Text-delta\")) {\n+\t\t\t\tnode_ctx.text_delta = !strcmp(val, \"true\");\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (constcmp(t, \"Prop-delta\"))\n+\t\t\t\tcontinue;\n \t\t\tnode_ctx.prop_delta = !strcmp(val, \"true\");\n-\t\t} else if (key == keys.content_length) {\n+\t\t\tbreak;\n+\t\tcase sizeof(\"Content-length\"):\n+\t\t\tif (constcmp(t, \"Content-length\"))\n+\t\t\t\tcontinue;\n \t\t\tlen = atoi(val);\n \t\t\tbuffer_read_line(&input);\n \t\t\tif (active_ctx == REV_CTX) {\n@@ -419,7 +430,6 @@ int svndump_init(const char *filename)\n \treset_dump_ctx(~0);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n-\tinit_keys();\n \treturn 0;\n }\n \n-- \n1.7.3.2.846.gf4b062\n"},{"id":"163996","messageId":"1300751400-7427-7-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 06/11] vcs-svn: use switch rather than cascading ifs","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:55Z","receivedAt":"2011-03-21T23:49:55Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"In the spirit of the last two changes:\nSwitch on length and use constcmp for parsing headers with restricted values.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n vcs-svn/svndump.c |   40 ++++++++++++++++++++++++++++++----------\n 1 files changed, 30 insertions(+), 10 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 3ad48e5..7b5b5ec 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -343,25 +343,45 @@ void svndump_read(const char *url)\n \t\t\t}\n \t\t\tif (constcmp(t + strlen(\"Node-\"), \"kind\"))\n \t\t\t\tcontinue;\n-\t\t\tif (!strcmp(val, \"dir\"))\n+\t\t\tswitch (strlen(val) + 1) {\n+\t\t\tcase sizeof(\"dir\"):\n+\t\t\t\tif (constcmp(val, \"dir\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.type = REPO_MODE_DIR;\n-\t\t\telse if (!strcmp(val, \"file\"))\n+\t\t\t\tbreak;\n+\t\t\tcase sizeof(\"file\"):\n+\t\t\t\tif (constcmp(val, \"file\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.type = REPO_MODE_BLB;\n-\t\t\telse\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n \t\t\t\tfprintf(stderr, \"Unknown node-kind: %s\\n\", val);\n+\t\t\t}\n \t\t\tbreak;\n \t\tcase sizeof(\"Node-action\"):\n \t\t\tif (constcmp(t, \"Node-action\"))\n \t\t\t\tcontinue;\n-\t\t\tif (!strcmp(val, \"delete\")) {\n-\t\t\t\tnode_ctx.action = NODEACT_DELETE;\n-\t\t\t} else if (!strcmp(val, \"add\")) {\n+\t\t\tswitch (strlen(val) + 1) {\n+\t\t\tcase sizeof(\"add\"):\n+\t\t\t\tif (constcmp(val, \"add\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.action = NODEACT_ADD;\n-\t\t\t} else if (!strcmp(val, \"change\")) {\n-\t\t\t\tnode_ctx.action = NODEACT_CHANGE;\n-\t\t\t} else if (!strcmp(val, \"replace\")) {\n+\t\t\t\tbreak;\n+\t\t\tcase sizeof(\"change\"):\n+\t\t\t\tif (!constcmp(val, \"change\")) {\n+\t\t\t\t\tnode_ctx.action = NODEACT_CHANGE;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\tif (constcmp(val, \"delete\"))\n+\t\t\t\t\tbreak;\n+\t\t\t\tnode_ctx.action = NODEACT_DELETE;\n+\t\t\t\tbreak;\n+\t\t\tcase sizeof(\"replace\"):\n+\t\t\t\tif (constcmp(val, \"replace\"))\n+\t\t\t\t\tbreak;\n \t\t\t\tnode_ctx.action = NODEACT_REPLACE;\n-\t\t\t} else {\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n \t\t\t\tfprintf(stderr, \"Unknown node-action: %s\\n\", val);\n \t\t\t\tnode_ctx.action = NODEACT_UNKNOWN;\n \t\t\t}\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164005","messageId":"1300751400-7427-8-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 07/11] vcs-svn: factor out usage of string_pool","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:56Z","receivedAt":"2011-03-21T23:49:56Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"That is, use strbufs and strings instead of interned\nstrings for values of rev, dump, and node fields that\nhappen to be strings.  After this change, there are\nno more users of the string-pool library left.\n\nThere is a small functional change inlined: test for\nemtpy rather than NULL when falling back to defaults\nfor commit metadata.\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/fast_export.c |   17 +++++++----------\n vcs-svn/fast_export.h |    5 +++--\n vcs-svn/svndump.c     |   46 ++++++++++++++++++++++++++++++----------------\n 3 files changed, 40 insertions(+), 28 deletions(-)\n\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex bb5e9aa..1d50512 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -9,7 +9,6 @@\n #include \"fast_export.h\"\n #include \"line_buffer.h\"\n #include \"repo_tree.h\"\n-#include \"string_pool.h\"\n #include \"strbuf.h\"\n \n #define MAX_GITSVN_LINE_LEN 4096\n@@ -61,25 +60,23 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n }\n \n static char gitsvnline[MAX_GITSVN_LINE_LEN];\n-void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,\n-\t\t\tuint32_t uuid, uint32_t url,\n+void fast_export_begin_commit(uint32_t revision, const char *author,\n+\t\t\tconst char *log, const char *uuid, const char *url,\n \t\t\tunsigned long timestamp)\n {\n-\tif (!log)\n-\t\tlog = \"\";\n-\tif (~uuid && ~url) {\n+\tif (*uuid && *url) {\n \t\tsnprintf(gitsvnline, MAX_GITSVN_LINE_LEN,\n \t\t\t\t\"\\n\\ngit-svn-id: %s@%\"PRIu32\" %s\\n\",\n-\t\t\t\t pool_fetch(url), revision, pool_fetch(uuid));\n+\t\t\t\t url, revision, uuid);\n \t} else {\n \t\t*gitsvnline = '\\0';\n \t}\n \tprintf(\"commit refs/heads/master\\n\");\n \tprintf(\"mark :%\"PRIu32\"\\n\", revision);\n \tprintf(\"committer %s <%s@%s> %ld +0000\\n\",\n-\t\t   ~author ? pool_fetch(author) : \"nobody\",\n-\t\t   ~author ? pool_fetch(author) : \"nobody\",\n-\t\t   ~uuid ? pool_fetch(uuid) : \"local\", timestamp);\n+\t\t   *author ? author : \"nobody\",\n+\t\t   *author ? author : \"nobody\",\n+\t\t   *uuid ? uuid : \"local\", timestamp);\n \tprintf(\"data %\"PRIu32\"\\n%s%s\\n\",\n \t\t   (uint32_t) (strlen(log) + strlen(gitsvnline)),\n \t\t   log, gitsvnline);\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex a47c609..bc5bddf 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -10,8 +10,9 @@ void fast_export_reset(void);\n \n void fast_export_delete(const char *path);\n void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n-void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,\n-\t\t\tuint32_t uuid, uint32_t url, unsigned long timestamp);\n+void fast_export_begin_commit(uint32_t revision, const char *author,\n+\t\t\tconst char *log, const char *uuid, const char *url,\n+\t\t\tunsigned long timestamp);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input);\n \ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 7b5b5ec..897349e 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -11,7 +11,6 @@\n #include \"repo_tree.h\"\n #include \"fast_export.h\"\n #include \"line_buffer.h\"\n-#include \"string_pool.h\"\n #include \"strbuf.h\"\n \n #define REPORT_FILENO 3\n@@ -42,13 +41,14 @@ static struct {\n } node_ctx;\n \n static struct {\n-\tuint32_t revision, author;\n+\tuint32_t revision;\n \tunsigned long timestamp;\n-\tstruct strbuf log;\n+\tstruct strbuf log, author;\n } rev_ctx;\n \n static struct {\n-\tuint32_t version, uuid, url;\n+\tuint32_t version;\n+\tstruct strbuf uuid, url;\n } dump_ctx;\n \n static void reset_node_ctx(char *fname)\n@@ -71,14 +71,16 @@ static void reset_rev_ctx(uint32_t revision)\n \trev_ctx.revision = revision;\n \trev_ctx.timestamp = 0;\n \tstrbuf_reset(&rev_ctx.log);\n-\trev_ctx.author = ~0;\n+\tstrbuf_reset(&rev_ctx.author);\n }\n \n-static void reset_dump_ctx(uint32_t url)\n+static void reset_dump_ctx(const char *url)\n {\n-\tdump_ctx.url = url;\n+\tstrbuf_reset(&dump_ctx.url);\n+\tif (url)\n+\t\tstrbuf_addstr(&dump_ctx.url, url);\n \tdump_ctx.version = 1;\n-\tdump_ctx.uuid = ~0;\n+\tstrbuf_reset(&dump_ctx.uuid);\n }\n \n /* Compare string to literal of equal length; must be guarded by length test. */\n@@ -101,7 +103,9 @@ static void handle_property(struct strbuf *key_buf, const char *val, uint32_t le\n \tcase sizeof(\"svn:author\"):\n \t\tif (constcmp(key, \"svn:author\"))\n \t\t\tbreak;\n-\t\trev_ctx.author = pool_intern(val);\n+\t\tstrbuf_reset(&rev_ctx.author);\n+\t\tif (val)\n+\t\t\tstrbuf_add(&rev_ctx.author, val, len);\n \t\tbreak;\n \tcase sizeof(\"svn:date\"):\n \t\tif (constcmp(key, \"svn:date\"))\n@@ -277,8 +281,9 @@ static void begin_revision(void)\n {\n \tif (!rev_ctx.revision)\t/* revision 0 gets no git commit. */\n \t\treturn;\n-\tfast_export_begin_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log.buf,\n-\t\tdump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);\n+\tfast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,\n+\t\trev_ctx.log.buf, dump_ctx.uuid.buf, dump_ctx.url.buf,\n+\t\trev_ctx.timestamp);\n }\n \n static void end_revision(void)\n@@ -294,7 +299,7 @@ void svndump_read(const char *url)\n \tuint32_t active_ctx = DUMP_CTX;\n \tuint32_t len;\n \n-\treset_dump_ctx(pool_intern(url));\n+\treset_dump_ctx(url);\n \twhile ((t = buffer_read_line(&input))) {\n \t\tval = strstr(t, \": \");\n \t\tif (!val)\n@@ -315,7 +320,8 @@ void svndump_read(const char *url)\n \t\tcase sizeof(\"UUID\"):\n \t\t\tif (constcmp(t, \"UUID\"))\n \t\t\t\tcontinue;\n-\t\t\tdump_ctx.uuid = pool_intern(val);\n+\t\t\tstrbuf_reset(&dump_ctx.uuid);\n+\t\t\tstrbuf_addstr(&dump_ctx.uuid, val);\n \t\t\tbreak;\n \t\tcase sizeof(\"Revision-number\"):\n \t\t\tif (constcmp(t, \"Revision-number\"))\n@@ -444,10 +450,13 @@ int svndump_init(const char *filename)\n \tif (buffer_init(&input, filename))\n \t\treturn error(\"cannot open %s: %s\", filename, strerror(errno));\n \tfast_export_init(REPORT_FILENO);\n+\tstrbuf_init(&dump_ctx.uuid, 4096);\n+\tstrbuf_init(&dump_ctx.url, 4096);\n \tstrbuf_init(&rev_ctx.log, 4096);\n+\tstrbuf_init(&rev_ctx.author, 4096);\n \tstrbuf_init(&node_ctx.src, 4096);\n \tstrbuf_init(&node_ctx.dst, 4096);\n-\treset_dump_ctx(~0);\n+\treset_dump_ctx(NULL);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n \treturn 0;\n@@ -456,7 +465,7 @@ int svndump_init(const char *filename)\n void svndump_deinit(void)\n {\n \tfast_export_deinit();\n-\treset_dump_ctx(~0);\n+\treset_dump_ctx(NULL);\n \treset_rev_ctx(0);\n \treset_node_ctx(NULL);\n \tstrbuf_release(&rev_ctx.log);\n@@ -472,5 +481,10 @@ void svndump_reset(void)\n {\n \tfast_export_reset();\n \tbuffer_reset(&input);\n-\tpool_reset();\n+\tstrbuf_release(&dump_ctx.uuid);\n+\tstrbuf_release(&dump_ctx.url);\n+\tstrbuf_release(&rev_ctx.log);\n+\tstrbuf_release(&rev_ctx.author);\n+\tstrbuf_release(&node_ctx.src);\n+\tstrbuf_release(&node_ctx.dst);\n }\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164003","messageId":"1300751400-7427-9-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 08/11] vcs-svn: drop string_pool","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:57Z","receivedAt":"2011-03-21T23:49:57Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Signed-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n .gitignore              |    1 -\n Makefile                |   12 ++---\n t/t0080-vcs-svn.sh      |   16 -------\n test-string-pool.c      |   31 -------------\n vcs-svn/string_pool.c   |  113 -----------------------------------------------\n vcs-svn/string_pool.h   |   12 -----\n vcs-svn/string_pool.txt |   43 ------------------\n 7 files changed, 4 insertions(+), 224 deletions(-)\n delete mode 100644 test-string-pool.c\n delete mode 100644 vcs-svn/string_pool.c\n delete mode 100644 vcs-svn/string_pool.h\n delete mode 100644 vcs-svn/string_pool.txt\n\ndiff --git a/.gitignore b/.gitignore\nindex c460c66..215e842 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -177,7 +177,6 @@\n /test-run-command\n /test-sha1\n /test-sigchain\n-/test-string-pool\n /test-subprocess\n /test-svn-fe\n /test-treap\ndiff --git a/Makefile b/Makefile\nindex ade7923..f8182e5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -430,7 +430,6 @@ TEST_PROGRAMS_NEED_X += test-path-utils\n TEST_PROGRAMS_NEED_X += test-run-command\n TEST_PROGRAMS_NEED_X += test-sha1\n TEST_PROGRAMS_NEED_X += test-sigchain\n-TEST_PROGRAMS_NEED_X += test-string-pool\n TEST_PROGRAMS_NEED_X += test-subprocess\n TEST_PROGRAMS_NEED_X += test-svn-fe\n TEST_PROGRAMS_NEED_X += test-treap\n@@ -1838,10 +1837,9 @@ ifndef NO_CURL\n endif\n XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \\\n \txdiff/xmerge.o xdiff/xpatience.o\n-VCSSVN_OBJS = vcs-svn/string_pool.o vcs-svn/line_buffer.o \\\n-\tvcs-svn/repo_tree.o vcs-svn/fast_export.o vcs-svn/svndump.o\n-VCSSVN_TEST_OBJS = test-obj-pool.o test-string-pool.o \\\n-\ttest-line-buffer.o test-treap.o\n+VCSSVN_OBJS = vcs-svn/line_buffer.o vcs-svn/repo_tree.o \\\n+\tvcs-svn/fast_export.o vcs-svn/svndump.o\n+VCSSVN_TEST_OBJS = test-obj-pool.o test-line-buffer.o test-treap.o\n OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)\n \n dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)\n@@ -1965,7 +1963,7 @@ xdiff-interface.o $(XDIFF_OBJS): \\\n \txdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h\n \n $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \\\n-\tvcs-svn/obj_pool.h vcs-svn/trp.h vcs-svn/string_pool.h \\\n+\tvcs-svn/obj_pool.h vcs-svn/trp.h \\\n \tvcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \\\n \tvcs-svn/svndump.h\n \n@@ -2133,8 +2131,6 @@ test-line-buffer$X: vcs-svn/lib.a\n \n test-parse-options$X: parse-options.o\n \n-test-string-pool$X: vcs-svn/lib.a\n-\n test-svn-fe$X: vcs-svn/lib.a\n \n .PRECIOUS: $(TEST_OBJS)\ndiff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh\nindex 99a314b..ce02c58 100755\n--- a/t/t0080-vcs-svn.sh\n+++ b/t/t0080-vcs-svn.sh\n@@ -76,22 +76,6 @@ test_expect_success 'obj pool: high-water mark' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'string pool' '\n-\techo a does not equal b >expected.differ &&\n-\techo a equals a >expected.match &&\n-\techo equals equals equals >expected.matchmore &&\n-\n-\ttest-string-pool \"a,--b\" >actual.differ &&\n-\ttest-string-pool \"a,a\" >actual.match &&\n-\ttest-string-pool \"equals-equals\" >actual.matchmore &&\n-\ttest_must_fail test-string-pool a,a,a &&\n-\ttest_must_fail test-string-pool a &&\n-\n-\ttest_cmp expected.differ actual.differ &&\n-\ttest_cmp expected.match actual.match &&\n-\ttest_cmp expected.matchmore actual.matchmore\n-'\n-\n test_expect_success 'treap sort' '\n \tcat <<-\\EOF >unsorted &&\n \t68\ndiff --git a/test-string-pool.c b/test-string-pool.c\ndeleted file mode 100644\nindex c5782e6..0000000\n--- a/test-string-pool.c\n+++ /dev/null\n@@ -1,31 +0,0 @@\n-/*\n- * test-string-pool.c: code to exercise the svn importer's string pool\n- */\n-\n-#include \"git-compat-util.h\"\n-#include \"vcs-svn/string_pool.h\"\n-\n-int main(int argc, char *argv[])\n-{\n-\tconst uint32_t unequal = pool_intern(\"does not equal\");\n-\tconst uint32_t equal = pool_intern(\"equals\");\n-\tuint32_t buf[3];\n-\tuint32_t n;\n-\n-\tif (argc != 2)\n-\t\tusage(\"test-string-pool <string>,<string>\");\n-\n-\tn = pool_tok_seq(3, buf, \",-\", argv[1]);\n-\tif (n >= 3)\n-\t\tdie(\"too many strings\");\n-\tif (n <= 1)\n-\t\tdie(\"too few strings\");\n-\n-\tbuf[2] = buf[1];\n-\tbuf[1] = (buf[0] == buf[2]) ? equal : unequal;\n-\tpool_print_seq(3, buf, ' ', stdout);\n-\tfputc('\\n', stdout);\n-\n-\tpool_reset();\n-\treturn 0;\n-}\ndiff --git a/vcs-svn/string_pool.c b/vcs-svn/string_pool.c\ndeleted file mode 100644\nindex be43598..0000000\n--- a/vcs-svn/string_pool.c\n+++ /dev/null\n@@ -1,113 +0,0 @@\n-/*\n- * Licensed under a two-clause BSD-style license.\n- * See LICENSE for details.\n- */\n-\n-#include \"git-compat-util.h\"\n-#include \"quote.h\"\n-#include \"trp.h\"\n-#include \"obj_pool.h\"\n-#include \"string_pool.h\"\n-\n-static struct trp_root tree = { ~0 };\n-\n-struct node {\n-\tuint32_t offset;\n-\tstruct trp_node children;\n-};\n-\n-/* Two memory pools: one for struct node, and another for strings */\n-obj_pool_gen(node, struct node, 4096)\n-obj_pool_gen(string, char, 4096)\n-\n-static char *node_value(struct node *node)\n-{\n-\treturn node ? string_pointer(node->offset) : NULL;\n-}\n-\n-static int node_cmp(struct node *a, struct node *b)\n-{\n-\treturn strcmp(node_value(a), node_value(b));\n-}\n-\n-/* Build a Treap from the node structure (a trp_node w/ offset) */\n-trp_gen(static, tree_, struct node, children, node, node_cmp);\n-\n-const char *pool_fetch(uint32_t entry)\n-{\n-\treturn node_value(node_pointer(entry));\n-}\n-\n-uint32_t pool_intern(const char *key)\n-{\n-\t/* Canonicalize key */\n-\tstruct node *match = NULL, *node;\n-\tuint32_t key_len;\n-\tif (key == NULL)\n-\t\treturn ~0;\n-\tkey_len = strlen(key) + 1;\n-\tnode = node_pointer(node_alloc(1));\n-\tnode->offset = string_alloc(key_len);\n-\tstrcpy(node_value(node), key);\n-\tmatch = tree_search(&tree, node);\n-\tif (!match) {\n-\t\ttree_insert(&tree, node);\n-\t} else {\n-\t\tnode_free(1);\n-\t\tstring_free(key_len);\n-\t\tnode = match;\n-\t}\n-\treturn node_offset(node);\n-}\n-\n-uint32_t pool_tok_r(char *str, const char *delim, char **saveptr)\n-{\n-\tchar *token = strtok_r(str, delim, saveptr);\n-\treturn token ? pool_intern(token) : ~0;\n-}\n-\n-void pool_print_seq(uint32_t len, const uint32_t *seq, char delim, FILE *stream)\n-{\n-\tuint32_t i;\n-\tfor (i = 0; i < len && ~seq[i]; i++) {\n-\t\tfputs(pool_fetch(seq[i]), stream);\n-\t\tif (i < len - 1 && ~seq[i + 1])\n-\t\t\tfputc(delim, stream);\n-\t}\n-}\n-\n-void pool_print_seq_q(uint32_t len, const uint32_t *seq, char delim, FILE *stream)\n-{\n-\tuint32_t i;\n-\tfor (i = 0; i < len && ~seq[i]; i++) {\n-\t\tquote_c_style(pool_fetch(seq[i]), NULL, stream, 1);\n-\t\tif (i < len - 1 && ~seq[i + 1])\n-\t\t\tfputc(delim, stream);\n-\t}\n-}\n-\n-uint32_t pool_tok_seq(uint32_t sz, uint32_t *seq, const char *delim, char *str)\n-{\n-\tchar *context = NULL;\n-\tuint32_t token = ~0;\n-\tuint32_t length;\n-\n-\tif (sz == 0)\n-\t\treturn ~0;\n-\tif (str)\n-\t\ttoken = pool_tok_r(str, delim, &context);\n-\tfor (length = 0; length < sz; length++) {\n-\t\tseq[length] = token;\n-\t\tif (token == ~0)\n-\t\t\treturn length;\n-\t\ttoken = pool_tok_r(NULL, delim, &context);\n-\t}\n-\tseq[sz - 1] = ~0;\n-\treturn sz;\n-}\n-\n-void pool_reset(void)\n-{\n-\tnode_reset();\n-\tstring_reset();\n-}\ndiff --git a/vcs-svn/string_pool.h b/vcs-svn/string_pool.h\ndeleted file mode 100644\nindex 96e501d..0000000\n--- a/vcs-svn/string_pool.h\n+++ /dev/null\n@@ -1,12 +0,0 @@\n-#ifndef STRING_POOL_H_\n-#define STRING_POOL_H_\n-\n-uint32_t pool_intern(const char *key);\n-const char *pool_fetch(uint32_t entry);\n-uint32_t pool_tok_r(char *str, const char *delim, char **saveptr);\n-void pool_print_seq(uint32_t len, const uint32_t *seq, char delim, FILE *stream);\n-void pool_print_seq_q(uint32_t len, const uint32_t *seq, char delim, FILE *stream);\n-uint32_t pool_tok_seq(uint32_t sz, uint32_t *seq, const char *delim, char *str);\n-void pool_reset(void);\n-\n-#endif\ndiff --git a/vcs-svn/string_pool.txt b/vcs-svn/string_pool.txt\ndeleted file mode 100644\nindex 1b41f15..0000000\n--- a/vcs-svn/string_pool.txt\n+++ /dev/null\n@@ -1,43 +0,0 @@\n-string_pool API\n-===============\n-\n-The string_pool API provides facilities for replacing strings\n-with integer keys that can be more easily compared and stored.\n-The facilities are designed so that one could teach Git without\n-too much trouble to store the information needed for these keys to\n-remain valid over multiple executions.\n-\n-Functions\n----------\n-\n-pool_intern::\n-\tInclude a string in the string pool and get its key.\n-\tIf that string is already in the pool, retrieves its\n-\texisting key.\n-\n-pool_fetch::\n-\tRetrieve the string associated to a given key.\n-\n-pool_tok_r::\n-\tExtract the key of the next token from a string.\n-\tInterface mimics strtok_r.\n-\n-pool_print_seq::\n-\tPrint a sequence of strings named by key to a file, using the\n-\tspecified delimiter to separate them.\n-\n-\tIf NULL (key ~0) appears in the sequence, the sequence ends\n-\tearly.\n-\n-pool_tok_seq::\n-\tSplit a string into tokens, storing the keys of segments\n-\tinto a caller-provided array.\n-\n-\tUnless sz is 0, the array will always be ~0-terminated.\n-\tIf there is not enough room for all the tokens, the\n-\tarray holds as many tokens as fit in the entries before\n-\tthe terminating ~0.  Return value is the index after the\n-\tlast token, or sz if the tokens did not fit.\n-\n-pool_reset::\n-\tDeallocate storage for the string pool.\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164006","messageId":"1300751400-7427-10-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"=?\u001b?q?=5BPATCH=2009/11=5D=20vcs-svn=3A=20drop=20trp=2Eh?=","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:58Z","receivedAt":"2011-03-21T23:49:58Z","isPatch":false,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Signed-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n .gitignore         |    1 -\n Makefile           |    5 +-\n t/t0080-vcs-svn.sh |   22 -----\n test-treap.c       |   70 ---------------\n vcs-svn/LICENSE    |    3 -\n vcs-svn/trp.h      |  237 ----------------------------------------------------\n vcs-svn/trp.txt    |  109 ------------------------\n 7 files changed, 2 insertions(+), 445 deletions(-)\n delete mode 100644 test-treap.c\n delete mode 100644 vcs-svn/trp.h\n delete mode 100644 vcs-svn/trp.txt\n\ndiff --git a/.gitignore b/.gitignore\nindex 215e842..aa94ff1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -179,7 +179,6 @@\n /test-sigchain\n /test-subprocess\n /test-svn-fe\n-/test-treap\n /common-cmds.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex f8182e5..a2cadc5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -432,7 +432,6 @@ TEST_PROGRAMS_NEED_X += test-sha1\n TEST_PROGRAMS_NEED_X += test-sigchain\n TEST_PROGRAMS_NEED_X += test-subprocess\n TEST_PROGRAMS_NEED_X += test-svn-fe\n-TEST_PROGRAMS_NEED_X += test-treap\n TEST_PROGRAMS_NEED_X += test-index-version\n TEST_PROGRAMS_NEED_X += test-mktemp\n \n@@ -1839,7 +1838,7 @@ XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \\\n \txdiff/xmerge.o xdiff/xpatience.o\n VCSSVN_OBJS = vcs-svn/line_buffer.o vcs-svn/repo_tree.o \\\n \tvcs-svn/fast_export.o vcs-svn/svndump.o\n-VCSSVN_TEST_OBJS = test-obj-pool.o test-line-buffer.o test-treap.o\n+VCSSVN_TEST_OBJS = test-obj-pool.o test-line-buffer.o\n OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)\n \n dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)\n@@ -1963,7 +1962,7 @@ xdiff-interface.o $(XDIFF_OBJS): \\\n \txdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h\n \n $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \\\n-\tvcs-svn/obj_pool.h vcs-svn/trp.h \\\n+\tvcs-svn/obj_pool.h \\\n \tvcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \\\n \tvcs-svn/svndump.h\n \ndiff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh\nindex ce02c58..3f29496 100755\n--- a/t/t0080-vcs-svn.sh\n+++ b/t/t0080-vcs-svn.sh\n@@ -76,26 +76,4 @@ test_expect_success 'obj pool: high-water mark' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'treap sort' '\n-\tcat <<-\\EOF >unsorted &&\n-\t68\n-\t12\n-\t13\n-\t13\n-\t68\n-\t13\n-\t13\n-\t21\n-\t10\n-\t11\n-\t12\n-\t13\n-\t13\n-\tEOF\n-\tsort unsorted >expected &&\n-\n-\ttest-treap <unsorted >actual &&\n-\ttest_cmp expected actual\n-'\n-\n test_done\ndiff --git a/test-treap.c b/test-treap.c\ndeleted file mode 100644\nindex ab8c951..0000000\n--- a/test-treap.c\n+++ /dev/null\n@@ -1,70 +0,0 @@\n-/*\n- * test-treap.c: code to exercise the svn importer's treap structure\n- */\n-\n-#include \"cache.h\"\n-#include \"vcs-svn/obj_pool.h\"\n-#include \"vcs-svn/trp.h\"\n-\n-struct int_node {\n-\tuintmax_t n;\n-\tstruct trp_node children;\n-};\n-\n-obj_pool_gen(node, struct int_node, 3)\n-\n-static int node_cmp(struct int_node *a, struct int_node *b)\n-{\n-\treturn (a->n > b->n) - (a->n < b->n);\n-}\n-\n-trp_gen(static, treap_, struct int_node, children, node, node_cmp)\n-\n-static void strtonode(struct int_node *item, const char *s)\n-{\n-\tchar *end;\n-\titem->n = strtoumax(s, &end, 10);\n-\tif (*s == '\\0' || (*end != '\\n' && *end != '\\0'))\n-\t\tdie(\"invalid integer: %s\", s);\n-}\n-\n-int main(int argc, char *argv[])\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tstruct trp_root root = { ~0 };\n-\tuint32_t item;\n-\n-\tif (argc != 1)\n-\t\tusage(\"test-treap < ints\");\n-\n-\twhile (strbuf_getline(&sb, stdin, '\\n') != EOF) {\n-\t\tstruct int_node *node = node_pointer(node_alloc(1));\n-\n-\t\titem = node_offset(node);\n-\t\tstrtonode(node, sb.buf);\n-\t\tnode = treap_insert(&root, node_pointer(item));\n-\t\tif (node_offset(node) != item)\n-\t\t\tdie(\"inserted %\"PRIu32\" in place of %\"PRIu32\"\",\n-\t\t\t\tnode_offset(node), item);\n-\t}\n-\n-\titem = node_offset(treap_first(&root));\n-\twhile (~item) {\n-\t\tuint32_t next;\n-\t\tstruct int_node *tmp = node_pointer(node_alloc(1));\n-\n-\t\ttmp->n = node_pointer(item)->n;\n-\t\tnext = node_offset(treap_next(&root, node_pointer(item)));\n-\n-\t\ttreap_remove(&root, node_pointer(item));\n-\t\titem = node_offset(treap_nsearch(&root, tmp));\n-\n-\t\tif (item != next && (!~item || node_pointer(item)->n != tmp->n))\n-\t\t\tdie(\"found %\"PRIuMAX\" in place of %\"PRIuMAX\"\",\n-\t\t\t\t~item ? node_pointer(item)->n : ~(uintmax_t) 0,\n-\t\t\t\t~next ? node_pointer(next)->n : ~(uintmax_t) 0);\n-\t\tprintf(\"%\"PRIuMAX\"\\n\", tmp->n);\n-\t}\n-\tnode_reset();\n-\treturn 0;\n-}\ndiff --git a/vcs-svn/LICENSE b/vcs-svn/LICENSE\nindex 0a5e3c4..533f585 100644\n--- a/vcs-svn/LICENSE\n+++ b/vcs-svn/LICENSE\n@@ -1,9 +1,6 @@\n Copyright (C) 2010 David Barr <david.barr@cordelta.com>.\n All rights reserved.\n \n-Copyright (C) 2008 Jason Evans <jasone@canonware.com>.\n-All rights reserved.\n-\n Copyright (C) 2005 Stefan Hegny, hydrografix Consulting GmbH,\n Frankfurt/Main, Germany\n and others, see http://svn2cc.sarovar.org\ndiff --git a/vcs-svn/trp.h b/vcs-svn/trp.h\ndeleted file mode 100644\nindex c32b918..0000000\n--- a/vcs-svn/trp.h\n+++ /dev/null\n@@ -1,237 +0,0 @@\n-/*\n- * C macro implementation of treaps.\n- *\n- * Usage:\n- *   #include <stdint.h>\n- *   #include \"trp.h\"\n- *   trp_gen(...)\n- *\n- * Licensed under a two-clause BSD-style license.\n- * See LICENSE for details.\n- */\n-\n-#ifndef TRP_H_\n-#define TRP_H_\n-\n-#define MAYBE_UNUSED __attribute__((__unused__))\n-\n-/* Node structure. */\n-struct trp_node {\n-\tuint32_t trpn_left;\n-\tuint32_t trpn_right;\n-};\n-\n-/* Root structure. */\n-struct trp_root {\n-\tuint32_t trp_root;\n-};\n-\n-/* Pointer/Offset conversion. */\n-#define trpn_pointer(a_base, a_offset) (a_base##_pointer(a_offset))\n-#define trpn_offset(a_base, a_pointer) (a_base##_offset(a_pointer))\n-#define trpn_modify(a_base, a_offset) \\\n-\tdo { \\\n-\t\tif ((a_offset) < a_base##_pool.committed) { \\\n-\t\t\tuint32_t old_offset = (a_offset);\\\n-\t\t\t(a_offset) = a_base##_alloc(1); \\\n-\t\t\t*trpn_pointer(a_base, a_offset) = \\\n-\t\t\t\t*trpn_pointer(a_base, old_offset); \\\n-\t\t} \\\n-\t} while (0)\n-\n-/* Left accessors. */\n-#define trp_left_get(a_base, a_field, a_node) \\\n-\t(trpn_pointer(a_base, a_node)->a_field.trpn_left)\n-#define trp_left_set(a_base, a_field, a_node, a_left) \\\n-\tdo { \\\n-\t\ttrpn_modify(a_base, a_node); \\\n-\t\ttrp_left_get(a_base, a_field, a_node) = (a_left); \\\n-\t} while (0)\n-\n-/* Right accessors. */\n-#define trp_right_get(a_base, a_field, a_node) \\\n-\t(trpn_pointer(a_base, a_node)->a_field.trpn_right)\n-#define trp_right_set(a_base, a_field, a_node, a_right) \\\n-\tdo { \\\n-\t\ttrpn_modify(a_base, a_node); \\\n-\t\ttrp_right_get(a_base, a_field, a_node) = (a_right); \\\n-\t} while (0)\n-\n-/*\n- * Fibonacci hash function.\n- * The multiplier is the nearest prime to (2^32 times (√5 - 1)/2).\n- * See Knuth §6.4: volume 3, 3rd ed, p518.\n- */\n-#define trpn_hash(a_node) (uint32_t) (2654435761u * (a_node))\n-\n-/* Priority accessors. */\n-#define trp_prio_get(a_node) trpn_hash(a_node)\n-\n-/* Node initializer. */\n-#define trp_node_new(a_base, a_field, a_node) \\\n-\tdo { \\\n-\t\ttrp_left_set(a_base, a_field, (a_node), ~0); \\\n-\t\ttrp_right_set(a_base, a_field, (a_node), ~0); \\\n-\t} while (0)\n-\n-/* Internal utility macros. */\n-#define trpn_first(a_base, a_field, a_root, r_node) \\\n-\tdo { \\\n-\t\t(r_node) = (a_root); \\\n-\t\tif ((r_node) == ~0) \\\n-\t\t\treturn NULL; \\\n-\t\twhile (~trp_left_get(a_base, a_field, (r_node))) \\\n-\t\t\t(r_node) = trp_left_get(a_base, a_field, (r_node)); \\\n-\t} while (0)\n-\n-#define trpn_rotate_left(a_base, a_field, a_node, r_node) \\\n-\tdo { \\\n-\t\t(r_node) = trp_right_get(a_base, a_field, (a_node)); \\\n-\t\ttrp_right_set(a_base, a_field, (a_node), \\\n-\t\t\ttrp_left_get(a_base, a_field, (r_node))); \\\n-\t\ttrp_left_set(a_base, a_field, (r_node), (a_node)); \\\n-\t} while (0)\n-\n-#define trpn_rotate_right(a_base, a_field, a_node, r_node) \\\n-\tdo { \\\n-\t\t(r_node) = trp_left_get(a_base, a_field, (a_node)); \\\n-\t\ttrp_left_set(a_base, a_field, (a_node), \\\n-\t\t\ttrp_right_get(a_base, a_field, (r_node))); \\\n-\t\ttrp_right_set(a_base, a_field, (r_node), (a_node)); \\\n-\t} while (0)\n-\n-#define trp_gen(a_attr, a_pre, a_type, a_field, a_base, a_cmp) \\\n-a_attr a_type MAYBE_UNUSED *a_pre##first(struct trp_root *treap) \\\n-{ \\\n-\tuint32_t ret; \\\n-\ttrpn_first(a_base, a_field, treap->trp_root, ret); \\\n-\treturn trpn_pointer(a_base, ret); \\\n-} \\\n-a_attr a_type MAYBE_UNUSED *a_pre##next(struct trp_root *treap, a_type *node) \\\n-{ \\\n-\tuint32_t ret; \\\n-\tuint32_t offset = trpn_offset(a_base, node); \\\n-\tif (~trp_right_get(a_base, a_field, offset)) { \\\n-\t\ttrpn_first(a_base, a_field, \\\n-\t\t\ttrp_right_get(a_base, a_field, offset), ret); \\\n-\t} else { \\\n-\t\tuint32_t tnode = treap->trp_root; \\\n-\t\tret = ~0; \\\n-\t\twhile (1) { \\\n-\t\t\tint cmp = (a_cmp)(trpn_pointer(a_base, offset), \\\n-\t\t\t\ttrpn_pointer(a_base, tnode)); \\\n-\t\t\tif (cmp < 0) { \\\n-\t\t\t\tret = tnode; \\\n-\t\t\t\ttnode = trp_left_get(a_base, a_field, tnode); \\\n-\t\t\t} else if (cmp > 0) { \\\n-\t\t\t\ttnode = trp_right_get(a_base, a_field, tnode); \\\n-\t\t\t} else { \\\n-\t\t\t\tbreak; \\\n-\t\t\t} \\\n-\t\t} \\\n-\t} \\\n-\treturn trpn_pointer(a_base, ret); \\\n-} \\\n-a_attr a_type MAYBE_UNUSED *a_pre##search(struct trp_root *treap, a_type *key) \\\n-{ \\\n-\tint cmp; \\\n-\tuint32_t ret = treap->trp_root; \\\n-\twhile (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base, ret)))) { \\\n-\t\tif (cmp < 0) { \\\n-\t\t\tret = trp_left_get(a_base, a_field, ret); \\\n-\t\t} else { \\\n-\t\t\tret = trp_right_get(a_base, a_field, ret); \\\n-\t\t} \\\n-\t} \\\n-\treturn trpn_pointer(a_base, ret); \\\n-} \\\n-a_attr a_type MAYBE_UNUSED *a_pre##nsearch(struct trp_root *treap, a_type *key) \\\n-{ \\\n-\tint cmp; \\\n-\tuint32_t ret = treap->trp_root; \\\n-\twhile (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base, ret)))) { \\\n-\t\tif (cmp < 0) { \\\n-\t\t\tif (!~trp_left_get(a_base, a_field, ret)) \\\n-\t\t\t\tbreak; \\\n-\t\t\tret = trp_left_get(a_base, a_field, ret); \\\n-\t\t} else { \\\n-\t\t\tret = trp_right_get(a_base, a_field, ret); \\\n-\t\t} \\\n-\t} \\\n-\treturn trpn_pointer(a_base, ret); \\\n-} \\\n-a_attr uint32_t MAYBE_UNUSED a_pre##insert_recurse(uint32_t cur_node, uint32_t ins_node) \\\n-{ \\\n-\tif (cur_node == ~0) { \\\n-\t\treturn ins_node; \\\n-\t} else { \\\n-\t\tuint32_t ret; \\\n-\t\tint cmp = (a_cmp)(trpn_pointer(a_base, ins_node), \\\n-\t\t\t\t\ttrpn_pointer(a_base, cur_node)); \\\n-\t\tif (cmp < 0) { \\\n-\t\t\tuint32_t left = a_pre##insert_recurse( \\\n-\t\t\t\ttrp_left_get(a_base, a_field, cur_node), ins_node); \\\n-\t\t\ttrp_left_set(a_base, a_field, cur_node, left); \\\n-\t\t\tif (trp_prio_get(left) < trp_prio_get(cur_node)) \\\n-\t\t\t\ttrpn_rotate_right(a_base, a_field, cur_node, ret); \\\n-\t\t\telse \\\n-\t\t\t\tret = cur_node; \\\n-\t\t} else { \\\n-\t\t\tuint32_t right = a_pre##insert_recurse( \\\n-\t\t\t\ttrp_right_get(a_base, a_field, cur_node), ins_node); \\\n-\t\t\ttrp_right_set(a_base, a_field, cur_node, right); \\\n-\t\t\tif (trp_prio_get(right) < trp_prio_get(cur_node)) \\\n-\t\t\t\ttrpn_rotate_left(a_base, a_field, cur_node, ret); \\\n-\t\t\telse \\\n-\t\t\t\tret = cur_node; \\\n-\t\t} \\\n-\t\treturn ret; \\\n-\t} \\\n-} \\\n-a_attr a_type *MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \\\n-{ \\\n-\tuint32_t offset = trpn_offset(a_base, node); \\\n-\ttrp_node_new(a_base, a_field, offset); \\\n-\ttreap->trp_root = a_pre##insert_recurse(treap->trp_root, offset); \\\n-\treturn trpn_pointer(a_base, offset); \\\n-} \\\n-a_attr uint32_t MAYBE_UNUSED a_pre##remove_recurse(uint32_t cur_node, uint32_t rem_node) \\\n-{ \\\n-\tint cmp = a_cmp(trpn_pointer(a_base, rem_node), \\\n-\t\t\ttrpn_pointer(a_base, cur_node)); \\\n-\tif (cmp == 0) { \\\n-\t\tuint32_t ret; \\\n-\t\tuint32_t left = trp_left_get(a_base, a_field, cur_node); \\\n-\t\tuint32_t right = trp_right_get(a_base, a_field, cur_node); \\\n-\t\tif (left == ~0) { \\\n-\t\t\tif (right == ~0) \\\n-\t\t\t\treturn ~0; \\\n-\t\t} else if (right == ~0 || trp_prio_get(left) < trp_prio_get(right)) { \\\n-\t\t\ttrpn_rotate_right(a_base, a_field, cur_node, ret); \\\n-\t\t\tright = a_pre##remove_recurse(cur_node, rem_node); \\\n-\t\t\ttrp_right_set(a_base, a_field, ret, right); \\\n-\t\t\treturn ret; \\\n-\t\t} \\\n-\t\ttrpn_rotate_left(a_base, a_field, cur_node, ret); \\\n-\t\tleft = a_pre##remove_recurse(cur_node, rem_node); \\\n-\t\ttrp_left_set(a_base, a_field, ret, left); \\\n-\t\treturn ret; \\\n-\t} else if (cmp < 0) { \\\n-\t\tuint32_t left = a_pre##remove_recurse( \\\n-\t\t\ttrp_left_get(a_base, a_field, cur_node), rem_node); \\\n-\t\ttrp_left_set(a_base, a_field, cur_node, left); \\\n-\t\treturn cur_node; \\\n-\t} else { \\\n-\t\tuint32_t right = a_pre##remove_recurse( \\\n-\t\t\ttrp_right_get(a_base, a_field, cur_node), rem_node); \\\n-\t\ttrp_right_set(a_base, a_field, cur_node, right); \\\n-\t\treturn cur_node; \\\n-\t} \\\n-} \\\n-a_attr void MAYBE_UNUSED a_pre##remove(struct trp_root *treap, a_type *node) \\\n-{ \\\n-\ttreap->trp_root = a_pre##remove_recurse(treap->trp_root, \\\n-\t\ttrpn_offset(a_base, node)); \\\n-} \\\n-\n-#endif\ndiff --git a/vcs-svn/trp.txt b/vcs-svn/trp.txt\ndeleted file mode 100644\nindex 5ca6b42..0000000\n--- a/vcs-svn/trp.txt\n+++ /dev/null\n@@ -1,109 +0,0 @@\n-Motivation\n-==========\n-\n-Treaps provide a memory-efficient binary search tree structure.\n-Insertion/deletion/search are about as about as fast in the average\n-case as red-black trees and the chances of worst-case behavior are\n-vanishingly small, thanks to (pseudo-)randomness.  The bad worst-case\n-behavior is a small price to pay, given that treaps are much simpler\n-to implement.\n-\n-API\n-===\n-\n-The trp API generates a data structure and functions to handle a\n-large growing set of objects stored in a pool.\n-\n-The caller:\n-\n-. Specifies parameters for the generated functions with the\n-  trp_gen(static, foo_, ...) macro.\n-\n-. Allocates a `struct trp_root` variable and sets it to {~0}.\n-\n-. Adds new nodes to the set using `foo_insert`.  Any pointers\n-  to existing nodes cannot be relied upon any more, so the caller\n-  might retrieve them anew with `foo_pointer`.\n-\n-. Can find a specific item in the set using `foo_search`.\n-\n-. Can iterate over items in the set using `foo_first` and `foo_next`.\n-\n-. Can remove an item from the set using `foo_remove`.\n-\n-Example:\n-\n-----\n-struct ex_node {\n-\tconst char *s;\n-\tstruct trp_node ex_link;\n-};\n-static struct trp_root ex_base = {~0};\n-obj_pool_gen(ex, struct ex_node, 4096);\n-trp_gen(static, ex_, struct ex_node, ex_link, ex, strcmp)\n-struct ex_node *item;\n-\n-item = ex_pointer(ex_alloc(1));\n-item->s = \"hello\";\n-ex_insert(&ex_base, item);\n-item = ex_pointer(ex_alloc(1));\n-item->s = \"goodbye\";\n-ex_insert(&ex_base, item);\n-for (item = ex_first(&ex_base); item; item = ex_next(&ex_base, item))\n-\tprintf(\"%s\\n\", item->s);\n-----\n-\n-Functions\n----------\n-\n-trp_gen(attr, foo_, node_type, link_field, pool, cmp)::\n-\n-\tGenerate a type-specific treap implementation.\n-+\n-. The storage class for generated functions will be 'attr' (e.g., `static`).\n-. Generated function names are prefixed with 'foo_' (e.g., `treap_`).\n-. Treap nodes will be of type 'node_type' (e.g., `struct treap_node`).\n-  This type must be a struct with at least one `struct trp_node` field\n-  to point to its children.\n-. The field used to access child nodes will be 'link_field'.\n-. All treap nodes must lie in the 'pool' object pool.\n-. Treap nodes must be totally ordered by the 'cmp' relation, with the\n-  following prototype:\n-+\n-int (*cmp)(node_type \\*a, node_type \\*b)\n-+\n-and returning a value less than, equal to, or greater than zero\n-according to the result of comparison.\n-\n-node_type {asterisk}foo_insert(struct trp_root *treap, node_type \\*node)::\n-\n-\tInsert node into treap.  If inserted multiple times,\n-\ta node will appear in the treap multiple times.\n-+\n-The return value is the address of the node within the treap,\n-which might differ from `node` if `pool_alloc` had to call\n-`realloc` to expand the pool.\n-\n-void foo_remove(struct trp_root *treap, node_type \\*node)::\n-\n-\tRemove node from treap.  Caller must ensure node is\n-\tpresent in treap before using this function.\n-\n-node_type *foo_search(struct trp_root \\*treap, node_type \\*key)::\n-\n-\tSearch for a node that matches key.  If no match is found,\n-\tresult is NULL.\n-\n-node_type *foo_nsearch(struct trp_root \\*treap, node_type \\*key)::\n-\n-\tLike `foo_search`, but if if the key is missing return what\n-\twould be key's successor, were key in treap (NULL if no\n-\tsuccessor).\n-\n-node_type *foo_first(struct trp_root \\*treap)::\n-\n-\tFind the first item from the treap, in sorted order.\n-\n-node_type *foo_next(struct trp_root \\*treap, node_type \\*node)::\n-\n-\tFind the next item.\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164007","messageId":"1300751400-7427-11-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 10/11] vcs-svn: drop obj_pool.h","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:49:59Z","receivedAt":"2011-03-21T23:49:59Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Signed-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n .gitignore         |    1 -\n Makefile           |    4 +-\n t/t0080-vcs-svn.sh |   79 -----------------------------------\n test-obj-pool.c    |  116 ----------------------------------------------------\n vcs-svn/obj_pool.h |   61 ---------------------------\n 5 files changed, 1 insertions(+), 260 deletions(-)\n delete mode 100755 t/t0080-vcs-svn.sh\n delete mode 100644 test-obj-pool.c\n delete mode 100644 vcs-svn/obj_pool.h\n\ndiff --git a/.gitignore b/.gitignore\nindex aa94ff1..789f922 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -171,7 +171,6 @@\n /test-line-buffer\n /test-match-trees\n /test-mktemp\n-/test-obj-pool\n /test-parse-options\n /test-path-utils\n /test-run-command\ndiff --git a/Makefile b/Makefile\nindex a2cadc5..b802ae9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -424,7 +424,6 @@ TEST_PROGRAMS_NEED_X += test-dump-cache-tree\n TEST_PROGRAMS_NEED_X += test-genrandom\n TEST_PROGRAMS_NEED_X += test-line-buffer\n TEST_PROGRAMS_NEED_X += test-match-trees\n-TEST_PROGRAMS_NEED_X += test-obj-pool\n TEST_PROGRAMS_NEED_X += test-parse-options\n TEST_PROGRAMS_NEED_X += test-path-utils\n TEST_PROGRAMS_NEED_X += test-run-command\n@@ -1838,7 +1837,7 @@ XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \\\n \txdiff/xmerge.o xdiff/xpatience.o\n VCSSVN_OBJS = vcs-svn/line_buffer.o vcs-svn/repo_tree.o \\\n \tvcs-svn/fast_export.o vcs-svn/svndump.o\n-VCSSVN_TEST_OBJS = test-obj-pool.o test-line-buffer.o\n+VCSSVN_TEST_OBJS = test-line-buffer.o\n OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)\n \n dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)\n@@ -1962,7 +1961,6 @@ xdiff-interface.o $(XDIFF_OBJS): \\\n \txdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h\n \n $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \\\n-\tvcs-svn/obj_pool.h \\\n \tvcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \\\n \tvcs-svn/svndump.h\n \ndiff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh\ndeleted file mode 100755\nindex 3f29496..0000000\n--- a/t/t0080-vcs-svn.sh\n+++ /dev/null\n@@ -1,79 +0,0 @@\n-#!/bin/sh\n-\n-test_description='check infrastructure for svn importer'\n-\n-. ./test-lib.sh\n-uint32_max=4294967295\n-\n-test_expect_success 'obj pool: store data' '\n-\tcat <<-\\EOF >expected &&\n-\t0\n-\t1\n-\tEOF\n-\n-\ttest-obj-pool <<-\\EOF >actual &&\n-\talloc one 16\n-\tset one 13\n-\ttest one 13\n-\treset one\n-\tEOF\n-\ttest_cmp expected actual\n-'\n-\n-test_expect_success 'obj pool: NULL is offset ~0' '\n-\techo \"$uint32_max\" >expected &&\n-\techo null one | test-obj-pool >actual &&\n-\ttest_cmp expected actual\n-'\n-\n-test_expect_success 'obj pool: out-of-bounds access' '\n-\tcat <<-EOF >expected &&\n-\t0\n-\t0\n-\t$uint32_max\n-\t$uint32_max\n-\t16\n-\t20\n-\t$uint32_max\n-\tEOF\n-\n-\ttest-obj-pool <<-\\EOF >actual &&\n-\talloc one 16\n-\talloc two 16\n-\toffset one 20\n-\toffset two 20\n-\talloc one 5\n-\toffset one 20\n-\tfree one 1\n-\toffset one 20\n-\treset one\n-\treset two\n-\tEOF\n-\ttest_cmp expected actual\n-'\n-\n-test_expect_success 'obj pool: high-water mark' '\n-\tcat <<-\\EOF >expected &&\n-\t0\n-\t0\n-\t10\n-\t20\n-\t20\n-\t20\n-\tEOF\n-\n-\ttest-obj-pool <<-\\EOF >actual &&\n-\talloc one 10\n-\tcommitted one\n-\talloc one 10\n-\tcommit one\n-\tcommitted one\n-\talloc one 10\n-\tfree one 20\n-\tcommitted one\n-\treset one\n-\tEOF\n-\ttest_cmp expected actual\n-'\n-\n-test_done\ndiff --git a/test-obj-pool.c b/test-obj-pool.c\ndeleted file mode 100644\nindex 5018863..0000000\n--- a/test-obj-pool.c\n+++ /dev/null\n@@ -1,116 +0,0 @@\n-/*\n- * test-obj-pool.c: code to exercise the svn importer's object pool\n- */\n-\n-#include \"cache.h\"\n-#include \"vcs-svn/obj_pool.h\"\n-\n-enum pool { POOL_ONE, POOL_TWO };\n-obj_pool_gen(one, int, 1)\n-obj_pool_gen(two, int, 4096)\n-\n-static uint32_t strtouint32(const char *s)\n-{\n-\tchar *end;\n-\tuintmax_t n = strtoumax(s, &end, 10);\n-\tif (*s == '\\0' || (*end != '\\n' && *end != '\\0'))\n-\t\tdie(\"invalid offset: %s\", s);\n-\treturn (uint32_t) n;\n-}\n-\n-static void handle_command(const char *command, enum pool pool, const char *arg)\n-{\n-\tswitch (*command) {\n-\tcase 'a':\n-\t\tif (!prefixcmp(command, \"alloc \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tprintf(\"%\"PRIu32\"\\n\",\n-\t\t\t\tpool == POOL_ONE ?\n-\t\t\t\tone_alloc(n) : two_alloc(n));\n-\t\t\treturn;\n-\t\t}\n-\tcase 'c':\n-\t\tif (!prefixcmp(command, \"commit \")) {\n-\t\t\tpool == POOL_ONE ? one_commit() : two_commit();\n-\t\t\treturn;\n-\t\t}\n-\t\tif (!prefixcmp(command, \"committed \")) {\n-\t\t\tprintf(\"%\"PRIu32\"\\n\",\n-\t\t\t\tpool == POOL_ONE ?\n-\t\t\t\tone_pool.committed : two_pool.committed);\n-\t\t\treturn;\n-\t\t}\n-\tcase 'f':\n-\t\tif (!prefixcmp(command, \"free \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tpool == POOL_ONE ? one_free(n) : two_free(n);\n-\t\t\treturn;\n-\t\t}\n-\tcase 'n':\n-\t\tif (!prefixcmp(command, \"null \")) {\n-\t\t\tprintf(\"%\"PRIu32\"\\n\",\n-\t\t\t\tpool == POOL_ONE ?\n-\t\t\t\tone_offset(NULL) : two_offset(NULL));\n-\t\t\treturn;\n-\t\t}\n-\tcase 'o':\n-\t\tif (!prefixcmp(command, \"offset \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tprintf(\"%\"PRIu32\"\\n\",\n-\t\t\t\tpool == POOL_ONE ?\n-\t\t\t\tone_offset(one_pointer(n)) :\n-\t\t\t\ttwo_offset(two_pointer(n)));\n-\t\t\treturn;\n-\t\t}\n-\tcase 'r':\n-\t\tif (!prefixcmp(command, \"reset \")) {\n-\t\t\tpool == POOL_ONE ? one_reset() : two_reset();\n-\t\t\treturn;\n-\t\t}\n-\tcase 's':\n-\t\tif (!prefixcmp(command, \"set \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tif (pool == POOL_ONE)\n-\t\t\t\t*one_pointer(n) = 1;\n-\t\t\telse\n-\t\t\t\t*two_pointer(n) = 1;\n-\t\t\treturn;\n-\t\t}\n-\tcase 't':\n-\t\tif (!prefixcmp(command, \"test \")) {\n-\t\t\tuint32_t n = strtouint32(arg);\n-\t\t\tprintf(\"%d\\n\", pool == POOL_ONE ?\n-\t\t\t\t*one_pointer(n) : *two_pointer(n));\n-\t\t\treturn;\n-\t\t}\n-\tdefault:\n-\t\tdie(\"unrecognized command: %s\", command);\n-\t}\n-}\n-\n-static void handle_line(const char *line)\n-{\n-\tconst char *arg = strchr(line, ' ');\n-\tenum pool pool;\n-\n-\tif (arg && !prefixcmp(arg + 1, \"one\"))\n-\t\tpool = POOL_ONE;\n-\telse if (arg && !prefixcmp(arg + 1, \"two\"))\n-\t\tpool = POOL_TWO;\n-\telse\n-\t\tdie(\"no pool specified: %s\", line);\n-\n-\thandle_command(line, pool, arg + strlen(\"one \"));\n-}\n-\n-int main(int argc, char *argv[])\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 1)\n-\t\tusage(\"test-obj-str < script\");\n-\n-\twhile (strbuf_getline(&sb, stdin, '\\n') != EOF)\n-\t\thandle_line(sb.buf);\n-\tstrbuf_release(&sb);\n-\treturn 0;\n-}\ndiff --git a/vcs-svn/obj_pool.h b/vcs-svn/obj_pool.h\ndeleted file mode 100644\nindex deb6eb8..0000000\n--- a/vcs-svn/obj_pool.h\n+++ /dev/null\n@@ -1,61 +0,0 @@\n-/*\n- * Licensed under a two-clause BSD-style license.\n- * See LICENSE for details.\n- */\n-\n-#ifndef OBJ_POOL_H_\n-#define OBJ_POOL_H_\n-\n-#include \"git-compat-util.h\"\n-\n-#define MAYBE_UNUSED __attribute__((__unused__))\n-\n-#define obj_pool_gen(pre, obj_t, initial_capacity) \\\n-static struct { \\\n-\tuint32_t committed; \\\n-\tuint32_t size; \\\n-\tuint32_t capacity; \\\n-\tobj_t *base; \\\n-} pre##_pool = {0, 0, 0, NULL}; \\\n-static MAYBE_UNUSED uint32_t pre##_alloc(uint32_t count) \\\n-{ \\\n-\tuint32_t offset; \\\n-\tif (pre##_pool.size + count > pre##_pool.capacity) { \\\n-\t\twhile (pre##_pool.size + count > pre##_pool.capacity) \\\n-\t\t\tif (pre##_pool.capacity) \\\n-\t\t\t\tpre##_pool.capacity *= 2; \\\n-\t\t\telse \\\n-\t\t\t\tpre##_pool.capacity = initial_capacity; \\\n-\t\tpre##_pool.base = realloc(pre##_pool.base, \\\n-\t\t\t\t\tpre##_pool.capacity * sizeof(obj_t)); \\\n-\t} \\\n-\toffset = pre##_pool.size; \\\n-\tpre##_pool.size += count; \\\n-\treturn offset; \\\n-} \\\n-static MAYBE_UNUSED void pre##_free(uint32_t count) \\\n-{ \\\n-\tpre##_pool.size -= count; \\\n-} \\\n-static MAYBE_UNUSED uint32_t pre##_offset(obj_t *obj) \\\n-{ \\\n-\treturn obj == NULL ? ~0 : obj - pre##_pool.base; \\\n-} \\\n-static MAYBE_UNUSED obj_t *pre##_pointer(uint32_t offset) \\\n-{ \\\n-\treturn offset >= pre##_pool.size ? NULL : &pre##_pool.base[offset]; \\\n-} \\\n-static MAYBE_UNUSED void pre##_commit(void) \\\n-{ \\\n-\tpre##_pool.committed = pre##_pool.size; \\\n-} \\\n-static MAYBE_UNUSED void pre##_reset(void) \\\n-{ \\\n-\tfree(pre##_pool.base); \\\n-\tpre##_pool.base = NULL; \\\n-\tpre##_pool.size = 0; \\\n-\tpre##_pool.capacity = 0; \\\n-\tpre##_pool.committed = 0; \\\n-}\n-\n-#endif\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164002","messageId":"1300751400-7427-12-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH 11/11] vcs-svn: use strchr to find RFC822 delimiter","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-21T23:50:00Z","receivedAt":"2011-03-21T23:50:00Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"This is a small optimisation (4% reduction in user time) but is the largest\nartifact within the parsing portion of svndump.c\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n vcs-svn/svndump.c |    4 +++-\n 1 files changed, 3 insertions(+), 1 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 897349e..88abf60 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -301,10 +301,12 @@ void svndump_read(const char *url)\n \n \treset_dump_ctx(url);\n \twhile ((t = buffer_read_line(&input))) {\n-\t\tval = strstr(t, \": \");\n+\t\tval = strchr(t, ':');\n \t\tif (!val)\n \t\t\tcontinue;\n \t\t*val++ = '\\0';\n+\t\tif (*val != ' ')\n+\t\t\tcontinue;\n \t\t*val++ = '\\0';\n \n \t\t/* strlen(key) + 1 */\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164103","messageId":"20110323003240.GA4949@elie","threadId":"26784","inReplyTo":"1300751400-7427-1-git-send-email-david.barr@cordelta.com","subject":"[PULL svn-fe] vcs-svn: simplifications, error handling improvements","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-23T00:32:40Z","receivedAt":"2011-03-23T00:32:40Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"(culled cc list)\nHi Junio,\n\nPlease pull\n\n  git://repo.or.cz/git/jrn.git svn-fe\n\nto get the following changes on top of master.\n\nThese are the patches from David's recent code-purge series that do\nnot require incremental import support.  I'd like to push out\nincremental import support soon, too, but since that makes svn-fe\nrequire feedback from fast-import as it runs, it would be nice to\nprovide some simple wrapper script to set everything up at the same\ntime to avoid inconveniencing users too much.\n\nThe main impact of the patches currently in svn-fe should be to\nimprove error handling a little.\n\nDavid Barr wrote:\n\n> Patch 6 follows the spirit of patches 4 and 5, for a consistent\n> approach to switching on constant strings.\n\nI've skipped this one and applied the rest.  You can see the result\nin the svn-fe-pu branch.\n\nThoughts, suggestions, improvements welcome as always.\n\nDavid Barr (5):\n      vcs-svn: use strbuf for revision log\n      vcs-svn: use strbuf for author, UUID, and URL\n      vcs-svn: implement perfect hash for node-prop keys\n      vcs-svn: implement perfect hash for top-level keys\n      vcs-svn: use strchr to find RFC822 delimiter\n\nJonathan Nieder (9):\n      vcs-svn: introduce repo_read_path to check the content at a path\n      vcs-svn: handle_node: use repo_read_path\n      vcs-svn: simplify repo_modify_path and repo_copy\n      vcs-svn: allow input errors to be detected promptly\n      vcs-svn: improve support for reading large files\n      vcs-svn: make buffer_skip_bytes return length read\n      vcs-svn: make buffer_copy_bytes return length read\n      vcs-svn: improve reporting of input errors\n      Merge branch 'db/length-as-hash' into svn-fe\n\n vcs-svn/fast_export.c   |   27 +++--\n vcs-svn/fast_export.h   |    5 +-\n vcs-svn/line_buffer.c   |   36 ++++---\n vcs-svn/line_buffer.h   |    6 +-\n vcs-svn/line_buffer.txt |    3 +-\n vcs-svn/repo_tree.c     |   43 ++++---\n vcs-svn/repo_tree.h     |   10 +-\n vcs-svn/svndump.c       |  307 +++++++++++++++++++++++++++++------------------\n 8 files changed, 265 insertions(+), 172 deletions(-)\n"},{"id":"164111","messageId":"7vsjuegzj8.fsf@alter.siamese.dyndns.org","threadId":"26784","inReplyTo":"20110323003240.GA4949@elie","subject":"Re: [PULL svn-fe] vcs-svn: simplifications, error handling improvements","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-23T05:46:03Z","receivedAt":"2011-03-23T05:46:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Please pull\n>\n>   git://repo.or.cz/git/jrn.git svn-fe\n>\n> to get the following changes on top of master.\n\nDone.\n\nI only gave a cursory look at \"git diff ORIG_HEAD\" output immediately\nafter pulling, but I found that the majority of lines deleted were of\nquestionable style and the added ones looked more like normal C ;-)\n\nExcept for\n\n\tswitch (keylen + 1) {\n        case sizeof(\"constant string\"):\n        \t...\n                break;\n        case sizeof(\"another constant string\"):\n        \t...\n\t}\n\nwhich looked a bit unusual. But mistakes in this construct can be easily\ncaught by the compiler that would notice duplicated case labels, so it\nprobably is not so brittle as it first looks.\n\nBy the way, I've been getting annoyed by these three \"sleep 100\" getting\nstuck in t0081 and spending their sweet timeout while running my tests\n(prove is on, \"make test </dev/null\" to forbid it from reading my stdin).\nI see attempts to kill them early with \"kill $!\" but apparently they are\nnot working. Can you take a look at it?\n"},{"id":"164114","messageId":"7vbp12gyqk.fsf@alter.siamese.dyndns.org","threadId":"26784","inReplyTo":"7vsjuegzj8.fsf@alter.siamese.dyndns.org","subject":"Re: [PULL svn-fe] vcs-svn: simplifications, error handling improvements","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-23T06:03:15Z","receivedAt":"2011-03-23T06:03:15Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> By the way, I've been getting annoyed by these three \"sleep 100\" getting\n> stuck in t0081 and spending their sweet timeout while running my tests\n> (prove is on, \"make test </dev/null\" to forbid it from reading my stdin).\n> I see attempts to kill them early with \"kill $!\" but apparently they are\n> not working. Can you take a look at it?\n\nA bit more datapoint.  The first one works just fine, while the second one\ngets stuck:\n\n    $ cd t && make T=t0081-line-buffer.sh test\n    $ cd t && make T=t0081-line-buffer.sh prove\n\nI notice that [sh] spawned from prove is orphaned.\n\n21643 pts/9    Ss     0:00      \\_ bash\n17149 pts/9    S+     0:00      |   \\_ make T=t0081-line-buffer.sh prove\n17155 pts/9    S+     0:00      |       \\_ /bin/sh -c echo \"*** prove ***\"; GIT_CONFIG=.git/\n17156 pts/9    S+     0:00      |           \\_ /usr/bin/perl /usr/bin/prove --exec /bin/sh t\n17157 pts/9    Z+     0:00      |               \\_ [sh] <defunct>\n\nIs this a known bug in prove perhaps?\n\n    $ /usr/bin/prove --version\n    TAP::Harness v3.17 and Perl v5.10.1\n"},{"id":"164115","messageId":"2DDB3B13-8C13-4F41-BA38-F97C035CBDE8@gmail.com","threadId":"26784","inReplyTo":"7vsjuegzj8.fsf@alter.siamese.dyndns.org","subject":"Re: [PULL svn-fe] vcs-svn: simplifications, error handling improvements","fromName":"David Barr","fromEmail":"david.barr.cordelta@gmail.com","sentAt":"2011-03-23T07:11:25Z","receivedAt":"2011-03-23T07:11:25Z","isPatch":false,"sender":{"key":"david.barr.cordelta@gmail.com","avatar":null},"body":"Hi,\n\nJunio C Hamano wrote:\n\n> Jonathan Nieder <jrnieder@gmail.com> writes:\n> \n>> Please pull\n>> \n>>  git://repo.or.cz/git/jrn.git svn-fe\n>> \n>> to get the following changes on top of master.\n> \n> Done.\n> \n> I only gave a cursory look at \"git diff ORIG_HEAD\" output immediately\n> after pulling, but I found that the majority of lines deleted were of\n> questionable style and the added ones looked more like normal C ;-)\n> \n> Except for\n> \n> \tswitch (keylen + 1) {\n>        case sizeof(\"constant string\"):\n>        \t...\n>                break;\n>        case sizeof(\"another constant string\"):\n>        \t...\n> \t}\n> \n> which looked a bit unusual. But mistakes in this construct can be easily\n> caught by the compiler that would notice duplicated case labels, so it\n> probably is not so brittle as it first looks.\n\nAgreed, it is quite an odd construct but it took quite a bit of refinement to\narrive there. It is a compromise between moderately readable and\nreasonably fast. I did play around with perfect hash generators prior to\nsettling on this approach. Ditto re compile time checking.\n\nJonathan, I suppose I should set up a performance test for these patches\nbecause my first thought was \"I wonder what these buy us on their own?\"\n\n--\nDavid Barr.\n"},{"id":"164225","messageId":"1300970636-31743-1-git-send-email-david.barr@cordelta.com","threadId":"26784","inReplyTo":"7vsjuegzj8.fsf@alter.siamese.dyndns.org","subject":"[PATCH] fixup! vcs-svn: improve reporting of input errors","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2011-03-24T12:43:56Z","receivedAt":"2011-03-24T12:43:56Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"An excessive constraint was introduced in c9d1c8ba; when reading\nsvn props, it is permissible for both keys and values to contain\nnul characters. Thus the test `strlen(val) != len` may fail on\nsuch properties. This caused svn-fe to die early whilst handling\nrevision 59151 of the ASF repository.\n---\n vcs-svn/svndump.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex ea5b128..9bd4fb2 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -171,7 +171,7 @@ static void read_props(void)\n \t\t\tdie(\"invalid property line: %s\\n\", t);\n \t\tlen = atoi(&t[2]);\n \t\tval = buffer_read_string(&input, len);\n-\t\tif (!val || strlen(val) != len)\n+\t\tif (!val)\n \t\t\tdie_short_read();\n \n \t\t/* Discard trailing newline. */\n-- \n1.7.3.2.846.gf4b062\n"},{"id":"164268","messageId":"20110325011250.GA20364@elie","threadId":"26784","inReplyTo":"1300970636-31743-1-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH] fixup! vcs-svn: improve reporting of input errors","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-25T01:12:50Z","receivedAt":"2011-03-25T01:12:50Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi David,\n\nDavid Barr wrote:\n\n> An excessive constraint was introduced in c9d1c8ba; when reading\n> svn props, it is permissible for both keys and values to contain\n> nul characters.\n\nYes, that will work.\n\nbuffer_read_string returns a '\\0'-terminated string and on early EOF,\nthe part after the end-of-file will be gibberish (and probably\nuninitialized).  But it lives in an 1000-char buffer and errors out\nwhen it doesn't fit, so at least with the fix it wouldn't crash.\n\nSorry for the breakage.  I suppose a test like the following would\ncatch future problems of this kind?\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n t/t9010-svn-fe.sh |   79 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 79 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh\nindex 5a6a4b9..a91b59c 100755\n--- a/t/t9010-svn-fe.sh\n+++ b/t/t9010-svn-fe.sh\n@@ -370,6 +370,85 @@ test_expect_failure 'change file mode but keep old content' '\n \ttest_cmp hello actual.target\n '\n \n+test_expect_failure 'null bytes' '\n+\t# Caveat: svnadmin 1.6.16 (r1073529) truncates at \\0 in the\n+\t# svn:specialQnotreally example.\n+\treinit_git &&\n+\tcat >expect <<-\\EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tgreeting\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tgreeting\n+\tEOF\n+\tprintf \"%s\\n\" \"something with a null byte (Q)\" |\n+\t\tq_to_nul >expect.message &&\n+\tprintf \"%s\\n\" \"helQo\" |\n+\t\tq_to_nul >expect.hello1 &&\n+\tprintf \"%s\\n\" \"link hello\" >expect.hello2 &&\n+\t{\n+\t\tproperties svn:log \"something with a null byte (Q)\" &&\n+\t\techo PROPS-END\n+\t} |\n+\tq_to_nul >props &&\n+\t{\n+\t\tq_to_nul <<-\\EOF &&\n+\t\tSVN-fs-dump-format-version: 3\n+\n+\t\tRevision-number: 1\n+\t\tProp-content-length: 10\n+\t\tContent-length: 10\n+\n+\t\tPROPS-END\n+\n+\t\tNode-path: greeting\n+\t\tNode-kind: file\n+\t\tNode-action: add\n+\t\tProp-content-length: 10\n+\t\tText-content-length: 6\n+\t\tContent-length: 16\n+\n+\t\tPROPS-END\n+\t\thelQo\n+\n+\t\tRevision-number: 2\n+\t\tEOF\n+\t\techo Prop-content-length: $(wc -c <props) &&\n+\t\techo Content-length: $(wc -c <props) &&\n+\t\techo &&\n+\t\tcat props &&\n+\t\tq_to_nul <<-\\EOF\n+\n+\t\tNode-path: greeting\n+\t\tNode-kind: file\n+\t\tNode-action: change\n+\t\tProp-content-length: 43\n+\t\tText-content-length: 11\n+\t\tContent-length: 54\n+\n+\t\tK 21\n+\t\tsvn:specialQnotreally\n+\t\tV 1\n+\t\t*\n+\t\tPROPS-END\n+\t\tlink hello\n+\t\tEOF\n+\t} >8bitclean.dump &&\n+\ttest-svn-fe 8bitclean.dump >stream &&\n+\tgit fast-import <stream &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$_x40/OBJID/g\"\n+\t} >actual &&\n+\tgit diff-tree --always -s --format=%s HEAD >actual.message &&\n+\tgit cat-file blob HEAD^:greeting >actual.hello1 &&\n+\tgit cat-file blob HEAD:greeting >actual.hello2 &&\n+\ttest_cmp expect actual &&\n+\ttest_cmp expect.message actual.message &&\n+\ttest_cmp expect.hello1 actual.hello1 &&\n+\ttest_cmp expect.hello2 actual.hello2\n+'\n+\n test_expect_success 'change file mode and reiterate content' '\n \treinit_git &&\n \tcat >expect <<-\\EOF &&\n-- \n1.7.4.1\n"},{"id":"164270","messageId":"20110325033431.GA3007@elie","threadId":"26784","inReplyTo":"1300970636-31743-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH svn-fe 0/4] vcs-svn: null bytes in properties","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-25T03:34:31Z","receivedAt":"2011-03-25T03:34:31Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"David Barr wrote:\n\n> it is permissible for both keys and values to contain\n> nul characters.\n\nYou're right --- it's a regression to error out, though we never did\nsupport it all that well.  How about this?\n\nThis doesn't take care of preserving embedded null bytes in the author\nname.  That can come another day, I suppose.\n\nJonathan Nieder (4):\n  vcs-svn: make reading of properties binary-safe\n  vcs-svn: remove buffer_read_string\n  vcs-svn: avoid unnecessary copying of log message and author\n  vcs-svn: handle log message with embedded null bytes\n\n t/t0081-line-buffer.sh  |   35 ++++++----------\n t/t9010-svn-fe.sh       |  104 +++++++++++++++++++++++++++++++++++++++++++++++\n test-line-buffer.c      |    6 ---\n vcs-svn/fast_export.c   |   12 +++--\n vcs-svn/fast_export.h   |    9 ++--\n vcs-svn/line_buffer.c   |    8 ----\n vcs-svn/line_buffer.h   |    4 +-\n vcs-svn/line_buffer.txt |   12 +----\n vcs-svn/repo_tree.c     |    5 +-\n vcs-svn/repo_tree.h     |    4 +-\n vcs-svn/svndump.c       |   42 +++++++++----------\n 11 files changed, 157 insertions(+), 84 deletions(-)\n"},{"id":"164271","messageId":"20110325040730.GB3007@elie","threadId":"26784","inReplyTo":"20110325033431.GA3007@elie","subject":"[PATCH 1/4] vcs-svn: make reading of properties binary-safe","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-25T04:07:30Z","receivedAt":"2011-03-25T04:07:30Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"A caller to buffer_read_string cannot easily tell the difference\nbetween the string \"foo\" followed by an early end of file and the\nstring \"foo\\0bar\\0baz\".  In a half-hearted attempt to catch early EOF,\nc9d1c8ba (2010-12-28) introduced a safety strlen(val) == len for\nproperty keys and values, to at least keep svn-fe from reading\nuninitialized data when a property list ends early due to EOF.\n\nBut it is permissible for both keys and values to contain null\ncharacters, so in handling revision 59151 of the ASF repository svn-fe\nencounters a null byte and produces the following message:\n\n fatal: invalid dump: unexpected end of file\n\nFix it by using buffer_read_binary to read to a strbuf (and keep track\nof the actual length read).  Most consumers of properties still use\nC-style strings, so in practice we still can't use an author or log\nmessage with embedded nuls, but at least this way svn-fe won't error\nout.\n\nReported-by: David Barr <david.barr@cordelta.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n t/t9010-svn-fe.sh |   27 +++++++++++++++++++++++++++\n vcs-svn/svndump.c |   24 ++++++++++--------------\n 2 files changed, 37 insertions(+), 14 deletions(-)\n\ndiff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh\nindex 5a6a4b9..47f1e4f 100755\n--- a/t/t9010-svn-fe.sh\n+++ b/t/t9010-svn-fe.sh\n@@ -370,6 +370,33 @@ test_expect_failure 'change file mode but keep old content' '\n \ttest_cmp hello actual.target\n '\n \n+test_expect_success 'null byte in property value' '\n+\treinit_git &&\n+\techo \"commit message\" >expect.message &&\n+\t{\n+\t\tproperties \\\n+\t\t\tunimportant \"something with a null byte (Q)\" \\\n+\t\t\tsvn:log \"commit message\"&&\n+\t\techo PROPS-END\n+\t} |\n+\tq_to_nul >props &&\n+\t{\n+\t\tcat <<-\\EOF &&\n+\t\tSVN-fs-dump-format-version: 3\n+\n+\t\tRevision-number: 1\n+\t\tEOF\n+\t\techo Prop-content-length: $(wc -c <props) &&\n+\t\techo Content-length: $(wc -c <props) &&\n+\t\techo &&\n+\t\tcat props\n+\t} >nullprop.dump &&\n+\ttest-svn-fe nullprop.dump >stream &&\n+\tgit fast-import <stream &&\n+\tgit diff-tree --always -s --format=%s HEAD >actual.message &&\n+\ttest_cmp expect.message actual.message\n+'\n+\n test_expect_success 'change file mode and reiterate content' '\n \treinit_git &&\n \tcat >expect <<-\\EOF &&\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex ea5b128..c00f031 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -147,6 +147,7 @@ static void die_short_read(void)\n static void read_props(void)\n {\n \tstatic struct strbuf key = STRBUF_INIT;\n+\tstatic struct strbuf val = STRBUF_INIT;\n \tconst char *t;\n \t/*\n \t * NEEDSWORK: to support simple mode changes like\n@@ -163,15 +164,15 @@ static void read_props(void)\n \tuint32_t type_set = 0;\n \twhile ((t = buffer_read_line(&input)) && strcmp(t, \"PROPS-END\")) {\n \t\tuint32_t len;\n-\t\tconst char *val;\n \t\tconst char type = t[0];\n \t\tint ch;\n \n \t\tif (!type || t[1] != ' ')\n \t\t\tdie(\"invalid property line: %s\\n\", t);\n \t\tlen = atoi(&t[2]);\n-\t\tval = buffer_read_string(&input, len);\n-\t\tif (!val || strlen(val) != len)\n+\t\tstrbuf_reset(&val);\n+\t\tbuffer_read_binary(&input, &val, len);\n+\t\tif (val.len < len)\n \t\t\tdie_short_read();\n \n \t\t/* Discard trailing newline. */\n@@ -179,22 +180,17 @@ static void read_props(void)\n \t\tif (ch == EOF)\n \t\t\tdie_short_read();\n \t\tif (ch != '\\n')\n-\t\t\tdie(\"invalid dump: expected newline after %s\", val);\n+\t\t\tdie(\"invalid dump: expected newline after %s\", val.buf);\n \n \t\tswitch (type) {\n \t\tcase 'K':\n+\t\t\tstrbuf_swap(&key, &val);\n+\t\t\tcontinue;\n \t\tcase 'D':\n-\t\t\tstrbuf_reset(&key);\n-\t\t\tif (val)\n-\t\t\t\tstrbuf_add(&key, val, len);\n-\t\t\tif (type == 'K')\n-\t\t\t\tcontinue;\n-\t\t\tassert(type == 'D');\n-\t\t\tval = NULL;\n-\t\t\tlen = 0;\n-\t\t\t/* fall through */\n+\t\t\thandle_property(&val, NULL, 0, &type_set);\n+\t\t\tcontinue;\n \t\tcase 'V':\n-\t\t\thandle_property(&key, val, len, &type_set);\n+\t\t\thandle_property(&key, val.buf, len, &type_set);\n \t\t\tstrbuf_reset(&key);\n \t\t\tcontinue;\n \t\tdefault:\n-- \n1.7.4.1\n"},{"id":"164272","messageId":"20110325040919.GC3007@elie","threadId":"26784","inReplyTo":"20110325033431.GA3007@elie","subject":"[PATCH 2/4] vcs-svn: remove buffer_read_string","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-25T04:09:19Z","receivedAt":"2011-03-25T04:09:19Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"All previous users of buffer_read_string have already been converted\nto use the more intuitive buffer_read_binary, so remove the old API to\navoid some confusion.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n t/t0081-line-buffer.sh  |   35 +++++++++++++----------------------\n test-line-buffer.c      |    6 ------\n vcs-svn/line_buffer.c   |    8 --------\n vcs-svn/line_buffer.h   |    4 +---\n vcs-svn/line_buffer.txt |   12 +++---------\n 5 files changed, 17 insertions(+), 48 deletions(-)\n\ndiff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh\nindex 550fad0..1dbe1c9 100755\n--- a/t/t0081-line-buffer.sh\n+++ b/t/t0081-line-buffer.sh\n@@ -53,7 +53,7 @@ long_read_test () {\n \t\t} >input &\n \t} &&\n \ttest-line-buffer input <<-EOF >output &&\n-\tread $readsize\n+\tbinary $readsize\n \tcopy $copysize\n \tEOF\n \tkill $! &&\n@@ -71,23 +71,23 @@ test_expect_success 'setup: have pipes?' '\n '\n \n test_expect_success 'hello world' '\n-\techo HELLO >expect &&\n+\techo \">HELLO\" >expect &&\n \ttest-line-buffer <<-\\EOF >actual &&\n-\tread 6\n+\tbinary 6\n \tHELLO\n \tEOF\n \ttest_cmp expect actual\n '\n \n test_expect_success PIPE '0-length read, no input available' '\n-\t>expect &&\n+\tprintf \">\" >expect &&\n \trm -f input &&\n \tmkfifo input &&\n \t{\n \t\tsleep 100 >input &\n \t} &&\n \ttest-line-buffer input <<-\\EOF >actual &&\n-\tread 0\n+\tbinary 0\n \tcopy 0\n \tEOF\n \tkill $! &&\n@@ -95,9 +95,9 @@ test_expect_success PIPE '0-length read, no input available' '\n '\n \n test_expect_success '0-length read, send along greeting' '\n-\techo HELLO >expect &&\n+\techo \">HELLO\" >expect &&\n \ttest-line-buffer <<-\\EOF >actual &&\n-\tread 0\n+\tbinary 0\n \tcopy 6\n \tHELLO\n \tEOF\n@@ -105,7 +105,7 @@ test_expect_success '0-length read, send along greeting' '\n '\n \n test_expect_success PIPE '1-byte read, no input available' '\n-\tprintf \"%s\" ab >expect &&\n+\tprintf \">%s\" ab >expect &&\n \trm -f input &&\n \tmkfifo input &&\n \t{\n@@ -116,7 +116,7 @@ test_expect_success PIPE '1-byte read, no input available' '\n \t\t} >input &\n \t} &&\n \ttest-line-buffer input <<-\\EOF >actual &&\n-\tread 1\n+\tbinary 1\n \tcopy 1\n \tEOF\n \tkill $! &&\n@@ -140,15 +140,6 @@ test_expect_success 'read from file descriptor' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'buffer_read_string copes with null byte' '\n-\t>expect &&\n-\tq_to_nul <<-\\EOF | test-line-buffer >actual &&\n-\tread 2\n-\tQ\n-\tEOF\n-\ttest_cmp expect actual\n-'\n-\n test_expect_success 'skip, copy null byte' '\n \techo Q | q_to_nul >expect &&\n \tq_to_nul <<-\\EOF | test-line-buffer >actual &&\n@@ -170,18 +161,18 @@ test_expect_success 'read null byte' '\n '\n \n test_expect_success 'long reads are truncated' '\n-\techo foo >expect &&\n+\techo \">foo\" >expect &&\n \ttest-line-buffer <<-\\EOF >actual &&\n-\tread 5\n+\tbinary 5\n \tfoo\n \tEOF\n \ttest_cmp expect actual\n '\n \n test_expect_success 'long copies are truncated' '\n-\tprintf \"%s\\n\" \"\" foo >expect &&\n+\tprintf \"%s\\n\" \">\" foo >expect &&\n \ttest-line-buffer <<-\\EOF >actual &&\n-\tread 1\n+\tbinary 1\n \n \tcopy 5\n \tfoo\ndiff --git a/test-line-buffer.c b/test-line-buffer.c\nindex 25b20b9..7ec9b13 100644\n--- a/test-line-buffer.c\n+++ b/test-line-buffer.c\n@@ -32,12 +32,6 @@ static void handle_command(const char *command, const char *arg, struct line_buf\n \t\t\tbuffer_copy_bytes(buf, strtouint32(arg));\n \t\t\treturn;\n \t\t}\n-\tcase 'r':\n-\t\tif (!prefixcmp(command, \"read \")) {\n-\t\t\tconst char *s = buffer_read_string(buf, strtouint32(arg));\n-\t\t\tfputs(s, stdout);\n-\t\t\treturn;\n-\t\t}\n \tcase 's':\n \t\tif (!prefixcmp(command, \"skip \")) {\n \t\t\tbuffer_skip_bytes(buf, strtouint32(arg));\ndiff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c\nindex 33e733a..c390387 100644\n--- a/vcs-svn/line_buffer.c\n+++ b/vcs-svn/line_buffer.c\n@@ -91,13 +91,6 @@ char *buffer_read_line(struct line_buffer *buf)\n \treturn buf->line_buffer;\n }\n \n-char *buffer_read_string(struct line_buffer *buf, uint32_t len)\n-{\n-\tstrbuf_reset(&buf->blob_buffer);\n-\tstrbuf_fread(&buf->blob_buffer, len, buf->infile);\n-\treturn ferror(buf->infile) ? NULL : buf->blob_buffer.buf;\n-}\n-\n void buffer_read_binary(struct line_buffer *buf,\n \t\t\t\tstruct strbuf *sb, uint32_t size)\n {\n@@ -134,5 +127,4 @@ off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)\n \n void buffer_reset(struct line_buffer *buf)\n {\n-\tstrbuf_release(&buf->blob_buffer);\n }\ndiff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h\nindex f5c468a..d0b22dd 100644\n--- a/vcs-svn/line_buffer.h\n+++ b/vcs-svn/line_buffer.h\n@@ -7,10 +7,9 @@\n \n struct line_buffer {\n \tchar line_buffer[LINE_BUFFER_LEN];\n-\tstruct strbuf blob_buffer;\n \tFILE *infile;\n };\n-#define LINE_BUFFER_INIT {\"\", STRBUF_INIT, NULL}\n+#define LINE_BUFFER_INIT { \"\", NULL }\n \n int buffer_init(struct line_buffer *buf, const char *filename);\n int buffer_fdinit(struct line_buffer *buf, int fd);\n@@ -23,7 +22,6 @@ long buffer_tmpfile_prepare_to_read(struct line_buffer *buf);\n \n int buffer_ferror(struct line_buffer *buf);\n char *buffer_read_line(struct line_buffer *buf);\n-char *buffer_read_string(struct line_buffer *buf, uint32_t len);\n int buffer_read_char(struct line_buffer *buf);\n void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);\n /* Returns number of bytes read (not necessarily written). */\ndiff --git a/vcs-svn/line_buffer.txt b/vcs-svn/line_buffer.txt\nindex 4ef0755..8e139eb 100644\n--- a/vcs-svn/line_buffer.txt\n+++ b/vcs-svn/line_buffer.txt\n@@ -16,8 +16,8 @@ The calling program:\n \n  - initializes a `struct line_buffer` to LINE_BUFFER_INIT\n  - specifies a file to read with `buffer_init`\n- - processes input with `buffer_read_line`, `buffer_read_string`,\n-   `buffer_skip_bytes`, and `buffer_copy_bytes`\n+ - processes input with `buffer_read_line`, `buffer_skip_bytes`,\n+   and `buffer_copy_bytes`\n  - closes the file with `buffer_deinit`, perhaps to start over and\n    read another file.\n \n@@ -37,7 +37,7 @@ the calling program.  A program\n    the temporary file\n  - declares writing is over with `buffer_tmpfile_prepare_to_read`\n  - can re-read what was written with `buffer_read_line`,\n-   `buffer_read_string`, and so on\n+   `buffer_copy_bytes`, and so on\n  - can reuse the temporary file by calling `buffer_tmpfile_rewind`\n    again\n  - removes the temporary file with `buffer_deinit`, perhaps to\n@@ -64,12 +64,6 @@ Functions\n \tRead a line and strip off the trailing newline.\n \tOn failure or end of file, returns NULL.\n \n-`buffer_read_string`::\n-\tRead `len` characters of input or up to the end of the\n-\tfile, whichever comes first.  Returns NULL on error.\n-\tReturns whatever characters were read (possibly \"\")\n-\tfor end of file.\n-\n `buffer_copy_bytes`::\n \tRead `len` bytes of input and dump them to the standard output\n \tstream.  Returns early for error or end of file.\n-- \n1.7.4.1\n"},{"id":"164273","messageId":"20110325041000.GD3007@elie","threadId":"26784","inReplyTo":"20110325033431.GA3007@elie","subject":"[PATCH 3/4] vcs-svn: avoid unnecessary copying of log message and author","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-25T04:10:00Z","receivedAt":"2011-03-25T04:10:00Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Use strbuf_swap when storing the svn:log and svn:author properties, so\npointers to rather than the contents of buffers get copied.  The main\neffect should be to make the code a little easier to read.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n vcs-svn/svndump.c |   20 ++++++++++----------\n 1 files changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex c00f031..88ecef1 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -83,7 +83,7 @@ static void reset_dump_ctx(const char *url)\n }\n \n static void handle_property(const struct strbuf *key_buf,\n-\t\t\t\tconst char *val, uint32_t len,\n+\t\t\t\tstruct strbuf *val,\n \t\t\t\tuint32_t *type_set)\n {\n \tconst char *key = key_buf->buf;\n@@ -95,23 +95,23 @@ static void handle_property(const struct strbuf *key_buf,\n \t\t\tbreak;\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:log\");\n-\t\tstrbuf_reset(&rev_ctx.log);\n-\t\tstrbuf_add(&rev_ctx.log, val, len);\n+\t\tstrbuf_swap(&rev_ctx.log, val);\n \t\tbreak;\n \tcase sizeof(\"svn:author\"):\n \t\tif (constcmp(key, \"svn:author\"))\n \t\t\tbreak;\n-\t\tstrbuf_reset(&rev_ctx.author);\n-\t\tif (val)\n-\t\t\tstrbuf_add(&rev_ctx.author, val, len);\n+\t\tif (!val)\n+\t\t\tstrbuf_reset(&rev_ctx.author);\n+\t\telse\n+\t\t\tstrbuf_swap(&rev_ctx.author, val);\n \t\tbreak;\n \tcase sizeof(\"svn:date\"):\n \t\tif (constcmp(key, \"svn:date\"))\n \t\t\tbreak;\n \t\tif (!val)\n \t\t\tdie(\"invalid dump: unsets svn:date\");\n-\t\tif (parse_date_basic(val, &rev_ctx.timestamp, NULL))\n-\t\t\twarning(\"invalid timestamp: %s\", val);\n+\t\tif (parse_date_basic(val->buf, &rev_ctx.timestamp, NULL))\n+\t\t\twarning(\"invalid timestamp: %s\", val->buf);\n \t\tbreak;\n \tcase sizeof(\"svn:executable\"):\n \tcase sizeof(\"svn:special\"):\n@@ -187,10 +187,10 @@ static void read_props(void)\n \t\t\tstrbuf_swap(&key, &val);\n \t\t\tcontinue;\n \t\tcase 'D':\n-\t\t\thandle_property(&val, NULL, 0, &type_set);\n+\t\t\thandle_property(&val, NULL, &type_set);\n \t\t\tcontinue;\n \t\tcase 'V':\n-\t\t\thandle_property(&key, val.buf, len, &type_set);\n+\t\t\thandle_property(&key, &val, &type_set);\n \t\t\tstrbuf_reset(&key);\n \t\t\tcontinue;\n \t\tdefault:\n-- \n1.7.4.1\n"},{"id":"164274","messageId":"20110325041120.GE3007@elie","threadId":"26784","inReplyTo":"20110325033431.GA3007@elie","subject":"[PATCH 4/4] vcs-svn: handle log message with embedded null bytes","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-25T04:11:20Z","receivedAt":"2011-03-25T04:11:20Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Use fwrite instead of printf to write the log message to fast-import\nso embedded ASCII NUL characters can be preserved.\n\nCurrently \"git log\" doesn't show the embedded NULs but \"git cat-file\ncommit\" can.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n t/t9010-svn-fe.sh     |   77 +++++++++++++++++++++++++++++++++++++++++++++++++\n vcs-svn/fast_export.c |   12 ++++---\n vcs-svn/fast_export.h |    9 +++--\n vcs-svn/repo_tree.c   |    5 ++-\n vcs-svn/repo_tree.h   |    4 +-\n vcs-svn/svndump.c     |    2 +-\n 6 files changed, 95 insertions(+), 14 deletions(-)\n\ndiff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh\nindex 47f1e4f..be35139 100755\n--- a/t/t9010-svn-fe.sh\n+++ b/t/t9010-svn-fe.sh\n@@ -397,6 +397,83 @@ test_expect_success 'null byte in property value' '\n \ttest_cmp expect.message actual.message\n '\n \n+test_expect_success 'null bytes' '\n+\t# Caveat: svnadmin 1.6.16 (r1073529) truncates at \\0 in the\n+\t# svn:specialQnotreally example.\n+\treinit_git &&\n+\tcat >expect <<-\\EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tgreeting\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tgreeting\n+\tEOF\n+\tprintf \"\\n%s\" \"something with a null byte (Q)\" >expect.message &&\n+\tprintf \"%s\\n\" \"helQo\" >expect.hello1 &&\n+\tprintf \"%s\\n\" \"link hello\" >expect.hello2 &&\n+\t{\n+\t\tproperties svn:log \"something with a null byte (Q)\" &&\n+\t\techo PROPS-END\n+\t} |\n+\tq_to_nul >props &&\n+\t{\n+\t\tq_to_nul <<-\\EOF &&\n+\t\tSVN-fs-dump-format-version: 3\n+\n+\t\tRevision-number: 1\n+\t\tProp-content-length: 10\n+\t\tContent-length: 10\n+\n+\t\tPROPS-END\n+\n+\t\tNode-path: greeting\n+\t\tNode-kind: file\n+\t\tNode-action: add\n+\t\tProp-content-length: 10\n+\t\tText-content-length: 6\n+\t\tContent-length: 16\n+\n+\t\tPROPS-END\n+\t\thelQo\n+\n+\t\tRevision-number: 2\n+\t\tEOF\n+\t\techo Prop-content-length: $(wc -c <props) &&\n+\t\techo Content-length: $(wc -c <props) &&\n+\t\techo &&\n+\t\tcat props &&\n+\t\tq_to_nul <<-\\EOF\n+\n+\t\tNode-path: greeting\n+\t\tNode-kind: file\n+\t\tNode-action: change\n+\t\tProp-content-length: 43\n+\t\tText-content-length: 11\n+\t\tContent-length: 54\n+\n+\t\tK 21\n+\t\tsvn:specialQnotreally\n+\t\tV 1\n+\t\t*\n+\t\tPROPS-END\n+\t\tlink hello\n+\t\tEOF\n+\t} >8bitclean.dump &&\n+\ttest-svn-fe 8bitclean.dump >stream &&\n+\tgit fast-import <stream &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$_x40/OBJID/g\"\n+\t} >actual &&\n+\tgit cat-file commit HEAD | nul_to_q | sed -ne \"/^\\$/,\\$ p\" >actual.message &&\n+\tgit cat-file blob HEAD^:greeting | nul_to_q >actual.hello1 &&\n+\tgit cat-file blob HEAD:greeting | nul_to_q >actual.hello2 &&\n+\ttest_cmp expect actual &&\n+\ttest_cmp expect.message actual.message &&\n+\ttest_cmp expect.hello1 actual.hello1 &&\n+\ttest_cmp expect.hello2 actual.hello2\n+'\n+\n test_expect_success 'change file mode and reiterate content' '\n \treinit_git &&\n \tcat >expect <<-\\EOF &&\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex a4d4d99..2e5bb67 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -31,12 +31,14 @@ void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,\n }\n \n static char gitsvnline[MAX_GITSVN_LINE_LEN];\n-void fast_export_commit(uint32_t revision, const char *author, char *log,\n+void fast_export_commit(uint32_t revision, const char *author,\n+\t\t\tconst struct strbuf *log,\n \t\t\tconst char *uuid, const char *url,\n \t\t\tunsigned long timestamp)\n {\n+\tstatic const struct strbuf empty = STRBUF_INIT;\n \tif (!log)\n-\t\tlog = \"\";\n+\t\tlog = &empty;\n \tif (*uuid && *url) {\n \t\tsnprintf(gitsvnline, MAX_GITSVN_LINE_LEN,\n \t\t\t\t\"\\n\\ngit-svn-id: %s@%\"PRIu32\" %s\\n\",\n@@ -49,9 +51,9 @@ void fast_export_commit(uint32_t revision, const char *author, char *log,\n \t\t   *author ? author : \"nobody\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *uuid ? uuid : \"local\", timestamp);\n-\tprintf(\"data %\"PRIu32\"\\n%s%s\\n\",\n-\t\t   (uint32_t) (strlen(log) + strlen(gitsvnline)),\n-\t\t   log, gitsvnline);\n+\tprintf(\"data %\"PRIuMAX\"\\n\", log->len + strlen(gitsvnline));\n+\tfwrite(log->buf, log->len, 1, stdout);\n+\tprintf(\"%s\\n\", gitsvnline);\n \tif (!first_commit_done) {\n \t\tif (revision > 1)\n \t\t\tprintf(\"from refs/heads/master^0\\n\");\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex 05cf97f..5878381 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -1,14 +1,15 @@\n #ifndef FAST_EXPORT_H_\n #define FAST_EXPORT_H_\n \n-#include \"line_buffer.h\"\n+struct line_buffer;\n+struct strbuf;\n \n void fast_export_delete(uint32_t depth, uint32_t *path);\n void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,\n \t\t\tuint32_t mark);\n-void fast_export_commit(uint32_t revision, const char *author, char *log,\n-\t\t\tconst char *uuid, const char *url,\n-\t\t\tunsigned long timestamp);\n+void fast_export_commit(uint32_t revision, const char *author,\n+\t\t\tconst struct strbuf *log, const char *uuid,\n+\t\t\tconst char *url, unsigned long timestamp);\n void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,\n \t\t      struct line_buffer *input);\n \ndiff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c\nindex d722e32..8caa015 100644\n--- a/vcs-svn/repo_tree.c\n+++ b/vcs-svn/repo_tree.c\n@@ -278,8 +278,9 @@ void repo_diff(uint32_t r1, uint32_t r2)\n \t\t    repo_commit_root_dir(commit_pointer(r2)));\n }\n \n-void repo_commit(uint32_t revision, const char *author, char *log,\n-\t\t const char *uuid, const char *url, unsigned long timestamp)\n+void repo_commit(uint32_t revision, const char *author,\n+\t\tconst struct strbuf *log, const char *uuid, const char *url,\n+\t\tunsigned long timestamp)\n {\n \tfast_export_commit(revision, author, log, uuid, url, timestamp);\n \tdent_commit();\ndiff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h\nindex a1b0e87..37bde2e 100644\n--- a/vcs-svn/repo_tree.h\n+++ b/vcs-svn/repo_tree.h\n@@ -1,7 +1,7 @@\n #ifndef REPO_TREE_H_\n #define REPO_TREE_H_\n \n-#include \"git-compat-util.h\"\n+struct strbuf;\n \n #define REPO_MODE_DIR 0040000\n #define REPO_MODE_BLB 0100644\n@@ -18,7 +18,7 @@ uint32_t repo_read_path(const uint32_t *path);\n uint32_t repo_read_mode(const uint32_t *path);\n void repo_delete(uint32_t *path);\n void repo_commit(uint32_t revision, const char *author,\n-\t\tchar *log, const char *uuid, const char *url,\n+\t\tconst struct strbuf *log, const char *uuid, const char *url,\n \t\tlong unsigned timestamp);\n void repo_diff(uint32_t r1, uint32_t r2);\n void repo_init(void);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex 88ecef1..eef49ca 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -274,7 +274,7 @@ static void handle_revision(void)\n {\n \tif (rev_ctx.revision)\n \t\trepo_commit(rev_ctx.revision, rev_ctx.author.buf,\n-\t\t\trev_ctx.log.buf, dump_ctx.uuid.buf, dump_ctx.url.buf,\n+\t\t\t&rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,\n \t\t\trev_ctx.timestamp);\n }\n \n-- \n1.7.4.1\n"},{"id":"164350","messageId":"20110326064220.GB20529@elie","threadId":"26784","inReplyTo":"7vbp12gyqk.fsf@alter.siamese.dyndns.org","subject":"Re: [PULL svn-fe] vcs-svn: simplifications, error handling improvements","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-26T06:42:39Z","receivedAt":"2011-03-26T06:42:39Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n\n> A bit more datapoint.  The first one works just fine, while the second one\n> gets stuck:\n>\n>     $ cd t && make T=t0081-line-buffer.sh test\n>     $ cd t && make T=t0081-line-buffer.sh prove\n>\n> I notice that [sh] spawned from prove is orphaned.\n>\n> 21643 pts/9    Ss     0:00      \\_ bash\n> 17149 pts/9    S+     0:00      |   \\_ make T=t0081-line-buffer.sh prove\n> 17155 pts/9    S+     0:00      |       \\_ /bin/sh -c echo \"*** prove ***\"; GIT_CONFIG=.git/\n> 17156 pts/9    S+     0:00      |           \\_ /usr/bin/perl /usr/bin/prove --exec /bin/sh t\n> 17157 pts/9    Z+     0:00      |               \\_ [sh] <defunct>\n\nHmm, looks like the \"kill $!\" is not working like it is supposed to.\nWhat is your /bin/sh?  How far does\n\n\tmake T=0081-line-buffer.sh prove SHELL_PATH_SH='/bin/sh -x'\n\nget before the lull?\n"},{"id":"164351","messageId":"20110326064653.GC20529@elie","threadId":"26784","inReplyTo":"7vsjuegzj8.fsf@alter.siamese.dyndns.org","subject":"Re: [PULL svn-fe] vcs-svn: simplifications, error handling improvements","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-26T06:46:53Z","receivedAt":"2011-03-26T06:46:53Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nJunio C Hamano wrote:\n\n> Done.\n\nTurns out that introduced a regression (in handling of properties with\nembedded NULs; thanks to David for catching and debugging it).  Could\nyou pull\n\n  git://repo.or.cz/git/jrn.git svn-fe\n\nfor a fix and some other improvements in the area?\n\nSorry for the trouble,\nJonathan Nieder (4):\n      vcs-svn: make reading of properties binary-safe\n      vcs-svn: remove buffer_read_string\n      vcs-svn: avoid unnecessary copying of log message and author\n      vcs-svn: handle log message with embedded NUL\n\n t/t0081-line-buffer.sh  |   35 ++++++----------\n t/t9010-svn-fe.sh       |  104 +++++++++++++++++++++++++++++++++++++++++++++++\n test-line-buffer.c      |    6 ---\n vcs-svn/fast_export.c   |   12 +++--\n vcs-svn/fast_export.h   |    7 ++-\n vcs-svn/line_buffer.c   |    8 ----\n vcs-svn/line_buffer.h   |    4 +-\n vcs-svn/line_buffer.txt |   12 +----\n vcs-svn/repo_tree.c     |    5 +-\n vcs-svn/repo_tree.h     |    4 +-\n vcs-svn/svndump.c       |   42 +++++++++----------\n 11 files changed, 156 insertions(+), 83 deletions(-)\n"},{"id":"164356","messageId":"20110326094904.GB7031@elie","threadId":"26784","inReplyTo":"20110326064220.GB20529@elie","subject":"t0081-line-buffer.sh hangs (Re: [PULL svn-fe] vcs-svn: simplifications, error handling improvements)","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-26T09:49:04Z","receivedAt":"2011-03-26T09:49:04Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jonathan Nieder wrote:\n\n> What is your /bin/sh?\n\nLooks like\n\n\tprove --exec=bash t0081-line-buffer.sh\n\nis enough to reproduce this, while\n\n\tbash t0081-line-buffer.sh\n\nworks fine.  And it seems to be racy --- with prove, sometimes the\nfirst test hangs, sometimes the 13th, sometimes none.  Sadly that's\nall there's time for tonight.\n\nThanks for catching it.\n\nPuzzled,\nJonathan\n"},{"id":"164374","messageId":"7v1v1t4tkw.fsf@alter.siamese.dyndns.org","threadId":"26784","inReplyTo":"20110326064653.GC20529@elie","subject":"Re: [PULL svn-fe] vcs-svn: simplifications, error handling improvements","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-26T18:36:47Z","receivedAt":"2011-03-26T18:36:47Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Turns out that introduced a regression (in handling of properties with\n> embedded NULs; thanks to David for catching and debugging it).  Could\n> you pull\n>\n>   git://repo.or.cz/git/jrn.git svn-fe\n>\n> for a fix and some other improvements in the area?\n\nThanks.\n"},{"id":"164401","messageId":"20110328003815.GB11644@elie","threadId":"26784","inReplyTo":"7v1v1t4tkw.fsf@alter.siamese.dyndns.org","subject":"[PATCH svn-fe] vcs-svn: add missing cast to printf argument","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-28T00:38:15Z","receivedAt":"2011-03-28T00:38:15Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"gcc -m32 correctly warns:\n\n vcs-svn/fast_export.c: In function 'fast_export_commit':\n vcs-svn/fast_export.c:54:2: warning: format '%llu' expects\n   argument of type 'long long unsigned int', but argument 2\n   has type 'unsigned int' [-Wformat]\n\nFix it.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nJunio C Hamano wrote:\n\n> Thanks.\n\nAny time.  But clearly I can't be trusted. :/\n\n vcs-svn/fast_export.c |    3 ++-\n 1 files changed, 2 insertions(+), 1 deletions(-)\n\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 2e5bb67..99ed70b 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -51,7 +51,8 @@ void fast_export_commit(uint32_t revision, const char *author,\n \t\t   *author ? author : \"nobody\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *uuid ? uuid : \"local\", timestamp);\n-\tprintf(\"data %\"PRIuMAX\"\\n\", log->len + strlen(gitsvnline));\n+\tprintf(\"data %\"PRIuMAX\"\\n\",\n+\t\t(uintmax_t) (log->len + strlen(gitsvnline)));\n \tfwrite(log->buf, log->len, 1, stdout);\n \tprintf(\"%s\\n\", gitsvnline);\n \tif (!first_commit_done) {\n-- \n1.7.4.2.660.g270d4b.dirty\n"},{"id":"164403","messageId":"20110328033013.GD11987@elie","threadId":"26784","inReplyTo":"1300519254-20201-7-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH 06/16] vcs-svn: skeleton of an svn delta parser","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-28T03:30:13Z","receivedAt":"2011-03-28T03:30:13Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"(culling cc list)\nHi,\n\nDavid Barr wrote:\n\n> --- a/vcs-svn/line_buffer.c\n> +++ b/vcs-svn/line_buffer.c\n> @@ -98,10 +98,10 @@ char *buffer_read_string(struct line_buffer *buf, uint32_t len)\n>  \treturn ferror(buf->infile) ? NULL : buf->blob_buffer.buf;\n>  }\n>  \n> -void buffer_read_binary(struct line_buffer *buf,\n> -\t\t\t\tstruct strbuf *sb, uint32_t size)\n> +off_t buffer_read_binary(struct line_buffer *buf,\n> +\t\t\t\tstruct strbuf *sb, off_t size)\n>  {\n> -\tstrbuf_fread(sb, size, buf->infile);\n> +\treturn strbuf_fread(sb, size, buf->infile);\n>  }\n\nApparently this change is from in an evil merge.  Yikes.\n\nAnyway, I think the original patch was something like the following.\nWould you mind if the parameter and return value go back to being of\ntype size_t (to avoid a possibly problematic conversion when passing\nvalues to and from strbuf_fread)?\n\n-- 8< --\nDate: Sun, 2 Jan 2011 21:37:36 -0600\nSubject: vcs-svn: make buffer_read_binary API more convenient\n\nbuffer_read_binary is a thin wrapper around fread, but its signature\nis wrong:\n\n - fread can fill an arbitrary in-memory buffer.  buffer_read_binary\n   is limited to buffers whose size is representable by a 32-bit\n   integer.\n - The result from fread is the number of bytes actually read.\n   buffer_read_binary only reports the number of bytes read by\n   incrementing sb->len by that amount and returns void.\n\nFix both: let buffer_read_binary accept a size_t instead of uint32_t\nfor the number of bytes to try to read and as a convenience return the\nnumber of bytes read.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n vcs-svn/line_buffer.c |    6 +++---\n vcs-svn/line_buffer.h |    2 +-\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c\nindex c390387..01fcb84 100644\n--- a/vcs-svn/line_buffer.c\n+++ b/vcs-svn/line_buffer.c\n@@ -91,10 +91,10 @@ char *buffer_read_line(struct line_buffer *buf)\n \treturn buf->line_buffer;\n }\n \n-void buffer_read_binary(struct line_buffer *buf,\n-\t\t\t\tstruct strbuf *sb, uint32_t size)\n+size_t buffer_read_binary(struct line_buffer *buf,\n+\t\t\t\tstruct strbuf *sb, size_t size)\n {\n-\tstrbuf_fread(sb, size, buf->infile);\n+\treturn strbuf_fread(sb, size, buf->infile);\n }\n \n off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)\ndiff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h\nindex d0b22dd..8901f21 100644\n--- a/vcs-svn/line_buffer.h\n+++ b/vcs-svn/line_buffer.h\n@@ -23,7 +23,7 @@ long buffer_tmpfile_prepare_to_read(struct line_buffer *buf);\n int buffer_ferror(struct line_buffer *buf);\n char *buffer_read_line(struct line_buffer *buf);\n int buffer_read_char(struct line_buffer *buf);\n-void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);\n+size_t buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, size_t len);\n /* Returns number of bytes read (not necessarily written). */\n off_t buffer_copy_bytes(struct line_buffer *buf, off_t len);\n off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);\n-- \n1.7.4.2.660.g270d4b.dirty\n"},{"id":"164406","messageId":"20110328070015.GE11987@elie","threadId":"26784","inReplyTo":"1300519254-20201-1-git-send-email-david.barr@cordelta.com","subject":"Re: vcs-svn: integrate support for text deltas","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-28T07:00:15Z","receivedAt":"2011-03-28T07:00:15Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nDavid Barr wrote:\n\n> As previously, I have tested against\n> the ASF subversion repository to increase confidence in the series.\n> Hopefully, this brings us a little closer to having full support for\n> version 3 of the subversion dump format in master.\n\nThanks much for digging this up.  (To think, it's been half a year\nsince the svndiff0 parser was written!)  I've queued everything except\npatch 16, and grabbing patch 16 on top of db/delta-applier +\ndb/vcs-svn-incremental should be just a formality.\n\nThe patches have had over three months to cook already.  Whether or\nnot a nice UI wrapper is ready[*], I'll be testing and then merging them\nto svn-fe in the next couple of weeks.  Sorry to take so long at this.\n\n[*] which will probably mean finally figuring out Tomas's work\n"},{"id":"164421","messageId":"E60A9EC9-DD21-46A8-9BB6-2A5FBC6FF6A9@gmail.com","threadId":"26784","inReplyTo":"20110328070015.GE11987@elie","subject":"Re: vcs-svn: integrate support for text deltas","fromName":"David Barr","fromEmail":"david.barr.cordelta@gmail.com","sentAt":"2011-03-28T11:56:17Z","receivedAt":"2011-03-28T11:56:17Z","isPatch":false,"sender":{"key":"david.barr.cordelta@gmail.com","avatar":null},"body":"Hi,\n\n> Thanks much for digging this up.  (To think, it's been half a year\n> since the svndiff0 parser was written!)  I've queued everything except\n> patch 16, and grabbing patch 16 on top of db/delta-applier +\n> db/vcs-svn-incremental should be just a formality.\n\n\nOnce more, I'll run the tests just in case there's any regression.\n(Having applied the aforementioned skipped patch.)\n\n--\nDavid Barr.\n"},{"id":"164442","messageId":"4D90AA6A.1090904@web.de","threadId":"26784","inReplyTo":"20110325040730.GB3007@elie","subject":"Re: [PATCH 1/4] vcs-svn: make reading of properties binary-safe","fromName":"tb","fromEmail":"tboegi@web.de","sentAt":"2011-03-28T15:34:02Z","receivedAt":"2011-03-28T15:34:02Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"Hej,\nI'm not sure if this was the origin email ...\n\nCommit e7d04ee147dcbe6af1fa1d2147466696e is OK.\n\nBut:\nfailure on t9010 with commit 195b7ca6f229455da61f9f6b\n=============\n#               test_cmp expect.message actual.message &&\n#               test_cmp expect.hello1 actual.hello1 &&\n#               test_cmp expect.hello2 actual.hello2\n#\nok 14 - change file mode and reiterate content\nok 15 - deltas not supported\nok 16 - property deltas supported\nok 17 - properties on /\nok 18 - deltas for typechange\nok 19 - set up svn repo\nok 20 - t9135/svn.dump\n# still have 3 known breakage(s)\n# failed 1 among remaining 17 test(s)\n1..20\n=====================\n\nSome more info:\nb@birne:~/projects/git/git.git> uname -a\nDarwin birne.lan 10.7.0 Darwin Kernel Version 10.7.0: Sat Jan 29 \n15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386\n\ntb@birne:~/projects/git/git.git> svn --version\nsvn, version 1.6.15 (r1038135)\n    compiled Jan 29 2011, 15:18:15\n\n\ntb@birne:~/projects/git/git.git> svnadmin --version\nsvnadmin, version 1.6.15 (r1038135)\n    compiled Jan 29 2011, 15:18:15\n\n  which svn\n/usr/bin/svn\n\nI can assist with some more testing\nBR\n/Torsten\n\n\nOn 03/25/2011 05:07 AM, Jonathan Nieder wrote:\n > A caller to buffer_read_string cannot easily tell the difference\n > between the string \"foo\" followed by an early end of file and the\n > string \"foo\\0bar\\0baz\".  In a half-hearted attempt to catch early EOF,\n > c9d1c8ba (2010-12-28) introduced a safety strlen(val) == len for\n > property keys and values, to at least keep svn-fe from reading\n > uninitialized data when a property list ends early due to EOF.\n >\n > But it is permissible for both keys and values to contain null\n > characters, so in handling revision 59151 of the ASF repository svn-fe\n > encounters a null byte and produces the following message:\n >\n >   fatal: invalid dump: unexpected end of file\n >\n > Fix it by using buffer_read_binary to read to a strbuf (and keep track\n > of the actual length read).  Most consumers of properties still use\n > C-style strings, so in practice we still can't use an author or log\n > message with embedded nuls, but at least this way svn-fe won't error\n > out.\n >\n > Reported-by: David Barr<david.barr@cordelta.com>\n > Signed-off-by: Jonathan Nieder<jrnieder@gmail.com>\n > ---\n >   t/t9010-svn-fe.sh |   27 +++++++++++++++++++++++++++\n >   vcs-svn/svndump.c |   24 ++++++++++--------------\n >   2 files changed, 37 insertions(+), 14 deletions(-)\n >\n > diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh\n > index 5a6a4b9..47f1e4f 100755\n > --- a/t/t9010-svn-fe.sh\n > +++ b/t/t9010-svn-fe.sh\n > @@ -370,6 +370,33 @@ test_expect_failure 'change file mode but keep \nold content' '\n >   \ttest_cmp hello actual.target\n >   '\n >\n > +test_expect_success 'null byte in property value' '\n > +\treinit_git&&\n > +\techo \"commit message\">expect.message&&\n > +\t{\n > +\t\tproperties \\\n > +\t\t\tunimportant \"something with a null byte (Q)\" \\\n > +\t\t\tsvn:log \"commit message\"&&\n > +\t\techo PROPS-END\n > +\t} |\n > +\tq_to_nul>props&&\n > +\t{\n > +\t\tcat<<-\\EOF&&\n > +\t\tSVN-fs-dump-format-version: 3\n > +\n > +\t\tRevision-number: 1\n > +\t\tEOF\n > +\t\techo Prop-content-length: $(wc -c<props)&&\n > +\t\techo Content-length: $(wc -c<props)&&\n > +\t\techo&&\n > +\t\tcat props\n > +\t}>nullprop.dump&&\n > +\ttest-svn-fe nullprop.dump>stream&&\n > +\tgit fast-import<stream&&\n > +\tgit diff-tree --always -s --format=%s HEAD>actual.message&&\n > +\ttest_cmp expect.message actual.message\n > +'\n > +\n >   test_expect_success 'change file mode and reiterate content' '\n >   \treinit_git&&\n >   \tcat>expect<<-\\EOF&&\n > diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\n > index ea5b128..c00f031 100644\n > --- a/vcs-svn/svndump.c\n > +++ b/vcs-svn/svndump.c\n > @@ -147,6 +147,7 @@ static void die_short_read(void)\n >   static void read_props(void)\n >   {\n >   \tstatic struct strbuf key = STRBUF_INIT;\n > +\tstatic struct strbuf val = STRBUF_INIT;\n >   \tconst char *t;\n >   \t/*\n >   \t * NEEDSWORK: to support simple mode changes like\n > @@ -163,15 +164,15 @@ static void read_props(void)\n >   \tuint32_t type_set = 0;\n >   \twhile ((t = buffer_read_line(&input))&&  strcmp(t, \"PROPS-END\")) {\n >   \t\tuint32_t len;\n > -\t\tconst char *val;\n >   \t\tconst char type = t[0];\n >   \t\tint ch;\n >\n >   \t\tif (!type || t[1] != ' ')\n >   \t\t\tdie(\"invalid property line: %s\\n\", t);\n >   \t\tlen = atoi(&t[2]);\n > -\t\tval = buffer_read_string(&input, len);\n > -\t\tif (!val || strlen(val) != len)\n > +\t\tstrbuf_reset(&val);\n > +\t\tbuffer_read_binary(&input,&val, len);\n > +\t\tif (val.len<  len)\n >   \t\t\tdie_short_read();\n >\n >   \t\t/* Discard trailing newline. */\n > @@ -179,22 +180,17 @@ static void read_props(void)\n >   \t\tif (ch == EOF)\n >   \t\t\tdie_short_read();\n >   \t\tif (ch != '\\n')\n > -\t\t\tdie(\"invalid dump: expected newline after %s\", val);\n > +\t\t\tdie(\"invalid dump: expected newline after %s\", val.buf);\n >\n >   \t\tswitch (type) {\n >   \t\tcase 'K':\n > +\t\t\tstrbuf_swap(&key,&val);\n > +\t\t\tcontinue;\n >   \t\tcase 'D':\n > -\t\t\tstrbuf_reset(&key);\n > -\t\t\tif (val)\n > -\t\t\t\tstrbuf_add(&key, val, len);\n > -\t\t\tif (type == 'K')\n > -\t\t\t\tcontinue;\n > -\t\t\tassert(type == 'D');\n > -\t\t\tval = NULL;\n > -\t\t\tlen = 0;\n > -\t\t\t/* fall through */\n > +\t\t\thandle_property(&val, NULL, 0,&type_set);\n > +\t\t\tcontinue;\n >   \t\tcase 'V':\n > -\t\t\thandle_property(&key, val, len,&type_set);\n > +\t\t\thandle_property(&key, val.buf, len,&type_set);\n >   \t\t\tstrbuf_reset(&key);\n >   \t\t\tcontinue;\n >   \t\tdefault:\n\n\n======================\n\n\n\n\n\n\n\n\n\n\nOn 03/25/2011 05:07 AM, Jonathan Nieder wrote:\n> A caller to buffer_read_string cannot easily tell the difference\n> between the string \"foo\" followed by an early end of file and the\n> string \"foo\\0bar\\0baz\".  In a half-hearted attempt to catch early EOF,\n> c9d1c8ba (2010-12-28) introduced a safety strlen(val) == len for\n> property keys and values, to at least keep svn-fe from reading\n> uninitialized data when a property list ends early due to EOF.\n>\n> But it is permissible for both keys and values to contain null\n> characters, so in handling revision 59151 of the ASF repository svn-fe\n> encounters a null byte and produces the following message:\n>\n>   fatal: invalid dump: unexpected end of file\n>\n> Fix it by using buffer_read_binary to read to a strbuf (and keep track\n> of the actual length read).  Most consumers of properties still use\n> C-style strings, so in practice we still can't use an author or log\n> message with embedded nuls, but at least this way svn-fe won't error\n> out.\n>\n> Reported-by: David Barr<david.barr@cordelta.com>\n> Signed-off-by: Jonathan Nieder<jrnieder@gmail.com>\n> ---\n>   t/t9010-svn-fe.sh |   27 +++++++++++++++++++++++++++\n>   vcs-svn/svndump.c |   24 ++++++++++--------------\n>   2 files changed, 37 insertions(+), 14 deletions(-)\n>\n> diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh\n> index 5a6a4b9..47f1e4f 100755\n> --- a/t/t9010-svn-fe.sh\n> +++ b/t/t9010-svn-fe.sh\n> @@ -370,6 +370,33 @@ test_expect_failure 'change file mode but keep old content' '\n>   \ttest_cmp hello actual.target\n>   '\n>\n> +test_expect_success 'null byte in property value' '\n> +\treinit_git&&\n> +\techo \"commit message\">expect.message&&\n> +\t{\n> +\t\tproperties \\\n> +\t\t\tunimportant \"something with a null byte (Q)\" \\\n> +\t\t\tsvn:log \"commit message\"&&\n> +\t\techo PROPS-END\n> +\t} |\n> +\tq_to_nul>props&&\n> +\t{\n> +\t\tcat<<-\\EOF&&\n> +\t\tSVN-fs-dump-format-version: 3\n> +\n> +\t\tRevision-number: 1\n> +\t\tEOF\n> +\t\techo Prop-content-length: $(wc -c<props)&&\n> +\t\techo Content-length: $(wc -c<props)&&\n> +\t\techo&&\n> +\t\tcat props\n> +\t}>nullprop.dump&&\n> +\ttest-svn-fe nullprop.dump>stream&&\n> +\tgit fast-import<stream&&\n> +\tgit diff-tree --always -s --format=%s HEAD>actual.message&&\n> +\ttest_cmp expect.message actual.message\n> +'\n> +\n>   test_expect_success 'change file mode and reiterate content' '\n>   \treinit_git&&\n>   \tcat>expect<<-\\EOF&&\n> diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\n> index ea5b128..c00f031 100644\n> --- a/vcs-svn/svndump.c\n> +++ b/vcs-svn/svndump.c\n> @@ -147,6 +147,7 @@ static void die_short_read(void)\n>   static void read_props(void)\n>   {\n>   \tstatic struct strbuf key = STRBUF_INIT;\n> +\tstatic struct strbuf val = STRBUF_INIT;\n>   \tconst char *t;\n>   \t/*\n>   \t * NEEDSWORK: to support simple mode changes like\n> @@ -163,15 +164,15 @@ static void read_props(void)\n>   \tuint32_t type_set = 0;\n>   \twhile ((t = buffer_read_line(&input))&&  strcmp(t, \"PROPS-END\")) {\n>   \t\tuint32_t len;\n> -\t\tconst char *val;\n>   \t\tconst char type = t[0];\n>   \t\tint ch;\n>\n>   \t\tif (!type || t[1] != ' ')\n>   \t\t\tdie(\"invalid property line: %s\\n\", t);\n>   \t\tlen = atoi(&t[2]);\n> -\t\tval = buffer_read_string(&input, len);\n> -\t\tif (!val || strlen(val) != len)\n> +\t\tstrbuf_reset(&val);\n> +\t\tbuffer_read_binary(&input,&val, len);\n> +\t\tif (val.len<  len)\n>   \t\t\tdie_short_read();\n>\n>   \t\t/* Discard trailing newline. */\n> @@ -179,22 +180,17 @@ static void read_props(void)\n>   \t\tif (ch == EOF)\n>   \t\t\tdie_short_read();\n>   \t\tif (ch != '\\n')\n> -\t\t\tdie(\"invalid dump: expected newline after %s\", val);\n> +\t\t\tdie(\"invalid dump: expected newline after %s\", val.buf);\n>\n>   \t\tswitch (type) {\n>   \t\tcase 'K':\n> +\t\t\tstrbuf_swap(&key,&val);\n> +\t\t\tcontinue;\n>   \t\tcase 'D':\n> -\t\t\tstrbuf_reset(&key);\n> -\t\t\tif (val)\n> -\t\t\t\tstrbuf_add(&key, val, len);\n> -\t\t\tif (type == 'K')\n> -\t\t\t\tcontinue;\n> -\t\t\tassert(type == 'D');\n> -\t\t\tval = NULL;\n> -\t\t\tlen = 0;\n> -\t\t\t/* fall through */\n> +\t\t\thandle_property(&val, NULL, 0,&type_set);\n> +\t\t\tcontinue;\n>   \t\tcase 'V':\n> -\t\t\thandle_property(&key, val, len,&type_set);\n> +\t\t\thandle_property(&key, val.buf, len,&type_set);\n>   \t\t\tstrbuf_reset(&key);\n>   \t\t\tcontinue;\n>   \t\tdefault:\n"},{"id":"164484","messageId":"20110328194157.GC13433@elie","threadId":"26784","inReplyTo":"4D90AA6A.1090904@web.de","subject":"Re: [PATCH 1/4] vcs-svn: make reading of properties binary-safe","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-28T19:41:57Z","receivedAt":"2011-03-28T19:41:57Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"tb wrote:\n\n> failure on t9010 with commit 195b7ca6f229455da61f9f6b\n[...]\n> Darwin birne.lan 10.7.0 Darwin Kernel Version 10.7.0: Sat Jan 29\n> 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386\n\nCould you try 41e6b91f (vcs-svn: add missing cast to printf argument,\n2011-03-27) from\n\n\tgit://repo.or.cz/git/jrn.git svn-fe\n\n?  I suspect this is fallout from a missing cast in the commit you\npointed to.  Thanks for noticing.\n"},{"id":"164491","messageId":"4D90EFF5.9050603@web.de","threadId":"26784","inReplyTo":"20110328194157.GC13433@elie","subject":"Re: [PATCH 1/4] vcs-svn: make reading of properties binary-safe","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2011-03-28T20:30:45Z","receivedAt":"2011-03-28T20:30:45Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 03/28/2011 09:41 PM, Jonathan Nieder wrote:\n> tb wrote:\n>\n>> failure on t9010 with commit 195b7ca6f229455da61f9f6b\n> [...]\n>> Darwin birne.lan 10.7.0 Darwin Kernel Version 10.7.0: Sat Jan 29\n>> 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386\n>\n> Could you try 41e6b91f (vcs-svn: add missing cast to printf argument,\n> 2011-03-27) from\n>\n> \tgit://repo.or.cz/git/jrn.git svn-fe\n>\n> ?  I suspect this is fallout from a missing cast in the commit you\n> pointed to.  Thanks for noticing.\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\nNo good news from my side:\nSame (?) problem with 41e6b...\n\nnot ok - 13 NUL in log message, file content, and property name\n\n/Torsten\n\nNote:\n(commit 41e6b  works OK on  my 32 bit 386 linux machine.\n  There is no svn on that machine, and commit 195b7ca6f22 had 10 \nfailures in TC 9010. (If that is any useful information))\n"},{"id":"164493","messageId":"20110328204403.GC16202@elie","threadId":"26784","inReplyTo":"4D90EFF5.9050603@web.de","subject":"Re: [PATCH 1/4] vcs-svn: make reading of properties binary-safe","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-03-28T20:44:03Z","receivedAt":"2011-03-28T20:44:03Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Torsten Bögershausen wrote:\n\n> No good news from my side:\n> Same (?) problem with 41e6b...\n>\n> not ok - 13 NUL in log message, file content, and property name\n\nAlas.  Could you send the output for that test from\n\"sh t9010-svn-fe.sh -v -i\", or from\n\n\tGIT_TRACE=1 sh -x t9010-svn-fe.sh -v -i\n\nif it looks more enlightening?\n"}]}