archive.c (20686B)
1 /* POSIX ar archive reader/writer. */ 2 3 #include <kit/archive.h> 4 #include <kit/object.h> 5 6 #include "core/bytes.h" 7 #include "core/core.h" 8 #include "core/heap.h" 9 #include "core/slice.h" 10 11 /* ============================================================ 12 * Write helpers 13 * ============================================================ */ 14 15 static KitStatus wh_bytes(Writer* w, const void* p, size_t n) { 16 return kit_writer_write(w, p, n); 17 } 18 static KitStatus wh_char(Writer* w, char c) { 19 return kit_writer_write(w, &c, 1); 20 } 21 static KitStatus wh_nl(Writer* w) { return wh_char(w, '\n'); } 22 23 static void wh_ar_num(char* dst, int width, u64 v) { 24 char tmp[20]; 25 int len = 0, i; 26 if (v == 0) { 27 tmp[len++] = '0'; 28 } else { 29 u64 t = v; 30 while (t) { 31 tmp[len++] = '0' + (int)(t % 10); 32 t /= 10; 33 } 34 } 35 for (i = 0; i < len / 2; ++i) { 36 char x = tmp[i]; 37 tmp[i] = tmp[len - 1 - i]; 38 tmp[len - 1 - i] = x; 39 } 40 for (i = 0; i < len && i < width; ++i) dst[i] = tmp[i]; 41 for (; i < width; ++i) dst[i] = ' '; 42 } 43 44 static KitStatus wh_be32(Writer* w, u32 v) { 45 u8 b[4]; 46 wr_u32_be(b, v); 47 return wh_bytes(w, b, 4); 48 } 49 50 static Slice ar_name_basename(Slice in) { 51 size_t start = 0, i; 52 for (i = 0; i < in.len; ++i) { 53 if (in.s[i] == '/') start = i + 1; 54 } 55 return (Slice){.s = in.s + start, .len = in.len - start}; 56 } 57 58 static int ar_name_needs_longtable(const char* name, size_t len) { 59 size_t i; 60 if (len > 15) return 1; 61 for (i = 0; i < len; ++i) 62 if (name[i] == '/') return 1; 63 return 0; 64 } 65 66 static size_t ar_member_padded_size(size_t len) { return 60 + len + (len & 1); } 67 68 static void ar_fill_header(char hdr[60], const char name_field[16], 69 uint64_t epoch, uint64_t size) { 70 size_t j; 71 for (j = 0; j < 16; ++j) hdr[j] = name_field[j]; 72 for (j = 16; j < 28; ++j) hdr[j] = ' '; 73 if (epoch) 74 wh_ar_num(hdr + 16, 12, epoch); 75 else 76 hdr[16] = '0'; 77 for (j = 28; j < 34; ++j) hdr[j] = ' '; 78 hdr[28] = '0'; 79 for (j = 34; j < 40; ++j) hdr[j] = ' '; 80 hdr[34] = '0'; 81 for (j = 40; j < 48; ++j) hdr[j] = ' '; 82 hdr[40] = '6'; 83 hdr[41] = '4'; 84 hdr[42] = '4'; 85 wh_ar_num(hdr + 48, 10, size); 86 hdr[58] = '`'; 87 hdr[59] = '\n'; 88 } 89 90 KitStatus kit_ar_write(KitWriter* out, const KitArInput* members, 91 uint32_t nmembers, const KitArWriteOptions* opts) { 92 static const char magic[] = "!<arch>\n"; 93 static const KitArWriteOptions default_opts = {0, 0, 0, NULL}; 94 uint32_t i; 95 uint64_t epoch; 96 int long_names; 97 int symbol_index; 98 const KitArMemberSymbols* msyms; 99 uint64_t longtab_size = 0; 100 uint32_t nsyms = 0; 101 uint64_t names_size = 0; 102 uint64_t index_payload = 0; 103 uint64_t index_total = 0; 104 uint64_t longtab_total = 0; 105 char pad = '\n'; 106 107 if (!out) return KIT_INVALID; 108 if (!members && nmembers) return KIT_INVALID; 109 110 if (!opts) opts = &default_opts; 111 epoch = opts->epoch; 112 long_names = opts->long_names; 113 symbol_index = opts->symbol_index; 114 msyms = opts->member_symbols; 115 116 if (long_names) { 117 for (i = 0; i < nmembers; ++i) { 118 Slice base; 119 if (!members[i].name.s) return KIT_INVALID; 120 base = ar_name_basename(members[i].name); 121 if (ar_name_needs_longtable(base.s, base.len)) { 122 longtab_size += (uint64_t)base.len + 2; 123 } 124 } 125 } else { 126 for (i = 0; i < nmembers; ++i) { 127 if (!members[i].name.s) return KIT_INVALID; 128 } 129 } 130 131 if (symbol_index) { 132 if (msyms) { 133 for (i = 0; i < nmembers; ++i) { 134 u32 k; 135 if (msyms[i].count && !msyms[i].names) return KIT_INVALID; 136 for (k = 0; k < msyms[i].count; ++k) { 137 Slice nm = msyms[i].names[k]; 138 if (!nm.s) return KIT_INVALID; 139 nsyms += 1; 140 names_size += (uint64_t)nm.len + 1; 141 } 142 } 143 } 144 index_payload = (uint64_t)4 + (uint64_t)4 * (uint64_t)nsyms + names_size; 145 index_total = 60 + index_payload + (index_payload & 1); 146 } 147 if (longtab_size) { 148 longtab_total = 60 + longtab_size + (longtab_size & 1); 149 } 150 151 wh_bytes(out, magic, 8); 152 153 if (symbol_index) { 154 char hdr[60]; 155 char name_field[16]; 156 size_t j; 157 uint64_t cur_offset; 158 159 for (j = 0; j < 16; ++j) name_field[j] = ' '; 160 name_field[0] = '/'; 161 ar_fill_header(hdr, name_field, epoch, index_payload); 162 wh_bytes(out, hdr, 60); 163 164 wh_be32(out, nsyms); 165 166 cur_offset = (uint64_t)8 + index_total + longtab_total; 167 if (msyms) { 168 for (i = 0; i < nmembers; ++i) { 169 u32 k; 170 for (k = 0; k < msyms[i].count; ++k) { 171 wh_be32(out, (u32)cur_offset); 172 } 173 cur_offset += ar_member_padded_size(members[i].bytes.len); 174 } 175 } 176 177 if (msyms) { 178 for (i = 0; i < nmembers; ++i) { 179 u32 k; 180 for (k = 0; k < msyms[i].count; ++k) { 181 Slice nm = msyms[i].names[k]; 182 static const char nul = '\0'; 183 wh_bytes(out, nm.s, nm.len); 184 wh_bytes(out, &nul, 1); 185 } 186 } 187 } 188 189 if (index_payload & 1) wh_bytes(out, &pad, 1); 190 } 191 192 if (longtab_size) { 193 char hdr[60]; 194 char name_field[16]; 195 size_t j; 196 for (j = 0; j < 16; ++j) name_field[j] = ' '; 197 name_field[0] = '/'; 198 name_field[1] = '/'; 199 ar_fill_header(hdr, name_field, 0, longtab_size); 200 wh_bytes(out, hdr, 60); 201 for (i = 0; i < nmembers; ++i) { 202 Slice base = ar_name_basename(members[i].name); 203 if (ar_name_needs_longtable(base.s, base.len)) { 204 wh_bytes(out, base.s, base.len); 205 wh_bytes(out, "/\n", 2); 206 } 207 } 208 if (longtab_size & 1) wh_bytes(out, &pad, 1); 209 } 210 211 { 212 uint64_t longtab_off = 0; 213 for (i = 0; i < nmembers; ++i) { 214 const KitArInput* m = &members[i]; 215 Slice base = ar_name_basename(m->name); 216 char hdr[60]; 217 char name_field[16]; 218 size_t j; 219 220 for (j = 0; j < 16; ++j) name_field[j] = ' '; 221 if (long_names && ar_name_needs_longtable(base.s, base.len)) { 222 name_field[0] = '/'; 223 wh_ar_num(name_field + 1, 15, longtab_off); 224 longtab_off += (uint64_t)base.len + 2; 225 } else { 226 size_t emit = base.len > 15 ? 15 : base.len; 227 for (j = 0; j < emit; ++j) name_field[j] = base.s[j]; 228 name_field[emit] = '/'; 229 } 230 231 ar_fill_header(hdr, name_field, epoch, (uint64_t)m->bytes.len); 232 wh_bytes(out, hdr, 60); 233 if (m->bytes.data && m->bytes.len) 234 wh_bytes(out, m->bytes.data, m->bytes.len); 235 if (m->bytes.len & 1) wh_bytes(out, &pad, 1); 236 } 237 } 238 239 return kit_writer_status(out); 240 } 241 242 /* ============================================================ 243 * Read (iterator) and list 244 * ============================================================ */ 245 246 #define AR_NAMEBUF 256 247 248 struct KitArIter { 249 const KitContext* ctx; 250 const u8* p; 251 const u8* end; 252 const u8* longnames; 253 size_t longnames_len; 254 char namebuf[AR_NAMEBUF]; 255 }; 256 257 static size_t ar_resolve_longname(KitArIter* it, uint64_t off) { 258 size_t i; 259 if (!it->longnames) return 0; 260 if (off >= it->longnames_len) return 0; 261 for (i = 0; i + 1 < sizeof(it->namebuf); ++i) { 262 size_t k = (size_t)off + i; 263 char ch; 264 if (k >= it->longnames_len) break; 265 ch = (char)it->longnames[k]; 266 if (ch == '/' || ch == '\n') break; 267 it->namebuf[i] = ch; 268 } 269 it->namebuf[i] = '\0'; 270 return i; 271 } 272 273 KitStatus kit_ar_iter_new(const KitContext* ctx, const KitSlice* archive, 274 KitArIter** out) { 275 Heap* h; 276 KitArIter* it; 277 if (!out) return KIT_INVALID; 278 if (!ctx || !ctx->heap || !archive) return KIT_INVALID; 279 if (!archive->data && archive->len) return KIT_INVALID; 280 if (kit_detect_fmt(archive->data, archive->len) != KIT_BIN_AR) 281 return KIT_MALFORMED; 282 h = ctx->heap; 283 it = (KitArIter*)h->alloc(h, sizeof(*it), _Alignof(KitArIter)); 284 if (!it) return KIT_NOMEM; 285 it->ctx = ctx; 286 it->p = archive->data + 8; 287 it->end = archive->data + archive->len; 288 it->longnames = NULL; 289 it->longnames_len = 0; 290 it->namebuf[0] = '\0'; 291 *out = it; 292 return KIT_OK; 293 } 294 295 KitIterResult kit_ar_iter_next(KitArIter* it, KitArMember* out) { 296 if (!it || !out) return KIT_ITER_ERROR; 297 for (;;) { 298 uint64_t size; 299 size_t avail; 300 int j; 301 int namelen; 302 char name_field[16]; 303 304 if (it->p + 60 > it->end) return KIT_ITER_END; 305 306 for (j = 0; j < 16; ++j) name_field[j] = (char)it->p[j]; 307 308 size = 0; 309 for (j = 48; j < 58; ++j) { 310 char ch = (char)it->p[j]; 311 if (ch < '0' || ch > '9') break; 312 size = size * 10 + (uint64_t)(unsigned char)(ch - '0'); 313 } 314 315 it->p += 60; 316 avail = (size_t)(it->end - it->p); 317 if ((uint64_t)avail < size) return KIT_ITER_END; 318 319 if (name_field[0] == '/' && name_field[1] == '/') { 320 it->longnames = it->p; 321 it->longnames_len = (size_t)size; 322 goto advance; 323 } 324 if (name_field[0] == '/' && name_field[1] == ' ') { 325 goto advance; 326 } 327 328 if (name_field[0] == '/' && name_field[1] >= '0' && name_field[1] <= '9') { 329 uint64_t off = 0; 330 for (j = 1; j < 16; ++j) { 331 char ch = name_field[j]; 332 if (ch < '0' || ch > '9') break; 333 off = off * 10 + (uint64_t)(unsigned char)(ch - '0'); 334 } 335 namelen = (int)ar_resolve_longname(it, off); 336 } else if (name_field[0] == '#' && name_field[1] == '1' && 337 name_field[2] == '/') { 338 uint64_t nlen = 0; 339 size_t k; 340 for (j = 3; j < 16; ++j) { 341 char ch = name_field[j]; 342 if (ch < '0' || ch > '9') break; 343 nlen = nlen * 10 + (uint64_t)(unsigned char)(ch - '0'); 344 } 345 if (nlen > size || nlen + 1 > sizeof(it->namebuf)) return KIT_ITER_ERROR; 346 namelen = 0; 347 for (k = 0; k < (size_t)nlen; ++k) { 348 char ch = (char)it->p[k]; 349 if (ch == '\0') break; 350 it->namebuf[namelen++] = ch; 351 } 352 it->namebuf[namelen] = '\0'; 353 it->p += (size_t)nlen; 354 size -= nlen; 355 } else { 356 namelen = 0; 357 for (j = 0; j < 16; ++j) { 358 char ch = name_field[j]; 359 if (ch == '/' || ch == ' ' || ch == '\0') break; 360 it->namebuf[namelen++] = ch; 361 } 362 it->namebuf[namelen] = '\0'; 363 } 364 365 out->name.s = it->namebuf; 366 out->name.len = namelen; 367 out->data = it->p; 368 out->size = (size_t)size; 369 370 it->p += (size_t)size; 371 if ((size & 1) && it->p < it->end) it->p++; 372 373 if (it->namebuf[0] == '_' && it->namebuf[1] == '_' && 374 it->namebuf[2] == '.') { 375 continue; 376 } 377 if (namelen > 0) return KIT_ITER_ITEM; 378 continue; 379 380 advance: 381 it->p += (size_t)size; 382 if ((size & 1) && it->p < it->end) it->p++; 383 } 384 } 385 386 void kit_ar_iter_free(KitArIter* it) { 387 Heap* h; 388 if (!it) return; 389 h = it->ctx->heap; 390 h->free(h, it, sizeof(*it)); 391 } 392 393 /* ============================================================ 394 * Symbol-index automation 395 * ============================================================ */ 396 397 /* The owned block is laid out as 398 * [size_t alloc_sz][KitSlice names[count]][NUL-separated name bytes] 399 * so the exact size for the size-tracking heap free travels with the block. 400 * *out_owned points at the header; out_syms->names points past it. */ 401 #define AR_SYMBLOB_HDR_BYTES \ 402 ((sizeof(size_t) + _Alignof(KitSlice) - 1u) & ~(_Alignof(KitSlice) - 1u)) 403 404 KitStatus kit_obj_global_syms(const KitContext* ctx, const KitSlice* obj_bytes, 405 KitArMemberSymbols* out_syms, void** out_owned) { 406 Heap* h; 407 KitObjFile* of = NULL; 408 KitObjSymIter* it = NULL; 409 KitObjSymInfo si; 410 u32 count = 0; 411 size_t name_bytes = 0; 412 size_t alloc_sz; 413 char* blob; 414 KitSlice* name_arr; 415 char* name_storage; 416 size_t cursor = 0; 417 418 if (!out_syms || !out_owned) return KIT_INVALID; 419 out_syms->names = NULL; 420 out_syms->count = 0; 421 *out_owned = NULL; 422 if (!ctx || !ctx->heap || !obj_bytes) return KIT_INVALID; 423 h = ctx->heap; 424 425 if (kit_obj_open(ctx, KIT_SLICE_NULL, obj_bytes, &of) != KIT_OK) { 426 /* Not a recognized object — the empty set, not an error. */ 427 return KIT_OK; 428 } 429 430 /* Pass A: count + measure name bytes. */ 431 if (kit_obj_symiter_new(of, &it) != KIT_OK) { 432 kit_obj_free(of); 433 return KIT_NOMEM; 434 } 435 for (;;) { 436 KitIterResult r = kit_obj_symiter_next(it, &si); 437 if (r != KIT_ITER_ITEM) break; 438 if (si.bind != KIT_SB_GLOBAL) continue; 439 if (si.section == KIT_SECTION_NONE) continue; 440 if (!si.name.len) continue; 441 count += 1; 442 name_bytes += si.name.len + 1; /* +NUL */ 443 } 444 kit_obj_symiter_free(it); 445 446 if (count == 0) { 447 kit_obj_free(of); 448 return KIT_OK; 449 } 450 451 alloc_sz = AR_SYMBLOB_HDR_BYTES + (size_t)count * sizeof(KitSlice) + name_bytes; 452 blob = (char*)h->alloc(h, alloc_sz, _Alignof(KitSlice)); 453 if (!blob) { 454 kit_obj_free(of); 455 return KIT_NOMEM; 456 } 457 *(size_t*)(void*)blob = alloc_sz; 458 name_arr = (KitSlice*)(void*)(blob + AR_SYMBLOB_HDR_BYTES); 459 name_storage = (char*)name_arr + (size_t)count * sizeof(KitSlice); 460 461 /* Pass B: copy names. */ 462 if (kit_obj_symiter_new(of, &it) != KIT_OK) { 463 h->free(h, blob, alloc_sz); 464 kit_obj_free(of); 465 return KIT_NOMEM; 466 } 467 { 468 u32 k = 0; 469 for (;;) { 470 KitIterResult r; 471 char* dst; 472 size_t j; 473 if (k >= count) break; 474 r = kit_obj_symiter_next(it, &si); 475 if (r != KIT_ITER_ITEM) break; 476 if (si.bind != KIT_SB_GLOBAL) continue; 477 if (si.section == KIT_SECTION_NONE) continue; 478 if (!si.name.len) continue; 479 dst = name_storage + cursor; 480 name_arr[k].s = dst; 481 name_arr[k].len = si.name.len; 482 for (j = 0; j < si.name.len; ++j) *dst++ = si.name.s[j]; 483 *dst++ = '\0'; 484 cursor = (size_t)(dst - name_storage); 485 k++; 486 } 487 count = k; 488 } 489 kit_obj_symiter_free(it); 490 kit_obj_free(of); 491 492 out_syms->names = name_arr; 493 out_syms->count = count; 494 *out_owned = blob; 495 return KIT_OK; 496 } 497 498 void kit_obj_global_syms_free(const KitContext* ctx, void* owned) { 499 Heap* h; 500 size_t alloc_sz; 501 if (!ctx || !ctx->heap || !owned) return; 502 h = ctx->heap; 503 alloc_sz = *(const size_t*)owned; 504 h->free(h, owned, alloc_sz); 505 } 506 507 /* Serialize one builder into a fresh in-memory writer; the returned bytes 508 * alias that writer's buffer, so the writer must stay open until the bytes 509 * have been consumed. */ 510 static KitStatus ar_emit_member(const KitContext* ctx, KitObjBuilder* b, 511 KitSlice name, KitWriter** w_out, 512 KitSlice* bytes_out) { 513 const uint8_t* bytes; 514 size_t len = 0; 515 (void)name; 516 if (kit_writer_mem(ctx->heap, w_out) != KIT_OK) return KIT_NOMEM; 517 if (kit_obj_builder_emit(b, *w_out) != KIT_OK || 518 kit_writer_status(*w_out) != KIT_OK) 519 return KIT_ERR; 520 bytes = kit_writer_mem_bytes(*w_out, &len); 521 bytes_out->s = (const char*)bytes; 522 bytes_out->len = len; 523 return KIT_OK; 524 } 525 526 /* Shared tail of kit_ar_write_objs / kit_ar_reindex: given member name/byte 527 * slices already laid out in `members`, compute each member's symbol index and 528 * write the long-names + symbol-index archive. */ 529 static KitStatus ar_write_with_index(const KitContext* ctx, KitArInput* members, 530 u32 n, u64 epoch, KitWriter* out) { 531 Heap* h = ctx->heap; 532 KitArMemberSymbols* msyms = NULL; 533 void** owned = NULL; 534 KitArWriteOptions opts = {0}; 535 KitStatus st = KIT_OK; 536 u32 i; 537 538 if (n) { 539 msyms = (KitArMemberSymbols*)h->alloc(h, (size_t)n * sizeof(*msyms), 540 _Alignof(KitArMemberSymbols)); 541 owned = (void**)h->alloc(h, (size_t)n * sizeof(*owned), _Alignof(void*)); 542 if (!msyms || !owned) { 543 st = KIT_NOMEM; 544 goto out; 545 } 546 for (i = 0; i < n; ++i) { 547 msyms[i].names = NULL; 548 msyms[i].count = 0; 549 owned[i] = NULL; 550 } 551 for (i = 0; i < n; ++i) { 552 st = kit_obj_global_syms(ctx, &members[i].bytes, &msyms[i], &owned[i]); 553 if (st != KIT_OK) goto out; 554 } 555 } 556 557 opts.epoch = epoch; 558 opts.long_names = 1; 559 opts.symbol_index = 1; 560 opts.member_symbols = msyms; 561 st = kit_ar_write(out, members, n, &opts); 562 if (st == KIT_OK && kit_writer_status(out) != KIT_OK) st = KIT_ERR; 563 564 out: 565 if (owned) { 566 for (i = 0; i < n; ++i) 567 if (owned[i]) kit_obj_global_syms_free(ctx, owned[i]); 568 h->free(h, owned, (size_t)n * sizeof(*owned)); 569 } 570 if (msyms) h->free(h, msyms, (size_t)n * sizeof(*msyms)); 571 return st; 572 } 573 574 KitStatus kit_ar_write_objs(const KitContext* ctx, KitObjBuilder* const* objs, 575 const KitSlice* names, uint32_t n, uint64_t epoch, 576 KitWriter* out) { 577 Heap* h; 578 KitArInput* members = NULL; 579 KitWriter** memw = NULL; 580 KitStatus st = KIT_OK; 581 u32 i; 582 583 if (!ctx || !ctx->heap || !out) return KIT_INVALID; 584 if (n && (!objs || !names)) return KIT_INVALID; 585 h = ctx->heap; 586 587 if (n) { 588 members = 589 (KitArInput*)h->alloc(h, (size_t)n * sizeof(*members), _Alignof(KitArInput)); 590 memw = (KitWriter**)h->alloc(h, (size_t)n * sizeof(*memw), _Alignof(KitWriter*)); 591 if (!members || !memw) { 592 st = KIT_NOMEM; 593 goto out; 594 } 595 for (i = 0; i < n; ++i) { 596 members[i].name = names[i]; 597 members[i].bytes = KIT_SLICE_NULL; 598 memw[i] = NULL; 599 } 600 /* Serialize every builder; the member bytes alias each writer's buffer, so 601 * the writers stay open until ar_write_with_index has consumed them. */ 602 for (i = 0; i < n; ++i) { 603 st = ar_emit_member(ctx, objs[i], names[i], &memw[i], &members[i].bytes); 604 if (st != KIT_OK) goto out; 605 } 606 } 607 608 st = ar_write_with_index(ctx, members, n, epoch, out); 609 610 out: 611 if (memw) { 612 for (i = 0; i < n; ++i) 613 if (memw[i]) kit_writer_close(memw[i]); 614 h->free(h, memw, (size_t)n * sizeof(*memw)); 615 } 616 if (members) h->free(h, members, (size_t)n * sizeof(*members)); 617 return st; 618 } 619 620 KitStatus kit_ar_reindex(const KitContext* ctx, const KitSlice* archive_bytes, 621 uint64_t epoch, KitWriter* out) { 622 Heap* h; 623 KitArIter* it = NULL; 624 KitArMember m; 625 KitArInput* members = NULL; 626 char* name_storage = NULL; 627 size_t name_bytes_total = 0; 628 u32 nmembers = 0; 629 KitStatus st = KIT_OK; 630 631 if (!ctx || !ctx->heap || !archive_bytes || !out) return KIT_INVALID; 632 h = ctx->heap; 633 634 /* Pass 1: count members + total name bytes (member names alias an internal 635 * buffer overwritten on each next(), so a stable copy is stashed). */ 636 if (kit_ar_iter_new(ctx, archive_bytes, &it) != KIT_OK) return KIT_MALFORMED; 637 for (;;) { 638 KitIterResult r = kit_ar_iter_next(it, &m); 639 if (r != KIT_ITER_ITEM) break; 640 nmembers++; 641 name_bytes_total += m.name.len + 1; 642 } 643 kit_ar_iter_free(it); 644 it = NULL; 645 646 if (nmembers == 0) { 647 /* Empty archive: still emit an empty symbol index (matches GNU ranlib). */ 648 return ar_write_with_index(ctx, NULL, 0, epoch, out); 649 } 650 651 members = 652 (KitArInput*)h->alloc(h, (size_t)nmembers * sizeof(*members), 653 _Alignof(KitArInput)); 654 if (!members) return KIT_NOMEM; 655 if (name_bytes_total) { 656 name_storage = (char*)h->alloc(h, name_bytes_total, 1); 657 if (!name_storage) { 658 h->free(h, members, (size_t)nmembers * sizeof(*members)); 659 return KIT_NOMEM; 660 } 661 } 662 663 /* Pass 2: copy names and member byte-spans into the parallel arrays. */ 664 if (kit_ar_iter_new(ctx, archive_bytes, &it) != KIT_OK) { 665 st = KIT_MALFORMED; 666 goto out; 667 } 668 { 669 size_t cursor = 0; 670 u32 k = 0; 671 while (k < nmembers) { 672 KitIterResult r = kit_ar_iter_next(it, &m); 673 char* dst; 674 size_t j; 675 if (r != KIT_ITER_ITEM) break; 676 dst = name_storage + cursor; 677 for (j = 0; j < m.name.len; ++j) *dst++ = m.name.s[j]; 678 *dst++ = '\0'; 679 members[k].name.s = name_storage + cursor; 680 members[k].name.len = m.name.len; 681 members[k].bytes.data = m.data; 682 members[k].bytes.len = m.size; 683 cursor = (size_t)(dst - name_storage); 684 k++; 685 } 686 } 687 kit_ar_iter_free(it); 688 it = NULL; 689 690 st = ar_write_with_index(ctx, members, nmembers, epoch, out); 691 692 out: 693 if (it) kit_ar_iter_free(it); 694 if (name_storage) h->free(h, name_storage, name_bytes_total); 695 if (members) h->free(h, members, (size_t)nmembers * sizeof(*members)); 696 return st; 697 } 698 699 KitStatus kit_ar_list(const KitSlice* archive, KitWriter* out) { 700 /* Iter API requires a context; emulate locally without heap allocation. */ 701 struct KitArIter local; 702 KitArMember m; 703 704 if (!out) return KIT_INVALID; 705 if (!archive) return KIT_INVALID; 706 if (kit_detect_fmt(archive->data, archive->len) != KIT_BIN_AR) 707 return KIT_MALFORMED; 708 local.ctx = NULL; 709 local.p = archive->data + 8; 710 local.end = archive->data + archive->len; 711 local.longnames = NULL; 712 local.longnames_len = 0; 713 local.namebuf[0] = '\0'; 714 715 for (;;) { 716 KitIterResult r = kit_ar_iter_next(&local, &m); 717 if (r != KIT_ITER_ITEM) break; 718 wh_bytes(out, m.name.s, m.name.len); 719 wh_nl(out); 720 } 721 722 return kit_writer_status(out); 723 }