summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: ddcc8c5)
raw | patch | inline | side by side (parent: ddcc8c5)
author | Jonathan Nieder <jrnieder@gmail.com> | |
Wed, 13 Oct 2010 09:21:43 +0000 (04:21 -0500) | ||
committer | Jonathan Nieder <jrnieder@gmail.com> | |
Mon, 28 Mar 2011 03:42:53 +0000 (22:42 -0500) |
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>
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>
t/t9011-svn-da.sh | patch | blob | history | |
vcs-svn/svndiff.c | patch | blob | history |
diff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh
index ee0c1e2087cf6c0d4061f9f30fa38b17e16827e8..be1234094fc5a5913955ce51973b59aae28f0206 100755 (executable)
--- a/t/t9011-svn-da.sh
+++ b/t/t9011-svn-da.sh
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 591603669c733e9b36ef614b72598ee6a0e5e235..249efb6eeda1b6fe7eff488cdeedbaf74fddff73 100644 (file)
--- a/vcs-svn/svndiff.c
+++ b/vcs-svn/svndiff.c
* 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))
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)
{
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;
}