| File: | got/../lib/pack.c |
| Warning: | line 866, 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 | } |