archive.c (11299B)
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 KitStatus kit_ar_list(const KitSlice* archive, KitWriter* out) { 394 /* Iter API requires a context; emulate locally without heap allocation. */ 395 struct KitArIter local; 396 KitArMember m; 397 398 if (!out) return KIT_INVALID; 399 if (!archive) return KIT_INVALID; 400 if (kit_detect_fmt(archive->data, archive->len) != KIT_BIN_AR) 401 return KIT_MALFORMED; 402 local.ctx = NULL; 403 local.p = archive->data + 8; 404 local.end = archive->data + archive->len; 405 local.longnames = NULL; 406 local.longnames_len = 0; 407 local.namebuf[0] = '\0'; 408 409 for (;;) { 410 KitIterResult r = kit_ar_iter_next(&local, &m); 411 if (r != KIT_ITER_ITEM) break; 412 wh_bytes(out, m.name.s, m.name.len); 413 wh_nl(out); 414 } 415 416 return kit_writer_status(out); 417 }