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>
29 #include "got_compat.h"
30 #include "got_error.h"
31 #include "got_repository.h"
32 #include "got_object.h"
35 #include "got_lib_delta.h"
36 #include "got_lib_inflate.h"
37 #include "got_lib_object.h"
40 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
44 got_delta_open(off_t offset
, size_t tslen
, int type
, size_t size
,
47 struct got_delta
*delta
;
49 delta
= malloc(sizeof(*delta
));
54 delta
->offset
= offset
;
57 delta
->data_offset
= data_offset
;
61 const struct got_error
*
62 got_delta_chain_get_base_type(int *type
, struct got_delta_chain
*deltas
)
64 struct got_delta
*delta
;
66 /* The first delta in the chain should represent the base object. */
67 delta
= STAILQ_FIRST(&deltas
->entries
);
68 if (delta
->type
== GOT_OBJ_TYPE_COMMIT
||
69 delta
->type
== GOT_OBJ_TYPE_TREE
||
70 delta
->type
== GOT_OBJ_TYPE_BLOB
||
71 delta
->type
== GOT_OBJ_TYPE_TAG
) {
76 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
79 /* Fetch another (required) byte from the delta stream. */
80 static const struct got_error
*
81 next_delta_byte(const uint8_t **p
, size_t *remain
)
84 return got_error_msg(GOT_ERR_BAD_DELTA
,
85 "delta data truncated");
90 static const struct got_error
*
91 parse_size(uint64_t *size
, const uint8_t **p
, size_t *remain
)
93 const struct got_error
*err
= NULL
;
98 /* We do not support size values which don't fit in 64 bit. */
100 return got_error(GOT_ERR_NO_SPACE
);
103 *size
= ((**p
) & GOT_DELTA_SIZE_VAL_MASK
);
105 size_t shift
= GOT_DELTA_SIZE_SHIFT
* i
;
106 *size
|= (((**p
) & GOT_DELTA_SIZE_VAL_MASK
) << shift
);
109 if (((**p
) & GOT_DELTA_SIZE_MORE
) == 0)
112 err
= next_delta_byte(p
, remain
);
113 } while (err
== NULL
);
118 static const struct got_error
*
119 parse_opcode(off_t
*offset
, size_t *len
, const uint8_t **p
, size_t *remain
)
121 const struct got_error
*err
= NULL
;
124 uint8_t opcode
= **p
;
126 if (opcode
& GOT_DELTA_COPY_OFF1
) {
127 err
= next_delta_byte(p
, remain
);
132 if (opcode
& GOT_DELTA_COPY_OFF2
) {
133 err
= next_delta_byte(p
, remain
);
136 o
|= ((off_t
)(**p
)) << 8;
138 if (opcode
& GOT_DELTA_COPY_OFF3
) {
139 err
= next_delta_byte(p
, remain
);
142 o
|= ((off_t
)(**p
)) << 16;
144 if (opcode
& GOT_DELTA_COPY_OFF4
) {
145 err
= next_delta_byte(p
, remain
);
148 o
|= ((off_t
)(**p
)) << 24;
151 if (opcode
& GOT_DELTA_COPY_LEN1
) {
152 err
= next_delta_byte(p
, remain
);
157 if (opcode
& GOT_DELTA_COPY_LEN2
) {
158 err
= next_delta_byte(p
, remain
);
161 l
|= ((off_t
)(**p
)) << 8;
163 if (opcode
& GOT_DELTA_COPY_LEN3
) {
164 err
= next_delta_byte(p
, remain
);
167 l
|= ((off_t
)(**p
)) << 16;
171 o
= GOT_DELTA_COPY_DEFAULT_OFF
;
173 l
= GOT_DELTA_COPY_DEFAULT_LEN
;
180 static const struct got_error
*
181 copy_from_base(FILE *base_file
, off_t offset
, size_t size
, FILE *outfile
)
183 if (fseeko(base_file
, offset
, SEEK_SET
) != 0)
184 return got_error_from_errno("fseeko");
188 size_t len
= MIN(size
, sizeof(data
));
191 n
= fread(data
, len
, 1, base_file
);
193 return got_ferror(base_file
, GOT_ERR_IO
);
195 n
= fwrite(data
, len
, 1, outfile
);
197 return got_ferror(outfile
, GOT_ERR_IO
);
205 static const struct got_error
*
206 copy_from_delta(const uint8_t **p
, size_t *remain
, size_t len
, FILE *outfile
)
211 return got_error_msg(GOT_ERR_BAD_DELTA
,
212 "copy from beyond end of delta data");
214 n
= fwrite(*p
, len
, 1, outfile
);
216 return got_ferror(outfile
, GOT_ERR_IO
);
223 static const struct got_error
*
224 parse_delta_sizes(uint64_t *base_size
, uint64_t *result_size
,
225 const uint8_t **p
, size_t *remain
)
227 const struct got_error
*err
;
229 /* Read the two size fields at the beginning of the stream. */
230 err
= parse_size(base_size
, p
, remain
);
233 err
= next_delta_byte(p
, remain
);
236 err
= parse_size(result_size
, p
, remain
);
243 const struct got_error
*
244 got_delta_get_sizes(uint64_t *base_size
, uint64_t *result_size
,
245 const uint8_t *delta_buf
, size_t delta_len
)
250 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
251 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
255 return parse_delta_sizes(base_size
, result_size
, &p
, &remain
);
258 const struct got_error
*
259 got_delta_apply_in_mem(uint8_t *base_buf
, size_t base_bufsz
,
260 const uint8_t *delta_buf
, size_t delta_len
, uint8_t *outbuf
,
261 size_t *outsize
, size_t maxoutsize
)
263 const struct got_error
*err
= NULL
;
264 uint64_t base_size
, result_size
;
270 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
271 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
275 err
= parse_delta_sizes(&base_size
, &result_size
, &p
, &remain
);
279 /* Decode and execute copy instructions from the delta stream. */
280 err
= next_delta_byte(&p
, &remain
);
281 while (err
== NULL
&& remain
> 0) {
282 if (*p
& GOT_DELTA_BASE_COPY
) {
285 err
= parse_opcode(&offset
, &len
, &p
, &remain
);
288 if (SIZE_MAX
- offset
< len
|| offset
+ len
< 0 ||
289 base_bufsz
< offset
+ len
||
290 *outsize
+ len
> maxoutsize
)
291 return got_error_msg(GOT_ERR_BAD_DELTA
,
292 "bad delta copy length");
293 memcpy(outbuf
+ *outsize
, base_buf
+ offset
, len
);
302 size_t len
= (size_t)*p
;
304 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
305 "zero length delta");
308 err
= next_delta_byte(&p
, &remain
);
311 if (remain
< len
|| SIZE_MAX
- *outsize
< len
||
312 *outsize
+ len
> maxoutsize
)
313 return got_error_msg(GOT_ERR_BAD_DELTA
,
314 "bad delta copy length");
315 memcpy(outbuf
+ *outsize
, p
, len
);
322 if (*outsize
!= result_size
)
323 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
324 "delta application result size mismatch");
328 const struct got_error
*
329 got_delta_apply(FILE *base_file
, const uint8_t *delta_buf
,
330 size_t delta_len
, FILE *outfile
, size_t *outsize
)
332 const struct got_error
*err
= NULL
;
333 uint64_t base_size
, result_size
;
336 FILE *memstream
= NULL
;
337 char *memstream_buf
= NULL
;
338 size_t memstream_size
= 0;
342 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
343 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
347 err
= parse_delta_sizes(&base_size
, &result_size
, &p
, &remain
);
351 if (result_size
< GOT_DELTA_RESULT_SIZE_CACHED_MAX
)
352 memstream
= open_memstream(&memstream_buf
, &memstream_size
);
354 /* Decode and execute copy instructions from the delta stream. */
355 err
= next_delta_byte(&p
, &remain
);
356 while (err
== NULL
&& remain
> 0) {
357 if (*p
& GOT_DELTA_BASE_COPY
) {
360 err
= parse_opcode(&offset
, &len
, &p
, &remain
);
363 err
= copy_from_base(base_file
, offset
, len
,
364 memstream
? memstream
: outfile
);
373 size_t len
= (size_t)*p
;
375 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
376 "zero length delta");
379 err
= next_delta_byte(&p
, &remain
);
382 err
= copy_from_delta(&p
, &remain
, len
,
383 memstream
? memstream
: outfile
);
389 if (*outsize
!= result_size
)
390 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
391 "delta application result size mismatch");
393 if (memstream
!= NULL
) {
394 if (fclose(memstream
) == EOF
)
395 err
= got_error_from_errno("fclose");
398 n
= fwrite(memstream_buf
, 1, memstream_size
, outfile
);
399 if (n
!= memstream_size
)
400 err
= got_ferror(outfile
, GOT_ERR_IO
);