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

[PATCH 06/16] vcs-svn: skeleton of an svn delta parser

From
David Barr <david.barr@cordelta.com>
Date
Mar 19, 2011, 07:20 UTC
Message-ID
<1300519254-20201-7-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>

A delta in the subversion delta (svndiff0) format consists of the magic bytes SVN\0 followed by a sequence of windows of a certain well specified format (starting with five integers).

Add an svndiff0_apply function and test-svn-fe -d commandline tool to parse such a delta in the special case of not including any windows.

Later patches will add features to turn this into a fully functional delta applier for use by svn-fe in parsing the streams produced by "svnrdump dump" and "svnadmin dump --deltas".

The content of symlinks starts with the word "link " in Subversion's worldview, so we will need to prepend that text for the sake of delta application. Initialization of the input state of the delta preimage is left to the calling program, which gives callers a chance to seed the sliding window with text of their choice.

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>
---
 Makefile              |    4 +-
 t/t9011-svn-da.sh     |   37 ++++++++++++++++++++++++++++++++++
 test-svn-fe.c         |   42 ++++++++++++++++++++++++++++++++-------
 vcs-svn/line_buffer.c |    6 ++--
 vcs-svn/line_buffer.h |    2 +-
 vcs-svn/svndiff.c     |   52 +++++++++++++++++++++++++++++++++++++++++++++++++
 vcs-svn/svndiff.h     |   10 +++++++++
 7 files changed, 139 insertions(+), 14 deletions(-)
 create mode 100755 t/t9011-svn-da.sh
 create mode 100644 vcs-svn/svndiff.c
 create mode 100644 vcs-svn/svndiff.h
diff --git a/Makefile b/Makefile
index bac415d..bc6690a 100644
--- a/Makefile
+++ b/Makefile
@@ -1837,7 +1837,7 @@ XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
 	xdiff/xmerge.o xdiff/xpatience.o
 VCSSVN_OBJS = vcs-svn/line_buffer.o vcs-svn/repo_tree.o \
 	vcs-svn/fast_export.o vcs-svn/svndump.o \
-	vcs-svn/sliding_window.o
+	vcs-svn/sliding_window.o vcs-svn/svndiff.o
 VCSSVN_TEST_OBJS = test-obj-pool.o test-line-buffer.o test-treap.o
 OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)
 
@@ -1963,7 +1963,7 @@ xdiff-interface.o $(XDIFF_OBJS): \
 
 $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \
 	vcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \
-	vcs-svn/svndump.h vcs-svn/sliding_window.h
+	vcs-svn/sliding_window.h vcs-svn/svndiff.h vcs-svn/svndump.h
 
 test-svn-fe.o: vcs-svn/svndump.h
 endif
diff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh
new file mode 100755
index 0000000..6d6a406
--- /dev/null
+++ b/t/t9011-svn-da.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+test_description='test parsing of svndiff0 files
+
+Using the "test-svn-fe -d" helper, check that svn-fe correctly
+interprets deltas using various facilities (some from the spec,
+some only learned from practice).
+'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	>empty &&
+	printf foo >preimage
+'
+
+test_expect_success 'reject empty delta' '
+	test_must_fail test-svn-fe -d preimage empty 0
+'
+
+test_expect_success 'delta can empty file' '
+	printf "SVNQ" | q_to_nul >clear.delta &&
+	test-svn-fe -d preimage clear.delta 4 >actual &&
+	test_cmp empty actual
+'
+
+test_expect_success 'reject svndiff2' '
+	printf "SVN\002" >bad.filetype &&
+	test_must_fail test-svn-fe -d preimage bad.filetype 4
+'
+
+test_expect_failure '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_done
diff --git a/test-svn-fe.c b/test-svn-fe.c
index b42ba78..6558b52 100644
--- a/test-svn-fe.c
+++ b/test-svn-fe.c
@@ -4,15 +4,41 @@
 
 #include "git-compat-util.h"
 #include "vcs-svn/svndump.h"
