From: Jonathan Nieder Date: Sat, 26 Mar 2011 05:49:37 +0000 (-0500) Subject: vcs-svn: handle log message with embedded NUL X-Git-Tag: v1.7.5-rc0~3^2~4 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=195b7ca6f229455da61f9f6b6e56a6558fb0e8ee;p=git.git vcs-svn: handle log message with embedded NUL Pass the log message by strbuf instead of as a C-style string and use fwrite instead of printf to write it to fast-import so embedded '\0' bytes can be preserved. Currently "git log" doesn't show the embedded NULs but "git cat-file commit" can. While at it, stop including system headers from repo_tree.h. git source files need to include git-compat-util.h (or cache.h or builtin.h) sooner to ensure the appropriate feature test macros are defined. Signed-off-by: Jonathan Nieder --- diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh index 5e2b12308..478c86064 100755 --- a/t/t9010-svn-fe.sh +++ b/t/t9010-svn-fe.sh @@ -397,6 +397,83 @@ test_expect_success 'NUL in property value' ' test_cmp expect.message actual.message ' +test_expect_success 'NUL in log message, file content, and property name' ' + # Caveat: svnadmin 1.6.16 (r1073529) truncates at \0 in the + # svn:specialQnotreally example. + reinit_git && + cat >expect <<-\EOF && + OBJID + :100644 100644 OBJID OBJID M greeting + OBJID + :000000 100644 OBJID OBJID A greeting + EOF + printf "\n%s" "something with an ASCII NUL (Q)" >expect.message && + printf "%s\n" "helQo" >expect.hello1 && + printf "%s\n" "link hello" >expect.hello2 && + { + properties svn:log "something with an ASCII NUL (Q)" && + echo PROPS-END + } | + q_to_nul >props && + { + q_to_nul <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: greeting + Node-kind: file + Node-action: add + Prop-content-length: 10 + Text-content-length: 6 + Content-length: 16 + + PROPS-END + helQo + + Revision-number: 2 + EOF + echo Prop-content-length: $(wc -c 8bitclean.dump && + test-svn-fe 8bitclean.dump >stream && + git fast-import actual && + git cat-file commit HEAD | nul_to_q | sed -ne "/^\$/,\$ p" >actual.message && + git cat-file blob HEAD^:greeting | nul_to_q >actual.hello1 && + git cat-file blob HEAD:greeting | nul_to_q >actual.hello2 && + test_cmp expect actual && + test_cmp expect.message actual.message && + test_cmp expect.hello1 actual.hello1 && + test_cmp expect.hello2 actual.hello2 +' + test_expect_success 'change file mode and reiterate content' ' reinit_git && cat >expect <<-\EOF && diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c index a4d4d9993..2e5bb6725 100644 --- a/vcs-svn/fast_export.c +++ b/vcs-svn/fast_export.c @@ -31,12 +31,14 @@ void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode, } static char gitsvnline[MAX_GITSVN_LINE_LEN]; -void fast_export_commit(uint32_t revision, const char *author, char *log, +void fast_export_commit(uint32_t revision, const char *author, + const struct strbuf *log, const char *uuid, const char *url, unsigned long timestamp) { + static const struct strbuf empty = STRBUF_INIT; if (!log) - log = ""; + log = ∅ if (*uuid && *url) { snprintf(gitsvnline, MAX_GITSVN_LINE_LEN, "\n\ngit-svn-id: %s@%"PRIu32" %s\n", @@ -49,9 +51,9 @@ void fast_export_commit(uint32_t revision, const char *author, char *log, *author ? author : "nobody", *author ? author : "nobody", *uuid ? uuid : "local", timestamp); - printf("data %"PRIu32"\n%s%s\n", - (uint32_t) (strlen(log) + strlen(gitsvnline)), - log, gitsvnline); + printf("data %"PRIuMAX"\n", log->len + strlen(gitsvnline)); + fwrite(log->buf, log->len, 1, stdout); + printf("%s\n", gitsvnline); if (!first_commit_done) { if (revision > 1) printf("from refs/heads/master^0\n"); diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h index 05cf97f3a..33a8fe996 100644 --- a/vcs-svn/fast_export.h +++ b/vcs-svn/fast_export.h @@ -2,13 +2,14 @@ #define FAST_EXPORT_H_ #include "line_buffer.h" +struct strbuf; void fast_export_delete(uint32_t depth, uint32_t *path); void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode, uint32_t mark); -void fast_export_commit(uint32_t revision, const char *author, char *log, - const char *uuid, const char *url, - unsigned long timestamp); +void fast_export_commit(uint32_t revision, const char *author, + const struct strbuf *log, const char *uuid, + const char *url, unsigned long timestamp); void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input); diff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c index d722e3212..8caa0159d 100644 --- a/vcs-svn/repo_tree.c +++ b/vcs-svn/repo_tree.c @@ -278,8 +278,9 @@ void repo_diff(uint32_t r1, uint32_t r2) repo_commit_root_dir(commit_pointer(r2))); } -void repo_commit(uint32_t revision, const char *author, char *log, - const char *uuid, const char *url, unsigned long timestamp) +void repo_commit(uint32_t revision, const char *author, + const struct strbuf *log, const char *uuid, const char *url, + unsigned long timestamp) { fast_export_commit(revision, author, log, uuid, url, timestamp); dent_commit(); diff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h index a1b0e8765..37bde2e37 100644 --- a/vcs-svn/repo_tree.h +++ b/vcs-svn/repo_tree.h @@ -1,7 +1,7 @@ #ifndef REPO_TREE_H_ #define REPO_TREE_H_ -#include "git-compat-util.h" +struct strbuf; #define REPO_MODE_DIR 0040000 #define REPO_MODE_BLB 0100644 @@ -18,7 +18,7 @@ uint32_t repo_read_path(const uint32_t *path); uint32_t repo_read_mode(const uint32_t *path); void repo_delete(uint32_t *path); void repo_commit(uint32_t revision, const char *author, - char *log, const char *uuid, const char *url, + const struct strbuf *log, const char *uuid, const char *url, long unsigned timestamp); void repo_diff(uint32_t r1, uint32_t r2); void repo_init(void); diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c index 88ecef106..eef49ca19 100644 --- a/vcs-svn/svndump.c +++ b/vcs-svn/svndump.c @@ -274,7 +274,7 @@ static void handle_revision(void) { if (rev_ctx.revision) repo_commit(rev_ctx.revision, rev_ctx.author.buf, - rev_ctx.log.buf, dump_ctx.uuid.buf, dump_ctx.url.buf, + &rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf, rev_ctx.timestamp); }