git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 07/16] vcs-svn: parse svndiff0 window header

From
David Barr <david.barr@cordelta.com>
Date
Mar 19, 2011, 07:20 UTC
Message-ID
<1300519254-20201-8-git-send-email-david.barr@cordelta.com>
In-Reply-To
<1300519254-20201-1-git-send-email-david.barr@cordelta.com>
From: Jonathan Nieder <jrnieder@gmail.com>

Each window in a subversion delta (svndiff0-format file) starts with a window header, consisting of five integers with variable-length representation:

	source view offset
	source view length
	output length
	instructions length
	auxiliary data length

Parse it. The result is not usable for deltas with nonempty postimage yet; in fact, this only adds support for deltas without any instructions or auxiliary data. This is a good place to stop, though, since that little support lets us add some simple passing tests concerning error handling to the test suite.

Improved-by: Ramkumar Ramachandra <artagnon@gmail.com>
Improved-by: David Barr <david.barr@cordelta.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: David Barr <david.barr@cordelta.com>
---
 t/t9011-svn-da.sh |   56 +++++++++++++++++++++++++++++++-
 vcs-svn/svndiff.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 142 insertions(+), 6 deletions(-)
diff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh
index 6d6a406..2ab580a 100755
--- a/t/t9011-svn-da.sh
+++ b/t/t9011-svn-da.sh
@@ -28,10 +28,64 @@ test_expect_success 'reject svndiff2' '
 	test_must_fail test-svn-fe -d preimage bad.filetype 4
 '
 
-test_expect_failure 'one-window empty delta' '
+test_expect_success 'one-window empty delta' '
 	printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow &&
 	test-svn-fe -d preimage clear.onewindow 9 >actual &&
 	test_cmp empty actual
 '
 
+test_expect_success 'reject incomplete window header' '
+	printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow &&
+	printf "SVNQ%s" "QQ" | q_to_nul >clear.partialwindow &&
+	test_must_fail test-svn-fe -d preimage clear.onewindow 6 &&
+	test_must_fail test-svn-fe -d preimage clear.partialwindow 6
+'
+
+test_expect_success 'reject declared delta longer than actual delta' '
+	printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow &&
+	printf "SVNQ%s" "QQ" | q_to_nul >clear.partialwindow &&
+	test_must_fail test-svn-fe -d preimage clear.onewindow 14 &&
+	test_must_fail test-svn-fe -d preimage clear.partialwindow 9
+'
+
+test_expect_success 'two-window empty delta' '
+	printf "SVNQ%s%s" "QQQQQ" "QQQQQ" | q_to_nul >clear.twowindow &&
+	test-svn-fe -d preimage clear.twowindow 14 >actual &&
+	test_must_fail test-svn-fe -d preimage clear.twowindow 13 &&
+	test_cmp empty actual
+'
+
+test_expect_success 'noisy zeroes' '
+	printf "SVNQ%s" \
+		"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQ" |
+		tr R "\200" |
+		q_to_nul >clear.noisy &&
+	len=$(wc -c <clear.noisy) &&
+	test-svn-fe -d preimage clear.noisy $len &&
+	test_cmp empty actual
+'
+
+test_expect_success 'reject variable-length int in magic' '
+	printf "SVNRQ" | tr R "\200" | q_to_nul >clear.badmagic &&
+	test_must_fail test-svn-fe -d preimage clear.badmagic 5
+'
+
+test_expect_success 'reject truncated integer' '
+	printf "SVNQ%s%s" "QQQQQ" "QQQQRRQ" |
+		tr R "\200" |
+		q_to_nul >clear.fullint &&
+	printf "SVNQ%s%s" "QQQQQ" "QQQQRR" |
+		tr RT "\201" |
+		q_to_nul >clear.partialint &&
+	test_must_fail test-svn-fe -d preimage clear.fullint 15 &&
+	test-svn-fe -d preimage clear.fullint 16 &&
+	test_must_fail test-svn-fe -d preimage clear.partialint 15
+'
+
+test_expect_success 'nonempty (but unused) preimage view' '
+	printf "SVNQ%b" "Q\003QQQ" | q_to_nul >clear.readpreimage &&
+	test-svn-fe -d preimage clear.readpreimage 9 >actual &&
+	test_cmp empty actual
+'
+
 test_done
diff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c
index 5916036..249efb6 100644
--- a/vcs-svn/svndiff.c
+++ b/vcs-svn/svndiff.c
@@ -13,8 +13,16 @@
  * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff.
  *
  * svndiff0 ::= 'SVN\0' window*
+ * window ::= int int int int int instructions inline_data;
+ * int ::= highdigit* lowdigit;
+ * highdigit ::= # binary 1000 0000 OR-ed with 7 bit value;
+ * lowdigit ::= # 7 bit value;
  */
 