+#include "vcs-svn/svndiff.h"
+#include "vcs-svn/sliding_window.h"
+#include "vcs-svn/line_buffer.h"
 
 int main(int argc, char *argv[])
 {
-	if (argc != 2)
-		usage("test-svn-fe <file>");
-	if (svndump_init(argv[1]))
-		return 1;
-	svndump_read(NULL);
-	svndump_deinit();
-	svndump_reset();
-	return 0;
+	static const char test_svnfe_usage[] =
+		"test-svn-fe (<dumpfile> | [-d] <preimage> <delta> <len>)";
+	if (argc == 2) {
+		if (svndump_init(argv[1]))
+			return 1;
+		svndump_read(NULL);
+		svndump_deinit();
+		svndump_reset();
+		return 0;
+	}
+	if (argc == 5 && !strcmp(argv[1], "-d")) {
+		struct line_buffer preimage = LINE_BUFFER_INIT;
+		struct line_buffer delta = LINE_BUFFER_INIT;
+		struct sliding_view preimage_view = SLIDING_VIEW_INIT(&preimage);
+		if (buffer_init(&preimage, argv[2]))
+			die_errno("cannot open preimage");
+		if (buffer_init(&delta, argv[3]))
+			die_errno("cannot open delta");
+		if (svndiff0_apply(&delta, (off_t) strtoull(argv[4], NULL, 0),
+				   &preimage_view, stdout))
+			return 1;
+		if (buffer_deinit(&preimage))
+			die_errno("cannot close preimage");
+		if (buffer_deinit(&delta))
+			die_errno("cannot close delta");
+		buffer_reset(&preimage);
+		strbuf_release(&preimage_view.buf);
+		buffer_reset(&delta);
+		return 0;
+	}
+	usage(test_svnfe_usage);
 }
diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c
index 08d7cae..2f59670 100644
--- a/vcs-svn/line_buffer.c
+++ b/vcs-svn/line_buffer.c
@@ -98,10 +98,10 @@ char *buffer_read_string(struct line_buffer *buf, uint32_t len)
 	return ferror(buf->infile) ? NULL : buf->blob_buffer.buf;
 }
 
-void buffer_read_binary(struct line_buffer *buf,
-				struct strbuf *sb, uint32_t size)
+off_t buffer_read_binary(struct line_buffer *buf,
+				struct strbuf *sb, off_t size)
 {
-	strbuf_fread(sb, size, buf->infile);
+	return strbuf_fread(sb, size, buf->infile);
 }
 
 off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)
diff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h
index f5c468a..a253070 100644
--- a/vcs-svn/line_buffer.h
+++ b/vcs-svn/line_buffer.h
@@ -25,7 +25,7 @@ int buffer_ferror(struct line_buffer *buf);
 char *buffer_read_line(struct line_buffer *buf);
 char *buffer_read_string(struct line_buffer *buf, uint32_t len);
 int buffer_read_char(struct line_buffer *buf);
-void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);
+off_t buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, off_t len);
 /* Returns number of bytes read (not necessarily written). */
 off_t buffer_copy_bytes(struct line_buffer *buf, off_t len);
 off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);
diff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c
new file mode 100644
index 0000000..5916036
--- /dev/null
+++ b/vcs-svn/svndiff.c
@@ -0,0 +1,52 @@
+/*
+ * Licensed under a two-clause BSD-style license.
+ * See LICENSE for details.
+ */
+
+#include "git-compat-util.h"
+#include "line_buffer.h"
+#include "svndiff.h"
+
+/*
+ * svndiff0 applier
+ *
+ * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff.
+ *
+ * svndiff0 ::= 'SVN\0' window*
+ */
+
+static int error_short_read(struct line_buffer *input)
+{
+	if (buffer_ferror(input))
+		return error("error reading delta: %s", strerror(errno));
+	return error("invalid delta: unexpected end of file");
+}
+
+static int read_magic(struct line_buffer *in, off_t *len)
+{
+	static const char magic[] = {'S', 'V', 'N', '\0'};
+	struct strbuf sb = STRBUF_INIT;
+
+	if (*len < sizeof(magic) ||
+	    buffer_read_binary(in, &sb, sizeof(magic)) != sizeof(magic))
+		return error_short_read(in);
+
+	if (memcmp(sb.buf, magic, sizeof(magic)))
+		return error("invalid delta: unrecognized file type");
+
+	*len -= sizeof(magic);
+	strbuf_release(&sb);
+	return 0;
+}
+
+int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
+			struct sliding_view *preimage, FILE *postimage)
+{
+	assert(delta && preimage && postimage);
+
+	if (read_magic(delta, &delta_len))
+		return -1;
+	if (delta_len)
+		return error("What do you think I am?  A delta applier?");
+	return 0;
+}
diff --git a/vcs-svn/svndiff.h b/vcs-svn/svndiff.h
new file mode 100644
index 0000000..74eb464
--- /dev/null
+++ b/vcs-svn/svndiff.h
@@ -0,0 +1,10 @@
+#ifndef SVNDIFF_H_
+#define SVNDIFF_H_
+
+struct line_buffer;
+struct sliding_view;
+
+extern int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
+		struct sliding_view *preimage, FILE *postimage);
+
+#endif
-- 
1.7.3.2.846.gf4b062
Previous: David BarrNext: Jonathan Nieder
Message 27 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.