bundle.c (58097B)
1 #include "bundle.h" 2 3 #include <stdio.h> 4 #include <string.h> 5 6 #define BUILD_BUNDLE_MANIFEST_PATH "manifest" 7 #define BUILD_BUNDLE_TRACE_DIR "trace" 8 #define BUILD_BUNDLE_BLOB_DIR "blob" 9 #define BUILD_BUNDLE_TEST_DEEP 2u 10 #define BUILD_BUNDLE_TEST_SHALLOW 3u 11 12 #if defined(__GNUC__) || defined(__clang__) 13 #define BUILD_MAYBE_UNUSED __attribute__((unused)) 14 #else 15 #define BUILD_MAYBE_UNUSED 16 #endif 17 18 typedef struct BuildIdVec { 19 uint8_t (*ids)[BUILD_HASH_LEN]; 20 size_t n; 21 size_t cap; 22 } BuildIdVec; 23 24 typedef struct ParsedTrace { 25 char target[BUILD_TARGET_MAX]; 26 uint8_t kind; 27 uint8_t output[BUILD_HASH_LEN]; 28 } ParsedTrace; 29 30 typedef struct RenderedArgv { 31 KitSlice* argv; 32 size_t argc; 33 char* storage; 34 size_t storage_size; 35 } RenderedArgv; 36 37 typedef struct TraceRenderTokens { 38 const char* target; 39 const char* out; 40 } TraceRenderTokens; 41 42 static int write_cstr(KitWriter* out, const char* s) { 43 return out && kit_writer_write(out, s, strlen(s)) == KIT_OK ? BUILD_OK 44 : BUILD_ERR; 45 } 46 47 static int hex_val(char c, unsigned* out) { 48 if (c >= '0' && c <= '9') { 49 *out = (unsigned)(c - '0'); 50 return BUILD_OK; 51 } 52 if (c >= 'a' && c <= 'f') { 53 *out = (unsigned)(c - 'a') + 10u; 54 return BUILD_OK; 55 } 56 return BUILD_ERR; 57 } 58 59 static void hex_encode(char out[BUILD_HEX_LEN], 60 const uint8_t in[BUILD_HASH_LEN]) { 61 size_t i; 62 static const char hexdigits[] = "0123456789abcdef"; 63 for (i = 0; i < BUILD_HASH_LEN; ++i) { 64 out[2u * i] = hexdigits[in[i] >> 4]; 65 out[2u * i + 1u] = hexdigits[in[i] & 0x0fu]; 66 } 67 out[2u * BUILD_HASH_LEN] = '\0'; 68 } 69 70 static int hex_decode(const char* s, uint8_t out[BUILD_HASH_LEN]) { 71 size_t i; 72 if (!s || strlen(s) != 2u * BUILD_HASH_LEN) return BUILD_ERR; 73 for (i = 0; i < BUILD_HASH_LEN; ++i) { 74 unsigned hi, lo; 75 if (hex_val(s[2u * i], &hi) != BUILD_OK || 76 hex_val(s[2u * i + 1u], &lo) != BUILD_OK) 77 return BUILD_ERR; 78 out[i] = (uint8_t)((hi << 4) | lo); 79 } 80 return BUILD_OK; 81 } 82 83 static int valid_token(const char* s, size_t cap) { 84 size_t i; 85 if (!s || !s[0]) return 0; 86 for (i = 0; s[i]; ++i) { 87 unsigned char c = (unsigned char)s[i]; 88 if (i + 1u >= cap || c <= 0x20u || c >= 0x7fu) return 0; 89 } 90 return 1; 91 } 92 93 static KitSlice str_slice(const char* s) { return kit_slice_cstr(s); } 94 95 static int BUILD_MAYBE_UNUSED path_set(char* out, size_t cap, KitSlice s) { 96 if (!out || cap == 0u || !s.s || s.len + 1u > cap) return BUILD_ERR; 97 memcpy(out, s.s, s.len); 98 out[s.len] = '\0'; 99 return BUILD_OK; 100 } 101 102 static int path_join2(char* out, size_t cap, const char* a, const char* b) { 103 size_t na, nb; 104 int need_sep; 105 if (!out || cap == 0u || !a || !b) return BUILD_ERR; 106 na = strlen(a); 107 nb = strlen(b); 108 need_sep = na > 0u && a[na - 1u] != '/'; 109 if (na + (need_sep ? 1u : 0u) + nb + 1u > cap) return BUILD_ERR; 110 memcpy(out, a, na); 111 if (need_sep) out[na++] = '/'; 112 memcpy(out + na, b, nb); 113 out[na + nb] = '\0'; 114 return BUILD_OK; 115 } 116 117 static int mkdir_p_host(const KitBuildCoordinator* c, const char* path) { 118 if (!c || !c->host.cas_host || !c->host.cas_host->mkdir_p || !path) 119 return BUILD_ERR; 120 return c->host.cas_host->mkdir_p(c->host.cas_host->user, path) == 0 121 ? BUILD_OK 122 : BUILD_ERR; 123 } 124 125 static int BUILD_MAYBE_UNUSED remove_path(const KitBuildCoordinator* c, 126 const char* path, int recursive) { 127 if (!c || !c->host.store_io || !c->host.store_io->remove || !path) 128 return BUILD_ERR; 129 return c->host.store_io->remove(c->host.store_io->user, str_slice(path), 130 recursive) == 0 131 ? BUILD_OK 132 : BUILD_ERR; 133 } 134 135 static int BUILD_MAYBE_UNUSED make_tmp_dir(const KitBuildCoordinator* c, 136 char* out, size_t cap) { 137 char parent[BUILD_PATH_MAX]; 138 if (!c || !c->host.store_io || !c->host.store_io->make_temp_dir) 139 return BUILD_ERR; 140 if (path_join2(parent, sizeof parent, c->store.root, "tmp") != BUILD_OK) 141 return BUILD_ERR; 142 if (mkdir_p_host(c, parent) != BUILD_OK) return BUILD_ERR; 143 return c->host.store_io->make_temp_dir(c->host.store_io->user, 144 str_slice(parent), out, cap) == 0 145 ? BUILD_OK 146 : BUILD_ERR; 147 } 148 149 static int write_file(const KitBuildCoordinator* c, const char* path, 150 const uint8_t* data, size_t len) { 151 KitWriter* w = NULL; 152 KitStatus st; 153 if (!c || !c->host.cas_host || !c->host.cas_host->file_io || 154 !c->host.cas_host->file_io->open_writer || !path || (!data && len)) 155 return BUILD_ERR; 156 if (c->host.cas_host->file_io->open_writer( 157 c->host.cas_host->file_io->user, path, &w) != KIT_OK || 158 !w) 159 return BUILD_ERR; 160 st = len ? kit_writer_write(w, data, len) : KIT_OK; 161 if (st == KIT_OK) st = kit_writer_status(w); 162 kit_writer_close(w); 163 return st == KIT_OK ? BUILD_OK : BUILD_ERR; 164 } 165 166 static int read_file(const KitBuildCoordinator* c, const char* path, 167 KitFileData* out) { 168 if (!c || !c->host.cas_host || !c->host.cas_host->file_io || 169 !c->host.cas_host->file_io->read_all || !path || !out) 170 return BUILD_ERR; 171 out->data = NULL; 172 out->size = 0u; 173 out->token = NULL; 174 return c->host.cas_host->file_io->read_all(c->host.cas_host->file_io->user, 175 path, out) == KIT_OK 176 ? BUILD_OK 177 : BUILD_ERR; 178 } 179 180 static void release_file(const KitBuildCoordinator* c, KitFileData* fd) { 181 if (!c || !fd || !c->host.cas_host || !c->host.cas_host->file_io || 182 !c->host.cas_host->file_io->release) 183 return; 184 if (fd->data) c->host.cas_host->file_io->release(c->host.cas_host->file_io->user, fd); 185 fd->data = NULL; 186 fd->size = 0u; 187 fd->token = NULL; 188 } 189 190 static int ensure_parent_dir(const KitBuildCoordinator* c, const char* path) { 191 char parent[BUILD_PATH_MAX]; 192 size_t n, i; 193 if (!path) return BUILD_ERR; 194 n = strlen(path); 195 for (i = n; i > 0u; --i) { 196 if (path[i - 1u] == '/') { 197 size_t len = i - 1u; 198 if (len == 0u) len = 1u; 199 if (len + 1u > sizeof parent) return BUILD_ERR; 200 memcpy(parent, path, len); 201 parent[len] = '\0'; 202 return mkdir_p_host(c, parent); 203 } 204 } 205 return BUILD_OK; 206 } 207 208 static int payload_id_path(char* out, size_t cap, const char* root, 209 const char* kind, 210 const uint8_t id[BUILD_HASH_LEN]) { 211 char hex[BUILD_HEX_LEN]; 212 char rel[BUILD_PATH_MAX]; 213 kit_hex_encode(hex, id, BUILD_HASH_LEN); 214 if (!root || !kind || !id) return BUILD_ERR; 215 if (snprintf(rel, sizeof rel, "%s/%c%c/%s", kind, hex[0], hex[1], hex) >= 216 (int)sizeof rel) 217 return BUILD_ERR; 218 return path_join2(out, cap, root, rel); 219 } 220 221 static size_t count_lines(const uint8_t* data, size_t len) { 222 size_t i, n = 0u; 223 for (i = 0u; i < len; ++i) 224 if (data[i] == '\n') ++n; 225 return n; 226 } 227 228 static int id_vec_contains(const BuildIdVec* v, 229 const uint8_t id[BUILD_HASH_LEN]) { 230 size_t i; 231 if (!v || !id) return 0; 232 for (i = 0u; i < v->n; ++i) 233 if (build_id_eq(v->ids[i], id)) return 1; 234 return 0; 235 } 236 237 static int id_vec_add(const KitContext* ctx, BuildIdVec* v, 238 const uint8_t id[BUILD_HASH_LEN]) { 239 uint8_t (*next)[BUILD_HASH_LEN]; 240 size_t next_cap; 241 if (!ctx || !ctx->heap || !v || !id) return BUILD_ERR; 242 if (id_vec_contains(v, id)) return BUILD_OK; 243 if (v->n == v->cap) { 244 next_cap = v->cap ? 2u * v->cap : 16u; 245 next = (uint8_t(*)[BUILD_HASH_LEN])ctx->heap->alloc( 246 ctx->heap, next_cap * sizeof *next, _Alignof(uint8_t)); 247 if (!next) return BUILD_ERR; 248 if (v->ids) { 249 memcpy(next, v->ids, v->n * sizeof *next); 250 ctx->heap->free(ctx->heap, v->ids, v->cap * sizeof *v->ids); 251 } 252 v->ids = next; 253 v->cap = next_cap; 254 } 255 memcpy(v->ids[v->n++], id, BUILD_HASH_LEN); 256 return BUILD_OK; 257 } 258 259 static void BUILD_MAYBE_UNUSED id_vec_free(const KitContext* ctx, 260 BuildIdVec* v) { 261 if (!ctx || !ctx->heap || !v) return; 262 if (v->ids) ctx->heap->free(ctx->heap, v->ids, v->cap * sizeof *v->ids); 263 v->ids = NULL; 264 v->n = 0u; 265 v->cap = 0u; 266 } 267 268 static int kind_valid(uint8_t kind) { 269 return kind == (uint8_t)BUILD_TRACE_DEEP || 270 kind == (uint8_t)BUILD_TRACE_SHALLOW || 271 kind == (uint8_t)BUILD_BUNDLE_TEST_DEEP || 272 kind == (uint8_t)BUILD_BUNDLE_TEST_SHALLOW; 273 } 274 275 static const char* kind_name(uint8_t kind) { 276 if (kind == (uint8_t)BUILD_TRACE_DEEP) return "deep"; 277 if (kind == (uint8_t)BUILD_TRACE_SHALLOW) return "shallow"; 278 if (kind == (uint8_t)BUILD_BUNDLE_TEST_DEEP) return "test-deep"; 279 if (kind == (uint8_t)BUILD_BUNDLE_TEST_SHALLOW) return "test-shallow"; 280 return NULL; 281 } 282 283 static int kind_parse(const char* s, uint8_t* out) { 284 if (strcmp(s, "deep") == 0) { 285 *out = (uint8_t)BUILD_TRACE_DEEP; 286 return BUILD_OK; 287 } 288 if (strcmp(s, "shallow") == 0) { 289 *out = (uint8_t)BUILD_TRACE_SHALLOW; 290 return BUILD_OK; 291 } 292 if (strcmp(s, "test-deep") == 0) { 293 *out = (uint8_t)BUILD_BUNDLE_TEST_DEEP; 294 return BUILD_OK; 295 } 296 if (strcmp(s, "test-shallow") == 0) { 297 *out = (uint8_t)BUILD_BUNDLE_TEST_SHALLOW; 298 return BUILD_OK; 299 } 300 return BUILD_ERR; 301 } 302 303 static void* heap_array(const KitContext* ctx, size_t n, size_t elem, 304 size_t align) { 305 if (!ctx || !ctx->heap || elem == 0u) return NULL; 306 if (n == 0u) n = 1u; 307 if (n > (size_t)-1 / elem) return NULL; 308 return ctx->heap->alloc(ctx->heap, n * elem, align); 309 } 310 311 static void heap_free_array(const KitContext* ctx, void* p, size_t n, 312 size_t elem) { 313 if (!ctx || !ctx->heap || !p || elem == 0u) return; 314 if (n == 0u) n = 1u; 315 ctx->heap->free(ctx->heap, p, n * elem); 316 } 317 318 static int BUILD_MAYBE_UNUSED parse_trace_header(const KitContext* ctx, 319 const uint8_t* data, 320 size_t len, 321 ParsedTrace* out) { 322 char err[160]; 323 if (!ctx || !data || !out) return BUILD_ERR; 324 memset(out, 0, sizeof *out); 325 if (len >= sizeof BUILD_DEEP_MAGIC && 326 memcmp(data, BUILD_DEEP_MAGIC "\n", sizeof BUILD_DEEP_MAGIC) == 0) { 327 BuildDeepTrace t; 328 if (build_deep_parse(data, len, &t, err, sizeof err) != BUILD_OK) 329 return BUILD_ERR; 330 snprintf(out->target, sizeof out->target, "%s", t.target); 331 out->kind = (uint8_t)BUILD_TRACE_DEEP; 332 memcpy(out->output, t.output, BUILD_HASH_LEN); 333 return BUILD_OK; 334 } 335 if (len >= sizeof BUILD_TEST_DEEP_MAGIC && 336 memcmp(data, BUILD_TEST_DEEP_MAGIC "\n", 337 sizeof BUILD_TEST_DEEP_MAGIC) == 0) { 338 BuildDeepTrace t; 339 if (build_test_deep_parse(data, len, &t, err, sizeof err) != BUILD_OK) 340 return BUILD_ERR; 341 snprintf(out->target, sizeof out->target, "%s", t.target); 342 out->kind = (uint8_t)BUILD_BUNDLE_TEST_DEEP; 343 memcpy(out->output, t.output, BUILD_HASH_LEN); 344 return BUILD_OK; 345 } 346 if (len >= sizeof BUILD_SHALLOW_MAGIC && 347 memcmp(data, BUILD_SHALLOW_MAGIC "\n", sizeof BUILD_SHALLOW_MAGIC) == 0) { 348 BuildShallowTrace t; 349 size_t rows = count_lines(data, len); 350 memset(&t, 0, sizeof t); 351 t.configs = (BuildConfigLeaf*)heap_array( 352 ctx, rows, sizeof *t.configs, _Alignof(BuildConfigLeaf)); 353 t.sources = (BuildSourceLeaf*)heap_array(ctx, rows, sizeof *t.sources, 354 _Alignof(BuildSourceLeaf)); 355 t.globs = (BuildGlobLeaf*)heap_array(ctx, rows, sizeof *t.globs, 356 _Alignof(BuildGlobLeaf)); 357 t.blobs = (BuildBlobLeaf*)heap_array(ctx, rows, sizeof *t.blobs, 358 _Alignof(BuildBlobLeaf)); 359 t.deps = (BuildDepEdge*)heap_array(ctx, rows, sizeof *t.deps, 360 _Alignof(BuildDepEdge)); 361 if (!t.configs || !t.sources || !t.globs || !t.blobs || !t.deps) { 362 heap_free_array(ctx, t.configs, rows, sizeof *t.configs); 363 heap_free_array(ctx, t.sources, rows, sizeof *t.sources); 364 heap_free_array(ctx, t.globs, rows, sizeof *t.globs); 365 heap_free_array(ctx, t.blobs, rows, sizeof *t.blobs); 366 heap_free_array(ctx, t.deps, rows, sizeof *t.deps); 367 return BUILD_ERR; 368 } 369 t.cap_configs = rows; 370 t.cap_sources = rows; 371 t.cap_globs = rows; 372 t.cap_blobs = rows; 373 t.cap_deps = rows; 374 if (build_shallow_parse(data, len, &t, err, sizeof err) != BUILD_OK) { 375 heap_free_array(ctx, t.configs, rows, sizeof *t.configs); 376 heap_free_array(ctx, t.sources, rows, sizeof *t.sources); 377 heap_free_array(ctx, t.globs, rows, sizeof *t.globs); 378 heap_free_array(ctx, t.blobs, rows, sizeof *t.blobs); 379 heap_free_array(ctx, t.deps, rows, sizeof *t.deps); 380 return BUILD_ERR; 381 } 382 snprintf(out->target, sizeof out->target, "%s", t.target); 383 out->kind = (uint8_t)BUILD_TRACE_SHALLOW; 384 memcpy(out->output, t.output, BUILD_HASH_LEN); 385 heap_free_array(ctx, t.configs, rows, sizeof *t.configs); 386 heap_free_array(ctx, t.sources, rows, sizeof *t.sources); 387 heap_free_array(ctx, t.globs, rows, sizeof *t.globs); 388 heap_free_array(ctx, t.blobs, rows, sizeof *t.blobs); 389 heap_free_array(ctx, t.deps, rows, sizeof *t.deps); 390 return BUILD_OK; 391 } 392 if (len >= sizeof BUILD_TEST_SHALLOW_MAGIC && 393 memcmp(data, BUILD_TEST_SHALLOW_MAGIC "\n", 394 sizeof BUILD_TEST_SHALLOW_MAGIC) == 0) { 395 BuildShallowTrace t; 396 size_t rows = count_lines(data, len); 397 memset(&t, 0, sizeof t); 398 t.configs = (BuildConfigLeaf*)heap_array( 399 ctx, rows, sizeof *t.configs, _Alignof(BuildConfigLeaf)); 400 t.sources = (BuildSourceLeaf*)heap_array(ctx, rows, sizeof *t.sources, 401 _Alignof(BuildSourceLeaf)); 402 t.globs = (BuildGlobLeaf*)heap_array(ctx, rows, sizeof *t.globs, 403 _Alignof(BuildGlobLeaf)); 404 t.blobs = (BuildBlobLeaf*)heap_array(ctx, rows, sizeof *t.blobs, 405 _Alignof(BuildBlobLeaf)); 406 t.deps = (BuildDepEdge*)heap_array(ctx, rows, sizeof *t.deps, 407 _Alignof(BuildDepEdge)); 408 if (!t.configs || !t.sources || !t.globs || !t.blobs || !t.deps) { 409 heap_free_array(ctx, t.configs, rows, sizeof *t.configs); 410 heap_free_array(ctx, t.sources, rows, sizeof *t.sources); 411 heap_free_array(ctx, t.globs, rows, sizeof *t.globs); 412 heap_free_array(ctx, t.blobs, rows, sizeof *t.blobs); 413 heap_free_array(ctx, t.deps, rows, sizeof *t.deps); 414 return BUILD_ERR; 415 } 416 t.cap_configs = rows; 417 t.cap_sources = rows; 418 t.cap_globs = rows; 419 t.cap_blobs = rows; 420 t.cap_deps = rows; 421 if (build_test_shallow_parse(data, len, &t, err, sizeof err) != BUILD_OK) { 422 heap_free_array(ctx, t.configs, rows, sizeof *t.configs); 423 heap_free_array(ctx, t.sources, rows, sizeof *t.sources); 424 heap_free_array(ctx, t.globs, rows, sizeof *t.globs); 425 heap_free_array(ctx, t.blobs, rows, sizeof *t.blobs); 426 heap_free_array(ctx, t.deps, rows, sizeof *t.deps); 427 return BUILD_ERR; 428 } 429 snprintf(out->target, sizeof out->target, "%s", t.target); 430 out->kind = (uint8_t)BUILD_BUNDLE_TEST_SHALLOW; 431 memcpy(out->output, t.output, BUILD_HASH_LEN); 432 heap_free_array(ctx, t.configs, rows, sizeof *t.configs); 433 heap_free_array(ctx, t.sources, rows, sizeof *t.sources); 434 heap_free_array(ctx, t.globs, rows, sizeof *t.globs); 435 heap_free_array(ctx, t.blobs, rows, sizeof *t.blobs); 436 heap_free_array(ctx, t.deps, rows, sizeof *t.deps); 437 return BUILD_OK; 438 } 439 return BUILD_ERR; 440 } 441 442 static int claim_cmp(const BuildTraceClaim* a, const BuildTraceClaim* b) { 443 int c = strcmp(a->target, b->target); 444 if (c != 0) return c; 445 if (a->kind != b->kind) return a->kind < b->kind ? -1 : 1; 446 c = memcmp(a->trace_id, b->trace_id, BUILD_HASH_LEN); 447 if (c != 0) return c; 448 return memcmp(a->output_tree, b->output_tree, BUILD_HASH_LEN); 449 } 450 451 int build_bundle_manifest_emit(const BuildTraceClaim* claims, size_t n, 452 KitWriter* out) { 453 const BuildTraceClaim* prev = NULL; 454 size_t emitted = 0; 455 if (!out || (n && !claims)) return BUILD_ERR; 456 if (write_cstr(out, BUILD_TRACES_MAGIC "\n") != BUILD_OK) return BUILD_ERR; 457 while (emitted < n) { 458 const BuildTraceClaim* best = NULL; 459 size_t i; 460 for (i = 0; i < n; ++i) { 461 const BuildTraceClaim* cur = &claims[i]; 462 if (!valid_token(cur->target, BUILD_TARGET_MAX) || !kind_valid(cur->kind)) 463 return BUILD_ERR; 464 if ((!prev || claim_cmp(prev, cur) < 0) && 465 (!best || claim_cmp(cur, best) < 0)) 466 best = cur; 467 } 468 if (!best) return BUILD_ERR; 469 { 470 char tid[BUILD_HEX_LEN], tree[BUILD_HEX_LEN], line[BUILD_TARGET_MAX + 160u]; 471 hex_encode(tid, best->trace_id); 472 hex_encode(tree, best->output_tree); 473 snprintf(line, sizeof line, "%s %s %s %s\n", best->target, 474 kind_name(best->kind), tid, tree); 475 if (write_cstr(out, line) != BUILD_OK) return BUILD_ERR; 476 } 477 prev = best; 478 ++emitted; 479 } 480 return kit_writer_status(out) == KIT_OK ? BUILD_OK : BUILD_ERR; 481 } 482 483 static int set_err(char* err, size_t errcap, const char* msg) { 484 if (err && errcap) snprintf(err, errcap, "%s", msg); 485 return BUILD_ERR; 486 } 487 488 static int next_line(const uint8_t* data, size_t len, size_t* pos, 489 char* line, size_t cap, char* err, size_t errcap) { 490 size_t end = *pos; 491 size_t n, i; 492 if (*pos >= len) return 0; 493 while (end < len && data[end] != '\n') ++end; 494 if (end == len) return set_err(err, errcap, "missing final newline"); 495 n = end - *pos; 496 if (n >= cap) return set_err(err, errcap, "manifest line too long"); 497 for (i = *pos; i < end; ++i) 498 if (data[i] == 0 || data[i] == '\r') 499 return set_err(err, errcap, "bad manifest byte"); 500 memcpy(line, data + *pos, n); 501 line[n] = '\0'; 502 *pos = end + 1u; 503 return 1; 504 } 505 506 static int split4(char* line, char** f) { 507 size_t n = 0; 508 char* p = line; 509 while (*p) { 510 if (*p == ' ' || n >= 4u) return BUILD_ERR; 511 f[n++] = p; 512 while (*p && *p != ' ') { 513 unsigned char c = (unsigned char)*p; 514 if (c <= 0x20u || c >= 0x7fu) return BUILD_ERR; 515 ++p; 516 } 517 if (*p == ' ') { 518 *p++ = '\0'; 519 if (!*p) return BUILD_ERR; 520 } 521 } 522 return n == 4u ? BUILD_OK : BUILD_ERR; 523 } 524 525 int build_bundle_manifest_parse(const uint8_t* data, size_t len, 526 BuildTraceClaim* out, size_t cap, size_t* n, 527 char* err, size_t errcap) { 528 size_t pos = 0, count = 0; 529 char line[BUILD_TARGET_MAX + 160u]; 530 BuildTraceClaim prev; 531 int have_prev = 0; 532 int r; 533 if (!data || !n || (cap && !out)) 534 return set_err(err, errcap, "missing manifest storage"); 535 *n = 0; 536 r = next_line(data, len, &pos, line, sizeof line, err, errcap); 537 if (r != 1 || strcmp(line, BUILD_TRACES_MAGIC) != 0) 538 return set_err(err, errcap, "bad trace manifest magic/version"); 539 while (pos < len) { 540 char* f[4]; 541 BuildTraceClaim row; 542 r = next_line(data, len, &pos, line, sizeof line, err, errcap); 543 if (r != 1) return BUILD_ERR; 544 if (split4(line, f) != BUILD_OK) 545 return set_err(err, errcap, "bad trace manifest row"); 546 if (!valid_token(f[0], BUILD_TARGET_MAX) || 547 kind_parse(f[1], &row.kind) != BUILD_OK || 548 hex_decode(f[2], row.trace_id) != BUILD_OK || 549 hex_decode(f[3], row.output_tree) != BUILD_OK) 550 return set_err(err, errcap, "bad trace manifest field"); 551 snprintf(row.target, sizeof row.target, "%s", f[0]); 552 if (have_prev && claim_cmp(&prev, &row) >= 0) 553 return set_err(err, errcap, "non-canonical trace manifest ordering"); 554 if (count >= cap) return set_err(err, errcap, "too many trace claims"); 555 out[count++] = row; 556 prev = row; 557 have_prev = 1; 558 } 559 *n = count; 560 return BUILD_OK; 561 } 562 563 static int payload_write_blob_from_cas(KitBuildCoordinator* c, 564 const uint8_t id[BUILD_HASH_LEN], 565 const char* root, BuildIdVec* seen) { 566 KitFileData fd; 567 char path[BUILD_PATH_MAX]; 568 int ok = BUILD_ERR; 569 if (!c || !id || !root || !seen) return BUILD_ERR; 570 if (id_vec_contains(seen, id)) return BUILD_OK; 571 if (kit_cas_get_blob(c->cas, id, &fd) != KIT_OK) return BUILD_ERR; 572 if (payload_id_path(path, sizeof path, root, BUILD_BUNDLE_BLOB_DIR, id) != 573 BUILD_OK || 574 ensure_parent_dir(c, path) != BUILD_OK || 575 write_file(c, path, fd.data, fd.size) != BUILD_OK) 576 goto out; 577 ok = id_vec_add(c->ctx, seen, id); 578 out: 579 kit_cas_release(c->cas, &fd); 580 return ok; 581 } 582 583 static int payload_install_blob(KitBuildCoordinator* c, 584 const uint8_t id[BUILD_HASH_LEN], 585 const char* root, BuildIdVec* seen, 586 const uint8_t** data_out, size_t* len_out, 587 KitFileData* fd_out) { 588 KitBlobInfo info; 589 char path[BUILD_PATH_MAX]; 590 if (!c || !id || !root || !seen || !fd_out) return BUILD_ERR; 591 if (data_out) *data_out = NULL; 592 if (len_out) *len_out = 0u; 593 fd_out->data = NULL; 594 fd_out->size = 0u; 595 fd_out->token = NULL; 596 if (payload_id_path(path, sizeof path, root, BUILD_BUNDLE_BLOB_DIR, id) != 597 BUILD_OK || 598 read_file(c, path, fd_out) != BUILD_OK) 599 return BUILD_ERR; 600 if (kit_cas_add_blob(c->cas, fd_out->data, fd_out->size, &info) != KIT_OK || 601 !build_id_eq(info.id, id)) { 602 release_file(c, fd_out); 603 return BUILD_ERR; 604 } 605 if (id_vec_add(c->ctx, seen, id) != BUILD_OK) { 606 release_file(c, fd_out); 607 return BUILD_ERR; 608 } 609 if (data_out) *data_out = fd_out->data; 610 if (len_out) *len_out = fd_out->size; 611 return BUILD_OK; 612 } 613 614 static int export_deepset_closure(KitBuildCoordinator* c, 615 const uint8_t id[BUILD_HASH_LEN], 616 const char* root, BuildIdVec* seen) { 617 KitFileData fd; 618 BuildDeepSet ds; 619 size_t rows; 620 size_t i; 621 char err[160]; 622 int ok = BUILD_ERR; 623 if (id_vec_contains(seen, id)) return BUILD_OK; 624 if (payload_write_blob_from_cas(c, id, root, seen) != BUILD_OK) 625 return BUILD_ERR; 626 if (kit_cas_get_blob(c->cas, id, &fd) != KIT_OK) return BUILD_ERR; 627 rows = count_lines(fd.data, fd.size); 628 memset(&ds, 0, sizeof ds); 629 ds.configs = (BuildConfigLeaf*)heap_array(c->ctx, rows, sizeof *ds.configs, 630 _Alignof(BuildConfigLeaf)); 631 ds.sources = (BuildSourceLeaf*)heap_array(c->ctx, rows, sizeof *ds.sources, 632 _Alignof(BuildSourceLeaf)); 633 ds.globs = (BuildGlobLeaf*)heap_array(c->ctx, rows, sizeof *ds.globs, 634 _Alignof(BuildGlobLeaf)); 635 ds.blobs = (BuildBlobLeaf*)heap_array(c->ctx, rows, sizeof *ds.blobs, 636 _Alignof(BuildBlobLeaf)); 637 ds.children = (uint8_t(*)[BUILD_HASH_LEN])heap_array( 638 c->ctx, rows, sizeof *ds.children, _Alignof(uint8_t)); 639 if (!ds.configs || !ds.sources || !ds.globs || !ds.blobs || !ds.children) 640 goto out; 641 ds.cap_configs = rows; 642 ds.cap_sources = rows; 643 ds.cap_globs = rows; 644 ds.cap_blobs = rows; 645 ds.cap_children = rows; 646 if (build_deepset_parse(fd.data, fd.size, &ds, err, sizeof err) != BUILD_OK) 647 goto out; 648 for (i = 0u; i < ds.n_blobs; ++i) 649 if (payload_write_blob_from_cas(c, ds.blobs[i].blob, root, seen) != 650 BUILD_OK) 651 goto out; 652 for (i = 0u; i < ds.n_children; ++i) 653 if (export_deepset_closure(c, ds.children[i], root, seen) != BUILD_OK) 654 goto out; 655 ok = BUILD_OK; 656 out: 657 heap_free_array(c->ctx, ds.configs, rows, sizeof *ds.configs); 658 heap_free_array(c->ctx, ds.sources, rows, sizeof *ds.sources); 659 heap_free_array(c->ctx, ds.globs, rows, sizeof *ds.globs); 660 heap_free_array(c->ctx, ds.blobs, rows, sizeof *ds.blobs); 661 heap_free_array(c->ctx, ds.children, rows, sizeof *ds.children); 662 kit_cas_release(c->cas, &fd); 663 return ok; 664 } 665 666 static int import_deepset_closure(KitBuildCoordinator* c, 667 const uint8_t id[BUILD_HASH_LEN], 668 const char* root, BuildIdVec* seen) { 669 KitFileData fd; 670 const uint8_t* data = NULL; 671 size_t len = 0u; 672 BuildDeepSet ds; 673 size_t rows; 674 size_t i; 675 char err[160]; 676 int ok = BUILD_ERR; 677 if (id_vec_contains(seen, id)) return BUILD_OK; 678 if (payload_install_blob(c, id, root, seen, &data, &len, &fd) != BUILD_OK) 679 return BUILD_ERR; 680 rows = count_lines(data, len); 681 memset(&ds, 0, sizeof ds); 682 ds.configs = (BuildConfigLeaf*)heap_array(c->ctx, rows, sizeof *ds.configs, 683 _Alignof(BuildConfigLeaf)); 684 ds.sources = (BuildSourceLeaf*)heap_array(c->ctx, rows, sizeof *ds.sources, 685 _Alignof(BuildSourceLeaf)); 686 ds.globs = (BuildGlobLeaf*)heap_array(c->ctx, rows, sizeof *ds.globs, 687 _Alignof(BuildGlobLeaf)); 688 ds.blobs = (BuildBlobLeaf*)heap_array(c->ctx, rows, sizeof *ds.blobs, 689 _Alignof(BuildBlobLeaf)); 690 ds.children = (uint8_t(*)[BUILD_HASH_LEN])heap_array( 691 c->ctx, rows, sizeof *ds.children, _Alignof(uint8_t)); 692 if (!ds.configs || !ds.sources || !ds.globs || !ds.blobs || !ds.children) 693 goto out; 694 ds.cap_configs = rows; 695 ds.cap_sources = rows; 696 ds.cap_globs = rows; 697 ds.cap_blobs = rows; 698 ds.cap_children = rows; 699 if (build_deepset_parse(data, len, &ds, err, sizeof err) != BUILD_OK) 700 goto out; 701 for (i = 0u; i < ds.n_blobs; ++i) { 702 KitFileData dep_fd; 703 memset(&dep_fd, 0, sizeof dep_fd); 704 if (payload_install_blob(c, ds.blobs[i].blob, root, seen, NULL, NULL, 705 &dep_fd) != BUILD_OK) 706 goto out; 707 release_file(c, &dep_fd); 708 } 709 for (i = 0u; i < ds.n_children; ++i) 710 if (import_deepset_closure(c, ds.children[i], root, seen) != BUILD_OK) 711 goto out; 712 ok = BUILD_OK; 713 out: 714 heap_free_array(c->ctx, ds.configs, rows, sizeof *ds.configs); 715 heap_free_array(c->ctx, ds.sources, rows, sizeof *ds.sources); 716 heap_free_array(c->ctx, ds.globs, rows, sizeof *ds.globs); 717 heap_free_array(c->ctx, ds.blobs, rows, sizeof *ds.blobs); 718 heap_free_array(c->ctx, ds.children, rows, sizeof *ds.children); 719 release_file(c, &fd); 720 return ok; 721 } 722 723 static int BUILD_MAYBE_UNUSED export_trace_refs(KitBuildCoordinator* c, 724 const uint8_t* data, 725 size_t len, const char* root, 726 BuildIdVec* seen) { 727 char err[160]; 728 if (len >= sizeof BUILD_DEEP_MAGIC && 729 memcmp(data, BUILD_DEEP_MAGIC "\n", sizeof BUILD_DEEP_MAGIC) == 0) { 730 BuildDeepTrace t; 731 if (build_deep_parse(data, len, &t, err, sizeof err) != BUILD_OK) 732 return BUILD_ERR; 733 if (payload_write_blob_from_cas(c, t.argv, root, seen) != BUILD_OK || 734 export_deepset_closure(c, t.deepset, root, seen) != BUILD_OK) 735 return BUILD_ERR; 736 return BUILD_OK; 737 } 738 if (len >= sizeof BUILD_TEST_DEEP_MAGIC && 739 memcmp(data, BUILD_TEST_DEEP_MAGIC "\n", 740 sizeof BUILD_TEST_DEEP_MAGIC) == 0) { 741 BuildDeepTrace t; 742 if (build_test_deep_parse(data, len, &t, err, sizeof err) != BUILD_OK) 743 return BUILD_ERR; 744 if (payload_write_blob_from_cas(c, t.argv, root, seen) != BUILD_OK || 745 export_deepset_closure(c, t.deepset, root, seen) != BUILD_OK) 746 return BUILD_ERR; 747 return BUILD_OK; 748 } 749 if (len >= sizeof BUILD_SHALLOW_MAGIC && 750 memcmp(data, BUILD_SHALLOW_MAGIC "\n", sizeof BUILD_SHALLOW_MAGIC) == 0) { 751 BuildShallowTrace t; 752 size_t rows = count_lines(data, len); 753 size_t i; 754 int ok = BUILD_ERR; 755 memset(&t, 0, sizeof t); 756 t.configs = (BuildConfigLeaf*)heap_array( 757 c->ctx, rows, sizeof *t.configs, _Alignof(BuildConfigLeaf)); 758 t.sources = (BuildSourceLeaf*)heap_array(c->ctx, rows, sizeof *t.sources, 759 _Alignof(BuildSourceLeaf)); 760 t.globs = (BuildGlobLeaf*)heap_array(c->ctx, rows, sizeof *t.globs, 761 _Alignof(BuildGlobLeaf)); 762 t.blobs = (BuildBlobLeaf*)heap_array(c->ctx, rows, sizeof *t.blobs, 763 _Alignof(BuildBlobLeaf)); 764 t.deps = (BuildDepEdge*)heap_array(c->ctx, rows, sizeof *t.deps, 765 _Alignof(BuildDepEdge)); 766 if (!t.configs || !t.sources || !t.globs || !t.blobs || !t.deps) 767 goto shallow_out; 768 t.cap_configs = rows; 769 t.cap_sources = rows; 770 t.cap_globs = rows; 771 t.cap_blobs = rows; 772 t.cap_deps = rows; 773 if (build_shallow_parse(data, len, &t, err, sizeof err) != BUILD_OK) 774 goto shallow_out; 775 if (payload_write_blob_from_cas(c, t.argv, root, seen) != BUILD_OK) 776 goto shallow_out; 777 for (i = 0u; i < t.n_deps; ++i) { 778 if (payload_write_blob_from_cas(c, t.deps[i].overlay_id, root, seen) != 779 BUILD_OK || 780 payload_write_blob_from_cas(c, t.deps[i].argv_id, root, seen) != 781 BUILD_OK) 782 goto shallow_out; 783 } 784 for (i = 0u; i < t.n_blobs; ++i) 785 if (payload_write_blob_from_cas(c, t.blobs[i].blob, root, seen) != 786 BUILD_OK) 787 goto shallow_out; 788 ok = BUILD_OK; 789 shallow_out: 790 heap_free_array(c->ctx, t.configs, rows, sizeof *t.configs); 791 heap_free_array(c->ctx, t.sources, rows, sizeof *t.sources); 792 heap_free_array(c->ctx, t.globs, rows, sizeof *t.globs); 793 heap_free_array(c->ctx, t.blobs, rows, sizeof *t.blobs); 794 heap_free_array(c->ctx, t.deps, rows, sizeof *t.deps); 795 return ok; 796 } 797 if (len >= sizeof BUILD_TEST_SHALLOW_MAGIC && 798 memcmp(data, BUILD_TEST_SHALLOW_MAGIC "\n", 799 sizeof BUILD_TEST_SHALLOW_MAGIC) == 0) { 800 BuildShallowTrace t; 801 size_t rows = count_lines(data, len); 802 size_t i; 803 int ok = BUILD_ERR; 804 memset(&t, 0, sizeof t); 805 t.configs = (BuildConfigLeaf*)heap_array( 806 c->ctx, rows, sizeof *t.configs, _Alignof(BuildConfigLeaf)); 807 t.sources = (BuildSourceLeaf*)heap_array(c->ctx, rows, sizeof *t.sources, 808 _Alignof(BuildSourceLeaf)); 809 t.globs = (BuildGlobLeaf*)heap_array(c->ctx, rows, sizeof *t.globs, 810 _Alignof(BuildGlobLeaf)); 811 t.blobs = (BuildBlobLeaf*)heap_array(c->ctx, rows, sizeof *t.blobs, 812 _Alignof(BuildBlobLeaf)); 813 t.deps = (BuildDepEdge*)heap_array(c->ctx, rows, sizeof *t.deps, 814 _Alignof(BuildDepEdge)); 815 if (!t.configs || !t.sources || !t.globs || !t.blobs || !t.deps) 816 goto test_out; 817 t.cap_configs = rows; 818 t.cap_sources = rows; 819 t.cap_globs = rows; 820 t.cap_blobs = rows; 821 t.cap_deps = rows; 822 if (build_test_shallow_parse(data, len, &t, err, sizeof err) != BUILD_OK) 823 goto test_out; 824 if (payload_write_blob_from_cas(c, t.argv, root, seen) != BUILD_OK) 825 goto test_out; 826 for (i = 0u; i < t.n_deps; ++i) { 827 if (payload_write_blob_from_cas(c, t.deps[i].overlay_id, root, seen) != 828 BUILD_OK || 829 payload_write_blob_from_cas(c, t.deps[i].argv_id, root, seen) != 830 BUILD_OK) 831 goto test_out; 832 } 833 for (i = 0u; i < t.n_blobs; ++i) 834 if (payload_write_blob_from_cas(c, t.blobs[i].blob, root, seen) != 835 BUILD_OK) 836 goto test_out; 837 ok = BUILD_OK; 838 test_out: 839 heap_free_array(c->ctx, t.configs, rows, sizeof *t.configs); 840 heap_free_array(c->ctx, t.sources, rows, sizeof *t.sources); 841 heap_free_array(c->ctx, t.globs, rows, sizeof *t.globs); 842 heap_free_array(c->ctx, t.blobs, rows, sizeof *t.blobs); 843 heap_free_array(c->ctx, t.deps, rows, sizeof *t.deps); 844 return ok; 845 } 846 return BUILD_ERR; 847 } 848 849 static int BUILD_MAYBE_UNUSED import_trace_refs(KitBuildCoordinator* c, 850 const uint8_t* data, 851 size_t len, const char* root, 852 BuildIdVec* seen) { 853 char err[160]; 854 if (len >= sizeof BUILD_DEEP_MAGIC && 855 memcmp(data, BUILD_DEEP_MAGIC "\n", sizeof BUILD_DEEP_MAGIC) == 0) { 856 BuildDeepTrace t; 857 KitFileData fd; 858 if (build_deep_parse(data, len, &t, err, sizeof err) != BUILD_OK) 859 return BUILD_ERR; 860 if (payload_install_blob(c, t.argv, root, seen, NULL, NULL, &fd) != 861 BUILD_OK) 862 return BUILD_ERR; 863 release_file(c, &fd); 864 return import_deepset_closure(c, t.deepset, root, seen); 865 } 866 if (len >= sizeof BUILD_TEST_DEEP_MAGIC && 867 memcmp(data, BUILD_TEST_DEEP_MAGIC "\n", 868 sizeof BUILD_TEST_DEEP_MAGIC) == 0) { 869 BuildDeepTrace t; 870 KitFileData fd; 871 if (build_test_deep_parse(data, len, &t, err, sizeof err) != BUILD_OK) 872 return BUILD_ERR; 873 if (payload_install_blob(c, t.argv, root, seen, NULL, NULL, &fd) != 874 BUILD_OK) 875 return BUILD_ERR; 876 release_file(c, &fd); 877 return import_deepset_closure(c, t.deepset, root, seen); 878 } 879 if (len >= sizeof BUILD_SHALLOW_MAGIC && 880 memcmp(data, BUILD_SHALLOW_MAGIC "\n", sizeof BUILD_SHALLOW_MAGIC) == 0) { 881 BuildShallowTrace t; 882 size_t rows = count_lines(data, len); 883 size_t i; 884 int ok = BUILD_ERR; 885 KitFileData fd; 886 memset(&t, 0, sizeof t); 887 memset(&fd, 0, sizeof fd); 888 t.configs = (BuildConfigLeaf*)heap_array( 889 c->ctx, rows, sizeof *t.configs, _Alignof(BuildConfigLeaf)); 890 t.sources = (BuildSourceLeaf*)heap_array(c->ctx, rows, sizeof *t.sources, 891 _Alignof(BuildSourceLeaf)); 892 t.globs = (BuildGlobLeaf*)heap_array(c->ctx, rows, sizeof *t.globs, 893 _Alignof(BuildGlobLeaf)); 894 t.blobs = (BuildBlobLeaf*)heap_array(c->ctx, rows, sizeof *t.blobs, 895 _Alignof(BuildBlobLeaf)); 896 t.deps = (BuildDepEdge*)heap_array(c->ctx, rows, sizeof *t.deps, 897 _Alignof(BuildDepEdge)); 898 if (!t.configs || !t.sources || !t.globs || !t.blobs || !t.deps) 899 goto shallow_out; 900 t.cap_configs = rows; 901 t.cap_sources = rows; 902 t.cap_globs = rows; 903 t.cap_blobs = rows; 904 t.cap_deps = rows; 905 if (build_shallow_parse(data, len, &t, err, sizeof err) != BUILD_OK) 906 goto shallow_out; 907 if (payload_install_blob(c, t.argv, root, seen, NULL, NULL, &fd) != 908 BUILD_OK) 909 goto shallow_out; 910 release_file(c, &fd); 911 for (i = 0u; i < t.n_deps; ++i) { 912 if (payload_install_blob(c, t.deps[i].overlay_id, root, seen, NULL, NULL, 913 &fd) != BUILD_OK) 914 goto shallow_out; 915 release_file(c, &fd); 916 if (payload_install_blob(c, t.deps[i].argv_id, root, seen, NULL, NULL, 917 &fd) != BUILD_OK) 918 goto shallow_out; 919 release_file(c, &fd); 920 } 921 for (i = 0u; i < t.n_blobs; ++i) { 922 if (payload_install_blob(c, t.blobs[i].blob, root, seen, NULL, NULL, 923 &fd) != BUILD_OK) 924 goto shallow_out; 925 release_file(c, &fd); 926 } 927 ok = BUILD_OK; 928 shallow_out: 929 release_file(c, &fd); 930 heap_free_array(c->ctx, t.configs, rows, sizeof *t.configs); 931 heap_free_array(c->ctx, t.sources, rows, sizeof *t.sources); 932 heap_free_array(c->ctx, t.globs, rows, sizeof *t.globs); 933 heap_free_array(c->ctx, t.blobs, rows, sizeof *t.blobs); 934 heap_free_array(c->ctx, t.deps, rows, sizeof *t.deps); 935 return ok; 936 } 937 if (len >= sizeof BUILD_TEST_SHALLOW_MAGIC && 938 memcmp(data, BUILD_TEST_SHALLOW_MAGIC "\n", 939 sizeof BUILD_TEST_SHALLOW_MAGIC) == 0) { 940 BuildShallowTrace t; 941 size_t rows = count_lines(data, len); 942 size_t i; 943 int ok = BUILD_ERR; 944 KitFileData fd; 945 memset(&t, 0, sizeof t); 946 memset(&fd, 0, sizeof fd); 947 t.configs = (BuildConfigLeaf*)heap_array( 948 c->ctx, rows, sizeof *t.configs, _Alignof(BuildConfigLeaf)); 949 t.sources = (BuildSourceLeaf*)heap_array(c->ctx, rows, sizeof *t.sources, 950 _Alignof(BuildSourceLeaf)); 951 t.globs = (BuildGlobLeaf*)heap_array(c->ctx, rows, sizeof *t.globs, 952 _Alignof(BuildGlobLeaf)); 953 t.blobs = (BuildBlobLeaf*)heap_array(c->ctx, rows, sizeof *t.blobs, 954 _Alignof(BuildBlobLeaf)); 955 t.deps = (BuildDepEdge*)heap_array(c->ctx, rows, sizeof *t.deps, 956 _Alignof(BuildDepEdge)); 957 if (!t.configs || !t.sources || !t.globs || !t.blobs || !t.deps) 958 goto test_out; 959 t.cap_configs = rows; 960 t.cap_sources = rows; 961 t.cap_globs = rows; 962 t.cap_blobs = rows; 963 t.cap_deps = rows; 964 if (build_test_shallow_parse(data, len, &t, err, sizeof err) != BUILD_OK) 965 goto test_out; 966 if (payload_install_blob(c, t.argv, root, seen, NULL, NULL, &fd) != 967 BUILD_OK) 968 goto test_out; 969 release_file(c, &fd); 970 for (i = 0u; i < t.n_deps; ++i) { 971 if (payload_install_blob(c, t.deps[i].overlay_id, root, seen, NULL, NULL, 972 &fd) != BUILD_OK) 973 goto test_out; 974 release_file(c, &fd); 975 if (payload_install_blob(c, t.deps[i].argv_id, root, seen, NULL, NULL, 976 &fd) != BUILD_OK) 977 goto test_out; 978 release_file(c, &fd); 979 } 980 for (i = 0u; i < t.n_blobs; ++i) { 981 if (payload_install_blob(c, t.blobs[i].blob, root, seen, NULL, NULL, 982 &fd) != BUILD_OK) 983 goto test_out; 984 release_file(c, &fd); 985 } 986 ok = BUILD_OK; 987 test_out: 988 release_file(c, &fd); 989 heap_free_array(c->ctx, t.configs, rows, sizeof *t.configs); 990 heap_free_array(c->ctx, t.sources, rows, sizeof *t.sources); 991 heap_free_array(c->ctx, t.globs, rows, sizeof *t.globs); 992 heap_free_array(c->ctx, t.blobs, rows, sizeof *t.blobs); 993 heap_free_array(c->ctx, t.deps, rows, sizeof *t.deps); 994 return ok; 995 } 996 return BUILD_ERR; 997 } 998 999 static int gather_export_claims(KitBuildCoordinator* c, 1000 const KitBuildExportOptions* opts, 1001 BuildTraceClaim* claims, size_t cap, 1002 size_t* nclaims, const char* root, 1003 BuildIdVec* seen_blobs) { 1004 size_t ti; 1005 if (!c || !opts || !claims || !nclaims || !root || !seen_blobs) 1006 return BUILD_ERR; 1007 *nclaims = 0u; 1008 for (ti = 0u; ti < opts->ntargets; ++ti) { 1009 uint8_t key[BUILD_HASH_LEN]; 1010 BuildRecordRow rows[2u * KIT_BUILD_RECORD_CAP]; 1011 BuildTargetRecord rec; 1012 size_t ri; 1013 if (build_target_key(opts->targets[ti], key) != BUILD_OK) 1014 return BUILD_ERR; 1015 memset(&rec, 0, sizeof rec); 1016 rec.rows = rows; 1017 rec.cap_rows = sizeof rows / sizeof rows[0]; 1018 if (build_store_record_load(&c->store, key, opts->targets[ti], &rec) != 1019 BUILD_OK) 1020 return BUILD_ERR; 1021 for (ri = 0u; ri < rec.n_rows; ++ri) { 1022 KitFileData fd; 1023 ParsedTrace pt; 1024 BuildTraceClaim* cl; 1025 char path[BUILD_PATH_MAX]; 1026 if (*nclaims >= cap) return BUILD_ERR; 1027 if (build_store_get_trace(&c->store, rec.rows[ri].trace_id, &fd) != 1028 BUILD_OK) 1029 continue; 1030 if (parse_trace_header(c->ctx, fd.data, fd.size, &pt) != BUILD_OK || 1031 pt.kind != rec.rows[ri].kind || 1032 !kit_slice_eq_cstr(opts->targets[ti], pt.target)) { 1033 build_store_release(&c->store, &fd); 1034 continue; 1035 } 1036 if (payload_id_path(path, sizeof path, root, BUILD_BUNDLE_TRACE_DIR, 1037 rec.rows[ri].trace_id) != BUILD_OK || 1038 ensure_parent_dir(c, path) != BUILD_OK || 1039 write_file(c, path, fd.data, fd.size) != BUILD_OK || 1040 export_trace_refs(c, fd.data, fd.size, root, seen_blobs) != 1041 BUILD_OK) { 1042 build_store_release(&c->store, &fd); 1043 return BUILD_ERR; 1044 } 1045 cl = &claims[(*nclaims)++]; 1046 snprintf(cl->target, sizeof cl->target, "%s", pt.target); 1047 cl->kind = pt.kind; 1048 memcpy(cl->trace_id, rec.rows[ri].trace_id, BUILD_HASH_LEN); 1049 memcpy(cl->output_tree, pt.output, BUILD_HASH_LEN); 1050 build_store_release(&c->store, &fd); 1051 } 1052 if (build_test_target_key(opts->targets[ti], key) != BUILD_OK) 1053 return BUILD_ERR; 1054 memset(&rec, 0, sizeof rec); 1055 rec.rows = rows; 1056 rec.cap_rows = sizeof rows / sizeof rows[0]; 1057 if (build_store_record_load(&c->store, key, opts->targets[ti], &rec) != 1058 BUILD_OK) 1059 return BUILD_ERR; 1060 for (ri = 0u; ri < rec.n_rows; ++ri) { 1061 KitFileData fd; 1062 ParsedTrace pt; 1063 BuildTraceClaim* cl; 1064 char path[BUILD_PATH_MAX]; 1065 uint8_t want_kind = 1066 rec.rows[ri].kind == (uint8_t)BUILD_TRACE_DEEP 1067 ? (uint8_t)BUILD_BUNDLE_TEST_DEEP 1068 : (uint8_t)BUILD_BUNDLE_TEST_SHALLOW; 1069 if (*nclaims >= cap) return BUILD_ERR; 1070 if (build_store_get_trace(&c->store, rec.rows[ri].trace_id, &fd) != 1071 BUILD_OK) 1072 continue; 1073 if (parse_trace_header(c->ctx, fd.data, fd.size, &pt) != BUILD_OK || 1074 pt.kind != want_kind || 1075 !kit_slice_eq_cstr(opts->targets[ti], pt.target)) { 1076 build_store_release(&c->store, &fd); 1077 continue; 1078 } 1079 if (payload_id_path(path, sizeof path, root, BUILD_BUNDLE_TRACE_DIR, 1080 rec.rows[ri].trace_id) != BUILD_OK || 1081 ensure_parent_dir(c, path) != BUILD_OK || 1082 write_file(c, path, fd.data, fd.size) != BUILD_OK || 1083 export_trace_refs(c, fd.data, fd.size, root, seen_blobs) != 1084 BUILD_OK) { 1085 build_store_release(&c->store, &fd); 1086 return BUILD_ERR; 1087 } 1088 cl = &claims[(*nclaims)++]; 1089 snprintf(cl->target, sizeof cl->target, "%s", pt.target); 1090 cl->kind = pt.kind; 1091 memcpy(cl->trace_id, rec.rows[ri].trace_id, BUILD_HASH_LEN); 1092 memcpy(cl->output_tree, pt.output, BUILD_HASH_LEN); 1093 build_store_release(&c->store, &fd); 1094 } 1095 } 1096 return BUILD_OK; 1097 } 1098 1099 int build_bundle_export(KitBuildCoordinator* c, 1100 const KitBuildExportOptions* opts) { 1101 BuildTraceClaim* claims = NULL; 1102 size_t cap, nclaims = 0u; 1103 KitWriter* manw = NULL; 1104 const uint8_t* man; 1105 size_t man_len; 1106 char root[BUILD_PATH_MAX]; 1107 char manifest_path[BUILD_PATH_MAX]; 1108 char out_path[BUILD_PATH_MAX]; 1109 KitPkgCreateOptions popts; 1110 KitPkgCreateResult pres; 1111 BuildIdVec seen_blobs; 1112 int ok = BUILD_ERR; 1113 1114 memset(&seen_blobs, 0, sizeof seen_blobs); 1115 root[0] = '\0'; 1116 if (!c || !opts || !opts->targets || opts->ntargets == 0u || !opts->sk || 1117 !opts->keyid || !opts->out_path.s) 1118 return BUILD_ERR; 1119 if (opts->ntargets > (size_t)-1 / (4u * KIT_BUILD_RECORD_CAP)) 1120 return BUILD_ERR; 1121 if (opts->format == KIT_PKG_FORMAT_AUTO) { 1122 build_diagf(c->ctx, "trace bundle export: explicit package format required"); 1123 return BUILD_ERR; 1124 } 1125 if (opts->include_outputs) { 1126 build_diagf(c->ctx, 1127 "trace bundle export: include_outputs needs public CAS tree " 1128 "entry enumeration"); 1129 return BUILD_ERR; 1130 } 1131 if (!c->host.cas_host || !c->host.cas_host->walk_regular_files) { 1132 build_diagf(c->ctx, 1133 "trace bundle export: package root walk is unavailable"); 1134 return BUILD_ERR; 1135 } 1136 if (path_set(out_path, sizeof out_path, opts->out_path) != BUILD_OK) 1137 return BUILD_ERR; 1138 cap = opts->ntargets * 4u * KIT_BUILD_RECORD_CAP; 1139 claims = (BuildTraceClaim*)heap_array(c->ctx, cap, sizeof *claims, 1140 _Alignof(BuildTraceClaim)); 1141 if (!claims) return BUILD_ERR; 1142 if (make_tmp_dir(c, root, sizeof root) != BUILD_OK) goto out; 1143 if (gather_export_claims(c, opts, claims, cap, &nclaims, root, 1144 &seen_blobs) != BUILD_OK) 1145 goto out; 1146 if (kit_writer_mem(c->ctx->heap, &manw) != KIT_OK || !manw) goto out; 1147 if (build_bundle_manifest_emit(claims, nclaims, manw) != BUILD_OK || 1148 kit_writer_status(manw) != KIT_OK) 1149 goto out; 1150 man = kit_writer_mem_bytes(manw, &man_len); 1151 if (path_join2(manifest_path, sizeof manifest_path, root, 1152 BUILD_BUNDLE_MANIFEST_PATH) != BUILD_OK || 1153 write_file(c, manifest_path, man, man_len) != BUILD_OK) 1154 goto out; 1155 1156 memset(&popts, 0, sizeof popts); 1157 memset(&pres, 0, sizeof pres); 1158 popts.name = "kit-build-traces"; 1159 popts.version = "1"; 1160 popts.description = "kit build trace bundle"; 1161 popts.format = opts->format; 1162 popts.native_shape = KIT_PKG_SHAPE_FAT; 1163 popts.compression = KIT_PKG_COMPRESSION_NONE; 1164 popts.root_dir = root; 1165 popts.sk = opts->sk; 1166 popts.keyid = opts->keyid; 1167 popts.out_path = out_path; 1168 if (kit_pkg_create(c->ctx, c->host.cas_host, &popts, &pres) != KIT_OK) 1169 goto out; 1170 ok = BUILD_OK; 1171 out: 1172 if (manw) kit_writer_close(manw); 1173 if (root[0]) (void)remove_path(c, root, 1); 1174 id_vec_free(c->ctx, &seen_blobs); 1175 heap_free_array(c->ctx, claims, cap, sizeof *claims); 1176 if (ok != BUILD_OK) 1177 build_diagf(c->ctx, "trace bundle export: failed to create bundle"); 1178 return ok; 1179 } 1180 1181 static int read_payload_manifest(KitBuildCoordinator* c, const char* root, 1182 KitFileData* out) { 1183 char path[BUILD_PATH_MAX]; 1184 if (path_join2(path, sizeof path, root, BUILD_BUNDLE_MANIFEST_PATH) != 1185 BUILD_OK) 1186 return BUILD_ERR; 1187 return read_file(c, path, out); 1188 } 1189 1190 static int validate_import_claim(KitBuildCoordinator* c, const char* root, 1191 const BuildTraceClaim* cl, 1192 BuildIdVec* seen_blobs) { 1193 KitFileData fd; 1194 ParsedTrace pt; 1195 uint8_t got[BUILD_HASH_LEN]; 1196 char path[BUILD_PATH_MAX]; 1197 int ok = BUILD_ERR; 1198 if (!c || !root || !cl || !seen_blobs) return BUILD_ERR; 1199 if (payload_id_path(path, sizeof path, root, BUILD_BUNDLE_TRACE_DIR, 1200 cl->trace_id) != BUILD_OK || 1201 read_file(c, path, &fd) != BUILD_OK) 1202 return BUILD_ERR; 1203 build_trace_id(fd.data, fd.size, got); 1204 if (!build_id_eq(got, cl->trace_id)) goto out; 1205 if (parse_trace_header(c->ctx, fd.data, fd.size, &pt) != BUILD_OK) 1206 goto out; 1207 if (strcmp(pt.target, cl->target) != 0 || pt.kind != cl->kind || 1208 !build_id_eq(pt.output, cl->output_tree)) 1209 goto out; 1210 if (import_trace_refs(c, fd.data, fd.size, root, seen_blobs) != BUILD_OK) 1211 goto out; 1212 if (build_store_put_trace(&c->store, fd.data, fd.size, got) != BUILD_OK || 1213 !build_id_eq(got, cl->trace_id)) 1214 goto out; 1215 ok = BUILD_OK; 1216 out: 1217 release_file(c, &fd); 1218 return ok; 1219 } 1220 1221 int build_bundle_import(KitBuildCoordinator* c, const KitBuildImportOptions* opts, 1222 KitBuildImportResult* result) { 1223 KitPkgVerifyOptions vopts; 1224 KitPkgVerifyResult vres; 1225 KitFileData manfd; 1226 BuildTraceClaim* claims = NULL; 1227 size_t nclaims = 0u, cap = 0u; 1228 char unpack[BUILD_PATH_MAX]; 1229 char err[160]; 1230 BuildIdVec seen_blobs; 1231 size_t i; 1232 int ok = BUILD_ERR; 1233 1234 memset(&seen_blobs, 0, sizeof seen_blobs); 1235 memset(&manfd, 0, sizeof manfd); 1236 unpack[0] = '\0'; 1237 if (result) memset(result, 0, sizeof *result); 1238 if (!c || !opts || !opts->pkg_data || opts->pkg_len == 0u || 1239 opts->format == KIT_PKG_FORMAT_AUTO) 1240 return BUILD_ERR; 1241 if (make_tmp_dir(c, unpack, sizeof unpack) != BUILD_OK) goto out; 1242 memset(&vopts, 0, sizeof vopts); 1243 memset(&vres, 0, sizeof vres); 1244 vopts.pkg_data = opts->pkg_data; 1245 vopts.pkg_len = opts->pkg_len; 1246 vopts.format = opts->format; 1247 vopts.unpack_dir = unpack; 1248 vopts.pubkey_bytes = opts->pubkey_bytes; 1249 vopts.pubkey_len = opts->pubkey_len; 1250 vopts.tofu = opts->tofu; 1251 vopts.trusted_keys = opts->trusted_keys; 1252 vopts.trusted_keys_len = opts->trusted_keys_len; 1253 if (kit_pkg_verify(c->ctx, c->host.cas_host, &vopts, &vres) != KIT_OK) 1254 goto out; 1255 if (strcmp(vres.name, "kit-build-traces") != 0 || 1256 strcmp(vres.version, "1") != 0) { 1257 build_diagf(c->ctx, "trace bundle import: package is not a trace bundle"); 1258 goto out; 1259 } 1260 if (read_payload_manifest(c, unpack, &manfd) != BUILD_OK) goto out; 1261 cap = count_lines(manfd.data, manfd.size); 1262 claims = (BuildTraceClaim*)heap_array(c->ctx, cap, sizeof *claims, 1263 _Alignof(BuildTraceClaim)); 1264 if (!claims) goto out; 1265 if (build_bundle_manifest_parse(manfd.data, manfd.size, claims, cap, 1266 &nclaims, err, sizeof err) != BUILD_OK) { 1267 build_diagf(c->ctx, "trace bundle import: %s", err); 1268 goto out; 1269 } 1270 for (i = 0u; i < nclaims; ++i) 1271 if (validate_import_claim(c, unpack, &claims[i], &seen_blobs) != BUILD_OK) 1272 goto out; 1273 if (nclaims > (uint32_t)-1) goto out; 1274 for (i = 0u; i < nclaims; ++i) { 1275 uint8_t key[BUILD_HASH_LEN]; 1276 BuildTraceKind record_kind; 1277 if (claims[i].kind == (uint8_t)BUILD_BUNDLE_TEST_DEEP || 1278 claims[i].kind == (uint8_t)BUILD_BUNDLE_TEST_SHALLOW) { 1279 record_kind = claims[i].kind == (uint8_t)BUILD_BUNDLE_TEST_DEEP 1280 ? BUILD_TRACE_DEEP 1281 : BUILD_TRACE_SHALLOW; 1282 if (build_test_target_key(str_slice(claims[i].target), key) != BUILD_OK) 1283 goto out; 1284 } else { 1285 record_kind = (BuildTraceKind)claims[i].kind; 1286 if (build_target_key(str_slice(claims[i].target), key) != BUILD_OK) 1287 goto out; 1288 } 1289 if (build_store_record_update(&c->store, key, str_slice(claims[i].target), 1290 record_kind, claims[i].trace_id) != BUILD_OK) 1291 goto out; 1292 } 1293 if (result) { 1294 result->n_traces = (uint32_t)nclaims; 1295 memcpy(result->keyid, vres.keyid, KIT_PKG_KEYID_LEN); 1296 result->tofu_pin = vres.tofu_pin; 1297 memcpy(result->tofu_pk, vres.tofu_pk, KIT_PKG_PK_LEN); 1298 } 1299 ok = BUILD_OK; 1300 out: 1301 release_file(c, &manfd); 1302 if (unpack[0]) (void)remove_path(c, unpack, 1); 1303 id_vec_free(c->ctx, &seen_blobs); 1304 heap_free_array(c->ctx, claims, cap, sizeof *claims); 1305 if (ok != BUILD_OK) 1306 build_diagf(c->ctx, "trace bundle import: failed to verify/install bundle"); 1307 return ok; 1308 } 1309 1310 static int ascii_space(char c) { 1311 return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || 1312 c == '\v'; 1313 } 1314 1315 static int add_size(size_t* v, size_t n) { 1316 if (!v || *v > (size_t)-1 - n) return BUILD_ERR; 1317 *v += n; 1318 return BUILD_OK; 1319 } 1320 1321 static int trace_token_match(const char* p, const char* end, const char* lit, 1322 const char* repl, const char** repl_out, 1323 size_t* lit_len_out, size_t* repl_len_out) { 1324 size_t n; 1325 if (!lit || !repl) return 0; 1326 n = strlen(lit); 1327 if ((size_t)(end - p) < n || memcmp(p, lit, n) != 0) return 0; 1328 *repl_out = repl; 1329 *lit_len_out = n; 1330 *repl_len_out = strlen(repl); 1331 return 1; 1332 } 1333 1334 static int trace_find_token(const char* p, const char* end, 1335 const TraceRenderTokens* toks, 1336 const char** repl_out, size_t* lit_len_out, 1337 size_t* repl_len_out) { 1338 return trace_token_match(p, end, "{target}", toks->target, repl_out, 1339 lit_len_out, repl_len_out) || 1340 trace_token_match(p, end, "{out}", toks->out, repl_out, lit_len_out, 1341 repl_len_out); 1342 } 1343 1344 static int render_emit_bytes(char* storage, size_t* off, size_t cap, 1345 const char* data, size_t len) { 1346 if (!off || (!data && len)) return BUILD_ERR; 1347 if (storage) { 1348 if (*off > cap || len > cap - *off) return BUILD_ERR; 1349 if (len) memcpy(storage + *off, data, len); 1350 } 1351 return add_size(off, len); 1352 } 1353 1354 static int trace_render_pass(KitSlice tmpl, const TraceRenderTokens* toks, 1355 KitSlice* argv, size_t* argc_io, char* storage, 1356 size_t storage_cap, size_t* storage_len_out) { 1357 const char* p; 1358 const char* end; 1359 size_t argc = 0u; 1360 size_t off = 0u; 1361 size_t word_start = 0u; 1362 size_t word_len = 0u; 1363 int in_word = 0; 1364 char quote = 0; 1365 if (!tmpl.s || !toks || !argc_io || !storage_len_out) return BUILD_ERR; 1366 p = tmpl.s; 1367 end = tmpl.s + tmpl.len; 1368 while (p < end) { 1369 char ch = *p; 1370 if (quote == 0 && ascii_space(ch)) { 1371 if (in_word) { 1372 if (argv) { 1373 if (argc >= *argc_io || off >= storage_cap) return BUILD_ERR; 1374 storage[off] = '\0'; 1375 argv[argc].s = storage + word_start; 1376 argv[argc].len = word_len; 1377 } 1378 if (add_size(&off, 1u) != BUILD_OK) return BUILD_ERR; 1379 ++argc; 1380 in_word = 0; 1381 word_len = 0u; 1382 } 1383 ++p; 1384 continue; 1385 } 1386 if (!in_word) { 1387 in_word = 1; 1388 word_start = off; 1389 word_len = 0u; 1390 } 1391 if (quote == 0 && (ch == '\'' || ch == '"')) { 1392 quote = ch; 1393 ++p; 1394 continue; 1395 } 1396 if (quote != 0 && ch == quote) { 1397 quote = 0; 1398 ++p; 1399 continue; 1400 } 1401 if ((quote == 0 || quote == '"') && ch == '\\') { 1402 if (p + 1 >= end) return BUILD_ERR; 1403 if (render_emit_bytes(storage, &off, storage_cap, p + 1, 1u) != 1404 BUILD_OK) 1405 return BUILD_ERR; 1406 ++word_len; 1407 p += 2; 1408 continue; 1409 } 1410 { 1411 const char* repl = NULL; 1412 size_t lit_len = 0u; 1413 size_t repl_len = 0u; 1414 if (trace_find_token(p, end, toks, &repl, &lit_len, &repl_len)) { 1415 if (render_emit_bytes(storage, &off, storage_cap, repl, repl_len) != 1416 BUILD_OK) 1417 return BUILD_ERR; 1418 if (add_size(&word_len, repl_len) != BUILD_OK) return BUILD_ERR; 1419 p += lit_len; 1420 } else { 1421 if (render_emit_bytes(storage, &off, storage_cap, p, 1u) != BUILD_OK) 1422 return BUILD_ERR; 1423 ++word_len; 1424 ++p; 1425 } 1426 } 1427 } 1428 if (quote != 0) return BUILD_ERR; 1429 if (in_word) { 1430 if (argv) { 1431 if (argc >= *argc_io || off >= storage_cap) return BUILD_ERR; 1432 storage[off] = '\0'; 1433 argv[argc].s = storage + word_start; 1434 argv[argc].len = word_len; 1435 } 1436 if (add_size(&off, 1u) != BUILD_OK) return BUILD_ERR; 1437 ++argc; 1438 } 1439 if (argv && argc != *argc_io) return BUILD_ERR; 1440 *argc_io = argc; 1441 *storage_len_out = off; 1442 return BUILD_OK; 1443 } 1444 1445 static void rendered_argv_free(const KitContext* ctx, RenderedArgv* r) { 1446 if (!ctx || !ctx->heap || !r) return; 1447 if (r->storage) ctx->heap->free(ctx->heap, r->storage, r->storage_size); 1448 if (r->argv) ctx->heap->free(ctx->heap, r->argv, r->argc * sizeof *r->argv); 1449 r->argv = NULL; 1450 r->argc = 0u; 1451 r->storage = NULL; 1452 r->storage_size = 0u; 1453 } 1454 1455 static int trace_render_argv(const KitContext* ctx, KitSlice tmpl, 1456 const TraceRenderTokens* toks, 1457 RenderedArgv* out) { 1458 size_t argc = 0u; 1459 size_t storage_len = 0u; 1460 if (!ctx || !ctx->heap || !out) return BUILD_ERR; 1461 memset(out, 0, sizeof *out); 1462 if (trace_render_pass(tmpl, toks, NULL, &argc, NULL, 0u, &storage_len) != 1463 BUILD_OK || 1464 argc == 0u) 1465 return BUILD_ERR; 1466 out->argv = (KitSlice*)ctx->heap->alloc(ctx->heap, argc * sizeof *out->argv, 1467 _Alignof(KitSlice)); 1468 out->storage = 1469 (char*)ctx->heap->alloc(ctx->heap, storage_len, _Alignof(char)); 1470 if (!out->argv || !out->storage) { 1471 rendered_argv_free(ctx, out); 1472 return BUILD_ERR; 1473 } 1474 out->argc = argc; 1475 out->storage_size = storage_len; 1476 if (trace_render_pass(tmpl, toks, out->argv, &argc, out->storage, 1477 storage_len, &storage_len) != BUILD_OK) { 1478 rendered_argv_free(ctx, out); 1479 return BUILD_ERR; 1480 } 1481 return BUILD_OK; 1482 } 1483 1484 static int run_fetch(const KitBuildExec* exec, const KitSlice* argv, 1485 size_t argc, KitSlice cwd) { 1486 KitBuildProc* proc = NULL; 1487 KitExecOpts eo; 1488 int exit_code = 1; 1489 if (!exec || !exec->spawn || !exec->wait || !argv || argc == 0u) 1490 return BUILD_ERR; 1491 memset(&eo, 0, sizeof eo); 1492 eo.argv = argv; 1493 eo.argc = argc; 1494 eo.cwd = cwd; 1495 if (exec->spawn(exec->user, &eo, &proc) != 0 || !proc) return BUILD_ERR; 1496 if (exec->wait(exec->user, proc, &exit_code, NULL, NULL) != 0) 1497 return BUILD_ERR; 1498 return exit_code == 0 ? BUILD_OK : BUILD_ERR; 1499 } 1500 1501 int build_trace_remote_pull(KitBuildCoordinator* c, KitSlice target) { 1502 size_t i; 1503 char tmp[BUILD_PATH_MAX]; 1504 char out_path[BUILD_PATH_MAX]; 1505 int ok = BUILD_ERR; 1506 if (!c || !target.s || target.len == 0u || !c->opts.trace_remotes || 1507 c->opts.n_trace_remotes == 0u || !c->host.exec) { 1508 build_diagf(c ? c->ctx : NULL, 1509 "trace remote pull: no trace remote/exec configured"); 1510 return BUILD_ERR; 1511 } 1512 if (make_tmp_dir(c, tmp, sizeof tmp) != BUILD_OK) return BUILD_ERR; 1513 for (i = 0u; i < c->opts.n_trace_remotes; ++i) { 1514 const KitBuildTraceRemote* r = &c->opts.trace_remotes[i]; 1515 RenderedArgv argv; 1516 TraceRenderTokens toks; 1517 KitFileData fd; 1518 KitBuildImportOptions iopts; 1519 KitBuildImportResult ires; 1520 char target_buf[BUILD_TARGET_MAX]; 1521 char leaf[64]; 1522 memset(&argv, 0, sizeof argv); 1523 memset(&fd, 0, sizeof fd); 1524 if (path_set(target_buf, sizeof target_buf, target) != BUILD_OK) break; 1525 snprintf(leaf, sizeof leaf, "trace-%llu.kpkg", (unsigned long long)i); 1526 if (path_join2(out_path, sizeof out_path, tmp, leaf) != BUILD_OK) break; 1527 toks.target = target_buf; 1528 toks.out = out_path; 1529 if (trace_render_argv(c->ctx, r->fetch_argv_template, &toks, &argv) != 1530 BUILD_OK) { 1531 build_diagf(c->ctx, "trace remote pull: bad argv template"); 1532 continue; 1533 } 1534 if (run_fetch(c->host.exec, argv.argv, argv.argc, str_slice(tmp)) != 1535 BUILD_OK) { 1536 rendered_argv_free(c->ctx, &argv); 1537 continue; 1538 } 1539 rendered_argv_free(c->ctx, &argv); 1540 if (read_file(c, out_path, &fd) != BUILD_OK) continue; 1541 memset(&iopts, 0, sizeof iopts); 1542 memset(&ires, 0, sizeof ires); 1543 iopts.pkg_data = fd.data; 1544 iopts.pkg_len = fd.size; 1545 iopts.format = KIT_PKG_FORMAT_KPKG; 1546 iopts.trusted_keys = r->trusted_keys.data; 1547 iopts.trusted_keys_len = r->trusted_keys.len; 1548 iopts.tofu = r->tofu; 1549 if (build_bundle_import(c, &iopts, &ires) == BUILD_OK && ires.n_traces) { 1550 release_file(c, &fd); 1551 ok = BUILD_OK; 1552 break; 1553 } 1554 release_file(c, &fd); 1555 } 1556 (void)remove_path(c, tmp, 1); 1557 return ok; 1558 }