vcs-svn: Add outfile option to buffer_copy_bytes()
[svn-fe.git] / sliding_window.c
blob5c0882803841bdd9590750a2a9398daae633ffc6
1 /*
2 * Licensed under a two-clause BSD-style license.
3 * See LICENSE for details.
4 */
6 #include "git-compat-util.h"
7 #include "sliding_window.h"
8 #include "line_buffer.h"
9 #include "strbuf.h"
11 static void strbuf_remove_from_left(struct strbuf *sb, size_t nbytes)
13 assert(nbytes <= sb->len);
14 memmove(sb->buf, sb->buf + nbytes, sb->len - nbytes);
15 strbuf_setlen(sb, sb->len - nbytes);
18 static int check_overflow(off_t a, size_t b)
20 if ((off_t) b < 0)
21 return error("Unrepresentable length: "
22 "%"PRIu64" > OFF_MAX", (uint64_t) b);
23 if (signed_add_overflows(a, (off_t) b))
24 return error("Unrepresentable offset: "
25 "%"PRIu64" + %"PRIu64" > OFF_MAX",
26 (uint64_t) a, (uint64_t) b);
27 return 0;
30 int move_window(struct view *view, off_t off, size_t len)
32 off_t file_offset;
33 assert(view && view->file);
34 assert(!check_overflow(view->off, view->buf.len));
36 if (check_overflow(off, len))
37 return -1;
38 if (off < view->off || off + len < view->off + view->buf.len)
39 return error("Invalid delta: window slides left");
41 file_offset = view->off + view->buf.len;
42 if (off < file_offset)
43 /* Move the overlapping region into place. */
44 strbuf_remove_from_left(&view->buf, off - view->off);
45 else
46 strbuf_setlen(&view->buf, 0);
47 if (off > file_offset) {
48 /* Seek ahead to skip the gap. */
49 const off_t gap = off - file_offset;
50 const off_t nread = buffer_skip_bytes(view->file, gap);
51 if (nread != gap) {
52 if (!buffer_ferror(view->file))
53 return error("Preimage ends early");
54 return error("Cannot seek forward in input: %s",
55 strerror(errno));
57 file_offset += gap;
59 buffer_read_binary(&view->buf, len - view->buf.len, view->file);
60 if (view->buf.len != len) {
61 if (!buffer_ferror(view->file))
62 return error("Preimage ends early");
63 return error("Cannot read preimage: %s", strerror(errno));
65 view->off = off;
66 return 0;