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