manifest.c (28698B)
1 #include "manifest.h" 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #define DIST_LINE_MAX 1024u 8 9 #define F_NAME 0x01u 10 #define F_VERSION 0x02u 11 #define F_HASH 0x04u 12 #define F_ID 0x08u 13 #define F_PATH 0x10u 14 #define F_KIND 0x20u 15 #define F_BLAKE2B 0x40u 16 #define F_ROOT 0x80u 17 #define F_SIZE 0x100u 18 19 typedef enum { SEC_TOP, SEC_ART, SEC_DEP } Section; 20 21 static int emit(KitWriter* out, const char* s) { 22 return kit_writer_write(out, s, strlen(s)) == KIT_OK ? DIST_OK : DIST_ERR; 23 } 24 25 static int emit_kv(KitWriter* out, const char* key, const char* val) { 26 char line[DIST_LINE_MAX]; 27 snprintf(line, sizeof line, "%s = %s\n", key, val); 28 return emit(out, line); 29 } 30 31 static int emit_hex(KitWriter* out, const char* key, const uint8_t* h, 32 size_t n) { 33 char hex[2 * DIST_BLAKE2B_LEN + 1]; 34 dist_hex_encode(hex, h, n); 35 return emit_kv(out, key, hex); 36 } 37 38 static int emit_u64(KitWriter* out, const char* key, uint64_t v) { 39 char num[24]; 40 snprintf(num, sizeof num, "%llu", (unsigned long long)v); 41 return emit_kv(out, key, num); 42 } 43 44 int dist_manifest_emit(const DistManifest* m, KitWriter* out) { 45 size_t i; 46 if (emit(out, DIST_MANIFEST_MAGIC "\n") != DIST_OK) return DIST_ERR; 47 if (emit_kv(out, "name", m->name) != DIST_OK) return DIST_ERR; 48 if (emit_kv(out, "version", m->version) != DIST_OK) return DIST_ERR; 49 if (m->description[0] && 50 emit_kv(out, "description", m->description) != DIST_OK) 51 return DIST_ERR; 52 if (emit_kv(out, "hash", DIST_MANIFEST_HASH) != DIST_OK) return DIST_ERR; 53 54 for (i = 0; i < m->n_artifacts; ++i) { 55 const DistArtifact* a = &m->artifacts[i]; 56 if (emit(out, "\n[artifact]\n") != DIST_OK) return DIST_ERR; 57 if (emit_u64(out, "id", a->id) != DIST_OK) return DIST_ERR; 58 if (emit_kv(out, "path", a->path) != DIST_OK) return DIST_ERR; 59 if (a->target[0] && emit_kv(out, "target", a->target) != DIST_OK) 60 return DIST_ERR; 61 if (emit_kv(out, "kind", a->kind) != DIST_OK) return DIST_ERR; 62 if (emit_u64(out, "size", a->size) != DIST_OK) return DIST_ERR; 63 if (emit_hex(out, "blake2b", a->blake2b, DIST_BLAKE2B_LEN) != DIST_OK) 64 return DIST_ERR; 65 if (emit_hex(out, "root", a->root, DIST_BLAKE2B_LEN) != DIST_OK) 66 return DIST_ERR; 67 if (a->entry && emit_kv(out, "entry", "true") != DIST_OK) return DIST_ERR; 68 } 69 70 for (i = 0; i < m->n_deps; ++i) { 71 const DistDependency* d = &m->deps[i]; 72 if (emit(out, "\n[dependency]\n") != DIST_OK) return DIST_ERR; 73 if (emit_kv(out, "name", d->name) != DIST_OK) return DIST_ERR; 74 if (emit_kv(out, "version", d->version) != DIST_OK) return DIST_ERR; 75 if (d->has_blake2b && 76 emit_hex(out, "blake2b", d->blake2b, DIST_BLAKE2B_LEN) != DIST_OK) 77 return DIST_ERR; 78 if (d->has_keyid && 79 emit_hex(out, "key", d->keyid, DIST_KEYID_LEN) != DIST_OK) 80 return DIST_ERR; 81 } 82 return DIST_OK; 83 } 84 85 static char* trim_lead(char* s) { 86 while (*s == ' ' || *s == '\t') ++s; 87 return s; 88 } 89 90 static void trim_trail(char* s) { 91 size_t n = strlen(s); 92 while (n && (s[n - 1] == ' ' || s[n - 1] == '\t' || s[n - 1] == '\r' || 93 s[n - 1] == '\n')) 94 s[--n] = '\0'; 95 } 96 97 static int set_err(char* err, size_t cap, const char* msg) { 98 if (err && cap) snprintf(err, cap, "%s", msg); 99 return DIST_ERR; 100 } 101 102 static int copy_field(char* dst, size_t cap, const char* src, char* err, 103 size_t errcap) { 104 if (strlen(src) >= cap) return set_err(err, errcap, "field value too long"); 105 snprintf(dst, cap, "%s", src); 106 return DIST_OK; 107 } 108 109 static int kind_valid(const char* k) { 110 return strcmp(k, "exe") == 0 || strcmp(k, "dso") == 0 || 111 strcmp(k, "obj") == 0 || strcmp(k, "wasm") == 0 || 112 strcmp(k, "lib") == 0 || strcmp(k, "data") == 0 || 113 strcmp(k, "source") == 0; 114 } 115 116 int dist_manifest_path_valid(const char* p) { 117 size_t start = 0, i; 118 if (!p[0] || p[0] == '/') return 0; 119 for (i = 0;; ++i) { 120 char c = p[i]; 121 if (c == '\\' || c == ':') return 0; 122 if (c == '/' || c == '\0') { 123 size_t n = i - start; 124 if (n == 0) return 0; 125 if (n == 1 && p[start] == '.') return 0; 126 if (n == 2 && p[start] == '.' && p[start + 1] == '.') return 0; 127 if (c == '\0') return 1; 128 start = i + 1u; 129 } 130 } 131 } 132 133 static int parse_u64(const char* s, uint64_t* out) { 134 char* end = NULL; 135 unsigned long long v; 136 if (!*s) return DIST_ERR; 137 v = strtoull(s, &end, 10); 138 if (!end || *end != '\0') return DIST_ERR; 139 *out = (uint64_t)v; 140 return DIST_OK; 141 } 142 143 static int finalize(Section sec, uint32_t seen, char* err, size_t errcap) { 144 if (sec == SEC_TOP) { 145 if ((seen & (F_NAME | F_VERSION | F_HASH)) != (F_NAME | F_VERSION | F_HASH)) 146 return set_err(err, errcap, "missing required top-level field"); 147 } else if (sec == SEC_ART) { 148 if ((seen & (F_ID | F_PATH | F_KIND | F_BLAKE2B | F_ROOT | F_SIZE)) != 149 (F_ID | F_PATH | F_KIND | F_BLAKE2B | F_ROOT | F_SIZE)) 150 return set_err(err, errcap, "missing required [artifact] field"); 151 } else { 152 if ((seen & (F_NAME | F_VERSION)) != (F_NAME | F_VERSION)) 153 return set_err(err, errcap, "missing required [dependency] field"); 154 } 155 return DIST_OK; 156 } 157 158 int dist_manifest_parse(const uint8_t* data, size_t len, DistManifest* m, 159 char* err, size_t errcap) { 160 size_t pos = 0; 161 int first = 1; 162 Section sec = SEC_TOP; 163 uint32_t seen = 0; 164 DistArtifact* art = NULL; 165 DistDependency* dep = NULL; 166 167 memset(m, 0, sizeof *m); 168 169 while (pos < len) { 170 char buf[DIST_LINE_MAX]; 171 size_t end = pos; 172 size_t n; 173 char *t, *key, *val, *eq; 174 175 while (end < len && data[end] != '\n') ++end; 176 n = end - pos; 177 if (n >= sizeof buf) return set_err(err, errcap, "line too long"); 178 memcpy(buf, data + pos, n); 179 buf[n] = '\0'; 180 pos = (end < len) ? end + 1 : end; 181 trim_trail(buf); 182 183 if (first) { 184 first = 0; 185 if (strcmp(buf, DIST_MANIFEST_MAGIC) != 0) 186 return set_err(err, errcap, "bad manifest magic/version"); 187 continue; 188 } 189 190 t = trim_lead(buf); 191 if (*t == '\0' || *t == '#') continue; 192 193 if (*t == '[') { 194 if (finalize(sec, seen, err, errcap) != DIST_OK) return DIST_ERR; 195 seen = 0; 196 if (strcmp(t, "[artifact]") == 0) { 197 if (m->n_artifacts >= DIST_MAX_ARTIFACTS) 198 return set_err(err, errcap, "too many artifacts"); 199 sec = SEC_ART; 200 art = &m->artifacts[m->n_artifacts++]; 201 } else if (strcmp(t, "[dependency]") == 0) { 202 if (m->n_deps >= DIST_MAX_DEPS) 203 return set_err(err, errcap, "too many dependencies"); 204 sec = SEC_DEP; 205 dep = &m->deps[m->n_deps++]; 206 } else { 207 return set_err(err, errcap, "unknown section"); 208 } 209 continue; 210 } 211 212 eq = strchr(t, '='); 213 if (!eq) return set_err(err, errcap, "expected key = value"); 214 *eq = '\0'; 215 key = t; 216 trim_trail(key); 217 val = trim_lead(eq + 1); 218 219 if (sec == SEC_TOP) { 220 if (strcmp(key, "name") == 0) { 221 if (copy_field(m->name, sizeof m->name, val, err, errcap)) 222 return DIST_ERR; 223 seen |= F_NAME; 224 } else if (strcmp(key, "version") == 0) { 225 if (copy_field(m->version, sizeof m->version, val, err, errcap)) 226 return DIST_ERR; 227 seen |= F_VERSION; 228 } else if (strcmp(key, "description") == 0) { 229 if (copy_field(m->description, sizeof m->description, val, err, errcap)) 230 return DIST_ERR; 231 } else if (strcmp(key, "hash") == 0) { 232 if (strcmp(val, DIST_MANIFEST_HASH) != 0) 233 return set_err(err, errcap, "unsupported hash algorithm"); 234 seen |= F_HASH; 235 } else { 236 return set_err(err, errcap, "unknown top-level key"); 237 } 238 } else if (sec == SEC_ART) { 239 if (strcmp(key, "id") == 0) { 240 if (parse_u64(val, &art->id) != DIST_OK) 241 return set_err(err, errcap, "bad artifact id"); 242 seen |= F_ID; 243 } else if (strcmp(key, "path") == 0) { 244 if (!dist_manifest_path_valid(val)) 245 return set_err(err, errcap, "unsafe artifact path"); 246 if (copy_field(art->path, sizeof art->path, val, err, errcap)) 247 return DIST_ERR; 248 seen |= F_PATH; 249 } else if (strcmp(key, "target") == 0) { 250 if (copy_field(art->target, sizeof art->target, val, err, errcap)) 251 return DIST_ERR; 252 } else if (strcmp(key, "kind") == 0) { 253 if (!kind_valid(val)) 254 return set_err(err, errcap, "unknown artifact kind"); 255 if (copy_field(art->kind, sizeof art->kind, val, err, errcap)) 256 return DIST_ERR; 257 seen |= F_KIND; 258 } else if (strcmp(key, "size") == 0) { 259 if (parse_u64(val, &art->size) != DIST_OK) 260 return set_err(err, errcap, "bad artifact size"); 261 seen |= F_SIZE; 262 } else if (strcmp(key, "blake2b") == 0) { 263 if (strlen(val) != 2 * DIST_BLAKE2B_LEN || 264 dist_hex_decode(art->blake2b, val, DIST_BLAKE2B_LEN) != DIST_OK) 265 return set_err(err, errcap, "bad artifact blake2b"); 266 seen |= F_BLAKE2B; 267 } else if (strcmp(key, "root") == 0) { 268 if (strlen(val) != 2 * DIST_BLAKE2B_LEN || 269 dist_hex_decode(art->root, val, DIST_BLAKE2B_LEN) != DIST_OK) 270 return set_err(err, errcap, "bad artifact root"); 271 seen |= F_ROOT; 272 } else if (strcmp(key, "entry") == 0) { 273 art->entry = (strcmp(val, "true") == 0); 274 if (!art->entry && strcmp(val, "false") != 0) 275 return set_err(err, errcap, "bad entry value"); 276 } else { 277 return set_err(err, errcap, "unknown [artifact] key"); 278 } 279 } else { 280 if (strcmp(key, "name") == 0) { 281 if (copy_field(dep->name, sizeof dep->name, val, err, errcap)) 282 return DIST_ERR; 283 seen |= F_NAME; 284 } else if (strcmp(key, "version") == 0) { 285 if (copy_field(dep->version, sizeof dep->version, val, err, errcap)) 286 return DIST_ERR; 287 seen |= F_VERSION; 288 } else if (strcmp(key, "blake2b") == 0) { 289 if (strlen(val) != 2 * DIST_BLAKE2B_LEN || 290 dist_hex_decode(dep->blake2b, val, DIST_BLAKE2B_LEN) != DIST_OK) 291 return set_err(err, errcap, "bad dependency blake2b"); 292 dep->has_blake2b = 1; 293 } else if (strcmp(key, "key") == 0) { 294 if (strlen(val) != 2 * DIST_KEYID_LEN || 295 dist_hex_decode(dep->keyid, val, DIST_KEYID_LEN) != DIST_OK) 296 return set_err(err, errcap, "bad dependency key id"); 297 dep->has_keyid = 1; 298 } else { 299 return set_err(err, errcap, "unknown [dependency] key"); 300 } 301 } 302 } 303 304 if (finalize(sec, seen, err, errcap) != DIST_OK) return DIST_ERR; 305 { 306 size_t i, j; 307 for (i = 0; i < m->n_artifacts; ++i) { 308 for (j = i + 1u; j < m->n_artifacts; ++j) { 309 if (m->artifacts[i].id == m->artifacts[j].id) 310 return set_err(err, errcap, "duplicate artifact id"); 311 if (strcmp(m->artifacts[i].path, m->artifacts[j].path) == 0) 312 return set_err(err, errcap, "duplicate artifact path"); 313 } 314 } 315 } 316 return DIST_OK; 317 } 318 319 #define P3_F_NAME 0x00000001u 320 #define P3_F_VERSION 0x00000002u 321 #define P3_F_DESCRIPTION 0x00000004u 322 #define P3_F_HASH 0x00000008u 323 #define P3_F_TREE_FORMAT 0x00000010u 324 #define P3_F_BLOB_FORMAT 0x00000020u 325 #define P3_F_ID 0x00000040u 326 #define P3_F_OUTPUT_NAME 0x00000080u 327 #define P3_F_TREE_ID 0x00000100u 328 #define P3_F_TARGET 0x00000200u 329 #define P3_F_DEFAULT 0x00000400u 330 #define P3_F_OUTPUT 0x00000800u 331 #define P3_F_PATH 0x00001000u 332 #define P3_F_KIND 0x00002000u 333 #define P3_F_ENTRY 0x00004000u 334 #define P3_F_PACKAGE 0x00008000u 335 #define P3_F_KEY 0x00010000u 336 337 typedef enum { 338 P3_SEC_TOP, 339 P3_SEC_OUTPUT, 340 P3_SEC_ARTIFACT, 341 P3_SEC_DEPENDENCY 342 } PackageSection; 343 344 static int field_text_valid(const char* s, int required) { 345 if (required && !s[0]) return 0; 346 for (; *s; ++s) { 347 if (*s == '\n' || *s == '\r') return 0; 348 } 349 return 1; 350 } 351 352 static int parse_bool3(const char* s, int* out) { 353 if (strcmp(s, "true") == 0) { 354 *out = 1; 355 return DIST_OK; 356 } 357 if (strcmp(s, "false") == 0) { 358 *out = 0; 359 return DIST_OK; 360 } 361 return DIST_ERR; 362 } 363 364 static int parse_u64_dec3(const char* s, uint64_t* out) { 365 uint64_t v = 0; 366 if (!*s) return DIST_ERR; 367 for (; *s; ++s) { 368 unsigned digit; 369 if (*s < '0' || *s > '9') return DIST_ERR; 370 digit = (unsigned)(*s - '0'); 371 if (v > (UINT64_MAX - (uint64_t)digit) / 10u) return DIST_ERR; 372 v = v * 10u + (uint64_t)digit; 373 } 374 *out = v; 375 return DIST_OK; 376 } 377 378 static int decode_hash3(uint8_t out[DIST_BLAKE2B_LEN], const char* val, 379 const char* err_msg, char* err, size_t errcap) { 380 if (strlen(val) != 2u * DIST_BLAKE2B_LEN || 381 dist_hex_decode(out, val, DIST_BLAKE2B_LEN) != DIST_OK) 382 return set_err(err, errcap, err_msg); 383 return DIST_OK; 384 } 385 386 static int decode_keyid3(uint8_t out[DIST_KEYID_LEN], const char* val, 387 char* err, size_t errcap) { 388 if (strlen(val) != 2u * DIST_KEYID_LEN || 389 dist_hex_decode(out, val, DIST_KEYID_LEN) != DIST_OK) 390 return set_err(err, errcap, "bad dependency key id"); 391 return DIST_OK; 392 } 393 394 static int seen_once3(uint32_t* seen, uint32_t bit, const char* msg, char* err, 395 size_t errcap) { 396 if (*seen & bit) return set_err(err, errcap, msg); 397 *seen |= bit; 398 return DIST_OK; 399 } 400 401 static int find_output3(const DistPackageManifest* m, uint64_t id) { 402 size_t i; 403 for (i = 0; i < m->n_outputs; ++i) { 404 if (m->outputs[i].id == id) return (int)i; 405 } 406 return -1; 407 } 408 409 static int finalize_package_section3(PackageSection sec, uint32_t seen, 410 char* err, size_t errcap) { 411 if (sec == P3_SEC_TOP) { 412 if ((seen & (P3_F_NAME | P3_F_VERSION | P3_F_HASH | P3_F_TREE_FORMAT | 413 P3_F_BLOB_FORMAT)) != (P3_F_NAME | P3_F_VERSION | P3_F_HASH | 414 P3_F_TREE_FORMAT | P3_F_BLOB_FORMAT)) 415 return set_err(err, errcap, "missing required top-level field"); 416 } else if (sec == P3_SEC_OUTPUT) { 417 if ((seen & (P3_F_ID | P3_F_OUTPUT_NAME | P3_F_TREE_ID)) != 418 (P3_F_ID | P3_F_OUTPUT_NAME | P3_F_TREE_ID)) 419 return set_err(err, errcap, "missing required [output] field"); 420 } else if (sec == P3_SEC_ARTIFACT) { 421 if ((seen & (P3_F_OUTPUT | P3_F_PATH | P3_F_KIND)) != 422 (P3_F_OUTPUT | P3_F_PATH | P3_F_KIND)) 423 return set_err(err, errcap, "missing required [artifact] field"); 424 } else { 425 if ((seen & (P3_F_NAME | P3_F_VERSION)) != (P3_F_NAME | P3_F_VERSION)) 426 return set_err(err, errcap, "missing required [dependency] field"); 427 } 428 return DIST_OK; 429 } 430 431 int dist_package_manifest_validate(const DistPackageManifest* m, char* err, 432 size_t errcap) { 433 size_t i, j; 434 size_t default_outputs = 0; 435 436 if (!field_text_valid(m->name, 1) || !field_text_valid(m->version, 1) || 437 !field_text_valid(m->description, 0)) 438 return set_err(err, errcap, "bad package string field"); 439 if (m->n_outputs == 0) return set_err(err, errcap, "missing [output]"); 440 if (m->n_outputs > DIST_MAX_OUTPUTS) 441 return set_err(err, errcap, "too many outputs"); 442 if (m->n_artifacts > DIST_MAX_ARTIFACTS) 443 return set_err(err, errcap, "too many artifacts"); 444 if (m->n_deps > DIST_MAX_DEPS) 445 return set_err(err, errcap, "too many dependencies"); 446 447 for (i = 0; i < m->n_outputs; ++i) { 448 const DistPackageOutput* out = &m->outputs[i]; 449 if (!field_text_valid(out->name, 1) || !field_text_valid(out->target, 0)) 450 return set_err(err, errcap, "bad output string field"); 451 if (out->is_default) ++default_outputs; 452 for (j = i + 1u; j < m->n_outputs; ++j) { 453 if (out->id == m->outputs[j].id) 454 return set_err(err, errcap, "duplicate output id"); 455 } 456 } 457 if (default_outputs > 1u) 458 return set_err(err, errcap, "duplicate default output"); 459 460 for (i = 0; i < m->n_artifacts; ++i) { 461 const DistPackageArtifact* art = &m->artifacts[i]; 462 if (find_output3(m, art->output_id) < 0) 463 return set_err(err, errcap, "artifact references unknown output"); 464 if (!field_text_valid(art->path, 1) || !dist_manifest_path_valid(art->path)) 465 return set_err(err, errcap, "unsafe artifact path"); 466 if (!kind_valid(art->kind)) 467 return set_err(err, errcap, "unknown artifact kind"); 468 for (j = i + 1u; j < m->n_artifacts; ++j) { 469 const DistPackageArtifact* other = &m->artifacts[j]; 470 if (art->output_id == other->output_id && 471 strcmp(art->path, other->path) == 0) 472 return set_err(err, errcap, "duplicate artifact path"); 473 } 474 } 475 476 for (i = 0; i < m->n_deps; ++i) { 477 const DistPackageDependency* dep = &m->deps[i]; 478 if (!field_text_valid(dep->name, 1) || !field_text_valid(dep->version, 1)) 479 return set_err(err, errcap, "bad dependency string field"); 480 } 481 482 return DIST_OK; 483 } 484 485 int dist_package_manifest_emit(const DistPackageManifest* m, KitWriter* out) { 486 size_t i; 487 char err[128]; 488 489 if (dist_package_manifest_validate(m, err, sizeof err) != DIST_OK) 490 return DIST_ERR; 491 492 if (emit(out, DIST_PACKAGE3_MAGIC "\n") != DIST_OK) return DIST_ERR; 493 if (emit_kv(out, "name", m->name) != DIST_OK) return DIST_ERR; 494 if (emit_kv(out, "version", m->version) != DIST_OK) return DIST_ERR; 495 if (m->description[0] && 496 emit_kv(out, "description", m->description) != DIST_OK) 497 return DIST_ERR; 498 if (emit_kv(out, "hash", DIST_PACKAGE3_HASH) != DIST_OK) return DIST_ERR; 499 if (emit_kv(out, "tree", DIST_PACKAGE3_TREE_FORMAT) != DIST_OK) 500 return DIST_ERR; 501 if (emit_kv(out, "blob", DIST_PACKAGE3_BLOB_FORMAT) != DIST_OK) 502 return DIST_ERR; 503 504 for (i = 0; i < m->n_outputs; ++i) { 505 const DistPackageOutput* pkg_out = &m->outputs[i]; 506 if (emit(out, "\n[output]\n") != DIST_OK) return DIST_ERR; 507 if (emit_u64(out, "id", pkg_out->id) != DIST_OK) return DIST_ERR; 508 if (emit_kv(out, "name", pkg_out->name) != DIST_OK) return DIST_ERR; 509 if (emit_hex(out, "tree", pkg_out->tree, DIST_BLAKE2B_LEN) != DIST_OK) 510 return DIST_ERR; 511 if (pkg_out->target[0] && 512 emit_kv(out, "target", pkg_out->target) != DIST_OK) 513 return DIST_ERR; 514 if (pkg_out->is_default && emit_kv(out, "default", "true") != DIST_OK) 515 return DIST_ERR; 516 } 517 518 for (i = 0; i < m->n_artifacts; ++i) { 519 const DistPackageArtifact* art = &m->artifacts[i]; 520 if (emit(out, "\n[artifact]\n") != DIST_OK) return DIST_ERR; 521 if (emit_u64(out, "output", art->output_id) != DIST_OK) return DIST_ERR; 522 if (emit_kv(out, "path", art->path) != DIST_OK) return DIST_ERR; 523 if (emit_kv(out, "kind", art->kind) != DIST_OK) return DIST_ERR; 524 if (art->entry && emit_kv(out, "entry", "true") != DIST_OK) return DIST_ERR; 525 } 526 527 for (i = 0; i < m->n_deps; ++i) { 528 const DistPackageDependency* dep = &m->deps[i]; 529 if (emit(out, "\n[dependency]\n") != DIST_OK) return DIST_ERR; 530 if (emit_kv(out, "name", dep->name) != DIST_OK) return DIST_ERR; 531 if (emit_kv(out, "version", dep->version) != DIST_OK) return DIST_ERR; 532 if (dep->has_package && 533 emit_hex(out, "package", dep->package, DIST_BLAKE2B_LEN) != DIST_OK) 534 return DIST_ERR; 535 if (dep->has_keyid && 536 emit_hex(out, "key", dep->keyid, DIST_KEYID_LEN) != DIST_OK) 537 return DIST_ERR; 538 } 539 540 return DIST_OK; 541 } 542 543 int dist_package_manifest_parse(const uint8_t* data, size_t len, 544 DistPackageManifest* m, char* err, 545 size_t errcap) { 546 size_t pos = 0; 547 int first = 1; 548 PackageSection sec = P3_SEC_TOP; 549 uint32_t seen = 0; 550 DistPackageOutput* pkg_out = NULL; 551 DistPackageArtifact* art = NULL; 552 DistPackageDependency* dep = NULL; 553 554 memset(m, 0, sizeof *m); 555 556 while (pos < len) { 557 char buf[DIST_LINE_MAX]; 558 size_t end = pos; 559 size_t n; 560 char *t, *key, *val, *eq; 561 562 while (end < len && data[end] != '\n') ++end; 563 n = end - pos; 564 if (n >= sizeof buf) return set_err(err, errcap, "line too long"); 565 memcpy(buf, data + pos, n); 566 buf[n] = '\0'; 567 pos = (end < len) ? end + 1 : end; 568 trim_trail(buf); 569 570 if (first) { 571 first = 0; 572 if (strcmp(buf, DIST_PACKAGE3_MAGIC) != 0) 573 return set_err(err, errcap, "bad package manifest magic/version"); 574 continue; 575 } 576 577 t = trim_lead(buf); 578 if (*t == '\0' || *t == '#') continue; 579 580 if (*t == '[') { 581 if (finalize_package_section3(sec, seen, err, errcap) != DIST_OK) 582 return DIST_ERR; 583 seen = 0; 584 if (strcmp(t, "[output]") == 0) { 585 if (m->n_outputs >= DIST_MAX_OUTPUTS) 586 return set_err(err, errcap, "too many outputs"); 587 sec = P3_SEC_OUTPUT; 588 pkg_out = &m->outputs[m->n_outputs++]; 589 } else if (strcmp(t, "[artifact]") == 0) { 590 if (m->n_artifacts >= DIST_MAX_ARTIFACTS) 591 return set_err(err, errcap, "too many artifacts"); 592 sec = P3_SEC_ARTIFACT; 593 art = &m->artifacts[m->n_artifacts++]; 594 } else if (strcmp(t, "[dependency]") == 0) { 595 if (m->n_deps >= DIST_MAX_DEPS) 596 return set_err(err, errcap, "too many dependencies"); 597 sec = P3_SEC_DEPENDENCY; 598 dep = &m->deps[m->n_deps++]; 599 } else { 600 return set_err(err, errcap, "unknown section"); 601 } 602 continue; 603 } 604 605 eq = strchr(t, '='); 606 if (!eq) return set_err(err, errcap, "expected key = value"); 607 *eq = '\0'; 608 key = t; 609 trim_trail(key); 610 val = trim_lead(eq + 1); 611 612 if (sec == P3_SEC_TOP) { 613 if (strcmp(key, "name") == 0) { 614 if (seen_once3(&seen, P3_F_NAME, "duplicate top-level key", err, 615 errcap) != DIST_OK) 616 return DIST_ERR; 617 if (!field_text_valid(val, 1)) 618 return set_err(err, errcap, "bad package name"); 619 if (copy_field(m->name, sizeof m->name, val, err, errcap)) 620 return DIST_ERR; 621 } else if (strcmp(key, "version") == 0) { 622 if (seen_once3(&seen, P3_F_VERSION, "duplicate top-level key", err, 623 errcap) != DIST_OK) 624 return DIST_ERR; 625 if (!field_text_valid(val, 1)) 626 return set_err(err, errcap, "bad package version"); 627 if (copy_field(m->version, sizeof m->version, val, err, errcap)) 628 return DIST_ERR; 629 } else if (strcmp(key, "description") == 0) { 630 if (seen_once3(&seen, P3_F_DESCRIPTION, "duplicate top-level key", err, 631 errcap) != DIST_OK) 632 return DIST_ERR; 633 if (!field_text_valid(val, 0)) 634 return set_err(err, errcap, "bad package description"); 635 if (copy_field(m->description, sizeof m->description, val, err, errcap)) 636 return DIST_ERR; 637 } else if (strcmp(key, "hash") == 0) { 638 if (seen_once3(&seen, P3_F_HASH, "duplicate top-level key", err, 639 errcap) != DIST_OK) 640 return DIST_ERR; 641 if (strcmp(val, DIST_PACKAGE3_HASH) != 0) 642 return set_err(err, errcap, "unsupported hash algorithm"); 643 } else if (strcmp(key, "tree") == 0) { 644 if (seen_once3(&seen, P3_F_TREE_FORMAT, "duplicate top-level key", err, 645 errcap) != DIST_OK) 646 return DIST_ERR; 647 if (strcmp(val, DIST_PACKAGE3_TREE_FORMAT) != 0) 648 return set_err(err, errcap, "unsupported tree format"); 649 } else if (strcmp(key, "blob") == 0) { 650 if (seen_once3(&seen, P3_F_BLOB_FORMAT, "duplicate top-level key", err, 651 errcap) != DIST_OK) 652 return DIST_ERR; 653 if (strcmp(val, DIST_PACKAGE3_BLOB_FORMAT) != 0) 654 return set_err(err, errcap, "unsupported blob format"); 655 } else { 656 return set_err(err, errcap, "unknown top-level key"); 657 } 658 } else if (sec == P3_SEC_OUTPUT) { 659 if (strcmp(key, "id") == 0) { 660 if (seen_once3(&seen, P3_F_ID, "duplicate [output] key", err, errcap) != 661 DIST_OK) 662 return DIST_ERR; 663 if (parse_u64_dec3(val, &pkg_out->id) != DIST_OK) 664 return set_err(err, errcap, "bad output id"); 665 } else if (strcmp(key, "name") == 0) { 666 if (seen_once3(&seen, P3_F_OUTPUT_NAME, "duplicate [output] key", err, 667 errcap) != DIST_OK) 668 return DIST_ERR; 669 if (!field_text_valid(val, 1)) 670 return set_err(err, errcap, "bad output name"); 671 if (copy_field(pkg_out->name, sizeof pkg_out->name, val, err, errcap)) 672 return DIST_ERR; 673 } else if (strcmp(key, "tree") == 0) { 674 if (seen_once3(&seen, P3_F_TREE_ID, "duplicate [output] key", err, 675 errcap) != DIST_OK) 676 return DIST_ERR; 677 if (decode_hash3(pkg_out->tree, val, "bad output tree id", err, 678 errcap) != DIST_OK) 679 return DIST_ERR; 680 } else if (strcmp(key, "target") == 0) { 681 if (seen_once3(&seen, P3_F_TARGET, "duplicate [output] key", err, 682 errcap) != DIST_OK) 683 return DIST_ERR; 684 if (!field_text_valid(val, 0)) 685 return set_err(err, errcap, "bad output target"); 686 if (copy_field(pkg_out->target, sizeof pkg_out->target, val, err, 687 errcap)) 688 return DIST_ERR; 689 } else if (strcmp(key, "default") == 0) { 690 if (seen_once3(&seen, P3_F_DEFAULT, "duplicate [output] key", err, 691 errcap) != DIST_OK) 692 return DIST_ERR; 693 if (parse_bool3(val, &pkg_out->is_default) != DIST_OK) 694 return set_err(err, errcap, "bad default value"); 695 } else { 696 return set_err(err, errcap, "unknown [output] key"); 697 } 698 } else if (sec == P3_SEC_ARTIFACT) { 699 if (strcmp(key, "output") == 0) { 700 if (seen_once3(&seen, P3_F_OUTPUT, "duplicate [artifact] key", err, 701 errcap) != DIST_OK) 702 return DIST_ERR; 703 if (parse_u64_dec3(val, &art->output_id) != DIST_OK) 704 return set_err(err, errcap, "bad artifact output id"); 705 } else if (strcmp(key, "path") == 0) { 706 if (seen_once3(&seen, P3_F_PATH, "duplicate [artifact] key", err, 707 errcap) != DIST_OK) 708 return DIST_ERR; 709 if (!dist_manifest_path_valid(val)) 710 return set_err(err, errcap, "unsafe artifact path"); 711 if (copy_field(art->path, sizeof art->path, val, err, errcap)) 712 return DIST_ERR; 713 } else if (strcmp(key, "kind") == 0) { 714 if (seen_once3(&seen, P3_F_KIND, "duplicate [artifact] key", err, 715 errcap) != DIST_OK) 716 return DIST_ERR; 717 if (!kind_valid(val)) 718 return set_err(err, errcap, "unknown artifact kind"); 719 if (copy_field(art->kind, sizeof art->kind, val, err, errcap)) 720 return DIST_ERR; 721 } else if (strcmp(key, "entry") == 0) { 722 if (seen_once3(&seen, P3_F_ENTRY, "duplicate [artifact] key", err, 723 errcap) != DIST_OK) 724 return DIST_ERR; 725 if (parse_bool3(val, &art->entry) != DIST_OK) 726 return set_err(err, errcap, "bad entry value"); 727 } else { 728 return set_err(err, errcap, "unknown [artifact] key"); 729 } 730 } else { 731 if (strcmp(key, "name") == 0) { 732 if (seen_once3(&seen, P3_F_NAME, "duplicate [dependency] key", err, 733 errcap) != DIST_OK) 734 return DIST_ERR; 735 if (!field_text_valid(val, 1)) 736 return set_err(err, errcap, "bad dependency name"); 737 if (copy_field(dep->name, sizeof dep->name, val, err, errcap)) 738 return DIST_ERR; 739 } else if (strcmp(key, "version") == 0) { 740 if (seen_once3(&seen, P3_F_VERSION, "duplicate [dependency] key", err, 741 errcap) != DIST_OK) 742 return DIST_ERR; 743 if (!field_text_valid(val, 1)) 744 return set_err(err, errcap, "bad dependency version"); 745 if (copy_field(dep->version, sizeof dep->version, val, err, errcap)) 746 return DIST_ERR; 747 } else if (strcmp(key, "package") == 0) { 748 if (seen_once3(&seen, P3_F_PACKAGE, "duplicate [dependency] key", err, 749 errcap) != DIST_OK) 750 return DIST_ERR; 751 if (decode_hash3(dep->package, val, "bad dependency package id", err, 752 errcap) != DIST_OK) 753 return DIST_ERR; 754 dep->has_package = 1; 755 } else if (strcmp(key, "key") == 0) { 756 if (seen_once3(&seen, P3_F_KEY, "duplicate [dependency] key", err, 757 errcap) != DIST_OK) 758 return DIST_ERR; 759 if (decode_keyid3(dep->keyid, val, err, errcap) != DIST_OK) 760 return DIST_ERR; 761 dep->has_keyid = 1; 762 } else { 763 return set_err(err, errcap, "unknown [dependency] key"); 764 } 765 } 766 } 767 768 if (first) return set_err(err, errcap, "bad package manifest magic/version"); 769 if (finalize_package_section3(sec, seen, err, errcap) != DIST_OK) 770 return DIST_ERR; 771 return dist_package_manifest_validate(m, err, errcap); 772 }