kpkg.c (21812B)
1 #include "kpkg.h" 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #include "blake2b.h" 8 9 #define DESC_LINE_MAX 1024u 10 11 static void put_u32le(uint8_t* p, uint32_t v) { 12 p[0] = (uint8_t)v; 13 p[1] = (uint8_t)(v >> 8); 14 p[2] = (uint8_t)(v >> 16); 15 p[3] = (uint8_t)(v >> 24); 16 } 17 18 static void put_u64le(uint8_t* p, uint64_t v) { 19 unsigned i; 20 for (i = 0; i < 8u; ++i) p[i] = (uint8_t)(v >> (8u * i)); 21 } 22 23 static uint32_t get_u32le(const uint8_t* p) { 24 return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | 25 ((uint32_t)p[3] << 24); 26 } 27 28 static uint64_t get_u64le(const uint8_t* p) { 29 uint64_t v = 0; 30 unsigned i; 31 for (i = 0; i < 8u; ++i) v |= ((uint64_t)p[i]) << (8u * i); 32 return v; 33 } 34 35 static int emit(KitWriter* out, const char* s) { 36 return kit_writer_write(out, s, strlen(s)) == KIT_OK ? DIST_OK : DIST_ERR; 37 } 38 39 static int emit_kv(KitWriter* out, const char* key, const char* val) { 40 char line[DESC_LINE_MAX]; 41 snprintf(line, sizeof line, "%s = %s\n", key, val); 42 return emit(out, line); 43 } 44 45 static int emit_u64(KitWriter* out, const char* key, uint64_t v) { 46 char num[24]; 47 snprintf(num, sizeof num, "%llu", (unsigned long long)v); 48 return emit_kv(out, key, num); 49 } 50 51 static int emit_hex(KitWriter* out, const char* key, const uint8_t* h) { 52 char hex[2 * DIST_BLAKE2B_LEN + 1]; 53 dist_hex_encode(hex, h, DIST_BLAKE2B_LEN); 54 return emit_kv(out, key, hex); 55 } 56 57 static char* trim_lead(char* s) { 58 while (*s == ' ' || *s == '\t') ++s; 59 return s; 60 } 61 62 static void trim_trail(char* s) { 63 size_t n = strlen(s); 64 while (n && (s[n - 1] == ' ' || s[n - 1] == '\t' || s[n - 1] == '\r' || 65 s[n - 1] == '\n')) 66 s[--n] = '\0'; 67 } 68 69 static int set_err(char* err, size_t cap, const char* msg) { 70 if (err && cap) snprintf(err, cap, "%s", msg); 71 return DIST_ERR; 72 } 73 74 static int parse_u64_strict(const char* s, uint64_t* out) { 75 uint64_t v = 0; 76 if (!*s) return DIST_ERR; 77 while (*s) { 78 uint64_t digit; 79 if (*s < '0' || *s > '9') return DIST_ERR; 80 digit = (uint64_t)(*s - '0'); 81 if (v > (UINT64_MAX - digit) / 10u) return DIST_ERR; 82 v = v * 10u + digit; 83 ++s; 84 } 85 *out = v; 86 return DIST_OK; 87 } 88 89 static int parse_hex32(uint8_t out[DIST_BLAKE2B_LEN], const char* val) { 90 if (strlen(val) != 2 * DIST_BLAKE2B_LEN) return DIST_ERR; 91 return dist_hex_decode(out, val, DIST_BLAKE2B_LEN); 92 } 93 94 static int copy_field(char* out, size_t cap, const char* val) { 95 size_t n = strlen(val); 96 if (n >= cap) return DIST_ERR; 97 memcpy(out, val, n + 1u); 98 return DIST_OK; 99 } 100 101 static int seen_once(uint32_t* seen, uint32_t bit) { 102 if (*seen & bit) return DIST_ERR; 103 *seen |= bit; 104 return DIST_OK; 105 } 106 107 void dist_kpkg3_region_root(uint8_t out[DIST_BLAKE2B_LEN], const char* kind, 108 const uint8_t* data, size_t len) { 109 uint8_t region[DIST_BLAKE2B_LEN]; 110 DistBlake2b h; 111 static const uint8_t dom[] = "kit region v1"; 112 dist_blake2b_init(&h, DIST_BLAKE2B_LEN); 113 if (len) dist_blake2b_update(&h, data, len); 114 dist_blake2b_final(&h, region); 115 116 dist_blake2b_init(&h, DIST_BLAKE2B_LEN); 117 dist_blake2b_update(&h, dom, sizeof dom - 1u); 118 dist_blake2b_update(&h, (const uint8_t*)kind, strlen(kind)); 119 dist_blake2b_update(&h, region, DIST_BLAKE2B_LEN); 120 dist_blake2b_final(&h, out); 121 } 122 123 int dist_kpkg3_write_header(KitWriter* out, const DistKpkg3Header* h) { 124 uint8_t b[DIST_KPKG3_HEADER_SIZE]; 125 size_t off = 16u; 126 memset(b, 0, sizeof b); 127 memcpy(b, DIST_KPKG3_MAGIC, 7u); 128 put_u32le(b + 8u, DIST_KPKG3_VERSION); 129 put_u32le(b + 12u, DIST_KPKG3_HEADER_SIZE); 130 #define PUT3(v) \ 131 do { \ 132 put_u64le(b + off, (v)); \ 133 off += 8u; \ 134 } while (0) 135 PUT3(h->manifest_offset); 136 PUT3(h->manifest_size); 137 PUT3(h->signature_offset); 138 PUT3(h->signature_size); 139 PUT3(h->descriptor_offset); 140 PUT3(h->descriptor_size); 141 PUT3(h->descriptor_signature_offset); 142 PUT3(h->descriptor_signature_size); 143 PUT3(h->pubkey_offset); 144 PUT3(h->pubkey_size); 145 #undef PUT3 146 return kit_writer_write(out, b, sizeof b) == KIT_OK ? DIST_OK : DIST_ERR; 147 } 148 149 int dist_kpkg3_read_header(const uint8_t* data, size_t len, 150 DistKpkg3Header* h) { 151 size_t off = 16u; 152 if (len < DIST_KPKG3_HEADER_SIZE) return DIST_ERR; 153 if (memcmp(data, DIST_KPKG3_MAGIC, 7u) != 0) return DIST_ERR; 154 if (get_u32le(data + 8u) != DIST_KPKG3_VERSION || 155 get_u32le(data + 12u) != DIST_KPKG3_HEADER_SIZE) 156 return DIST_ERR; 157 #define GET3(dst) \ 158 do { \ 159 (dst) = get_u64le(data + off); \ 160 off += 8u; \ 161 } while (0) 162 GET3(h->manifest_offset); 163 GET3(h->manifest_size); 164 GET3(h->signature_offset); 165 GET3(h->signature_size); 166 GET3(h->descriptor_offset); 167 GET3(h->descriptor_size); 168 GET3(h->descriptor_signature_offset); 169 GET3(h->descriptor_signature_size); 170 GET3(h->pubkey_offset); 171 GET3(h->pubkey_size); 172 #undef GET3 173 return DIST_OK; 174 } 175 176 void dist_kpkg3_encode_index_record(uint8_t out[DIST_KPKG3_INDEX_RECORD_SIZE], 177 const DistKpkg3IndexRecord* r) { 178 memset(out, 0, DIST_KPKG3_INDEX_RECORD_SIZE); 179 memcpy(out + 0u, r->blob_id, DIST_BLAKE2B_LEN); 180 put_u64le(out + 32u, r->chunk_index); 181 put_u64le(out + 40u, r->content_offset); 182 put_u64le(out + 48u, r->stored_size); 183 put_u64le(out + 56u, r->raw_size); 184 put_u32le(out + 64u, r->compression); 185 put_u32le(out + 68u, 0u); 186 memcpy(out + 72u, r->stored_hash, DIST_BLAKE2B_LEN); 187 memcpy(out + 104u, r->raw_hash, DIST_BLAKE2B_LEN); 188 memcpy(out + 136u, r->leaf_hash, DIST_BLAKE2B_LEN); 189 } 190 191 int dist_kpkg3_decode_index_record(const uint8_t* data, size_t len, 192 DistKpkg3IndexRecord* r) { 193 if (len < DIST_KPKG3_INDEX_RECORD_SIZE) return DIST_ERR; 194 if (get_u32le(data + 68u) != 0u) return DIST_ERR; 195 memcpy(r->blob_id, data + 0u, DIST_BLAKE2B_LEN); 196 r->chunk_index = get_u64le(data + 32u); 197 r->content_offset = get_u64le(data + 40u); 198 r->stored_size = get_u64le(data + 48u); 199 r->raw_size = get_u64le(data + 56u); 200 r->compression = get_u32le(data + 64u); 201 memcpy(r->stored_hash, data + 72u, DIST_BLAKE2B_LEN); 202 memcpy(r->raw_hash, data + 104u, DIST_BLAKE2B_LEN); 203 memcpy(r->leaf_hash, data + 136u, DIST_BLAKE2B_LEN); 204 return DIST_OK; 205 } 206 207 int dist_kpkg3_descriptor_emit(KitWriter* out, const DistKpkg3Descriptor* d) { 208 size_t i; 209 if (emit(out, "kit-encoding 3\n") != DIST_OK) return DIST_ERR; 210 if (emit_hex(out, "package-id", d->package_id) != DIST_OK) return DIST_ERR; 211 if (emit_kv(out, "format", "kpkg") != DIST_OK) return DIST_ERR; 212 if (emit_kv(out, "hash", DIST_KPKG3_HASH) != DIST_OK) return DIST_ERR; 213 if (emit_kv(out, "tree", DIST_KPKG3_TREE_FORMAT) != DIST_OK) return DIST_ERR; 214 if (emit_kv(out, "blob", DIST_KPKG3_BLOB_FORMAT) != DIST_OK) return DIST_ERR; 215 if (emit_u64(out, "chunk-size", d->chunk_size) != DIST_OK) return DIST_ERR; 216 if (emit_u64(out, "alignment", d->alignment) != DIST_OK) return DIST_ERR; 217 if (emit_u64(out, "tree-offset", d->tree_offset) != DIST_OK) return DIST_ERR; 218 if (emit_u64(out, "tree-size", d->tree_size) != DIST_OK) return DIST_ERR; 219 if (emit_hex(out, "tree-root", d->tree_root) != DIST_OK) return DIST_ERR; 220 if (emit_u64(out, "index-offset", d->index_offset) != DIST_OK) 221 return DIST_ERR; 222 if (emit_u64(out, "index-size", d->index_size) != DIST_OK) return DIST_ERR; 223 if (emit_u64(out, "index-bytes", d->index_bytes) != DIST_OK) return DIST_ERR; 224 if (emit_hex(out, "index-root", d->index_root) != DIST_OK) return DIST_ERR; 225 if (d->index_url[0] && emit_kv(out, "index-url", d->index_url) != DIST_OK) 226 return DIST_ERR; 227 if (emit_u64(out, "content-offset", d->content_offset) != DIST_OK) 228 return DIST_ERR; 229 if (emit_u64(out, "content-size", d->content_size) != DIST_OK) 230 return DIST_ERR; 231 if (emit_hex(out, "content-root", d->content_root) != DIST_OK) 232 return DIST_ERR; 233 234 for (i = 0; i < d->n_trees; ++i) { 235 if (emit(out, "\n[tree-object]\n") != DIST_OK) return DIST_ERR; 236 if (emit_hex(out, "tree", d->trees[i].tree) != DIST_OK) return DIST_ERR; 237 if (d->trees[i].embedded) { 238 if (emit_u64(out, "offset", d->trees[i].offset) != DIST_OK) 239 return DIST_ERR; 240 if (emit_u64(out, "size", d->trees[i].size) != DIST_OK) return DIST_ERR; 241 } 242 if (emit_hex(out, "blake2b", d->trees[i].blake2b) != DIST_OK) 243 return DIST_ERR; 244 if (d->trees[i].url[0] && emit_kv(out, "url", d->trees[i].url) != DIST_OK) 245 return DIST_ERR; 246 } 247 248 for (i = 0; i < d->n_chunk_sources; ++i) { 249 if (emit(out, "\n[chunk-source]\n") != DIST_OK) return DIST_ERR; 250 if (d->chunk_sources[i].kind == DIST_KPKG3_CHUNK_SOURCE_EMBEDDED) { 251 if (emit_kv(out, "kind", "embedded") != DIST_OK) return DIST_ERR; 252 } else if (d->chunk_sources[i].kind == 253 DIST_KPKG3_CHUNK_SOURCE_URL_TEMPLATE) { 254 if (!d->chunk_sources[i].tmpl[0]) return DIST_ERR; 255 if (emit_kv(out, "kind", "url-template") != DIST_OK) return DIST_ERR; 256 if (emit_kv(out, "template", d->chunk_sources[i].tmpl) != DIST_OK) 257 return DIST_ERR; 258 } else { 259 return DIST_ERR; 260 } 261 } 262 return DIST_OK; 263 } 264 265 typedef enum Kpkg3DescriptorSection { 266 KPKG3_DESC_TOP = 0, 267 KPKG3_DESC_TREE_OBJECT = 1, 268 KPKG3_DESC_CHUNK_SOURCE = 2, 269 } Kpkg3DescriptorSection; 270 271 #define KPKG3_TOP_PACKAGE_ID (1u << 0) 272 #define KPKG3_TOP_FORMAT (1u << 1) 273 #define KPKG3_TOP_HASH (1u << 2) 274 #define KPKG3_TOP_TREE (1u << 3) 275 #define KPKG3_TOP_BLOB (1u << 4) 276 #define KPKG3_TOP_CHUNK_SIZE (1u << 5) 277 #define KPKG3_TOP_ALIGNMENT (1u << 6) 278 #define KPKG3_TOP_TREE_OFFSET (1u << 7) 279 #define KPKG3_TOP_TREE_SIZE (1u << 8) 280 #define KPKG3_TOP_TREE_ROOT (1u << 9) 281 #define KPKG3_TOP_INDEX_OFFSET (1u << 10) 282 #define KPKG3_TOP_INDEX_SIZE (1u << 11) 283 #define KPKG3_TOP_INDEX_BYTES (1u << 12) 284 #define KPKG3_TOP_INDEX_ROOT (1u << 13) 285 #define KPKG3_TOP_CONTENT_OFFSET (1u << 14) 286 #define KPKG3_TOP_CONTENT_SIZE (1u << 15) 287 #define KPKG3_TOP_CONTENT_ROOT (1u << 16) 288 #define KPKG3_TOP_INDEX_URL (1u << 17) 289 #define KPKG3_TOP_REQUIRED ((1u << 17) - 1u) 290 291 #define KPKG3_TREE_SEEN_TREE (1u << 0) 292 #define KPKG3_TREE_SEEN_OFFSET (1u << 1) 293 #define KPKG3_TREE_SEEN_SIZE (1u << 2) 294 #define KPKG3_TREE_SEEN_BLAKE2B (1u << 3) 295 #define KPKG3_TREE_SEEN_URL (1u << 4) 296 297 #define KPKG3_CHUNK_SEEN_KIND (1u << 0) 298 #define KPKG3_CHUNK_SEEN_TEMPLATE (1u << 1) 299 300 static int finish_kpkg3_section(Kpkg3DescriptorSection section, uint32_t seen, 301 DistKpkg3Descriptor* d, char* err, 302 size_t errcap) { 303 if (section == KPKG3_DESC_TREE_OBJECT) { 304 DistKpkg3TreeObject* tree = &d->trees[d->n_trees - 1u]; 305 int has_offset = (seen & KPKG3_TREE_SEEN_OFFSET) != 0; 306 int has_size = (seen & KPKG3_TREE_SEEN_SIZE) != 0; 307 if ((seen & KPKG3_TREE_SEEN_TREE) == 0 || 308 (seen & KPKG3_TREE_SEEN_BLAKE2B) == 0) 309 return set_err(err, errcap, "missing tree-object field"); 310 if (has_offset != has_size) 311 return set_err(err, errcap, "partial tree-object embedded range"); 312 tree->embedded = has_offset; 313 } else if (section == KPKG3_DESC_CHUNK_SOURCE) { 314 DistKpkg3ChunkSource* source = &d->chunk_sources[d->n_chunk_sources - 1u]; 315 if ((seen & KPKG3_CHUNK_SEEN_KIND) == 0) 316 return set_err(err, errcap, "missing chunk-source kind"); 317 if (source->kind == DIST_KPKG3_CHUNK_SOURCE_URL_TEMPLATE) { 318 if ((seen & KPKG3_CHUNK_SEEN_TEMPLATE) == 0) 319 return set_err(err, errcap, "missing chunk-source template"); 320 } else if (source->kind == DIST_KPKG3_CHUNK_SOURCE_EMBEDDED) { 321 if ((seen & KPKG3_CHUNK_SEEN_TEMPLATE) != 0) 322 return set_err(err, errcap, "embedded chunk-source has template"); 323 } else { 324 return set_err(err, errcap, "bad chunk-source kind"); 325 } 326 } 327 return DIST_OK; 328 } 329 330 static int parse_kpkg3_top_key(DistKpkg3Descriptor* d, uint32_t* seen, 331 const char* key, const char* val, char* err, 332 size_t errcap) { 333 if (strcmp(key, "package-id") == 0) { 334 if (seen_once(seen, KPKG3_TOP_PACKAGE_ID) != DIST_OK || 335 parse_hex32(d->package_id, val) != DIST_OK) 336 return set_err(err, errcap, "bad package-id"); 337 } else if (strcmp(key, "format") == 0) { 338 if (seen_once(seen, KPKG3_TOP_FORMAT) != DIST_OK || 339 strcmp(val, "kpkg") != 0) 340 return set_err(err, errcap, "bad format"); 341 } else if (strcmp(key, "hash") == 0) { 342 if (seen_once(seen, KPKG3_TOP_HASH) != DIST_OK || 343 strcmp(val, DIST_KPKG3_HASH) != 0) 344 return set_err(err, errcap, "bad hash algorithm"); 345 } else if (strcmp(key, "tree") == 0) { 346 if (seen_once(seen, KPKG3_TOP_TREE) != DIST_OK || 347 strcmp(val, DIST_KPKG3_TREE_FORMAT) != 0) 348 return set_err(err, errcap, "bad tree format"); 349 } else if (strcmp(key, "blob") == 0) { 350 if (seen_once(seen, KPKG3_TOP_BLOB) != DIST_OK || 351 strcmp(val, DIST_KPKG3_BLOB_FORMAT) != 0) 352 return set_err(err, errcap, "bad blob format"); 353 } else if (strcmp(key, "chunk-size") == 0) { 354 if (seen_once(seen, KPKG3_TOP_CHUNK_SIZE) != DIST_OK || 355 parse_u64_strict(val, &d->chunk_size) != DIST_OK || d->chunk_size == 0) 356 return set_err(err, errcap, "bad chunk-size"); 357 } else if (strcmp(key, "alignment") == 0) { 358 if (seen_once(seen, KPKG3_TOP_ALIGNMENT) != DIST_OK || 359 parse_u64_strict(val, &d->alignment) != DIST_OK || d->alignment == 0) 360 return set_err(err, errcap, "bad alignment"); 361 } else if (strcmp(key, "tree-offset") == 0) { 362 if (seen_once(seen, KPKG3_TOP_TREE_OFFSET) != DIST_OK || 363 parse_u64_strict(val, &d->tree_offset) != DIST_OK) 364 return set_err(err, errcap, "bad tree-offset"); 365 } else if (strcmp(key, "tree-size") == 0) { 366 if (seen_once(seen, KPKG3_TOP_TREE_SIZE) != DIST_OK || 367 parse_u64_strict(val, &d->tree_size) != DIST_OK) 368 return set_err(err, errcap, "bad tree-size"); 369 } else if (strcmp(key, "tree-root") == 0) { 370 if (seen_once(seen, KPKG3_TOP_TREE_ROOT) != DIST_OK || 371 parse_hex32(d->tree_root, val) != DIST_OK) 372 return set_err(err, errcap, "bad tree-root"); 373 } else if (strcmp(key, "index-offset") == 0) { 374 if (seen_once(seen, KPKG3_TOP_INDEX_OFFSET) != DIST_OK || 375 parse_u64_strict(val, &d->index_offset) != DIST_OK) 376 return set_err(err, errcap, "bad index-offset"); 377 } else if (strcmp(key, "index-size") == 0) { 378 if (seen_once(seen, KPKG3_TOP_INDEX_SIZE) != DIST_OK || 379 parse_u64_strict(val, &d->index_size) != DIST_OK) 380 return set_err(err, errcap, "bad index-size"); 381 } else if (strcmp(key, "index-bytes") == 0) { 382 if (seen_once(seen, KPKG3_TOP_INDEX_BYTES) != DIST_OK || 383 parse_u64_strict(val, &d->index_bytes) != DIST_OK) 384 return set_err(err, errcap, "bad index-bytes"); 385 } else if (strcmp(key, "index-root") == 0) { 386 if (seen_once(seen, KPKG3_TOP_INDEX_ROOT) != DIST_OK || 387 parse_hex32(d->index_root, val) != DIST_OK) 388 return set_err(err, errcap, "bad index-root"); 389 } else if (strcmp(key, "index-url") == 0) { 390 if (seen_once(seen, KPKG3_TOP_INDEX_URL) != DIST_OK || 391 copy_field(d->index_url, sizeof d->index_url, val) != DIST_OK) 392 return set_err(err, errcap, "bad index-url"); 393 } else if (strcmp(key, "content-offset") == 0) { 394 if (seen_once(seen, KPKG3_TOP_CONTENT_OFFSET) != DIST_OK || 395 parse_u64_strict(val, &d->content_offset) != DIST_OK) 396 return set_err(err, errcap, "bad content-offset"); 397 } else if (strcmp(key, "content-size") == 0) { 398 if (seen_once(seen, KPKG3_TOP_CONTENT_SIZE) != DIST_OK || 399 parse_u64_strict(val, &d->content_size) != DIST_OK) 400 return set_err(err, errcap, "bad content-size"); 401 } else if (strcmp(key, "content-root") == 0) { 402 if (seen_once(seen, KPKG3_TOP_CONTENT_ROOT) != DIST_OK || 403 parse_hex32(d->content_root, val) != DIST_OK) 404 return set_err(err, errcap, "bad content-root"); 405 } else { 406 return set_err(err, errcap, "unknown encoding descriptor key"); 407 } 408 return DIST_OK; 409 } 410 411 static int parse_kpkg3_tree_key(DistKpkg3TreeObject* tree, uint32_t* seen, 412 const char* key, const char* val, char* err, 413 size_t errcap) { 414 if (strcmp(key, "tree") == 0) { 415 if (seen_once(seen, KPKG3_TREE_SEEN_TREE) != DIST_OK || 416 parse_hex32(tree->tree, val) != DIST_OK) 417 return set_err(err, errcap, "bad tree-object tree"); 418 } else if (strcmp(key, "offset") == 0) { 419 if (seen_once(seen, KPKG3_TREE_SEEN_OFFSET) != DIST_OK || 420 parse_u64_strict(val, &tree->offset) != DIST_OK) 421 return set_err(err, errcap, "bad tree-object offset"); 422 } else if (strcmp(key, "size") == 0) { 423 if (seen_once(seen, KPKG3_TREE_SEEN_SIZE) != DIST_OK || 424 parse_u64_strict(val, &tree->size) != DIST_OK) 425 return set_err(err, errcap, "bad tree-object size"); 426 } else if (strcmp(key, "blake2b") == 0) { 427 if (seen_once(seen, KPKG3_TREE_SEEN_BLAKE2B) != DIST_OK || 428 parse_hex32(tree->blake2b, val) != DIST_OK) 429 return set_err(err, errcap, "bad tree-object blake2b"); 430 } else if (strcmp(key, "url") == 0) { 431 if (seen_once(seen, KPKG3_TREE_SEEN_URL) != DIST_OK || 432 copy_field(tree->url, sizeof tree->url, val) != DIST_OK) 433 return set_err(err, errcap, "bad tree-object url"); 434 } else { 435 return set_err(err, errcap, "unknown tree-object key"); 436 } 437 return DIST_OK; 438 } 439 440 static int parse_kpkg3_chunk_key(DistKpkg3ChunkSource* source, uint32_t* seen, 441 const char* key, const char* val, char* err, 442 size_t errcap) { 443 if (strcmp(key, "kind") == 0) { 444 if (seen_once(seen, KPKG3_CHUNK_SEEN_KIND) != DIST_OK) 445 return set_err(err, errcap, "bad chunk-source kind"); 446 if (strcmp(val, "embedded") == 0) { 447 source->kind = DIST_KPKG3_CHUNK_SOURCE_EMBEDDED; 448 } else if (strcmp(val, "url-template") == 0) { 449 source->kind = DIST_KPKG3_CHUNK_SOURCE_URL_TEMPLATE; 450 } else { 451 return set_err(err, errcap, "bad chunk-source kind"); 452 } 453 } else if (strcmp(key, "template") == 0) { 454 if (seen_once(seen, KPKG3_CHUNK_SEEN_TEMPLATE) != DIST_OK || 455 copy_field(source->tmpl, sizeof source->tmpl, val) != DIST_OK) 456 return set_err(err, errcap, "bad chunk-source template"); 457 } else { 458 return set_err(err, errcap, "unknown chunk-source key"); 459 } 460 return DIST_OK; 461 } 462 463 int dist_kpkg3_descriptor_parse(const uint8_t* data, size_t len, 464 DistKpkg3Descriptor* d, char* err, 465 size_t errcap) { 466 size_t pos = 0; 467 int first = 1; 468 uint32_t top_seen = 0, section_seen = 0; 469 Kpkg3DescriptorSection section = KPKG3_DESC_TOP; 470 memset(d, 0, sizeof *d); 471 while (pos < len) { 472 char buf[DESC_LINE_MAX], *t, *eq, *key, *val; 473 size_t end = pos, n; 474 while (end < len && data[end] != '\n') ++end; 475 n = end - pos; 476 if (n >= sizeof buf) return set_err(err, errcap, "line too long"); 477 memcpy(buf, data + pos, n); 478 buf[n] = '\0'; 479 pos = (end < len) ? end + 1u : end; 480 trim_trail(buf); 481 if (first) { 482 first = 0; 483 if (strcmp(buf, "kit-encoding 3") != 0) 484 return set_err(err, errcap, "bad encoding descriptor magic/version"); 485 continue; 486 } 487 t = trim_lead(buf); 488 if (*t == '\0' || *t == '#') continue; 489 if (*t == '[') { 490 if (finish_kpkg3_section(section, section_seen, d, err, errcap) != 491 DIST_OK) 492 return DIST_ERR; 493 section_seen = 0; 494 if (strcmp(t, "[tree-object]") == 0) { 495 if (d->n_trees == DIST_MAX_OUTPUTS) 496 return set_err(err, errcap, "too many tree-object sections"); 497 memset(&d->trees[d->n_trees], 0, sizeof d->trees[d->n_trees]); 498 ++d->n_trees; 499 section = KPKG3_DESC_TREE_OBJECT; 500 } else if (strcmp(t, "[chunk-source]") == 0) { 501 if (d->n_chunk_sources == DIST_MAX_OUTPUTS) 502 return set_err(err, errcap, "too many chunk-source sections"); 503 memset(&d->chunk_sources[d->n_chunk_sources], 0, 504 sizeof d->chunk_sources[d->n_chunk_sources]); 505 ++d->n_chunk_sources; 506 section = KPKG3_DESC_CHUNK_SOURCE; 507 } else { 508 return set_err(err, errcap, "unknown encoding descriptor section"); 509 } 510 continue; 511 } 512 eq = strchr(t, '='); 513 if (!eq) return set_err(err, errcap, "expected key = value"); 514 *eq = '\0'; 515 key = t; 516 trim_trail(key); 517 val = trim_lead(eq + 1); 518 if (section == KPKG3_DESC_TOP) { 519 if (parse_kpkg3_top_key(d, &top_seen, key, val, err, errcap) != DIST_OK) 520 return DIST_ERR; 521 } else if (section == KPKG3_DESC_TREE_OBJECT) { 522 if (parse_kpkg3_tree_key(&d->trees[d->n_trees - 1u], §ion_seen, key, 523 val, err, errcap) != DIST_OK) 524 return DIST_ERR; 525 } else { 526 if (parse_kpkg3_chunk_key(&d->chunk_sources[d->n_chunk_sources - 1u], 527 §ion_seen, key, val, err, 528 errcap) != DIST_OK) 529 return DIST_ERR; 530 } 531 } 532 if (first) return set_err(err, errcap, "empty encoding descriptor"); 533 if (finish_kpkg3_section(section, section_seen, d, err, errcap) != DIST_OK) 534 return DIST_ERR; 535 if ((top_seen & KPKG3_TOP_REQUIRED) != KPKG3_TOP_REQUIRED) 536 return set_err(err, errcap, "missing required encoding descriptor field"); 537 if (d->index_size != 0 && d->index_size != d->index_bytes) 538 return set_err(err, errcap, "embedded index size mismatch"); 539 return DIST_OK; 540 } 541 542 const char* dist_kpkg_compression_name(uint32_t c) { 543 if (c == DIST_KPKG_COMP_NONE) return "none"; 544 if (c == DIST_KPKG_COMP_LZ4_BLOCK_V1) return "lz4-block-v1"; 545 return NULL; 546 } 547 548 int dist_kpkg_compression_parse(const char* s, uint32_t* out) { 549 if (strcmp(s, "none") == 0) { 550 *out = DIST_KPKG_COMP_NONE; 551 return DIST_OK; 552 } 553 if (strcmp(s, "lz4-block-v1") == 0) { 554 *out = DIST_KPKG_COMP_LZ4_BLOCK_V1; 555 return DIST_OK; 556 } 557 return DIST_ERR; 558 }