]>
Commit | Line | Data |
---|---|---|
9d2f5ddf JN |
1 | /* |
2 | * Licensed under a two-clause BSD-style license. | |
3 | * See LICENSE for details. | |
4 | */ | |
5 | ||
6 | #include "git-compat-util.h" | |
7 | #include "sliding_window.h" | |
8 | #include "line_buffer.h" | |
9 | #include "strbuf.h" | |
10 | ||
11 | static int input_error(struct line_buffer *file) | |
12 | { | |
13 | if (!buffer_ferror(file)) | |
14 | return error("delta preimage ends early"); | |
1c8ead97 | 15 | return error_errno("cannot read delta preimage"); |
9d2f5ddf JN |
16 | } |
17 | ||
18 | static int skip_or_whine(struct line_buffer *file, off_t gap) | |
19 | { | |
20 | if (buffer_skip_bytes(file, gap) != gap) | |
21 | return input_error(file); | |
22 | return 0; | |
23 | } | |
24 | ||
25 | static int read_to_fill_or_whine(struct line_buffer *file, | |
26 | struct strbuf *buf, size_t width) | |
27 | { | |
28 | buffer_read_binary(file, buf, width - buf->len); | |
29 | if (buf->len != width) | |
30 | return input_error(file); | |
31 | return 0; | |
32 | } | |
33 | ||
5b8bf029 | 34 | static int check_offset_overflow(off_t offset, uintmax_t len) |
9d2f5ddf | 35 | { |
ce8ebcda | 36 | if (len > maximum_signed_value_of_type(off_t)) |
9d2f5ddf | 37 | return error("unrepresentable length in delta: " |
5b8bf029 | 38 | "%"PRIuMAX" > OFF_MAX", len); |
ce8ebcda | 39 | if (signed_add_overflows(offset, (off_t) len)) |
9d2f5ddf JN |
40 | return error("unrepresentable offset in delta: " |
41 | "%"PRIuMAX" + %"PRIuMAX" > OFF_MAX", | |
5b8bf029 | 42 | (uintmax_t) offset, len); |
9d2f5ddf JN |
43 | return 0; |
44 | } | |
45 | ||
46 | int move_window(struct sliding_view *view, off_t off, size_t width) | |
47 | { | |
48 | off_t file_offset; | |
49 | assert(view); | |
50 | assert(view->width <= view->buf.len); | |
ce8ebcda | 51 | assert(!check_offset_overflow(view->off, view->buf.len)); |
9d2f5ddf | 52 | |
ce8ebcda | 53 | if (check_offset_overflow(off, width)) |
9d2f5ddf JN |
54 | return -1; |
55 | if (off < view->off || off + width < view->off + view->width) | |
56 | return error("invalid delta: window slides left"); | |
c68038ef | 57 | if (view->max_off >= 0 && view->max_off < off + (off_t) width) |
fbdd4f6f | 58 | return error("delta preimage ends early"); |
9d2f5ddf JN |
59 | |
60 | file_offset = view->off + view->buf.len; | |
61 | if (off < file_offset) { | |
62 | /* Move the overlapping region into place. */ | |
63 | strbuf_remove(&view->buf, 0, off - view->off); | |
64 | } else { | |
65 | /* Seek ahead to skip the gap. */ | |
66 | if (skip_or_whine(view->file, off - file_offset)) | |
67 | return -1; | |
68 | strbuf_setlen(&view->buf, 0); | |
69 | } | |
70 | ||
71 | if (view->buf.len > width) | |
72 | ; /* Already read. */ | |
73 | else if (read_to_fill_or_whine(view->file, &view->buf, width)) | |
74 | return -1; | |
75 | ||
76 | view->off = off; | |
77 | view->width = width; | |
78 | return 0; | |
79 | } |