+#define VLI_CONTINUE	0x80
+#define VLI_DIGIT_MASK	0x7f
+#define VLI_BITS_PER_DIGIT 7
+
 static int error_short_read(struct line_buffer *input)
 {
 	if (buffer_ferror(input))
@@ -28,17 +36,84 @@ static int read_magic(struct line_buffer *in, off_t *len)
 	struct strbuf sb = STRBUF_INIT;
 
 	if (*len < sizeof(magic) ||
-	    buffer_read_binary(in, &sb, sizeof(magic)) != sizeof(magic))
-		return error_short_read(in);
+	    buffer_read_binary(in, &sb, sizeof(magic)) != sizeof(magic)) {
+		error_short_read(in);
+		strbuf_release(&sb);
+		return -1;
+	}
 
-	if (memcmp(sb.buf, magic, sizeof(magic)))
+	if (memcmp(sb.buf, magic, sizeof(magic))) {
+		strbuf_release(&sb);
 		return error("invalid delta: unrecognized file type");
+	}
 
 	*len -= sizeof(magic);
 	strbuf_release(&sb);
 	return 0;
 }
 
+static int read_int(struct line_buffer *in, uintmax_t *result, off_t *len)
+{
+	uintmax_t rv = 0;
+	off_t sz;
+	for (sz = *len; sz; sz--) {
+		const int ch = buffer_read_char(in);
+		if (ch == EOF)
+			break;
+
+		rv <<= VLI_BITS_PER_DIGIT;
+		rv += (ch & VLI_DIGIT_MASK);
+		if (ch & VLI_CONTINUE)
+			continue;
+
+		*result = rv;
+		*len = sz - 1;
+		return 0;
+	}
+	return error_short_read(in);
+}
+
+static int read_offset(struct line_buffer *in, off_t *result, off_t *len)
+{
+	uintmax_t val;
+	if (read_int(in, &val, len))
+		return -1;
+	if (val > maximum_signed_value_of_type(off_t))
+		return error("unrepresentable offset in delta: %"PRIuMAX"", val);
+	*result = val;
+	return 0;
+}
+
+static int read_length(struct line_buffer *in, size_t *result, off_t *len)
+{
+	uintmax_t val;
+	if (read_int(in, &val, len))
+		return -1;
+	if (val > SIZE_MAX)
+		return error("unrepresentable length in delta: %"PRIuMAX"", val);
+	*result = val;
+	return 0;
+}
+
+static int apply_one_window(struct line_buffer *delta, off_t *delta_len)
+{
+	size_t out_len;
+	size_t instructions_len;
+	size_t data_len;
+	assert(delta_len);
+
+	/* "source view" offset and length already handled; */
+	if (read_length(delta, &out_len, delta_len) ||
+	    read_length(delta, &instructions_len, delta_len) ||
+	    read_length(delta, &data_len, delta_len))
+		return -1;
+	if (instructions_len)
+		return error("What do you think I am?  A delta applier?");
+	if (data_len)
+		return error("No support for inline data yet");
+	return 0;
+}
+
 int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
 			struct sliding_view *preimage, FILE *postimage)
 {
@@ -46,7 +121,14 @@ int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
 
 	if (read_magic(delta, &delta_len))
 		return -1;
-	if (delta_len)
-		return error("What do you think I am?  A delta applier?");
+	while (delta_len) {	/* For each window: */
+		off_t pre_off;
+		size_t pre_len;
+
+		if (read_offset(delta, &pre_off, &delta_len) ||
+		    read_length(delta, &pre_len, &delta_len) ||
+		    apply_one_window(delta, &delta_len))
+			return -1;
+	}
 	return 0;
 }
