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 <jrnieder@gmail.com>
Jonathan Nieder committed
Mar 26, 2011 at 00:49 UTC
195b7ca6f229455da61f9f6b6e56a6558fb0e8ee
6 files changed
+94
-13
t/t9010-svn-fe.sh
+77
@@ -397,6 +397,83 @@ test_expect_success 'NUL in property value' '
397
test_cmp expect.message actual.message
398
'
399
400
+test_expect_success 'NUL in log message, file content, and property name' '
401
+ # Caveat: svnadmin 1.6.16 (r1073529) truncates at \0 in the
402
+ # svn:specialQnotreally example.
403
+ reinit_git &&
404
+ cat >expect <<-\EOF &&
405
+ OBJID
406
+ :100644 100644 OBJID OBJID M greeting
407
+ OBJID
408
+ :000000 100644 OBJID OBJID A greeting
409
+ EOF
410
+ printf "\n%s" "something with an ASCII NUL (Q)" >expect.message &&
411
+ printf "%s\n" "helQo" >expect.hello1 &&
412
+ printf "%s\n" "link hello" >expect.hello2 &&
413
+ {
414
+ properties svn:log "something with an ASCII NUL (Q)" &&
415
+ echo PROPS-END
416
+ } |
417
+ q_to_nul >props &&
418
+ {
419
+ q_to_nul <<-\EOF &&
420
+ SVN-fs-dump-format-version: 3
421
+
422
+ Revision-number: 1
423
+ Prop-content-length: 10
424
+ Content-length: 10
425
+
426
+ PROPS-END
427
+
428
+ Node-path: greeting
429
+ Node-kind: file
430
+ Node-action: add
431
+ Prop-content-length: 10
432
+ Text-content-length: 6
433
+ Content-length: 16
434
+
435
+ PROPS-END
436
+ helQo
437
+
438
+ Revision-number: 2
439
+ EOF
440
+ echo Prop-content-length: $(wc -c <props) &&
441
+ echo Content-length: $(wc -c <props) &&
442
+ echo &&
443
+ cat props &&
444
+ q_to_nul <<-\EOF
445
+
446
+ Node-path: greeting
447
+ Node-kind: file
448
+ Node-action: change
449
+ Prop-content-length: 43
450
+ Text-content-length: 11
451
+ Content-length: 54
452
+
453
+ K 21
454
+ svn:specialQnotreally
455
+ V 1
456
+ *
457
+ PROPS-END
458
+ link hello
459
+ EOF
460
+ } >8bitclean.dump &&
461
+ test-svn-fe 8bitclean.dump >stream &&
462
+ git fast-import <stream &&
463
+ {
464
+ git rev-list HEAD |
465
+ git diff-tree --root --stdin |
466
+ sed "s/$_x40/OBJID/g"
467
+ } >actual &&
468
+ git cat-file commit HEAD | nul_to_q | sed -ne "/^\$/,\$ p" >actual.message &&
469
+ git cat-file blob HEAD^:greeting | nul_to_q >actual.hello1 &&
470
+ git cat-file blob HEAD:greeting | nul_to_q >actual.hello2 &&
471
+ test_cmp expect actual &&
472
+ test_cmp expect.message actual.message &&
473
+ test_cmp expect.hello1 actual.hello1 &&
474
+ test_cmp expect.hello2 actual.hello2
475
+'
476
+
477
test_expect_success 'change file mode and reiterate content' '
478
reinit_git &&
479
cat >expect <<-\EOF &&
vcs-svn/fast_export.c
+7
-5
@@ -31,12 +31,14 @@ void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
31
}
32
33
static char gitsvnline[MAX_GITSVN_LINE_LEN];
34
-void fast_export_commit(uint32_t revision, const char *author, char *log,
34
+void fast_export_commit(uint32_t revision, const char *author,
35
+ const struct strbuf *log,
36
const char *uuid, const char *url,
37
unsigned long timestamp)
38
{
39
+ static const struct strbuf empty = STRBUF_INIT;
40
if (!log)
39
- log = "";
41
+ log = ∅
42
if (*uuid && *url) {
43
snprintf(gitsvnline, MAX_GITSVN_LINE_LEN,
44
"\n\ngit-svn-id: %s@%"PRIu32" %s\n",
@@ -49,9 +51,9 @@ void fast_export_commit(uint32_t revision, const char *author, char *log,
51
*author ? author : "nobody",
52
*author ? author : "nobody",
53
*uuid ? uuid : "local", timestamp);
52
- printf("data %"PRIu32"\n%s%s\n",
53
- (uint32_t) (strlen(log) + strlen(gitsvnline)),
54
- log, gitsvnline);
54
+ printf("data %"PRIuMAX"\n", log->len + strlen(gitsvnline));
55
+ fwrite(log->buf, log->len, 1, stdout);
56
+ printf("%s\n", gitsvnline);
57
if (!first_commit_done) {
58
if (revision > 1)
59
printf("from refs/heads/master^0\n");
vcs-svn/fast_export.h
+4
-3
@@ -2,13 +2,14 @@
2
#define FAST_EXPORT_H_
3
4
#include "line_buffer.h"
5
+struct strbuf;
6
7
void fast_export_delete(uint32_t depth, uint32_t *path);
8
void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
9
uint32_t mark);
9
-void fast_export_commit(uint32_t revision, const char *author, char *log,
10
- const char *uuid, const char *url,
11
- unsigned long timestamp);
10
+void fast_export_commit(uint32_t revision, const char *author,
11
+ const struct strbuf *log, const char *uuid,
12
+ const char *url, unsigned long timestamp);
13
void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,
14
struct line_buffer *input);
15
vcs-svn/repo_tree.c
+3
-2
@@ -278,8 +278,9 @@ void repo_diff(uint32_t r1, uint32_t r2)
278
repo_commit_root_dir(commit_pointer(r2)));
279
}
280
281
-void repo_commit(uint32_t revision, const char *author, char *log,
282
- const char *uuid, const char *url, unsigned long timestamp)
281
+void repo_commit(uint32_t revision, const char *author,
282
+ const struct strbuf *log, const char *uuid, const char *url,
283
+ unsigned long timestamp)
284
{
285
fast_export_commit(revision, author, log, uuid, url, timestamp);
286
dent_commit();
vcs-svn/repo_tree.h
+2
-2
@@ -1,7 +1,7 @@
1
#ifndef REPO_TREE_H_
2
#define REPO_TREE_H_
3
4
-#include "git-compat-util.h"
4
+struct strbuf;
5
6
#define REPO_MODE_DIR 0040000
7
#define REPO_MODE_BLB 0100644
@@ -18,7 +18,7 @@ uint32_t repo_read_path(const uint32_t *path);
18
uint32_t repo_read_mode(const uint32_t *path);
19
void repo_delete(uint32_t *path);
20
void repo_commit(uint32_t revision, const char *author,
21
- char *log, const char *uuid, const char *url,
21
+ const struct strbuf *log, const char *uuid, const char *url,
22
long unsigned timestamp);
23
void repo_diff(uint32_t r1, uint32_t r2);
24
void repo_init(void);
vcs-svn/svndump.c
+1
-1
@@ -274,7 +274,7 @@ static void handle_revision(void)
274
{
275
if (rev_ctx.revision)
276
repo_commit(rev_ctx.revision, rev_ctx.author.buf,
277
- rev_ctx.log.buf, dump_ctx.uuid.buf, dump_ctx.url.buf,
277
+ &rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
278
rev_ctx.timestamp);
279
}
280