summaryrefslogtreecommitdiff
path: root/vcs-svn/sliding_window.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2012-01-27 11:04:28 -0800
committerJunio C Hamano <gitster@pobox.com>2012-01-27 11:20:00 -0800
commitd47553665833935157292a71248278a40e32c320 (patch)
tree13a04cd180ad12b34dbf8cefba185f0c3ec65db9 /vcs-svn/sliding_window.c
parent69204d0ab18d28d07ee2c8c9b50bbf5bd80343ab (diff)
parentc5bcbcdcfa1e2a1977497cb3a342c0365c8d78d6 (diff)
downloadgit-d47553665833935157292a71248278a40e32c320.tar.gz
Merge branch 'svn-fe' of git://repo.or.cz/git/jrn into jn/svn-fe
This simplifies svn-fe a great deal and fulfills a longstanding wish: support for dumps with deltas in them, and incremental imports. The cost is that commandline usage of the svn-fe tool becomes a little more complicated since it no longer keeps state itself but instead reads blobs back from fast-import in order to copy them between revisions and apply deltas to them. Also removes a couple of custom data structures and replaces them with strbufs like other parts of Git. * 'svn-fe' of git://repo.or.cz/git/jrn: (32 commits) vcs-svn: reset first_commit_done in fast_export_init vcs-svn: do not initialize report_buffer twice vcs-svn: avoid hangs from corrupt deltas vcs-svn: guard against overflow when computing preimage length vcs-svn: cap number of bytes read from sliding view test-svn-fe: split off "test-svn-fe -d" into a separate function vcs-svn: implement text-delta handling vcs-svn: let deltas use data from preimage vcs-svn: let deltas use data from postimage vcs-svn: verify that deltas consume all inline data vcs-svn: implement copyfrom_data delta instruction vcs-svn: read instructions from deltas vcs-svn: read inline data from deltas vcs-svn: read the preimage when applying deltas vcs-svn: parse svndiff0 window header vcs-svn: skeleton of an svn delta parser vcs-svn: make buffer_read_binary API more convenient vcs-svn: learn to maintain a sliding view of a file Makefile: list one vcs-svn/xdiff object or header per line vcs-svn: avoid using ls command twice ... Conflicts: Makefile contrib/svn-fe/svn-fe.txt
Diffstat (limited to 'vcs-svn/sliding_window.c')
-rw-r--r--vcs-svn/sliding_window.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c
new file mode 100644
index 0000000000..1bac7a4c7f
--- /dev/null
+++ b/vcs-svn/sliding_window.c
@@ -0,0 +1,79 @@
+/*
+ * Licensed under a two-clause BSD-style license.
+ * See LICENSE for details.
+ */
+
+#include "git-compat-util.h"
+#include "sliding_window.h"
+#include "line_buffer.h"
+#include "strbuf.h"
+
+static int input_error(struct line_buffer *file)
+{
+ if (!buffer_ferror(file))
+ return error("delta preimage ends early");
+ return error("cannot read delta preimage: %s", strerror(errno));
+}
+
+static int skip_or_whine(struct line_buffer *file, off_t gap)
+{
+ if (buffer_skip_bytes(file, gap) != gap)
+ return input_error(file);
+ return 0;
+}
+
+static int read_to_fill_or_whine(struct line_buffer *file,
+ struct strbuf *buf, size_t width)
+{
+ buffer_read_binary(file, buf, width - buf->len);
+ if (buf->len != width)
+ return input_error(file);
+ return 0;
+}
+
+static int check_overflow(off_t a, size_t b)
+{
+ if (b > maximum_signed_value_of_type(off_t))
+ return error("unrepresentable length in delta: "
+ "%"PRIuMAX" > OFF_MAX", (uintmax_t) b);
+ if (signed_add_overflows(a, (off_t) b))
+ return error("unrepresentable offset in delta: "
+ "%"PRIuMAX" + %"PRIuMAX" > OFF_MAX",
+ (uintmax_t) a, (uintmax_t) b);
+ return 0;
+}
+
+int move_window(struct sliding_view *view, off_t off, size_t width)
+{
+ off_t file_offset;
+ assert(view);
+ assert(view->width <= view->buf.len);
+ assert(!check_overflow(view->off, view->buf.len));
+
+ if (check_overflow(off, width))
+ return -1;
+ if (off < view->off || off + width < view->off + view->width)
+ return error("invalid delta: window slides left");
+ if (view->max_off >= 0 && view->max_off < off + width)
+ return error("delta preimage ends early");
+
+ file_offset = view->off + view->buf.len;
+ if (off < file_offset) {
+ /* Move the overlapping region into place. */
+ strbuf_remove(&view->buf, 0, off - view->off);
+ } else {
+ /* Seek ahead to skip the gap. */
+ if (skip_or_whine(view->file, off - file_offset))
+ return -1;
+ strbuf_setlen(&view->buf, 0);
+ }
+
+ if (view->buf.len > width)
+ ; /* Already read. */
+ else if (read_to_fill_or_whine(view->file, &view->buf, width))
+ return -1;
+
+ view->off = off;
+ view->width = width;
+ return 0;
+}