-- 
1.7.3.2.846.gf4b062
Previous: Jonathan NiederNext: David Barr
Message 29 of 72 in “vcs-svn: purge obsolete data structures and code”
  1. David BarrMar 19, 2011
  2. 1/9 vcs-svn: pass paths through to fast-importDavid Barr, Mar 19, 2011
  3. Jonathan NiederMar 19, 2011
  4. 2/9 vcs-svn: avoid using ls command twiceDavid Barr, Mar 19, 2011
  5. Jonathan NiederMar 19, 2011
  6. 3/9 vcs-svn: implement perfect hash for node-prop keysDavid Barr, Mar 19, 2011
  7. Jonathan NiederMar 19, 2011
  8. 1/3 vcs-svn: implement perfect hash for node-prop keysDavid Barr, Mar 21, 2011
  9. 2/3 vcs-svn: implement perfect hash for top-level keysDavid Barr, Mar 21, 2011
  10. 3/3 vcs-svn: use switch rather than cascading ifsDavid Barr, Mar 21, 2011
  11. [PATCHv2] vcs-svn: use switch rather than cascading ifsDavid Barr, Mar 21, 2011
  12. 4/9 vcs-svn: implement perfect hash for top-level keysDavid Barr, Mar 19, 2011
  13. Jonathan NiederMar 19, 2011
  14. 5/9 vcs-svn: factor out usage of string_poolDavid Barr, Mar 19, 2011
  15. Jonathan NiederMar 19, 2011
  16. 6/9 vcs-svn: drop string_poolDavid Barr, Mar 19, 2011
  17. 7/9 vcs-svn: drop trp.hDavid Barr, Mar 19, 2011
  18. 8/9 vcs-svn: drop obj_pool.hDavid Barr, Mar 19, 2011
  19. 9/9 vcs-svn: use strchr to find RFC822 delimiterDavid Barr, Mar 19, 2011
  20. Jonathan NiederMar 19, 2011
  21. vcs-svn: integrate support for text deltasDavid Barr, Mar 19, 2011
  22. 01/16 vcs-svn: improve support for reading large filesDavid Barr, Mar 19, 2011
  23. 02/16 vcs-svn: make buffer_skip_bytes return length readDavid Barr, Mar 19, 2011
  24. 03/16 vcs-svn: make buffer_copy_bytes return length readDavid Barr, Mar 19, 2011
  25. 04/16 vcs-svn: improve reporting of input errorsDavid Barr, Mar 19, 2011
  26. 05/16 vcs-svn: learn to maintain a sliding view of a fileDavid Barr, Mar 19, 2011
  27. 06/16 vcs-svn: skeleton of an svn delta parserDavid Barr, Mar 19, 2011
  28. Jonathan NiederMar 28, 2011
  29. 07/16 vcs-svn: parse svndiff0 window headerDavid Barr, Mar 19, 2011
  30. 08/16 vcs-svn: read the preimage when applying deltasDavid Barr, Mar 19, 2011
  31. 09/16 vcs-svn: read inline data from deltasDavid Barr, Mar 19, 2011
  32. 10/16 vcs-svn: read instructions from deltasDavid Barr, Mar 19, 2011
  33. 11/16 vcs-svn: implement copyfrom_data delta instructionDavid Barr, Mar 19, 2011
  34. 12/16 vcs-svn: verify that deltas consume all inline dataDavid Barr, Mar 19, 2011
  35. 13/16 vcs-svn: let deltas use data from postimageDavid Barr, Mar 19, 2011
  36. 14/16 vcs-svn: let deltas use data from preimageDavid Barr, Mar 19, 2011
  37. 15/16 vcs-svn: microcleanup in svndiff0 window-reading codeDavid Barr, Mar 19, 2011
  38. 16/16 vcs-svn: implement text-delta handlingDavid Barr, Mar 19, 2011
  39. Jonathan NiederMar 28, 2011
  40. David BarrMar 28, 2011
  41. 00/11 vcs-svn: purge obsolete data structures and codeDavid Barr, Mar 21, 2011
  42. 01/11 vcs-svn: use strbuf for revision logDavid Barr, Mar 21, 2011
  43. 02/11 vcs-svn: pass paths through to fast-importDavid Barr, Mar 21, 2011
  44. 03/11 vcs-svn: avoid using ls command twiceDavid Barr, Mar 21, 2011
  45. 04/11 vcs-svn: implement perfect hash for node-prop keysDavid Barr, Mar 21, 2011
  46. 05/11 vcs-svn: implement perfect hash for top-level keysDavid Barr, Mar 21, 2011
  47. 06/11 vcs-svn: use switch rather than cascading ifsDavid Barr, Mar 21, 2011
  48. 07/11 vcs-svn: factor out usage of string_poolDavid Barr, Mar 21, 2011
  49. 08/11 vcs-svn: drop string_poolDavid Barr, Mar 21, 2011
  50. =??q?=5BPATCH=2009/11=5D=20vcs-svn=3A=20drop=20trp=2Eh?=David Barr, Mar 21, 2011
  51. 10/11 vcs-svn: drop obj_pool.hDavid Barr, Mar 21, 2011
  52. 11/11 vcs-svn: use strchr to find RFC822 delimiterDavid Barr, Mar 21, 2011
  53. [PULL svn-fe] vcs-svn: simplifications, error handling improvementsJonathan Nieder, Mar 23, 2011
  54. Junio C HamanoMar 23, 2011
  55. Junio C HamanoMar 23, 2011
  56. Jonathan NiederMar 26, 2011
  57. t0081-line-buffer.sh hangs (Re: [PULL svn-fe] vcs-svn: simplifications, error handling improvements)Jonathan Nieder, Mar 26, 2011
  58. David BarrMar 23, 2011
  59. fixup! vcs-svn: improve reporting of input errorsDavid Barr, Mar 24, 2011
  60. Jonathan NiederMar 25, 2011
  61. 0/4 vcs-svn: null bytes in propertiesJonathan Nieder, Mar 25, 2011
  62. 1/4 vcs-svn: make reading of properties binary-safeJonathan Nieder, Mar 25, 2011
  63. tbMar 28, 2011
  64. Jonathan NiederMar 28, 2011
  65. Torsten BögershausenMar 28, 2011
  66. Jonathan NiederMar 28, 2011
  67. 2/4 vcs-svn: remove buffer_read_stringJonathan Nieder, Mar 25, 2011
  68. 3/4 vcs-svn: avoid unnecessary copying of log message and authorJonathan Nieder, Mar 25, 2011
  69. 4/4 vcs-svn: handle log message with embedded null bytesJonathan Nieder, Mar 25, 2011
  70. Jonathan NiederMar 26, 2011
  71. Junio C HamanoMar 26, 2011
  72. vcs-svn: add missing cast to printf argumentJonathan Nieder, Mar 28, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.