2 * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <sys/queue.h>
28 #include "got_compat.h"
29 #include "got_error.h"
30 #include "got_repository.h"
31 #include "got_object.h"
34 #include "got_lib_delta.h"
35 #include "got_lib_inflate.h"
36 #include "got_lib_object.h"
39 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
43 got_delta_open(off_t offset
, size_t tslen
, int type
, size_t size
,
46 struct got_delta
*delta
;
48 delta
= malloc(sizeof(*delta
));
53 delta
->offset
= offset
;
56 delta
->data_offset
= data_offset
;
60 const struct got_error
*
61 got_delta_chain_get_base_type(int *type
, struct got_delta_chain
*deltas
)
63 struct got_delta
*delta
;
65 /* The first delta in the chain should represent the base object. */
66 delta
= STAILQ_FIRST(&deltas
->entries
);
67 if (delta
->type
== GOT_OBJ_TYPE_COMMIT
||
68 delta
->type
== GOT_OBJ_TYPE_TREE
||
69 delta
->type
== GOT_OBJ_TYPE_BLOB
||
70 delta
->type
== GOT_OBJ_TYPE_TAG
) {
75 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
78 /* Fetch another (required) byte from the delta stream. */
79 static const struct got_error
*
80 next_delta_byte(const uint8_t **p
, size_t *remain
)
83 return got_error_msg(GOT_ERR_BAD_DELTA
,
84 "delta data truncated");
89 static const struct got_error
*
90 parse_size(uint64_t *size
, const uint8_t **p
, size_t *remain
)
92 const struct got_error
*err
= NULL
;
97 /* We do not support size values which don't fit in 64 bit. */
99 return got_error(GOT_ERR_NO_SPACE
);
102 *size
= ((**p
) & GOT_DELTA_SIZE_VAL_MASK
);
104 size_t shift
= GOT_DELTA_SIZE_SHIFT
* i
;
105 *size
|= (((**p
) & GOT_DELTA_SIZE_VAL_MASK
) << shift
);
108 if (((**p
) & GOT_DELTA_SIZE_MORE
) == 0)
111 err
= next_delta_byte(p
, remain
);
112 } while (err
== NULL
);
117 static const struct got_error
*
118 parse_opcode(off_t
*offset
, size_t *len
, const uint8_t **p
, size_t *remain
)
120 const struct got_error
*err
= NULL
;
123 uint8_t opcode
= **p
;
125 if (opcode
& GOT_DELTA_COPY_OFF1
) {
126 err
= next_delta_byte(p
, remain
);
131 if (opcode
& GOT_DELTA_COPY_OFF2
) {
132 err
= next_delta_byte(p
, remain
);
135 o
|= ((off_t
)(**p
)) << 8;
137 if (opcode
& GOT_DELTA_COPY_OFF3
) {
138 err
= next_delta_byte(p
, remain
);
141 o
|= ((off_t
)(**p
)) << 16;
143 if (opcode
& GOT_DELTA_COPY_OFF4
) {
144 err
= next_delta_byte(p
, remain
);
147 o
|= ((off_t
)(**p
)) << 24;
150 if (opcode
& GOT_DELTA_COPY_LEN1
) {
151 err
= next_delta_byte(p
, remain
);
156 if (opcode
& GOT_DELTA_COPY_LEN2
) {
157 err
= next_delta_byte(p
, remain
);
160 l
|= ((off_t
)(**p
)) << 8;
162 if (opcode
& GOT_DELTA_COPY_LEN3
) {
163 err
= next_delta_byte(p
, remain
);
166 l
|= ((off_t
)(**p
)) << 16;
170 o
= GOT_DELTA_COPY_DEFAULT_OFF
;
172 l
= GOT_DELTA_COPY_DEFAULT_LEN
;
179 static const struct got_error
*
180 copy_from_base(FILE *base_file
, off_t offset
, size_t size
, FILE *outfile
)
182 if (fseeko(base_file
, offset
, SEEK_SET
) != 0)
183 return got_error_from_errno("fseeko");
187 size_t len
= MIN(size
, sizeof(data
));
190 n
= fread(data
, len
, 1, base_file
);
192 return got_ferror(base_file
, GOT_ERR_IO
);
194 n
= fwrite(data
, len
, 1, outfile
);
196 return got_ferror(outfile
, GOT_ERR_IO
);
204 static const struct got_error
*
205 copy_from_delta(const uint8_t **p
, size_t *remain
, size_t len
, FILE *outfile
)
210 return got_error_msg(GOT_ERR_BAD_DELTA
,
211 "copy from beyond end of delta data");
213 n
= fwrite(*p
, len
, 1, outfile
);
215 return got_ferror(outfile
, GOT_ERR_IO
);
222 static const struct got_error
*
223 parse_delta_sizes(uint64_t *base_size
, uint64_t *result_size
,
224 const uint8_t **p
, size_t *remain
)
226 const struct got_error
*err
;
228 /* Read the two size fields at the beginning of the stream. */
229 err
= parse_size(base_size
, p
, remain
);
232 err
= next_delta_byte(p
, remain
);
235 err
= parse_size(result_size
, p
, remain
);
242 const struct got_error
*
243 got_delta_get_sizes(uint64_t *base_size
, uint64_t *result_size
,
244 const uint8_t *delta_buf
, size_t delta_len
)
249 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
250 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
254 return parse_delta_sizes(base_size
, result_size
, &p
, &remain
);
257 const struct got_error
*
258 got_delta_apply_in_mem(uint8_t *base_buf
, size_t base_bufsz
,
259 const uint8_t *delta_buf
, size_t delta_len
, uint8_t *outbuf
,
260 size_t *outsize
, size_t maxoutsize
)
262 const struct got_error
*err
= NULL
;
263 uint64_t base_size
, result_size
;
269 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
270 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
274 err
= parse_delta_sizes(&base_size
, &result_size
, &p
, &remain
);
278 /* Decode and execute copy instructions from the delta stream. */
279 err
= next_delta_byte(&p
, &remain
);
280 while (err
== NULL
&& remain
> 0) {
281 if (*p
& GOT_DELTA_BASE_COPY
) {
284 err
= parse_opcode(&offset
, &len
, &p
, &remain
);
287 if (SIZE_MAX
- offset
< len
|| offset
+ len
< 0 ||
288 base_bufsz
< offset
+ len
||
289 *outsize
+ len
> maxoutsize
)
290 return got_error_msg(GOT_ERR_BAD_DELTA
,
291 "bad delta copy length");
292 memcpy(outbuf
+ *outsize
, base_buf
+ offset
, len
);
301 size_t len
= (size_t)*p
;
303 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
304 "zero length delta");
307 err
= next_delta_byte(&p
, &remain
);
310 if (remain
< len
|| SIZE_MAX
- *outsize
< len
||
311 *outsize
+ len
> maxoutsize
)
312 return got_error_msg(GOT_ERR_BAD_DELTA
,
313 "bad delta copy length");
314 memcpy(outbuf
+ *outsize
, p
, len
);
321 if (*outsize
!= result_size
)
322 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
323 "delta application result size mismatch");
327 const struct got_error
*
328 got_delta_apply(FILE *base_file
, const uint8_t *delta_buf
,
329 size_t delta_len
, FILE *outfile
, size_t *outsize
)
331 const struct got_error
*err
= NULL
;
332 uint64_t base_size
, result_size
;
335 FILE *memstream
= NULL
;
336 char *memstream_buf
= NULL
;
337 size_t memstream_size
= 0;
341 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
342 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
346 err
= parse_delta_sizes(&base_size
, &result_size
, &p
, &remain
);
350 if (result_size
< GOT_DELTA_RESULT_SIZE_CACHED_MAX
)
351 memstream
= open_memstream(&memstream_buf
, &memstream_size
);
353 /* Decode and execute copy instructions from the delta stream. */
354 err
= next_delta_byte(&p
, &remain
);
355 while (err
== NULL
&& remain
> 0) {
356 if (*p
& GOT_DELTA_BASE_COPY
) {
359 err
= parse_opcode(&offset
, &len
, &p
, &remain
);
362 err
= copy_from_base(base_file
, offset
, len
,
363 memstream
? memstream
: outfile
);
372 size_t len
= (size_t)*p
;
374 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
375 "zero length delta");
378 err
= next_delta_byte(&p
, &remain
);
381 err
= copy_from_delta(&p
, &remain
, len
,
382 memstream
? memstream
: outfile
);
388 if (*outsize
!= result_size
)
389 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
390 "delta application result size mismatch");
392 if (memstream
!= NULL
) {
393 if (fclose(memstream
) == EOF
)
394 err
= got_error_from_errno("fclose");
397 n
= fwrite(memstream_buf
, 1, memstream_size
, outfile
);
398 if (n
!= memstream_size
)
399 err
= got_ferror(outfile
, GOT_ERR_IO
);