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_error.h"
29 #include "got_repository.h"
30 #include "got_object.h"
33 #include "got_lib_delta.h"
34 #include "got_lib_inflate.h"
35 #include "got_lib_object.h"
38 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
42 got_delta_open(off_t offset
, size_t tslen
, int type
, size_t size
,
45 struct got_delta
*delta
;
47 delta
= malloc(sizeof(*delta
));
52 delta
->offset
= offset
;
55 delta
->data_offset
= data_offset
;
59 const struct got_error
*
60 got_delta_chain_get_base_type(int *type
, struct got_delta_chain
*deltas
)
62 struct got_delta
*delta
;
64 /* The first delta in the chain should represent the base object. */
65 delta
= STAILQ_FIRST(&deltas
->entries
);
66 if (delta
->type
== GOT_OBJ_TYPE_COMMIT
||
67 delta
->type
== GOT_OBJ_TYPE_TREE
||
68 delta
->type
== GOT_OBJ_TYPE_BLOB
||
69 delta
->type
== GOT_OBJ_TYPE_TAG
) {
74 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
77 /* Fetch another (required) byte from the delta stream. */
78 static const struct got_error
*
79 next_delta_byte(const uint8_t **p
, size_t *remain
)
82 return got_error_msg(GOT_ERR_BAD_DELTA
,
83 "delta data truncated");
88 static const struct got_error
*
89 parse_size(uint64_t *size
, const uint8_t **p
, size_t *remain
)
91 const struct got_error
*err
= NULL
;
96 /* We do not support size values which don't fit in 64 bit. */
98 return got_error(GOT_ERR_NO_SPACE
);
101 *size
= ((**p
) & GOT_DELTA_SIZE_VAL_MASK
);
103 size_t shift
= GOT_DELTA_SIZE_SHIFT
* i
;
104 *size
|= (((**p
) & GOT_DELTA_SIZE_VAL_MASK
) << shift
);
107 if (((**p
) & GOT_DELTA_SIZE_MORE
) == 0)
110 err
= next_delta_byte(p
, remain
);
111 } while (err
== NULL
);
116 static const struct got_error
*
117 parse_opcode(off_t
*offset
, size_t *len
, const uint8_t **p
, size_t *remain
)
119 const struct got_error
*err
= NULL
;
122 uint8_t opcode
= **p
;
124 if (opcode
& GOT_DELTA_COPY_OFF1
) {
125 err
= next_delta_byte(p
, remain
);
130 if (opcode
& GOT_DELTA_COPY_OFF2
) {
131 err
= next_delta_byte(p
, remain
);
134 o
|= ((off_t
)(**p
)) << 8;
136 if (opcode
& GOT_DELTA_COPY_OFF3
) {
137 err
= next_delta_byte(p
, remain
);
140 o
|= ((off_t
)(**p
)) << 16;
142 if (opcode
& GOT_DELTA_COPY_OFF4
) {
143 err
= next_delta_byte(p
, remain
);
146 o
|= ((off_t
)(**p
)) << 24;
149 if (opcode
& GOT_DELTA_COPY_LEN1
) {
150 err
= next_delta_byte(p
, remain
);
155 if (opcode
& GOT_DELTA_COPY_LEN2
) {
156 err
= next_delta_byte(p
, remain
);
159 l
|= ((off_t
)(**p
)) << 8;
161 if (opcode
& GOT_DELTA_COPY_LEN3
) {
162 err
= next_delta_byte(p
, remain
);
165 l
|= ((off_t
)(**p
)) << 16;
169 o
= GOT_DELTA_COPY_DEFAULT_OFF
;
171 l
= GOT_DELTA_COPY_DEFAULT_LEN
;
178 static const struct got_error
*
179 copy_from_base(FILE *base_file
, off_t offset
, size_t size
, FILE *outfile
)
181 if (fseeko(base_file
, offset
, SEEK_SET
) != 0)
182 return got_error_from_errno("fseeko");
186 size_t len
= MIN(size
, sizeof(data
));
189 n
= fread(data
, len
, 1, base_file
);
191 return got_ferror(base_file
, GOT_ERR_IO
);
193 n
= fwrite(data
, len
, 1, outfile
);
195 return got_ferror(outfile
, GOT_ERR_IO
);
203 static const struct got_error
*
204 copy_from_delta(const uint8_t **p
, size_t *remain
, size_t len
, FILE *outfile
)
209 return got_error_msg(GOT_ERR_BAD_DELTA
,
210 "copy from beyond end of delta data");
212 n
= fwrite(*p
, len
, 1, outfile
);
214 return got_ferror(outfile
, GOT_ERR_IO
);
221 static const struct got_error
*
222 parse_delta_sizes(uint64_t *base_size
, uint64_t *result_size
,
223 const uint8_t **p
, size_t *remain
)
225 const struct got_error
*err
;
227 /* Read the two size fields at the beginning of the stream. */
228 err
= parse_size(base_size
, p
, remain
);
231 err
= next_delta_byte(p
, remain
);
234 err
= parse_size(result_size
, p
, remain
);
241 const struct got_error
*
242 got_delta_get_sizes(uint64_t *base_size
, uint64_t *result_size
,
243 const uint8_t *delta_buf
, size_t delta_len
)
248 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
249 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
253 return parse_delta_sizes(base_size
, result_size
, &p
, &remain
);
256 const struct got_error
*
257 got_delta_apply_in_mem(uint8_t *base_buf
, size_t base_bufsz
,
258 const uint8_t *delta_buf
, size_t delta_len
, uint8_t *outbuf
,
259 size_t *outsize
, size_t maxoutsize
)
261 const struct got_error
*err
= NULL
;
262 uint64_t base_size
, result_size
;
268 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
269 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
273 err
= parse_delta_sizes(&base_size
, &result_size
, &p
, &remain
);
277 /* Decode and execute copy instructions from the delta stream. */
278 err
= next_delta_byte(&p
, &remain
);
279 while (err
== NULL
&& remain
> 0) {
280 if (*p
& GOT_DELTA_BASE_COPY
) {
283 err
= parse_opcode(&offset
, &len
, &p
, &remain
);
286 if (SIZE_MAX
- offset
< len
|| offset
+ len
< 0 ||
287 base_bufsz
< offset
+ len
||
288 *outsize
+ len
> maxoutsize
)
289 return got_error_msg(GOT_ERR_BAD_DELTA
,
290 "bad delta copy length");
291 memcpy(outbuf
+ *outsize
, base_buf
+ offset
, len
);
300 size_t len
= (size_t)*p
;
302 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
303 "zero length delta");
306 err
= next_delta_byte(&p
, &remain
);
309 if (remain
< len
|| SIZE_MAX
- *outsize
< len
||
310 *outsize
+ len
> maxoutsize
)
311 return got_error_msg(GOT_ERR_BAD_DELTA
,
312 "bad delta copy length");
313 memcpy(outbuf
+ *outsize
, p
, len
);
320 if (*outsize
!= result_size
)
321 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
322 "delta application result size mismatch");
326 const struct got_error
*
327 got_delta_apply(FILE *base_file
, const uint8_t *delta_buf
,
328 size_t delta_len
, FILE *outfile
, size_t *outsize
)
330 const struct got_error
*err
= NULL
;
331 uint64_t base_size
, result_size
;
334 FILE *memstream
= NULL
;
335 char *memstream_buf
= NULL
;
336 size_t memstream_size
= 0;
340 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
341 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
345 err
= parse_delta_sizes(&base_size
, &result_size
, &p
, &remain
);
349 if (result_size
< GOT_DELTA_RESULT_SIZE_CACHED_MAX
)
350 memstream
= open_memstream(&memstream_buf
, &memstream_size
);
352 /* Decode and execute copy instructions from the delta stream. */
353 err
= next_delta_byte(&p
, &remain
);
354 while (err
== NULL
&& remain
> 0) {
355 if (*p
& GOT_DELTA_BASE_COPY
) {
358 err
= parse_opcode(&offset
, &len
, &p
, &remain
);
361 err
= copy_from_base(base_file
, offset
, len
,
362 memstream
? memstream
: outfile
);
371 size_t len
= (size_t)*p
;
373 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
374 "zero length delta");
377 err
= next_delta_byte(&p
, &remain
);
380 err
= copy_from_delta(&p
, &remain
, len
,
381 memstream
? memstream
: outfile
);
387 if (*outsize
!= result_size
)
388 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
389 "delta application result size mismatch");
391 if (memstream
!= NULL
) {
392 if (fclose(memstream
) == EOF
)
393 err
= got_error_from_errno("fclose");
396 n
= fwrite(memstream_buf
, 1, memstream_size
, outfile
);
397 if (n
!= memstream_size
)
398 err
= got_ferror(outfile
, GOT_ERR_IO
);