File: | gotadmin/../lib/pack.c |
Warning: | line 806, column 9 6th function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org> | |||
3 | * | |||
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. | |||
7 | * | |||
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. | |||
15 | */ | |||
16 | ||||
17 | #include <sys/types.h> | |||
18 | #include <sys/stat.h> | |||
19 | #include <sys/queue.h> | |||
20 | #include <sys/uio.h> | |||
21 | #include <sys/mman.h> | |||
22 | ||||
23 | #include <fcntl.h> | |||
24 | #include <errno(*__errno()).h> | |||
25 | #include <stdio.h> | |||
26 | #include <stdint.h> | |||
27 | #include <stdlib.h> | |||
28 | #include <string.h> | |||
29 | #include <limits.h> | |||
30 | #include <sha1.h> | |||
31 | #include <endian.h> | |||
32 | #include <unistd.h> | |||
33 | #include <zlib.h> | |||
34 | #include <imsg.h> | |||
35 | ||||
36 | #include "got_error.h" | |||
37 | #include "got_object.h" | |||
38 | #include "got_opentemp.h" | |||
39 | #include "got_path.h" | |||
40 | ||||
41 | #include "got_lib_sha1.h" | |||
42 | #include "got_lib_delta.h" | |||
43 | #include "got_lib_delta_cache.h" | |||
44 | #include "got_lib_inflate.h" | |||
45 | #include "got_lib_object.h" | |||
46 | #include "got_lib_object_parse.h" | |||
47 | #include "got_lib_privsep.h" | |||
48 | #include "got_lib_pack.h" | |||
49 | ||||
50 | #ifndef nitems | |||
51 | #define nitems(_a)(sizeof(_a) / sizeof((_a)[0])) (sizeof(_a) / sizeof((_a)[0])) | |||
52 | #endif | |||
53 | ||||
54 | #ifndef MIN | |||
55 | #define MIN(_a,_b)((_a) < (_b) ? (_a) : (_b)) ((_a) < (_b) ? (_a) : (_b)) | |||
56 | #endif | |||
57 | ||||
58 | static const struct got_error * | |||
59 | verify_fanout_table(uint32_t *fanout_table) | |||
60 | { | |||
61 | int i; | |||
62 | ||||
63 | for (i = 0; i < 0xff - 1; i++) { | |||
64 | if (be32toh(fanout_table[i])(__uint32_t)(__builtin_constant_p(fanout_table[i]) ? (__uint32_t )(((__uint32_t)(fanout_table[i]) & 0xff) << 24 | (( __uint32_t)(fanout_table[i]) & 0xff00) << 8 | ((__uint32_t )(fanout_table[i]) & 0xff0000) >> 8 | ((__uint32_t) (fanout_table[i]) & 0xff000000) >> 24) : __swap32md (fanout_table[i])) > be32toh(fanout_table[i + 1])(__uint32_t)(__builtin_constant_p(fanout_table[i + 1]) ? (__uint32_t )(((__uint32_t)(fanout_table[i + 1]) & 0xff) << 24 | ((__uint32_t)(fanout_table[i + 1]) & 0xff00) << 8 | ((__uint32_t)(fanout_table[i + 1]) & 0xff0000) >> 8 | ((__uint32_t)(fanout_table[i + 1]) & 0xff000000) >> 24) : __swap32md(fanout_table[i + 1]))) | |||
65 | return got_error(GOT_ERR_BAD_PACKIDX14); | |||
66 | } | |||
67 | ||||
68 | return NULL((void *)0); | |||
69 | } | |||
70 | ||||
71 | const struct got_error * | |||
72 | got_packidx_init_hdr(struct got_packidx *p, int verify) | |||
73 | { | |||
74 | const struct got_error *err = NULL((void *)0); | |||
75 | struct got_packidx_v2_hdr *h; | |||
76 | SHA1_CTX ctx; | |||
77 | uint8_t sha1[SHA1_DIGEST_LENGTH20]; | |||
78 | size_t nobj, len_fanout, len_ids, offset, remain; | |||
79 | ssize_t n; | |||
80 | int i; | |||
81 | ||||
82 | SHA1Init(&ctx); | |||
83 | ||||
84 | h = &p->hdr; | |||
85 | offset = 0; | |||
86 | remain = p->len; | |||
87 | ||||
88 | if (remain < sizeof(*h->magic)) { | |||
89 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
90 | goto done; | |||
91 | } | |||
92 | if (p->map) | |||
93 | h->magic = (uint32_t *)(p->map + offset); | |||
94 | else { | |||
95 | h->magic = malloc(sizeof(*h->magic)); | |||
96 | if (h->magic == NULL((void *)0)) { | |||
97 | err = got_error_from_errno("malloc"); | |||
98 | goto done; | |||
99 | } | |||
100 | n = read(p->fd, h->magic, sizeof(*h->magic)); | |||
101 | if (n < 0) { | |||
102 | err = got_error_from_errno("read"); | |||
103 | goto done; | |||
104 | } else if (n != sizeof(*h->magic)) { | |||
105 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
106 | goto done; | |||
107 | } | |||
108 | } | |||
109 | if (*h->magic != htobe32(GOT_PACKIDX_V2_MAGIC)(__uint32_t)(__builtin_constant_p(0xff744f63) ? (__uint32_t)( ((__uint32_t)(0xff744f63) & 0xff) << 24 | ((__uint32_t )(0xff744f63) & 0xff00) << 8 | ((__uint32_t)(0xff744f63 ) & 0xff0000) >> 8 | ((__uint32_t)(0xff744f63) & 0xff000000) >> 24) : __swap32md(0xff744f63))) { | |||
110 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
111 | goto done; | |||
112 | } | |||
113 | offset += sizeof(*h->magic); | |||
114 | remain -= sizeof(*h->magic); | |||
115 | ||||
116 | if (verify) | |||
117 | SHA1Update(&ctx, (uint8_t *)h->magic, sizeof(*h->magic)); | |||
118 | ||||
119 | if (remain < sizeof(*h->version)) { | |||
120 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
121 | goto done; | |||
122 | } | |||
123 | if (p->map) | |||
124 | h->version = (uint32_t *)(p->map + offset); | |||
125 | else { | |||
126 | h->version = malloc(sizeof(*h->version)); | |||
127 | if (h->version == NULL((void *)0)) { | |||
128 | err = got_error_from_errno("malloc"); | |||
129 | goto done; | |||
130 | } | |||
131 | n = read(p->fd, h->version, sizeof(*h->version)); | |||
132 | if (n < 0) { | |||
133 | err = got_error_from_errno("read"); | |||
134 | goto done; | |||
135 | } else if (n != sizeof(*h->version)) { | |||
136 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
137 | goto done; | |||
138 | } | |||
139 | } | |||
140 | if (*h->version != htobe32(GOT_PACKIDX_VERSION)(__uint32_t)(__builtin_constant_p(2) ? (__uint32_t)(((__uint32_t )(2) & 0xff) << 24 | ((__uint32_t)(2) & 0xff00) << 8 | ((__uint32_t)(2) & 0xff0000) >> 8 | ( (__uint32_t)(2) & 0xff000000) >> 24) : __swap32md(2 ))) { | |||
141 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
142 | goto done; | |||
143 | } | |||
144 | offset += sizeof(*h->version); | |||
145 | remain -= sizeof(*h->version); | |||
146 | ||||
147 | if (verify) | |||
148 | SHA1Update(&ctx, (uint8_t *)h->version, sizeof(*h->version)); | |||
149 | ||||
150 | len_fanout = | |||
151 | sizeof(*h->fanout_table) * GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS(0xff + 1); | |||
152 | if (remain < len_fanout) { | |||
153 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
154 | goto done; | |||
155 | } | |||
156 | if (p->map) | |||
157 | h->fanout_table = (uint32_t *)(p->map + offset); | |||
158 | else { | |||
159 | h->fanout_table = malloc(len_fanout); | |||
160 | if (h->fanout_table == NULL((void *)0)) { | |||
161 | err = got_error_from_errno("malloc"); | |||
162 | goto done; | |||
163 | } | |||
164 | n = read(p->fd, h->fanout_table, len_fanout); | |||
165 | if (n < 0) { | |||
166 | err = got_error_from_errno("read"); | |||
167 | goto done; | |||
168 | } else if (n != len_fanout) { | |||
169 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
170 | goto done; | |||
171 | } | |||
172 | } | |||
173 | err = verify_fanout_table(h->fanout_table); | |||
174 | if (err) | |||
175 | goto done; | |||
176 | if (verify) | |||
177 | SHA1Update(&ctx, (uint8_t *)h->fanout_table, len_fanout); | |||
178 | offset += len_fanout; | |||
179 | remain -= len_fanout; | |||
180 | ||||
181 | nobj = be32toh(h->fanout_table[0xff])(__uint32_t)(__builtin_constant_p(h->fanout_table[0xff]) ? (__uint32_t)(((__uint32_t)(h->fanout_table[0xff]) & 0xff ) << 24 | ((__uint32_t)(h->fanout_table[0xff]) & 0xff00) << 8 | ((__uint32_t)(h->fanout_table[0xff]) & 0xff0000) >> 8 | ((__uint32_t)(h->fanout_table [0xff]) & 0xff000000) >> 24) : __swap32md(h->fanout_table [0xff])); | |||
182 | len_ids = nobj * sizeof(*h->sorted_ids); | |||
183 | if (len_ids <= nobj || len_ids > remain) { | |||
184 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
185 | goto done; | |||
186 | } | |||
187 | if (p->map) | |||
188 | h->sorted_ids = | |||
189 | (struct got_packidx_object_id *)((uint8_t*)(p->map + offset)); | |||
190 | else { | |||
191 | h->sorted_ids = malloc(len_ids); | |||
192 | if (h->sorted_ids == NULL((void *)0)) { | |||
193 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
194 | goto done; | |||
195 | } | |||
196 | n = read(p->fd, h->sorted_ids, len_ids); | |||
197 | if (n < 0) | |||
198 | err = got_error_from_errno("read"); | |||
199 | else if (n != len_ids) { | |||
200 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
201 | goto done; | |||
202 | } | |||
203 | } | |||
204 | if (verify) | |||
205 | SHA1Update(&ctx, (uint8_t *)h->sorted_ids, len_ids); | |||
206 | offset += len_ids; | |||
207 | remain -= len_ids; | |||
208 | ||||
209 | if (remain < nobj * sizeof(*h->crc32)) { | |||
210 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
211 | goto done; | |||
212 | } | |||
213 | if (p->map) | |||
214 | h->crc32 = (uint32_t *)((uint8_t*)(p->map + offset)); | |||
215 | else { | |||
216 | h->crc32 = malloc(nobj * sizeof(*h->crc32)); | |||
217 | if (h->crc32 == NULL((void *)0)) { | |||
218 | err = got_error_from_errno("malloc"); | |||
219 | goto done; | |||
220 | } | |||
221 | n = read(p->fd, h->crc32, nobj * sizeof(*h->crc32)); | |||
222 | if (n < 0) | |||
223 | err = got_error_from_errno("read"); | |||
224 | else if (n != nobj * sizeof(*h->crc32)) { | |||
225 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
226 | goto done; | |||
227 | } | |||
228 | } | |||
229 | if (verify) | |||
230 | SHA1Update(&ctx, (uint8_t *)h->crc32, nobj * sizeof(*h->crc32)); | |||
231 | remain -= nobj * sizeof(*h->crc32); | |||
232 | offset += nobj * sizeof(*h->crc32); | |||
233 | ||||
234 | if (remain < nobj * sizeof(*h->offsets)) { | |||
235 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
236 | goto done; | |||
237 | } | |||
238 | if (p->map) | |||
239 | h->offsets = (uint32_t *)((uint8_t*)(p->map + offset)); | |||
240 | else { | |||
241 | h->offsets = malloc(nobj * sizeof(*h->offsets)); | |||
242 | if (h->offsets == NULL((void *)0)) { | |||
243 | err = got_error_from_errno("malloc"); | |||
244 | goto done; | |||
245 | } | |||
246 | n = read(p->fd, h->offsets, nobj * sizeof(*h->offsets)); | |||
247 | if (n < 0) | |||
248 | err = got_error_from_errno("read"); | |||
249 | else if (n != nobj * sizeof(*h->offsets)) { | |||
250 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
251 | goto done; | |||
252 | } | |||
253 | } | |||
254 | if (verify) | |||
255 | SHA1Update(&ctx, (uint8_t *)h->offsets, | |||
256 | nobj * sizeof(*h->offsets)); | |||
257 | remain -= nobj * sizeof(*h->offsets); | |||
258 | offset += nobj * sizeof(*h->offsets); | |||
259 | ||||
260 | /* Large file offsets are contained only in files > 2GB. */ | |||
261 | for (i = 0; i < nobj; i++) { | |||
262 | uint32_t o = h->offsets[i]; | |||
263 | if (o & htobe32(GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX)(__uint32_t)(__builtin_constant_p(0x80000000) ? (__uint32_t)( ((__uint32_t)(0x80000000) & 0xff) << 24 | ((__uint32_t )(0x80000000) & 0xff00) << 8 | ((__uint32_t)(0x80000000 ) & 0xff0000) >> 8 | ((__uint32_t)(0x80000000) & 0xff000000) >> 24) : __swap32md(0x80000000))) | |||
264 | p->nlargeobj++; | |||
265 | } | |||
266 | if (p->nlargeobj == 0) | |||
267 | goto checksum; | |||
268 | ||||
269 | if (remain < p->nlargeobj * sizeof(*h->large_offsets)) { | |||
270 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
271 | goto done; | |||
272 | } | |||
273 | if (p->map) | |||
274 | h->large_offsets = (uint64_t *)((uint8_t*)(p->map + offset)); | |||
275 | else { | |||
276 | h->large_offsets = malloc(p->nlargeobj * | |||
277 | sizeof(*h->large_offsets)); | |||
278 | if (h->large_offsets == NULL((void *)0)) { | |||
279 | err = got_error_from_errno("malloc"); | |||
280 | goto done; | |||
281 | } | |||
282 | n = read(p->fd, h->large_offsets, | |||
283 | p->nlargeobj * sizeof(*h->large_offsets)); | |||
284 | if (n < 0) | |||
285 | err = got_error_from_errno("read"); | |||
286 | else if (n != p->nlargeobj * sizeof(*h->large_offsets)) { | |||
287 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
288 | goto done; | |||
289 | } | |||
290 | } | |||
291 | if (verify) | |||
292 | SHA1Update(&ctx, (uint8_t*)h->large_offsets, | |||
293 | p->nlargeobj * sizeof(*h->large_offsets)); | |||
294 | remain -= p->nlargeobj * sizeof(*h->large_offsets); | |||
295 | offset += p->nlargeobj * sizeof(*h->large_offsets); | |||
296 | ||||
297 | checksum: | |||
298 | if (remain < sizeof(*h->trailer)) { | |||
299 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
300 | goto done; | |||
301 | } | |||
302 | if (p->map) | |||
303 | h->trailer = | |||
304 | (struct got_packidx_trailer *)((uint8_t*)(p->map + offset)); | |||
305 | else { | |||
306 | h->trailer = malloc(sizeof(*h->trailer)); | |||
307 | if (h->trailer == NULL((void *)0)) { | |||
308 | err = got_error_from_errno("malloc"); | |||
309 | goto done; | |||
310 | } | |||
311 | n = read(p->fd, h->trailer, sizeof(*h->trailer)); | |||
312 | if (n < 0) | |||
313 | err = got_error_from_errno("read"); | |||
314 | else if (n != sizeof(*h->trailer)) { | |||
315 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
316 | goto done; | |||
317 | } | |||
318 | } | |||
319 | if (verify) { | |||
320 | SHA1Update(&ctx, h->trailer->packfile_sha1, SHA1_DIGEST_LENGTH20); | |||
321 | SHA1Final(sha1, &ctx); | |||
322 | if (memcmp(h->trailer->packidx_sha1, sha1, | |||
323 | SHA1_DIGEST_LENGTH20) != 0) | |||
324 | err = got_error(GOT_ERR_PACKIDX_CSUM15); | |||
325 | } | |||
326 | done: | |||
327 | return err; | |||
328 | } | |||
329 | ||||
330 | const struct got_error * | |||
331 | got_packidx_open(struct got_packidx **packidx, | |||
332 | int dir_fd, const char *relpath, int verify) | |||
333 | { | |||
334 | const struct got_error *err = NULL((void *)0); | |||
335 | struct got_packidx *p; | |||
336 | struct stat sb; | |||
337 | ||||
338 | *packidx = NULL((void *)0); | |||
339 | ||||
340 | p = calloc(1, sizeof(*p)); | |||
341 | if (p == NULL((void *)0)) | |||
342 | return got_error_from_errno("calloc"); | |||
343 | ||||
344 | p->fd = openat(dir_fd, relpath, O_RDONLY0x0000 | O_NOFOLLOW0x0100); | |||
345 | if (p->fd == -1) { | |||
346 | err = got_error_from_errno2("openat", relpath); | |||
347 | free(p); | |||
348 | return err; | |||
349 | } | |||
350 | ||||
351 | if (fstat(p->fd, &sb) != 0) { | |||
352 | err = got_error_from_errno2("fstat", relpath); | |||
353 | close(p->fd); | |||
354 | free(p); | |||
355 | return err; | |||
356 | } | |||
357 | p->len = sb.st_size; | |||
358 | if (p->len < sizeof(p->hdr)) { | |||
359 | err = got_error(GOT_ERR_BAD_PACKIDX14); | |||
360 | close(p->fd); | |||
361 | free(p); | |||
362 | return err; | |||
363 | } | |||
364 | ||||
365 | p->path_packidx = strdup(relpath); | |||
366 | if (p->path_packidx == NULL((void *)0)) { | |||
367 | err = got_error_from_errno("strdup"); | |||
368 | goto done; | |||
369 | } | |||
370 | ||||
371 | #ifndef GOT_PACK_NO_MMAP | |||
372 | p->map = mmap(NULL((void *)0), p->len, PROT_READ0x01, MAP_PRIVATE0x0002, p->fd, 0); | |||
373 | if (p->map == MAP_FAILED((void *)-1)) { | |||
374 | if (errno(*__errno()) != ENOMEM12) { | |||
375 | err = got_error_from_errno("mmap"); | |||
376 | goto done; | |||
377 | } | |||
378 | p->map = NULL((void *)0); /* fall back to read(2) */ | |||
379 | } | |||
380 | #endif | |||
381 | ||||
382 | err = got_packidx_init_hdr(p, verify); | |||
383 | done: | |||
384 | if (err) | |||
385 | got_packidx_close(p); | |||
386 | else | |||
387 | *packidx = p; | |||
388 | ||||
389 | return err; | |||
390 | } | |||
391 | ||||
392 | const struct got_error * | |||
393 | got_packidx_close(struct got_packidx *packidx) | |||
394 | { | |||
395 | const struct got_error *err = NULL((void *)0); | |||
396 | ||||
397 | free(packidx->path_packidx); | |||
398 | if (packidx->map) { | |||
399 | if (munmap(packidx->map, packidx->len) == -1) | |||
400 | err = got_error_from_errno("munmap"); | |||
401 | } else { | |||
402 | free(packidx->hdr.magic); | |||
403 | free(packidx->hdr.version); | |||
404 | free(packidx->hdr.fanout_table); | |||
405 | free(packidx->hdr.sorted_ids); | |||
406 | free(packidx->hdr.crc32); | |||
407 | free(packidx->hdr.offsets); | |||
408 | free(packidx->hdr.large_offsets); | |||
409 | free(packidx->hdr.trailer); | |||
410 | } | |||
411 | if (close(packidx->fd) == -1 && err == NULL((void *)0)) | |||
412 | err = got_error_from_errno("close"); | |||
413 | free(packidx); | |||
414 | ||||
415 | return err; | |||
416 | } | |||
417 | ||||
418 | const struct got_error * | |||
419 | got_packidx_get_packfile_path(char **path_packfile, struct got_packidx *packidx) | |||
420 | { | |||
421 | size_t size; | |||
422 | ||||
423 | /* Packfile path contains ".pack" instead of ".idx", so add one byte. */ | |||
424 | size = strlen(packidx->path_packidx) + 2; | |||
425 | if (size < GOT_PACKFILE_NAMELEN(strlen("pack-") + (20 * 2 + 1) - 1 + strlen(".pack")) + 1) | |||
426 | return got_error_path(packidx->path_packidx, GOT_ERR_BAD_PATH4); | |||
427 | ||||
428 | *path_packfile = malloc(size); | |||
429 | if (*path_packfile == NULL((void *)0)) | |||
430 | return got_error_from_errno("malloc"); | |||
431 | ||||
432 | /* Copy up to and excluding ".idx". */ | |||
433 | if (strlcpy(*path_packfile, packidx->path_packidx, | |||
434 | size - strlen(GOT_PACKIDX_SUFFIX".idx") - 1) >= size) | |||
435 | return got_error(GOT_ERR_NO_SPACE9); | |||
436 | ||||
437 | if (strlcat(*path_packfile, GOT_PACKFILE_SUFFIX".pack", size) >= size) | |||
438 | return got_error(GOT_ERR_NO_SPACE9); | |||
439 | ||||
440 | return NULL((void *)0); | |||
441 | } | |||
442 | ||||
443 | static off_t | |||
444 | get_object_offset(struct got_packidx *packidx, int idx) | |||
445 | { | |||
446 | uint32_t offset = be32toh(packidx->hdr.offsets[idx])(__uint32_t)(__builtin_constant_p(packidx->hdr.offsets[idx ]) ? (__uint32_t)(((__uint32_t)(packidx->hdr.offsets[idx]) & 0xff) << 24 | ((__uint32_t)(packidx->hdr.offsets [idx]) & 0xff00) << 8 | ((__uint32_t)(packidx->hdr .offsets[idx]) & 0xff0000) >> 8 | ((__uint32_t)(packidx ->hdr.offsets[idx]) & 0xff000000) >> 24) : __swap32md (packidx->hdr.offsets[idx])); | |||
447 | if (offset & GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX0x80000000) { | |||
448 | uint64_t loffset; | |||
449 | idx = offset & GOT_PACKIDX_OFFSET_VAL_MASK0x7fffffff; | |||
450 | if (idx < 0 || idx >= packidx->nlargeobj || | |||
451 | packidx->hdr.large_offsets == NULL((void *)0)) | |||
452 | return -1; | |||
453 | loffset = be64toh(packidx->hdr.large_offsets[idx])(__uint64_t)(__builtin_constant_p(packidx->hdr.large_offsets [idx]) ? (__uint64_t)((((__uint64_t)(packidx->hdr.large_offsets [idx]) & 0xff) << 56) | ((__uint64_t)(packidx->hdr .large_offsets[idx]) & 0xff00ULL) << 40 | ((__uint64_t )(packidx->hdr.large_offsets[idx]) & 0xff0000ULL) << 24 | ((__uint64_t)(packidx->hdr.large_offsets[idx]) & 0xff000000ULL) << 8 | ((__uint64_t)(packidx->hdr.large_offsets [idx]) & 0xff00000000ULL) >> 8 | ((__uint64_t)(packidx ->hdr.large_offsets[idx]) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(packidx->hdr.large_offsets[idx]) & 0xff000000000000ULL) >> 40 | ((__uint64_t)(packidx-> hdr.large_offsets[idx]) & 0xff00000000000000ULL) >> 56) : __swap64md(packidx->hdr.large_offsets[idx])); | |||
454 | return (loffset > INT64_MAX0x7fffffffffffffffLL ? -1 : (off_t)loffset); | |||
455 | } | |||
456 | return (off_t)(offset & GOT_PACKIDX_OFFSET_VAL_MASK0x7fffffff); | |||
457 | } | |||
458 | ||||
459 | int | |||
460 | got_packidx_get_object_idx(struct got_packidx *packidx, struct got_object_id *id) | |||
461 | { | |||
462 | u_int8_t id0 = id->sha1[0]; | |||
463 | uint32_t totobj = be32toh(packidx->hdr.fanout_table[0xff])(__uint32_t)(__builtin_constant_p(packidx->hdr.fanout_table [0xff]) ? (__uint32_t)(((__uint32_t)(packidx->hdr.fanout_table [0xff]) & 0xff) << 24 | ((__uint32_t)(packidx->hdr .fanout_table[0xff]) & 0xff00) << 8 | ((__uint32_t) (packidx->hdr.fanout_table[0xff]) & 0xff0000) >> 8 | ((__uint32_t)(packidx->hdr.fanout_table[0xff]) & 0xff000000 ) >> 24) : __swap32md(packidx->hdr.fanout_table[0xff ])); | |||
464 | int left = 0, right = totobj - 1; | |||
465 | ||||
466 | if (id0 > 0) | |||
467 | left = be32toh(packidx->hdr.fanout_table[id0 - 1])(__uint32_t)(__builtin_constant_p(packidx->hdr.fanout_table [id0 - 1]) ? (__uint32_t)(((__uint32_t)(packidx->hdr.fanout_table [id0 - 1]) & 0xff) << 24 | ((__uint32_t)(packidx-> hdr.fanout_table[id0 - 1]) & 0xff00) << 8 | ((__uint32_t )(packidx->hdr.fanout_table[id0 - 1]) & 0xff0000) >> 8 | ((__uint32_t)(packidx->hdr.fanout_table[id0 - 1]) & 0xff000000) >> 24) : __swap32md(packidx->hdr.fanout_table [id0 - 1])); | |||
468 | ||||
469 | while (left <= right) { | |||
470 | struct got_packidx_object_id *oid; | |||
471 | int i, cmp; | |||
472 | ||||
473 | i = ((left + right) / 2); | |||
474 | oid = &packidx->hdr.sorted_ids[i]; | |||
475 | cmp = memcmp(id->sha1, oid->sha1, SHA1_DIGEST_LENGTH20); | |||
476 | if (cmp == 0) | |||
477 | return i; | |||
478 | else if (cmp > 0) | |||
479 | left = i + 1; | |||
480 | else if (cmp < 0) | |||
481 | right = i - 1; | |||
482 | } | |||
483 | ||||
484 | return -1; | |||
485 | } | |||
486 | ||||
487 | const struct got_error * | |||
488 | got_packidx_match_id_str_prefix(struct got_object_id_queue *matched_ids, | |||
489 | struct got_packidx *packidx, const char *id_str_prefix) | |||
490 | { | |||
491 | const struct got_error *err = NULL((void *)0); | |||
492 | u_int8_t id0; | |||
493 | uint32_t totobj = be32toh(packidx->hdr.fanout_table[0xff])(__uint32_t)(__builtin_constant_p(packidx->hdr.fanout_table [0xff]) ? (__uint32_t)(((__uint32_t)(packidx->hdr.fanout_table [0xff]) & 0xff) << 24 | ((__uint32_t)(packidx->hdr .fanout_table[0xff]) & 0xff00) << 8 | ((__uint32_t) (packidx->hdr.fanout_table[0xff]) & 0xff0000) >> 8 | ((__uint32_t)(packidx->hdr.fanout_table[0xff]) & 0xff000000 ) >> 24) : __swap32md(packidx->hdr.fanout_table[0xff ])); | |||
494 | char hex[3]; | |||
495 | size_t prefix_len = strlen(id_str_prefix); | |||
496 | struct got_packidx_object_id *oid; | |||
497 | uint32_t i; | |||
498 | ||||
499 | SIMPLEQ_INIT(matched_ids)do { (matched_ids)->sqh_first = ((void *)0); (matched_ids) ->sqh_last = &(matched_ids)->sqh_first; } while (0); | |||
500 | ||||
501 | if (prefix_len < 2) | |||
502 | return got_error_path(id_str_prefix, GOT_ERR_BAD_OBJ_ID_STR23); | |||
503 | ||||
504 | hex[0] = id_str_prefix[0]; | |||
505 | hex[1] = id_str_prefix[1]; | |||
506 | hex[2] = '\0'; | |||
507 | if (!got_parse_xdigit(&id0, hex)) | |||
508 | return got_error_path(id_str_prefix, GOT_ERR_BAD_OBJ_ID_STR23); | |||
509 | ||||
510 | i = be32toh(packidx->hdr.fanout_table[id0 - 1])(__uint32_t)(__builtin_constant_p(packidx->hdr.fanout_table [id0 - 1]) ? (__uint32_t)(((__uint32_t)(packidx->hdr.fanout_table [id0 - 1]) & 0xff) << 24 | ((__uint32_t)(packidx-> hdr.fanout_table[id0 - 1]) & 0xff00) << 8 | ((__uint32_t )(packidx->hdr.fanout_table[id0 - 1]) & 0xff0000) >> 8 | ((__uint32_t)(packidx->hdr.fanout_table[id0 - 1]) & 0xff000000) >> 24) : __swap32md(packidx->hdr.fanout_table [id0 - 1])); | |||
511 | oid = &packidx->hdr.sorted_ids[i]; | |||
512 | while (i < totobj && oid->sha1[0] == id0) { | |||
513 | char id_str[SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1)]; | |||
514 | struct got_object_qid *qid; | |||
515 | int cmp; | |||
516 | ||||
517 | if (!got_sha1_digest_to_str(oid->sha1, id_str, sizeof(id_str))) | |||
518 | return got_error(GOT_ERR_NO_SPACE9); | |||
519 | ||||
520 | cmp = strncmp(id_str, id_str_prefix, prefix_len); | |||
521 | if (cmp < 0) { | |||
522 | oid = &packidx->hdr.sorted_ids[++i]; | |||
523 | continue; | |||
524 | } else if (cmp > 0) | |||
525 | break; | |||
526 | ||||
527 | err = got_object_qid_alloc_partial(&qid); | |||
528 | if (err) | |||
529 | break; | |||
530 | memcpy(qid->id->sha1, oid->sha1, SHA1_DIGEST_LENGTH20); | |||
531 | SIMPLEQ_INSERT_TAIL(matched_ids, qid, entry)do { (qid)->entry.sqe_next = ((void *)0); *(matched_ids)-> sqh_last = (qid); (matched_ids)->sqh_last = &(qid)-> entry.sqe_next; } while (0); | |||
532 | ||||
533 | oid = &packidx->hdr.sorted_ids[++i]; | |||
534 | } | |||
535 | ||||
536 | if (err) | |||
537 | got_object_id_queue_free(matched_ids); | |||
538 | return err; | |||
539 | } | |||
540 | ||||
541 | const struct got_error * | |||
542 | got_pack_stop_privsep_child(struct got_pack *pack) | |||
543 | { | |||
544 | const struct got_error *err = NULL((void *)0); | |||
545 | ||||
546 | if (pack->privsep_child == NULL((void *)0)) | |||
547 | return NULL((void *)0); | |||
548 | ||||
549 | err = got_privsep_send_stop(pack->privsep_child->imsg_fd); | |||
550 | if (err) | |||
551 | return err; | |||
552 | err = got_privsep_wait_for_child(pack->privsep_child->pid); | |||
553 | if (close(pack->privsep_child->imsg_fd) == -1 && err == NULL((void *)0)) | |||
554 | err = got_error_from_errno("close"); | |||
555 | free(pack->privsep_child); | |||
556 | pack->privsep_child = NULL((void *)0); | |||
557 | return err; | |||
558 | } | |||
559 | ||||
560 | const struct got_error * | |||
561 | got_pack_close(struct got_pack *pack) | |||
562 | { | |||
563 | const struct got_error *err = NULL((void *)0); | |||
564 | ||||
565 | err = got_pack_stop_privsep_child(pack); | |||
566 | if (pack->map && munmap(pack->map, pack->filesize) == -1 && !err) | |||
567 | err = got_error_from_errno("munmap"); | |||
568 | if (pack->fd != -1 && close(pack->fd) == -1 && err == NULL((void *)0)) | |||
569 | err = got_error_from_errno("close"); | |||
570 | pack->fd = -1; | |||
571 | free(pack->path_packfile); | |||
572 | pack->path_packfile = NULL((void *)0); | |||
573 | pack->filesize = 0; | |||
574 | if (pack->delta_cache) { | |||
575 | got_delta_cache_free(pack->delta_cache); | |||
576 | pack->delta_cache = NULL((void *)0); | |||
577 | } | |||
578 | ||||
579 | return err; | |||
580 | } | |||
581 | ||||
582 | const struct got_error * | |||
583 | got_pack_parse_object_type_and_size(uint8_t *type, uint64_t *size, size_t *len, | |||
584 | struct got_pack *pack, off_t offset) | |||
585 | { | |||
586 | uint8_t t = 0; | |||
587 | uint64_t s = 0; | |||
588 | uint8_t sizeN; | |||
589 | size_t mapoff = 0; | |||
590 | int i = 0; | |||
591 | ||||
592 | *len = 0; | |||
593 | ||||
594 | if (offset
| |||
595 | return got_error(GOT_ERR_PACK_OFFSET42); | |||
596 | ||||
597 | if (pack->map
| |||
598 | mapoff = (size_t)offset; | |||
599 | } else { | |||
600 | if (lseek(pack->fd, offset, SEEK_SET0) == -1) | |||
601 | return got_error_from_errno("lseek"); | |||
602 | } | |||
603 | ||||
604 | do { | |||
605 | /* We do not support size values which don't fit in 64 bit. */ | |||
606 | if (i
| |||
607 | return got_error(GOT_ERR_NO_SPACE9); | |||
608 | ||||
609 | if (pack->map
| |||
610 | sizeN = *(pack->map + mapoff); | |||
611 | mapoff += sizeof(sizeN); | |||
612 | } else { | |||
613 | ssize_t n = read(pack->fd, &sizeN, sizeof(sizeN)); | |||
614 | if (n < 0) | |||
615 | return got_error_from_errno("read"); | |||
616 | if (n != sizeof(sizeN)) | |||
617 | return got_error(GOT_ERR_BAD_PACKFILE16); | |||
618 | } | |||
619 | *len += sizeof(sizeN); | |||
620 | ||||
621 | if (i
| |||
622 | t = (sizeN & GOT_PACK_OBJ_SIZE0_TYPE_MASK0x70) >> | |||
623 | GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT4; | |||
624 | s = (sizeN & GOT_PACK_OBJ_SIZE0_VAL_MASK0x0f); | |||
625 | } else { | |||
626 | size_t shift = 4 + 7 * (i - 1); | |||
627 | s |= ((sizeN & GOT_PACK_OBJ_SIZE_VAL_MASK0x7f) << shift); | |||
628 | } | |||
629 | i++; | |||
630 | } while (sizeN & GOT_PACK_OBJ_SIZE_MORE0x80); | |||
631 | ||||
632 | *type = t; | |||
633 | *size = s; | |||
634 | return NULL((void *)0); | |||
635 | } | |||
636 | ||||
637 | static const struct got_error * | |||
638 | open_plain_object(struct got_object **obj, struct got_object_id *id, | |||
639 | uint8_t type, off_t offset, size_t size, int idx) | |||
640 | { | |||
641 | *obj = calloc(1, sizeof(**obj)); | |||
642 | if (*obj == NULL((void *)0)) | |||
643 | return got_error_from_errno("calloc"); | |||
644 | ||||
645 | (*obj)->type = type; | |||
646 | (*obj)->flags = GOT_OBJ_FLAG_PACKED0x01; | |||
647 | (*obj)->pack_idx = idx; | |||
648 | (*obj)->hdrlen = 0; | |||
649 | (*obj)->size = size; | |||
650 | memcpy(&(*obj)->id, id, sizeof((*obj)->id)); | |||
651 | (*obj)->pack_offset = offset; | |||
652 | ||||
653 | return NULL((void *)0); | |||
654 | } | |||
655 | ||||
656 | static const struct got_error * | |||
657 | parse_negative_offset(int64_t *offset, size_t *len, struct got_pack *pack, | |||
658 | off_t delta_offset) | |||
659 | { | |||
660 | int64_t o = 0; | |||
661 | uint8_t offN; | |||
662 | int i = 0; | |||
663 | ||||
664 | *offset = 0; | |||
665 | *len = 0; | |||
666 | ||||
667 | do { | |||
668 | /* We do not support offset values which don't fit in 64 bit. */ | |||
669 | if (i > 8) | |||
670 | return got_error(GOT_ERR_NO_SPACE9); | |||
671 | ||||
672 | if (pack->map) { | |||
673 | size_t mapoff; | |||
674 | if (delta_offset >= pack->filesize) | |||
675 | return got_error(GOT_ERR_PACK_OFFSET42); | |||
676 | mapoff = (size_t)delta_offset + *len; | |||
677 | offN = *(pack->map + mapoff); | |||
678 | } else { | |||
679 | ssize_t n; | |||
680 | n = read(pack->fd, &offN, sizeof(offN)); | |||
681 | if (n < 0) | |||
682 | return got_error_from_errno("read"); | |||
683 | if (n != sizeof(offN)) | |||
684 | return got_error(GOT_ERR_BAD_PACKFILE16); | |||
685 | } | |||
686 | *len += sizeof(offN); | |||
687 | ||||
688 | if (i == 0) | |||
689 | o = (offN & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK0x7f); | |||
690 | else { | |||
691 | o++; | |||
692 | o <<= 7; | |||
693 | o += (offN & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK0x7f); | |||
694 | } | |||
695 | i++; | |||
696 | } while (offN & GOT_PACK_OBJ_DELTA_OFF_MORE0x80); | |||
697 | ||||
698 | *offset = o; | |||
699 | return NULL((void *)0); | |||
700 | } | |||
701 | ||||
702 | const struct got_error * | |||
703 | got_pack_parse_offset_delta(off_t *base_offset, size_t *len, struct got_pack *pack, | |||
704 | off_t offset, int tslen) | |||
705 | { | |||
706 | const struct got_error *err; | |||
707 | int64_t negoffset; | |||
708 | size_t negofflen; | |||
709 | ||||
710 | *len = 0; | |||
711 | ||||
712 | err = parse_negative_offset(&negoffset, &negofflen, pack, | |||
713 | offset + tslen); | |||
714 | if (err) | |||
715 | return err; | |||
716 | ||||
717 | /* Compute the base object's offset (must be in the same pack file). */ | |||
718 | *base_offset = (offset - negoffset); | |||
719 | if (*base_offset <= 0) | |||
720 | return got_error(GOT_ERR_BAD_PACKFILE16); | |||
721 | ||||
722 | *len = negofflen; | |||
723 | return NULL((void *)0); | |||
724 | } | |||
725 | ||||
726 | static const struct got_error * | |||
727 | read_delta_data(uint8_t **delta_buf, size_t *delta_len, | |||
728 | size_t delta_data_offset, struct got_pack *pack) | |||
729 | { | |||
730 | const struct got_error *err = NULL((void *)0); | |||
731 | ||||
732 | if (pack->map) { | |||
733 | if (delta_data_offset >= pack->filesize) | |||
734 | return got_error(GOT_ERR_PACK_OFFSET42); | |||
735 | err = got_inflate_to_mem_mmap(delta_buf, delta_len, | |||
736 | NULL((void *)0), NULL((void *)0), pack->map, delta_data_offset, | |||
737 | pack->filesize - delta_data_offset); | |||
738 | } else { | |||
739 | if (lseek(pack->fd, delta_data_offset, SEEK_SET0) == -1) | |||
740 | return got_error_from_errno("lseek"); | |||
741 | err = got_inflate_to_mem_fd(delta_buf, delta_len, NULL((void *)0), | |||
742 | NULL((void *)0), 0, pack->fd); | |||
743 | } | |||
744 | return err; | |||
745 | } | |||
746 | ||||
747 | static const struct got_error * | |||
748 | add_delta(struct got_delta_chain *deltas, off_t delta_offset, size_t tslen, | |||
749 | int delta_type, size_t delta_size, size_t delta_data_offset) | |||
750 | { | |||
751 | struct got_delta *delta; | |||
752 | ||||
753 | delta = got_delta_open(delta_offset, tslen, delta_type, delta_size, | |||
754 | delta_data_offset); | |||
755 | if (delta == NULL((void *)0)) | |||
756 | return got_error_from_errno("got_delta_open"); | |||
757 | /* delta is freed in got_object_close() */ | |||
758 | deltas->nentries++; | |||
759 | SIMPLEQ_INSERT_HEAD(&deltas->entries, delta, entry)do { if (((delta)->entry.sqe_next = (&deltas->entries )->sqh_first) == ((void *)0)) (&deltas->entries)-> sqh_last = &(delta)->entry.sqe_next; (&deltas-> entries)->sqh_first = (delta); } while (0); | |||
760 | return NULL((void *)0); | |||
761 | } | |||
762 | ||||
763 | static const struct got_error * | |||
764 | resolve_offset_delta(struct got_delta_chain *deltas, | |||
765 | struct got_packidx *packidx, struct got_pack *pack, off_t delta_offset, | |||
766 | size_t tslen, int delta_type, size_t delta_size, unsigned int recursion) | |||
767 | ||||
768 | { | |||
769 | const struct got_error *err; | |||
770 | off_t base_offset; | |||
771 | uint8_t base_type; | |||
772 | uint64_t base_size; | |||
773 | size_t base_tslen; | |||
774 | off_t delta_data_offset; | |||
775 | size_t consumed; | |||
776 | ||||
777 | err = got_pack_parse_offset_delta(&base_offset, &consumed, pack, | |||
778 | delta_offset, tslen); | |||
779 | if (err
| |||
780 | return err; | |||
781 | ||||
782 | delta_data_offset = delta_offset + tslen + consumed; | |||
783 | if (delta_data_offset >= pack->filesize) | |||
784 | return got_error(GOT_ERR_PACK_OFFSET42); | |||
785 | ||||
786 | if (pack->map == NULL((void *)0)) { | |||
787 | delta_data_offset = lseek(pack->fd, 0, SEEK_CUR1); | |||
788 | if (delta_data_offset == -1) | |||
789 | return got_error_from_errno("lseek"); | |||
790 | } | |||
791 | ||||
792 | err = add_delta(deltas, delta_offset, tslen, delta_type, delta_size, | |||
793 | delta_data_offset); | |||
794 | if (err) | |||
795 | return err; | |||
796 | ||||
797 | /* An offset delta must be in the same packfile. */ | |||
798 | if (base_offset >= pack->filesize) | |||
799 | return got_error(GOT_ERR_PACK_OFFSET42); | |||
800 | ||||
801 | err = got_pack_parse_object_type_and_size(&base_type, &base_size, | |||
802 | &base_tslen, pack, base_offset); | |||
803 | if (err) | |||
804 | return err; | |||
805 | ||||
806 | return got_pack_resolve_delta_chain(deltas, packidx, pack, base_offset, | |||
| ||||
807 | base_tslen, base_type, base_size, recursion - 1); | |||
808 | } | |||
809 | ||||
810 | static const struct got_error * | |||
811 | resolve_ref_delta(struct got_delta_chain *deltas, struct got_packidx *packidx, | |||
812 | struct got_pack *pack, off_t delta_offset, size_t tslen, int delta_type, | |||
813 | size_t delta_size, unsigned int recursion) | |||
814 | { | |||
815 | const struct got_error *err; | |||
816 | struct got_object_id id; | |||
817 | int idx; | |||
818 | off_t base_offset; | |||
819 | uint8_t base_type; | |||
820 | uint64_t base_size; | |||
821 | size_t base_tslen; | |||
822 | off_t delta_data_offset; | |||
823 | ||||
824 | if (delta_offset + tslen >= pack->filesize) | |||
825 | return got_error(GOT_ERR_PACK_OFFSET42); | |||
826 | ||||
827 | if (pack->map) { | |||
828 | size_t mapoff = delta_offset + tslen; | |||
829 | memcpy(&id, pack->map + mapoff, sizeof(id)); | |||
830 | mapoff += sizeof(id); | |||
831 | delta_data_offset = (off_t)mapoff; | |||
832 | } else { | |||
833 | ssize_t n; | |||
834 | n = read(pack->fd, &id, sizeof(id)); | |||
835 | if (n < 0) | |||
836 | return got_error_from_errno("read"); | |||
837 | if (n != sizeof(id)) | |||
838 | return got_error(GOT_ERR_BAD_PACKFILE16); | |||
839 | delta_data_offset = lseek(pack->fd, 0, SEEK_CUR1); | |||
840 | if (delta_data_offset == -1) | |||
841 | return got_error_from_errno("lseek"); | |||
842 | } | |||
843 | ||||
844 | err = add_delta(deltas, delta_offset, tslen, delta_type, delta_size, | |||
845 | delta_data_offset); | |||
846 | if (err) | |||
847 | return err; | |||
848 | ||||
849 | /* Delta base must be in the same pack file. */ | |||
850 | idx = got_packidx_get_object_idx(packidx, &id); | |||
851 | if (idx == -1) | |||
852 | return got_error(GOT_ERR_NO_OBJ17); | |||
853 | ||||
854 | base_offset = get_object_offset(packidx, idx); | |||
855 | if (base_offset == (uint64_t)-1) | |||
856 | return got_error(GOT_ERR_BAD_PACKIDX14); | |||
857 | ||||
858 | if (base_offset >= pack->filesize) | |||
859 | return got_error(GOT_ERR_PACK_OFFSET42); | |||
860 | ||||
861 | err = got_pack_parse_object_type_and_size(&base_type, &base_size, | |||
862 | &base_tslen, pack, base_offset); | |||
863 | if (err) | |||
864 | return err; | |||
865 | ||||
866 | return got_pack_resolve_delta_chain(deltas, packidx, pack, base_offset, | |||
867 | base_tslen, base_type, base_size, recursion - 1); | |||
868 | } | |||
869 | ||||
870 | const struct got_error * | |||
871 | got_pack_resolve_delta_chain(struct got_delta_chain *deltas, | |||
872 | struct got_packidx *packidx, struct got_pack *pack, off_t delta_offset, | |||
873 | size_t tslen, int delta_type, size_t delta_size, unsigned int recursion) | |||
874 | { | |||
875 | const struct got_error *err = NULL((void *)0); | |||
876 | ||||
877 | if (--recursion == 0) | |||
878 | return got_error(GOT_ERR_RECURSION32); | |||
879 | ||||
880 | switch (delta_type) { | |||
881 | case GOT_OBJ_TYPE_COMMIT1: | |||
882 | case GOT_OBJ_TYPE_TREE2: | |||
883 | case GOT_OBJ_TYPE_BLOB3: | |||
884 | case GOT_OBJ_TYPE_TAG4: | |||
885 | /* Plain types are the final delta base. Recursion ends. */ | |||
886 | err = add_delta(deltas, delta_offset, tslen, delta_type, | |||
887 | delta_size, 0); | |||
888 | break; | |||
889 | case GOT_OBJ_TYPE_OFFSET_DELTA6: | |||
890 | err = resolve_offset_delta(deltas, packidx, pack, | |||
891 | delta_offset, tslen, delta_type, delta_size, recursion - 1); | |||
892 | break; | |||
893 | case GOT_OBJ_TYPE_REF_DELTA7: | |||
894 | err = resolve_ref_delta(deltas, packidx, pack, | |||
895 | delta_offset, tslen, delta_type, delta_size, recursion - 1); | |||
896 | break; | |||
897 | default: | |||
898 | return got_error(GOT_ERR_OBJ_TYPE11); | |||
899 | } | |||
900 | ||||
901 | return err; | |||
902 | } | |||
903 | ||||
904 | static const struct got_error * | |||
905 | open_delta_object(struct got_object **obj, struct got_packidx *packidx, | |||
906 | struct got_pack *pack, struct got_object_id *id, off_t offset, | |||
907 | size_t tslen, int delta_type, size_t delta_size, int idx) | |||
908 | { | |||
909 | const struct got_error *err = NULL((void *)0); | |||
910 | int resolved_type; | |||
911 | ||||
912 | *obj = calloc(1, sizeof(**obj)); | |||
913 | if (*obj == NULL((void *)0)) | |||
914 | return got_error_from_errno("calloc"); | |||
915 | ||||
916 | (*obj)->flags = 0; | |||
917 | (*obj)->hdrlen = 0; | |||
918 | (*obj)->size = 0; /* Not known because deltas aren't applied yet. */ | |||
919 | memcpy(&(*obj)->id, id, sizeof((*obj)->id)); | |||
920 | (*obj)->pack_offset = offset + tslen; | |||
921 | ||||
922 | SIMPLEQ_INIT(&(*obj)->deltas.entries)do { (&(*obj)->deltas.entries)->sqh_first = ((void * )0); (&(*obj)->deltas.entries)->sqh_last = &(& (*obj)->deltas.entries)->sqh_first; } while (0); | |||
923 | (*obj)->flags |= GOT_OBJ_FLAG_DELTIFIED0x02; | |||
924 | (*obj)->flags |= GOT_OBJ_FLAG_PACKED0x01; | |||
925 | (*obj)->pack_idx = idx; | |||
926 | ||||
927 | err = got_pack_resolve_delta_chain(&(*obj)->deltas, packidx, pack, | |||
928 | offset, tslen, delta_type, delta_size, | |||
929 | GOT_DELTA_CHAIN_RECURSION_MAX500); | |||
930 | if (err) | |||
931 | goto done; | |||
932 | ||||
933 | err = got_delta_chain_get_base_type(&resolved_type, &(*obj)->deltas); | |||
934 | if (err) | |||
935 | goto done; | |||
936 | (*obj)->type = resolved_type; | |||
937 | done: | |||
938 | if (err) { | |||
939 | got_object_close(*obj); | |||
940 | *obj = NULL((void *)0); | |||
941 | } | |||
942 | return err; | |||
943 | } | |||
944 | ||||
945 | const struct got_error * | |||
946 | got_packfile_open_object(struct got_object **obj, struct got_pack *pack, | |||
947 | struct got_packidx *packidx, int idx, struct got_object_id *id) | |||
948 | { | |||
949 | const struct got_error *err = NULL((void *)0); | |||
950 | off_t offset; | |||
951 | uint8_t type; | |||
952 | uint64_t size; | |||
953 | size_t tslen; | |||
954 | ||||
955 | *obj = NULL((void *)0); | |||
956 | ||||
957 | offset = get_object_offset(packidx, idx); | |||
958 | if (offset == (uint64_t)-1) | |||
| ||||
959 | return got_error(GOT_ERR_BAD_PACKIDX14); | |||
960 | ||||
961 | err = got_pack_parse_object_type_and_size(&type, &size, &tslen, | |||
962 | pack, offset); | |||
963 | if (err
| |||
964 | return err; | |||
965 | ||||
966 | switch (type) { | |||
967 | case GOT_OBJ_TYPE_COMMIT1: | |||
968 | case GOT_OBJ_TYPE_TREE2: | |||
969 | case GOT_OBJ_TYPE_BLOB3: | |||
970 | case GOT_OBJ_TYPE_TAG4: | |||
971 | err = open_plain_object(obj, id, type, offset + tslen, | |||
972 | size, idx); | |||
973 | break; | |||
974 | case GOT_OBJ_TYPE_OFFSET_DELTA6: | |||
975 | case GOT_OBJ_TYPE_REF_DELTA7: | |||
976 | err = open_delta_object(obj, packidx, pack, id, offset, | |||
977 | tslen, type, size, idx); | |||
978 | break; | |||
979 | default: | |||
980 | err = got_error(GOT_ERR_OBJ_TYPE11); | |||
981 | break; | |||
982 | } | |||
983 | ||||
984 | return err; | |||
985 | } | |||
986 | ||||
987 | const struct got_error * | |||
988 | got_pack_get_delta_chain_max_size(uint64_t *max_size, struct got_delta_chain *deltas, | |||
989 | struct got_pack *pack) | |||
990 | { | |||
991 | struct got_delta *delta; | |||
992 | uint64_t base_size = 0, result_size = 0; | |||
993 | ||||
994 | *max_size = 0; | |||
995 | SIMPLEQ_FOREACH(delta, &deltas->entries, entry)for((delta) = ((&deltas->entries)->sqh_first); (delta ) != ((void *)0); (delta) = ((delta)->entry.sqe_next)) { | |||
996 | /* Plain object types are the delta base. */ | |||
997 | if (delta->type != GOT_OBJ_TYPE_COMMIT1 && | |||
998 | delta->type != GOT_OBJ_TYPE_TREE2 && | |||
999 | delta->type != GOT_OBJ_TYPE_BLOB3 && | |||
1000 | delta->type != GOT_OBJ_TYPE_TAG4) { | |||
1001 | const struct got_error *err; | |||
1002 | uint8_t *delta_buf; | |||
1003 | size_t delta_len; | |||
1004 | int cached = 1; | |||
1005 | ||||
1006 | got_delta_cache_get(&delta_buf, &delta_len, | |||
1007 | pack->delta_cache, delta->data_offset); | |||
1008 | if (delta_buf == NULL((void *)0)) { | |||
1009 | cached = 0; | |||
1010 | err = read_delta_data(&delta_buf, &delta_len, | |||
1011 | delta->data_offset, pack); | |||
1012 | if (err) | |||
1013 | return err; | |||
1014 | err = got_delta_cache_add(pack->delta_cache, | |||
1015 | delta->data_offset, delta_buf, delta_len); | |||
1016 | if (err == NULL((void *)0)) | |||
1017 | cached = 1; | |||
1018 | else if (err->code != GOT_ERR_NO_SPACE9) { | |||
1019 | free(delta_buf); | |||
1020 | return err; | |||
1021 | } | |||
1022 | } | |||
1023 | err = got_delta_get_sizes(&base_size, &result_size, | |||
1024 | delta_buf, delta_len); | |||
1025 | if (!cached) | |||
1026 | free(delta_buf); | |||
1027 | if (err) | |||
1028 | return err; | |||
1029 | } else | |||
1030 | base_size = delta->size; | |||
1031 | if (base_size > *max_size) | |||
1032 | *max_size = base_size; | |||
1033 | if (result_size > *max_size) | |||
1034 | *max_size = result_size; | |||
1035 | } | |||
1036 | ||||
1037 | return NULL((void *)0); | |||
1038 | } | |||
1039 | ||||
1040 | const struct got_error * | |||
1041 | got_pack_get_max_delta_object_size(uint64_t *size, struct got_object *obj, | |||
1042 | struct got_pack *pack) | |||
1043 | { | |||
1044 | if ((obj->flags & GOT_OBJ_FLAG_DELTIFIED0x02) == 0) | |||
1045 | return got_error(GOT_ERR_OBJ_TYPE11); | |||
1046 | ||||
1047 | return got_pack_get_delta_chain_max_size(size, &obj->deltas, pack); | |||
1048 | } | |||
1049 | ||||
1050 | const struct got_error * | |||
1051 | got_pack_dump_delta_chain_to_file(size_t *result_size, | |||
1052 | struct got_delta_chain *deltas, struct got_pack *pack, FILE *outfile, | |||
1053 | FILE *base_file, FILE *accum_file) | |||
1054 | { | |||
1055 | const struct got_error *err = NULL((void *)0); | |||
1056 | struct got_delta *delta; | |||
1057 | uint8_t *base_buf = NULL((void *)0), *accum_buf = NULL((void *)0), *delta_buf; | |||
1058 | size_t base_bufsz = 0, accum_size = 0, delta_len; | |||
1059 | uint64_t max_size; | |||
1060 | int n = 0; | |||
1061 | ||||
1062 | *result_size = 0; | |||
1063 | ||||
1064 | if (SIMPLEQ_EMPTY(&deltas->entries)(((&deltas->entries)->sqh_first) == ((void *)0))) | |||
1065 | return got_error(GOT_ERR_BAD_DELTA_CHAIN20); | |||
1066 | ||||
1067 | /* We process small enough files entirely in memory for speed. */ | |||
1068 | err = got_pack_get_delta_chain_max_size(&max_size, deltas, pack); | |||
1069 | if (err) | |||
1070 | return err; | |||
1071 | if (max_size < GOT_DELTA_RESULT_SIZE_CACHED_MAX(8 * 1024 * 1024)) { | |||
1072 | accum_buf = malloc(max_size); | |||
1073 | if (accum_buf == NULL((void *)0)) | |||
1074 | return got_error_from_errno("malloc"); | |||
1075 | base_file = NULL((void *)0); | |||
1076 | accum_file = NULL((void *)0); | |||
1077 | } | |||
1078 | ||||
1079 | /* Deltas are ordered in ascending order. */ | |||
1080 | SIMPLEQ_FOREACH(delta, &deltas->entries, entry)for((delta) = ((&deltas->entries)->sqh_first); (delta ) != ((void *)0); (delta) = ((delta)->entry.sqe_next)) { | |||
1081 | int cached = 1; | |||
1082 | if (n == 0) { | |||
1083 | size_t mapoff; | |||
1084 | off_t delta_data_offset; | |||
1085 | ||||
1086 | /* Plain object types are the delta base. */ | |||
1087 | if (delta->type != GOT_OBJ_TYPE_COMMIT1 && | |||
1088 | delta->type != GOT_OBJ_TYPE_TREE2 && | |||
1089 | delta->type != GOT_OBJ_TYPE_BLOB3 && | |||
1090 | delta->type != GOT_OBJ_TYPE_TAG4) { | |||
1091 | err = got_error(GOT_ERR_BAD_DELTA_CHAIN20); | |||
1092 | goto done; | |||
1093 | } | |||
1094 | ||||
1095 | delta_data_offset = delta->offset + delta->tslen; | |||
1096 | if (delta_data_offset >= pack->filesize) { | |||
1097 | err = got_error(GOT_ERR_PACK_OFFSET42); | |||
1098 | goto done; | |||
1099 | } | |||
1100 | if (pack->map == NULL((void *)0)) { | |||
1101 | if (lseek(pack->fd, delta_data_offset, SEEK_SET0) | |||
1102 | == -1) { | |||
1103 | err = got_error_from_errno("lseek"); | |||
1104 | goto done; | |||
1105 | } | |||
1106 | } | |||
1107 | if (base_file) { | |||
1108 | if (pack->map) { | |||
1109 | mapoff = (size_t)delta_data_offset; | |||
1110 | err = got_inflate_to_file_mmap( | |||
1111 | &base_bufsz, NULL((void *)0), NULL((void *)0), pack->map, | |||
1112 | mapoff, pack->filesize - mapoff, | |||
1113 | base_file); | |||
1114 | } else | |||
1115 | err = got_inflate_to_file_fd( | |||
1116 | &base_bufsz, NULL((void *)0), NULL((void *)0), pack->fd, | |||
1117 | base_file); | |||
1118 | } else { | |||
1119 | if (pack->map) { | |||
1120 | mapoff = (size_t)delta_data_offset; | |||
1121 | err = got_inflate_to_mem_mmap(&base_buf, | |||
1122 | &base_bufsz, NULL((void *)0), NULL((void *)0), | |||
1123 | pack->map, mapoff, | |||
1124 | pack->filesize - mapoff); | |||
1125 | } else | |||
1126 | err = got_inflate_to_mem_fd(&base_buf, | |||
1127 | &base_bufsz, NULL((void *)0), NULL((void *)0), max_size, | |||
1128 | pack->fd); | |||
1129 | } | |||
1130 | if (err) | |||
1131 | goto done; | |||
1132 | n++; | |||
1133 | if (base_file) | |||
1134 | rewind(base_file); | |||
1135 | continue; | |||
1136 | } | |||
1137 | ||||
1138 | got_delta_cache_get(&delta_buf, &delta_len, | |||
1139 | pack->delta_cache, delta->data_offset); | |||
1140 | if (delta_buf == NULL((void *)0)) { | |||
1141 | cached = 0; | |||
1142 | err = read_delta_data(&delta_buf, &delta_len, | |||
1143 | delta->data_offset, pack); | |||
1144 | if (err) | |||
1145 | goto done; | |||
1146 | err = got_delta_cache_add(pack->delta_cache, | |||
1147 | delta->data_offset, delta_buf, delta_len); | |||
1148 | if (err == NULL((void *)0)) | |||
1149 | cached = 1; | |||
1150 | else if (err->code != GOT_ERR_NO_SPACE9) { | |||
1151 | free(delta_buf); | |||
1152 | goto done; | |||
1153 | } | |||
1154 | } | |||
1155 | if (base_buf) { | |||
1156 | err = got_delta_apply_in_mem(base_buf, base_bufsz, | |||
1157 | delta_buf, delta_len, accum_buf, | |||
1158 | &accum_size, max_size); | |||
1159 | n++; | |||
1160 | } else { | |||
1161 | err = got_delta_apply(base_file, delta_buf, | |||
1162 | delta_len, | |||
1163 | /* Final delta application writes to output file. */ | |||
1164 | ++n < deltas->nentries ? accum_file : outfile, | |||
1165 | &accum_size); | |||
1166 | } | |||
1167 | if (!cached) | |||
1168 | free(delta_buf); | |||
1169 | if (err) | |||
1170 | goto done; | |||
1171 | ||||
1172 | if (n < deltas->nentries) { | |||
1173 | /* Accumulated delta becomes the new base. */ | |||
1174 | if (base_buf) { | |||
1175 | uint8_t *tmp = accum_buf; | |||
1176 | /* | |||
1177 | * Base buffer switches roles with accumulation | |||
1178 | * buffer. Ensure it can hold the largest | |||
1179 | * result in the delta chain. The initial | |||
1180 | * allocation might have been smaller. | |||
1181 | */ | |||
1182 | if (base_bufsz < max_size) { | |||
1183 | uint8_t *p; | |||
1184 | p = reallocarray(base_buf, 1, max_size); | |||
1185 | if (p == NULL((void *)0)) { | |||
1186 | err = got_error_from_errno( | |||
1187 | "reallocarray"); | |||
1188 | goto done; | |||
1189 | } | |||
1190 | base_buf = p; | |||
1191 | base_bufsz = max_size; | |||
1192 | } | |||
1193 | accum_buf = base_buf; | |||
1194 | base_buf = tmp; | |||
1195 | } else { | |||
1196 | FILE *tmp = accum_file; | |||
1197 | accum_file = base_file; | |||
1198 | base_file = tmp; | |||
1199 | rewind(base_file); | |||
1200 | rewind(accum_file); | |||
1201 | } | |||
1202 | } | |||
1203 | } | |||
1204 | ||||
1205 | done: | |||
1206 | free(base_buf); | |||
1207 | if (accum_buf) { | |||
1208 | size_t len = fwrite(accum_buf, 1, accum_size, outfile); | |||
1209 | free(accum_buf); | |||
1210 | if (len != accum_size) | |||
1211 | err = got_ferror(outfile, GOT_ERR_IO6); | |||
1212 | } | |||
1213 | rewind(outfile); | |||
1214 | if (err == NULL((void *)0)) | |||
1215 | *result_size = accum_size; | |||
1216 | return err; | |||
1217 | } | |||
1218 | ||||
1219 | const struct got_error * | |||
1220 | got_pack_dump_delta_chain_to_mem(uint8_t **outbuf, size_t *outlen, | |||
1221 | struct got_delta_chain *deltas, struct got_pack *pack) | |||
1222 | { | |||
1223 | const struct got_error *err = NULL((void *)0); | |||
1224 | struct got_delta *delta; | |||
1225 | uint8_t *base_buf = NULL((void *)0), *accum_buf = NULL((void *)0), *delta_buf; | |||
1226 | size_t base_bufsz = 0, accum_size = 0, delta_len; | |||
1227 | uint64_t max_size; | |||
1228 | int n = 0; | |||
1229 | ||||
1230 | *outbuf = NULL((void *)0); | |||
1231 | *outlen = 0; | |||
1232 | ||||
1233 | if (SIMPLEQ_EMPTY(&deltas->entries)(((&deltas->entries)->sqh_first) == ((void *)0))) | |||
1234 | return got_error(GOT_ERR_BAD_DELTA_CHAIN20); | |||
1235 | ||||
1236 | err = got_pack_get_delta_chain_max_size(&max_size, deltas, pack); | |||
1237 | if (err) | |||
1238 | return err; | |||
1239 | accum_buf = malloc(max_size); | |||
1240 | if (accum_buf == NULL((void *)0)) | |||
1241 | return got_error_from_errno("malloc"); | |||
1242 | ||||
1243 | /* Deltas are ordered in ascending order. */ | |||
1244 | SIMPLEQ_FOREACH(delta, &deltas->entries, entry)for((delta) = ((&deltas->entries)->sqh_first); (delta ) != ((void *)0); (delta) = ((delta)->entry.sqe_next)) { | |||
1245 | int cached = 1; | |||
1246 | if (n == 0) { | |||
1247 | size_t delta_data_offset; | |||
1248 | ||||
1249 | /* Plain object types are the delta base. */ | |||
1250 | if (delta->type != GOT_OBJ_TYPE_COMMIT1 && | |||
1251 | delta->type != GOT_OBJ_TYPE_TREE2 && | |||
1252 | delta->type != GOT_OBJ_TYPE_BLOB3 && | |||
1253 | delta->type != GOT_OBJ_TYPE_TAG4) { | |||
1254 | err = got_error(GOT_ERR_BAD_DELTA_CHAIN20); | |||
1255 | goto done; | |||
1256 | } | |||
1257 | ||||
1258 | delta_data_offset = delta->offset + delta->tslen; | |||
1259 | if (delta_data_offset >= pack->filesize) { | |||
1260 | err = got_error(GOT_ERR_PACK_OFFSET42); | |||
1261 | goto done; | |||
1262 | } | |||
1263 | if (pack->map) { | |||
1264 | size_t mapoff = (size_t)delta_data_offset; | |||
1265 | err = got_inflate_to_mem_mmap(&base_buf, | |||
1266 | &base_bufsz, NULL((void *)0), NULL((void *)0), pack->map, | |||
1267 | mapoff, pack->filesize - mapoff); | |||
1268 | } else { | |||
1269 | if (lseek(pack->fd, delta_data_offset, SEEK_SET0) | |||
1270 | == -1) { | |||
1271 | err = got_error_from_errno("lseek"); | |||
1272 | goto done; | |||
1273 | } | |||
1274 | err = got_inflate_to_mem_fd(&base_buf, | |||
1275 | &base_bufsz, NULL((void *)0), NULL((void *)0), max_size, | |||
1276 | pack->fd); | |||
1277 | } | |||
1278 | if (err) | |||
1279 | goto done; | |||
1280 | n++; | |||
1281 | continue; | |||
1282 | } | |||
1283 | ||||
1284 | got_delta_cache_get(&delta_buf, &delta_len, | |||
1285 | pack->delta_cache, delta->data_offset); | |||
1286 | if (delta_buf == NULL((void *)0)) { | |||
1287 | cached = 0; | |||
1288 | err = read_delta_data(&delta_buf, &delta_len, | |||
1289 | delta->data_offset, pack); | |||
1290 | if (err) | |||
1291 | goto done; | |||
1292 | err = got_delta_cache_add(pack->delta_cache, | |||
1293 | delta->data_offset, delta_buf, delta_len); | |||
1294 | if (err == NULL((void *)0)) | |||
1295 | cached = 1; | |||
1296 | else if (err->code != GOT_ERR_NO_SPACE9) { | |||
1297 | free(delta_buf); | |||
1298 | goto done; | |||
1299 | } | |||
1300 | } | |||
1301 | err = got_delta_apply_in_mem(base_buf, base_bufsz, | |||
1302 | delta_buf, delta_len, accum_buf, | |||
1303 | &accum_size, max_size); | |||
1304 | if (!cached) | |||
1305 | free(delta_buf); | |||
1306 | n++; | |||
1307 | if (err) | |||
1308 | goto done; | |||
1309 | ||||
1310 | if (n < deltas->nentries) { | |||
1311 | /* Accumulated delta becomes the new base. */ | |||
1312 | uint8_t *tmp = accum_buf; | |||
1313 | /* | |||
1314 | * Base buffer switches roles with accumulation buffer. | |||
1315 | * Ensure it can hold the largest result in the delta | |||
1316 | * chain. Initial allocation might have been smaller. | |||
1317 | */ | |||
1318 | if (base_bufsz < max_size) { | |||
1319 | uint8_t *p; | |||
1320 | p = reallocarray(base_buf, 1, max_size); | |||
1321 | if (p == NULL((void *)0)) { | |||
1322 | err = got_error_from_errno( | |||
1323 | "reallocarray"); | |||
1324 | goto done; | |||
1325 | } | |||
1326 | base_buf = p; | |||
1327 | base_bufsz = max_size; | |||
1328 | } | |||
1329 | accum_buf = base_buf; | |||
1330 | base_buf = tmp; | |||
1331 | } | |||
1332 | } | |||
1333 | ||||
1334 | done: | |||
1335 | free(base_buf); | |||
1336 | if (err) { | |||
1337 | free(accum_buf); | |||
1338 | *outbuf = NULL((void *)0); | |||
1339 | *outlen = 0; | |||
1340 | } else { | |||
1341 | *outbuf = accum_buf; | |||
1342 | *outlen = accum_size; | |||
1343 | } | |||
1344 | return err; | |||
1345 | } | |||
1346 | ||||
1347 | const struct got_error * | |||
1348 | got_packfile_extract_object(struct got_pack *pack, struct got_object *obj, | |||
1349 | FILE *outfile, FILE *base_file, FILE *accum_file) | |||
1350 | { | |||
1351 | const struct got_error *err = NULL((void *)0); | |||
1352 | ||||
1353 | if ((obj->flags & GOT_OBJ_FLAG_PACKED0x01) == 0) | |||
1354 | return got_error(GOT_ERR_OBJ_NOT_PACKED19); | |||
1355 | ||||
1356 | if ((obj->flags & GOT_OBJ_FLAG_DELTIFIED0x02) == 0) { | |||
1357 | if (obj->pack_offset >= pack->filesize) | |||
1358 | return got_error(GOT_ERR_PACK_OFFSET42); | |||
1359 | ||||
1360 | if (pack->map) { | |||
1361 | size_t mapoff = (size_t)obj->pack_offset; | |||
1362 | err = got_inflate_to_file_mmap(&obj->size, NULL((void *)0), NULL((void *)0), | |||
1363 | pack->map, mapoff, pack->filesize - mapoff, | |||
1364 | outfile); | |||
1365 | } else { | |||
1366 | if (lseek(pack->fd, obj->pack_offset, SEEK_SET0) == -1) | |||
1367 | return got_error_from_errno("lseek"); | |||
1368 | err = got_inflate_to_file_fd(&obj->size, NULL((void *)0), NULL((void *)0), | |||
1369 | pack->fd, outfile); | |||
1370 | } | |||
1371 | } else | |||
1372 | err = got_pack_dump_delta_chain_to_file(&obj->size, | |||
1373 | &obj->deltas, pack, outfile, base_file, accum_file); | |||
1374 | ||||
1375 | return err; | |||
1376 | } | |||
1377 | ||||
1378 | const struct got_error * | |||
1379 | got_packfile_extract_object_to_mem(uint8_t **buf, size_t *len, | |||
1380 | struct got_object *obj, struct got_pack *pack) | |||
1381 | { | |||
1382 | const struct got_error *err = NULL((void *)0); | |||
1383 | ||||
1384 | if ((obj->flags & GOT_OBJ_FLAG_PACKED0x01) == 0) | |||
1385 | return got_error(GOT_ERR_OBJ_NOT_PACKED19); | |||
1386 | ||||
1387 | if ((obj->flags & GOT_OBJ_FLAG_DELTIFIED0x02) == 0) { | |||
1388 | if (obj->pack_offset >= pack->filesize) | |||
1389 | return got_error(GOT_ERR_PACK_OFFSET42); | |||
1390 | if (pack->map) { | |||
1391 | size_t mapoff = (size_t)obj->pack_offset; | |||
1392 | err = got_inflate_to_mem_mmap(buf, len, NULL((void *)0), NULL((void *)0), | |||
1393 | pack->map, mapoff, pack->filesize - mapoff); | |||
1394 | } else { | |||
1395 | if (lseek(pack->fd, obj->pack_offset, SEEK_SET0) == -1) | |||
1396 | return got_error_from_errno("lseek"); | |||
1397 | err = got_inflate_to_mem_fd(buf, len, NULL((void *)0), NULL((void *)0), | |||
1398 | obj->size, pack->fd); | |||
1399 | } | |||
1400 | } else | |||
1401 | err = got_pack_dump_delta_chain_to_mem(buf, len, &obj->deltas, | |||
1402 | pack); | |||
1403 | ||||
1404 | return err; | |||
1405 | } |