|
7 | 7 | #include "strbuf.h" |
8 | 8 | #include "quote.h" |
9 | 9 | #include "fast_export.h" |
10 | | -#include "line_buffer.h" |
11 | 10 | #include "repo_tree.h" |
12 | 11 | #include "strbuf.h" |
| 12 | +#include "svndiff.h" |
| 13 | +#include "sliding_window.h" |
| 14 | +#include "line_buffer.h" |
13 | 15 |
|
14 | 16 | #define MAX_GITSVN_LINE_LEN 4096 |
| 17 | +#define REPORT_FILENO 3 |
15 | 18 |
|
16 | 19 | static uint32_t first_commit_done; |
| 20 | +static struct line_buffer postimage = LINE_BUFFER_INIT; |
17 | 21 | static struct line_buffer report_buffer = LINE_BUFFER_INIT; |
18 | 22 |
|
| 23 | +/* NEEDSWORK: move to fast_export_init() */ |
| 24 | +static int init_postimage(void) |
| 25 | +{ |
| 26 | + static int postimage_initialized; |
| 27 | + if (postimage_initialized) |
| 28 | + return 0; |
| 29 | + postimage_initialized = 1; |
| 30 | + return buffer_tmpfile_init(&postimage); |
| 31 | +} |
| 32 | + |
| 33 | +static int init_report_buffer(int fd) |
| 34 | +{ |
| 35 | + static int report_buffer_initialized; |
| 36 | + if (report_buffer_initialized) |
| 37 | + return 0; |
| 38 | + report_buffer_initialized = 1; |
| 39 | + return buffer_fdinit(&report_buffer, fd); |
| 40 | +} |
| 41 | + |
19 | 42 | void fast_export_init(int fd) |
20 | 43 | { |
21 | 44 | if (buffer_fdinit(&report_buffer, fd)) |
@@ -132,6 +155,89 @@ static void die_short_read(struct line_buffer *input) |
132 | 155 | die("invalid dump: unexpected end of file"); |
133 | 156 | } |
134 | 157 |
|
| 158 | +static int ends_with(const char *s, size_t len, const char *suffix) |
| 159 | +{ |
| 160 | + const size_t suffixlen = strlen(suffix); |
| 161 | + if (len < suffixlen) |
| 162 | + return 0; |
| 163 | + return !memcmp(s + len - suffixlen, suffix, suffixlen); |
| 164 | +} |
| 165 | + |
| 166 | +static int parse_cat_response_line(const char *header, off_t *len) |
| 167 | +{ |
| 168 | + size_t headerlen = strlen(header); |
| 169 | + uintmax_t n; |
| 170 | + const char *type; |
| 171 | + const char *end; |
| 172 | + |
| 173 | + if (ends_with(header, headerlen, " missing")) |
| 174 | + return error("cat-blob reports missing blob: %s", header); |
| 175 | + type = memmem(header, headerlen, " blob ", strlen(" blob ")); |
| 176 | + if (!type) |
| 177 | + return error("cat-blob header has wrong object type: %s", header); |
| 178 | + n = strtoumax(type + strlen(" blob "), (char **) &end, 10); |
| 179 | + if (end == type + strlen(" blob ")) |
| 180 | + return error("cat-blob header does not contain length: %s", header); |
| 181 | + if (memchr(type + strlen(" blob "), '-', end - type - strlen(" blob "))) |
| 182 | + return error("cat-blob header contains negative length: %s", header); |
| 183 | + if (n == UINTMAX_MAX || n > maximum_signed_value_of_type(off_t)) |
| 184 | + return error("blob too large for current definition of off_t"); |
| 185 | + *len = n; |
| 186 | + if (*end) |
| 187 | + return error("cat-blob header contains garbage after length: %s", header); |
| 188 | + return 0; |
| 189 | +} |
| 190 | + |
| 191 | +static void check_preimage_overflow(off_t a, off_t b) |
| 192 | +{ |
| 193 | + if (signed_add_overflows(a, b)) |
| 194 | + die("blob too large for current definition of off_t"); |
| 195 | +} |
| 196 | + |
| 197 | +static long apply_delta(off_t len, struct line_buffer *input, |
| 198 | + const char *old_data, uint32_t old_mode) |
| 199 | +{ |
| 200 | + long ret; |
| 201 | + struct sliding_view preimage = SLIDING_VIEW_INIT(&report_buffer, 0); |
| 202 | + FILE *out; |
| 203 | + |
| 204 | + if (init_postimage() || !(out = buffer_tmpfile_rewind(&postimage))) |
| 205 | + die("cannot open temporary file for blob retrieval"); |
| 206 | + if (init_report_buffer(REPORT_FILENO)) |
| 207 | + die("cannot open fd 3 for feedback from fast-import"); |
| 208 | + if (old_data) { |
| 209 | + const char *response; |
| 210 | + printf("cat-blob %s\n", old_data); |
| 211 | + fflush(stdout); |
| 212 | + response = get_response_line(); |
| 213 | + if (parse_cat_response_line(response, &preimage.max_off)) |
| 214 | + die("invalid cat-blob response: %s", response); |
| 215 | + check_preimage_overflow(preimage.max_off, 1); |
| 216 | + } |
| 217 | + if (old_mode == REPO_MODE_LNK) { |
| 218 | + strbuf_addstr(&preimage.buf, "link "); |
| 219 | + check_preimage_overflow(preimage.max_off, strlen("link ")); |
| 220 | + preimage.max_off += strlen("link "); |
| 221 | + check_preimage_overflow(preimage.max_off, 1); |
| 222 | + } |
| 223 | + if (svndiff0_apply(input, len, &preimage, out)) |
| 224 | + die("cannot apply delta"); |
| 225 | + if (old_data) { |
| 226 | + /* Read the remainder of preimage and trailing newline. */ |
| 227 | + assert(!signed_add_overflows(preimage.max_off, 1)); |
| 228 | + preimage.max_off++; /* room for newline */ |
| 229 | + if (move_window(&preimage, preimage.max_off - 1, 1)) |
| 230 | + die("cannot seek to end of input"); |
| 231 | + if (preimage.buf.buf[0] != '\n') |
| 232 | + die("missing newline after cat-blob response"); |
| 233 | + } |
| 234 | + ret = buffer_tmpfile_prepare_to_read(&postimage); |
| 235 | + if (ret < 0) |
| 236 | + die("cannot read temporary file for blob retrieval"); |
| 237 | + strbuf_release(&preimage.buf); |
| 238 | + return ret; |
| 239 | +} |
| 240 | + |
135 | 241 | void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input) |
136 | 242 | { |
137 | 243 | if (mode == REPO_MODE_LNK) { |
@@ -199,3 +305,20 @@ int fast_export_ls(const char *path, uint32_t *mode, struct strbuf *dataref) |
199 | 305 | ls_from_active_commit(path); |
200 | 306 | return parse_ls_response(get_response_line(), mode, dataref); |
201 | 307 | } |
| 308 | + |
| 309 | +void fast_export_blob_delta(uint32_t mode, |
| 310 | + uint32_t old_mode, const char *old_data, |
| 311 | + uint32_t len, struct line_buffer *input) |
| 312 | +{ |
| 313 | + long postimage_len; |
| 314 | + if (len > maximum_signed_value_of_type(off_t)) |
| 315 | + die("enormous delta"); |
| 316 | + postimage_len = apply_delta((off_t) len, input, old_data, old_mode); |
| 317 | + if (mode == REPO_MODE_LNK) { |
| 318 | + buffer_skip_bytes(&postimage, strlen("link ")); |
| 319 | + postimage_len -= strlen("link "); |
| 320 | + } |
| 321 | + printf("data %ld\n", postimage_len); |
| 322 | + buffer_copy_bytes(&postimage, postimage_len); |
| 323 | + fputc('\n', stdout); |
| 324 | +} |
0 commit comments