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.
27 #include "got_error.h"
28 #include "got_repository.h"
29 #include "got_object.h"
32 #include "got_lib_delta.h"
33 #include "got_lib_inflate.h"
34 #include "got_lib_object.h"
37 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
41 got_delta_open(off_t offset
, size_t tslen
, int type
, size_t size
,
44 struct got_delta
*delta
;
46 delta
= malloc(sizeof(*delta
));
51 delta
->offset
= offset
;
54 delta
->data_offset
= data_offset
;
58 const struct got_error
*
59 got_delta_chain_get_base_type(int *type
, struct got_delta_chain
*deltas
)
61 struct got_delta
*delta
;
63 /* The first delta in the chain should represent the base object. */
64 delta
= STAILQ_FIRST(&deltas
->entries
);
65 if (delta
->type
== GOT_OBJ_TYPE_COMMIT
||
66 delta
->type
== GOT_OBJ_TYPE_TREE
||
67 delta
->type
== GOT_OBJ_TYPE_BLOB
||
68 delta
->type
== GOT_OBJ_TYPE_TAG
) {
73 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
76 /* Fetch another (required) byte from the delta stream. */
77 static const struct got_error
*
78 next_delta_byte(const uint8_t **p
, size_t *remain
)
81 return got_error_msg(GOT_ERR_BAD_DELTA
,
82 "delta data truncated");
87 static const struct got_error
*
88 parse_size(uint64_t *size
, const uint8_t **p
, size_t *remain
)
90 const struct got_error
*err
= NULL
;
95 /* We do not support size values which don't fit in 64 bit. */
97 return got_error(GOT_ERR_NO_SPACE
);
100 *size
= ((**p
) & GOT_DELTA_SIZE_VAL_MASK
);
102 size_t shift
= GOT_DELTA_SIZE_SHIFT
* i
;
103 *size
|= (((**p
) & GOT_DELTA_SIZE_VAL_MASK
) << shift
);
106 if (((**p
) & GOT_DELTA_SIZE_MORE
) == 0)
109 err
= next_delta_byte(p
, remain
);
110 } while (err
== NULL
);
115 static const struct got_error
*
116 parse_opcode(off_t
*offset
, size_t *len
, const uint8_t **p
, size_t *remain
)
118 const struct got_error
*err
= NULL
;
121 uint8_t opcode
= **p
;
123 if (opcode
& GOT_DELTA_COPY_OFF1
) {
124 err
= next_delta_byte(p
, remain
);
129 if (opcode
& GOT_DELTA_COPY_OFF2
) {
130 err
= next_delta_byte(p
, remain
);
133 o
|= ((off_t
)(**p
)) << 8;
135 if (opcode
& GOT_DELTA_COPY_OFF3
) {
136 err
= next_delta_byte(p
, remain
);
139 o
|= ((off_t
)(**p
)) << 16;
141 if (opcode
& GOT_DELTA_COPY_OFF4
) {
142 err
= next_delta_byte(p
, remain
);
145 o
|= ((off_t
)(**p
)) << 24;
148 if (opcode
& GOT_DELTA_COPY_LEN1
) {
149 err
= next_delta_byte(p
, remain
);
154 if (opcode
& GOT_DELTA_COPY_LEN2
) {
155 err
= next_delta_byte(p
, remain
);
158 l
|= ((off_t
)(**p
)) << 8;
160 if (opcode
& GOT_DELTA_COPY_LEN3
) {
161 err
= next_delta_byte(p
, remain
);
164 l
|= ((off_t
)(**p
)) << 16;
168 o
= GOT_DELTA_COPY_DEFAULT_OFF
;
170 l
= GOT_DELTA_COPY_DEFAULT_LEN
;
177 static const struct got_error
*
178 copy_from_base(FILE *base_file
, off_t offset
, size_t size
, FILE *outfile
)
180 if (fseeko(base_file
, offset
, SEEK_SET
) != 0)
181 return got_error_from_errno("fseeko");
185 size_t len
= MIN(size
, sizeof(data
));
188 n
= fread(data
, len
, 1, base_file
);
190 return got_ferror(base_file
, GOT_ERR_IO
);
192 n
= fwrite(data
, len
, 1, outfile
);
194 return got_ferror(outfile
, GOT_ERR_IO
);
202 static const struct got_error
*
203 copy_from_delta(const uint8_t **p
, size_t *remain
, size_t len
, FILE *outfile
)
208 return got_error_msg(GOT_ERR_BAD_DELTA
,
209 "copy from beyond end of delta data");
211 n
= fwrite(*p
, len
, 1, outfile
);
213 return got_ferror(outfile
, GOT_ERR_IO
);
220 static const struct got_error
*
221 parse_delta_sizes(uint64_t *base_size
, uint64_t *result_size
,
222 const uint8_t **p
, size_t *remain
)
224 const struct got_error
*err
;
226 /* Read the two size fields at the beginning of the stream. */
227 err
= parse_size(base_size
, p
, remain
);
230 err
= next_delta_byte(p
, remain
);
233 err
= parse_size(result_size
, p
, remain
);
240 const struct got_error
*
241 got_delta_get_sizes(uint64_t *base_size
, uint64_t *result_size
,
242 const uint8_t *delta_buf
, size_t delta_len
)
247 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
248 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
252 return parse_delta_sizes(base_size
, result_size
, &p
, &remain
);
255 const struct got_error
*
256 got_delta_apply_in_mem(uint8_t *base_buf
, size_t base_bufsz
,
257 const uint8_t *delta_buf
, size_t delta_len
, uint8_t *outbuf
,
258 size_t *outsize
, size_t maxoutsize
)
260 const struct got_error
*err
= NULL
;
261 uint64_t base_size
, result_size
;
267 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
268 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
272 err
= parse_delta_sizes(&base_size
, &result_size
, &p
, &remain
);
276 /* Decode and execute copy instructions from the delta stream. */
277 err
= next_delta_byte(&p
, &remain
);
278 while (err
== NULL
&& remain
> 0) {
279 if (*p
& GOT_DELTA_BASE_COPY
) {
282 err
= parse_opcode(&offset
, &len
, &p
, &remain
);
285 if (SIZE_MAX
- offset
< len
|| offset
+ len
< 0 ||
286 base_bufsz
< offset
+ len
||
287 *outsize
+ len
> maxoutsize
)
288 return got_error_msg(GOT_ERR_BAD_DELTA
,
289 "bad delta copy length");
290 memcpy(outbuf
+ *outsize
, base_buf
+ offset
, len
);
299 size_t len
= (size_t)*p
;
301 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
302 "zero length delta");
305 err
= next_delta_byte(&p
, &remain
);
308 if (remain
< len
|| SIZE_MAX
- *outsize
< len
||
309 *outsize
+ len
> maxoutsize
)
310 return got_error_msg(GOT_ERR_BAD_DELTA
,
311 "bad delta copy length");
312 memcpy(outbuf
+ *outsize
, p
, len
);
319 if (*outsize
!= result_size
)
320 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
321 "delta application result size mismatch");
325 const struct got_error
*
326 got_delta_apply(FILE *base_file
, const uint8_t *delta_buf
,
327 size_t delta_len
, FILE *outfile
, size_t *outsize
)
329 const struct got_error
*err
= NULL
;
330 uint64_t base_size
, result_size
;
333 FILE *memstream
= NULL
;
334 char *memstream_buf
= NULL
;
335 size_t memstream_size
= 0;
339 if (delta_len
< GOT_DELTA_STREAM_LENGTH_MIN
)
340 return got_error_msg(GOT_ERR_BAD_DELTA
, "delta too small");
344 err
= parse_delta_sizes(&base_size
, &result_size
, &p
, &remain
);
348 if (result_size
< GOT_DELTA_RESULT_SIZE_CACHED_MAX
)
349 memstream
= open_memstream(&memstream_buf
, &memstream_size
);
351 /* Decode and execute copy instructions from the delta stream. */
352 err
= next_delta_byte(&p
, &remain
);
353 while (err
== NULL
&& remain
> 0) {
354 if (*p
& GOT_DELTA_BASE_COPY
) {
357 err
= parse_opcode(&offset
, &len
, &p
, &remain
);
360 err
= copy_from_base(base_file
, offset
, len
,
361 memstream
? memstream
: outfile
);
370 size_t len
= (size_t)*p
;
372 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
373 "zero length delta");
376 err
= next_delta_byte(&p
, &remain
);
379 err
= copy_from_delta(&p
, &remain
, len
,
380 memstream
? memstream
: outfile
);
386 if (*outsize
!= result_size
)
387 err
= got_error_msg(GOT_ERR_BAD_DELTA
,
388 "delta application result size mismatch");
390 if (memstream
!= NULL
) {
391 if (fclose(memstream
) == EOF
)
392 err
= got_error_from_errno("fclose");
395 n
= fwrite(memstream_buf
, 1, memstream_size
, outfile
);
396 if (n
!= memstream_size
)
397 err
= got_ferror(outfile
, GOT_ERR_IO
);