Add a simple package list to the repo.
14 write_to_fd(int fd, void *p, size_t size)
20 len = write(fd, p, rest);
30 write_to_file(const char *filename, void *p, size_t size)
34 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
37 err = write_to_fd(fd, p, size);
43 struct hashtable_header {
46 struct { unsigned int type, offset; } sections[0];
49 #define HASHTABLE_MAGIC 0x7a7a7a7a
50 #define HASHTABLE_VERSION 1
51 #define HASHTABLE_BUCKETS 1
52 #define HASHTABLE_STRINGS 2
53 #define HASHTABLE_PACKAGES 3
57 unsigned long version;
61 unsigned long *buckets;
62 int bucket_count, bucket_alloc;
64 int pool_size, pool_alloc;
65 struct hashtable_header *header;
67 struct package *packages;
68 int package_count, package_alloc;
83 hashtable_create(void)
87 ht = zalloc(sizeof *ht);
88 ht->buckets = zalloc(4096 * sizeof *ht->buckets);
90 ht->bucket_alloc = 4096;
92 ht->string_pool = zalloc(4096);
94 ht->pool_alloc = 4096;
96 ht->packages = zalloc(4096 * sizeof *ht->packages);
97 ht->package_count = 0;
98 ht->package_alloc = 4096;
104 hashtable_create_from_file(const char *filename)
106 struct hashtable *ht;
108 unsigned int size, offset;
111 ht = zalloc(sizeof *ht);
112 fd = open(filename, O_RDONLY);
113 if (fstat(fd, &stat) < 0)
115 ht->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
116 if (ht->header == MAP_FAILED) {
121 for (i = 0; i < ht->header->sections[i].type; i++) {
122 offset = ht->header->sections[i].offset;
123 size = ht->header->sections[i + 1].offset - offset;
125 switch (ht->header->sections[i].type) {
126 case HASHTABLE_BUCKETS:
127 ht->buckets = (void *) ht->header + offset;
128 ht->bucket_count = size / sizeof *ht->buckets;
129 ht->bucket_alloc = ht->bucket_count;
131 case HASHTABLE_STRINGS:
132 ht->string_pool = (void *) ht->header + offset;
133 ht->pool_size = size;
134 ht->pool_alloc = size;
136 case HASHTABLE_PACKAGES:
137 ht->packages = (void *) ht->header + offset;
138 ht->package_count = size / sizeof *ht->packages;
139 ht->package_alloc = size / sizeof *ht->packages;
149 hashtable_destroy(struct hashtable *ht)
155 for (i = 0; ht->header->sections[i].type; i++)
157 size = ht->header->sections[i].type;
158 munmap(ht->header, size);
161 free(ht->string_pool);
168 hashtable_write(struct hashtable *ht, const char *filename)
171 struct hashtable_header *header = (struct hashtable_header *) data;
172 int fd, pool_size, package_size;
174 /* Align these to pages sizes */
175 pool_size = (ht->pool_size + 4095) & ~4095;
177 (ht->package_alloc * sizeof *ht->packages + 4095) & ~4095;
179 memset(data, 0, sizeof data);
180 header->magic = HASHTABLE_MAGIC;
181 header->version = HASHTABLE_VERSION;
183 header->sections[0].type = HASHTABLE_BUCKETS;
184 header->sections[0].offset = sizeof data;
186 header->sections[1].type = HASHTABLE_STRINGS;
187 header->sections[1].offset = header->sections[0].offset +
188 ht->bucket_alloc * sizeof *ht->buckets;
190 header->sections[2].type = HASHTABLE_PACKAGES;
191 header->sections[2].offset = header->sections[1].offset + pool_size;
193 header->sections[3].type = 0;
194 header->sections[3].offset = header->sections[2].offset + package_size;
196 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
200 write_to_fd(fd, data, sizeof data);
201 write_to_fd(fd, ht->buckets, ht->bucket_alloc * sizeof *ht->buckets);
202 write_to_fd(fd, ht->string_pool, pool_size);
203 write_to_fd(fd, ht->packages, package_size);
209 hash_string(const char *key)
212 unsigned int hash = 0;
214 for (p = key; *p; p++)
215 hash = (hash << 2) ^ *p;
221 hashtable_lookup(struct hashtable *ht, const char *key)
228 mask = ht->bucket_alloc - 1;
229 start = hash_string(key) & mask;
232 value = ht->buckets[i];
237 if (strcmp(key, &ht->string_pool[value]) == 0)
241 } while (i != start);
247 add_to_string_pool(struct hashtable *ht, const char *key)
253 len = strlen(key) + 1;
254 alloc = ht->pool_alloc;
255 while (alloc < ht->pool_size + len)
257 if (ht->pool_alloc < alloc) {
258 pool = realloc(ht->string_pool, alloc);
261 ht->string_pool = pool;
262 ht->pool_alloc = alloc;
265 memcpy(ht->string_pool + ht->pool_size, key, len);
266 value = ht->pool_size;
267 ht->pool_size += len;
273 do_insert(struct hashtable *ht, unsigned long value)
279 key = &ht->string_pool[value];
280 mask = ht->bucket_alloc - 1;
281 start = hash_string(key) & mask;
284 if (ht->buckets[i] == 0) {
285 ht->buckets[i] = value;
289 } while (i != start);
293 hashtable_insert(struct hashtable *ht, const char *key)
295 unsigned long value, *buckets, *old_buckets;
296 int i, alloc, old_alloc;
298 alloc = ht->bucket_alloc;
299 while (alloc < 4 * ht->bucket_count)
302 if (alloc != ht->bucket_alloc) {
303 buckets = zalloc(alloc * sizeof *ht->buckets);
306 old_buckets = ht->buckets;
307 ht->buckets = buckets;
308 old_alloc = ht->bucket_alloc;
309 ht->bucket_alloc = alloc;
311 for (i = 0; i < old_alloc; i++) {
312 value = old_buckets[i];
314 do_insert(ht, value);
319 value = add_to_string_pool(ht, key);
320 do_insert (ht, value);
327 hashtable_add_package(struct hashtable *ht,
328 unsigned long name, unsigned long version)
330 struct package *packages;
333 alloc = ht->package_alloc;
334 while (alloc < ht->package_count + 1)
336 if (ht->package_alloc < alloc) {
337 packages = realloc(ht->packages, alloc * sizeof ht->packages);
338 if (packages == NULL)
340 ht->packages = packages;
341 ht->package_alloc = alloc;
344 ht->packages[ht->package_count].name = name;
345 ht->packages[ht->package_count].version = version;
352 struct razor_context {
353 struct hashtable *global_ht;
356 struct razor_context *
357 razor_context_create (void)
359 struct razor_context *ctx;
361 ctx = malloc(sizeof *ctx);
362 ctx->global_ht = hashtable_create();
367 struct razor_context *
368 razor_context_create_from_file (const char *filename)
370 struct razor_context *ctx;
372 ctx = malloc(sizeof *ctx);
373 ctx->global_ht = hashtable_create_from_file(filename);
379 razor_context_tokenize(struct razor_context *ctx, const char *string)
383 token = hashtable_lookup(ctx->global_ht, string);
387 return hashtable_insert(ctx->global_ht, string);
390 static struct hashtable *qsort_ht;
393 compare_packages(const void *p1, const void *p2)
395 const struct package *pkg1 = p1, *pkg2 = p2;
397 return strcmp(&qsort_ht->string_pool[pkg1->name],
398 &qsort_ht->string_pool[pkg2->name]);
402 razor_context_sort(struct razor_context *ctx)
404 struct hashtable *ht = ctx->global_ht;
407 qsort(ht->packages, ht->package_count, sizeof *ht->packages,
412 struct razor_context *ctx;
415 struct parsing_context {
416 struct razor_context *ctx;
420 parse_package(struct parsing_context *ctx, const char **atts)
422 unsigned long name, version;
425 for (i = 0; atts[i]; i += 2) {
426 if (strcmp(atts[i], "name") == 0)
427 name = razor_context_tokenize(ctx->ctx, atts[i + 1]);
428 else if (strcmp(atts[i], "version") == 0)
429 version = razor_context_tokenize(ctx->ctx, atts[i + 1]);
432 if (name == 0 || version == 0) {
433 fprintf(stderr, "invalid package tag, "
434 "missing name or version attributes\n");
438 hashtable_add_package(ctx->ctx->global_ht, name, version);
442 start_element(void *data, const char *name, const char **atts)
444 struct parsing_context *ctx = data;
447 if (strcmp(name, "package") == 0)
448 parse_package(ctx, atts);
450 for (i = 0; atts[i]; i += 2)
451 razor_context_tokenize(ctx->ctx, atts[i + 1]);
455 end_element (void *data, const char *name)
460 sha1_to_hex(const unsigned char *sha1)
463 static char hexbuffer[4][50];
464 static const char hex[] = "0123456789abcdef";
465 char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
468 for (i = 0; i < 20; i++) {
469 unsigned int val = *sha1++;
470 *buf++ = hex[val >> 4];
471 *buf++ = hex[val & 0xf];
479 razor_context_read_file(struct razor_context *ctx, const char *filename)
483 struct parsing_context pctx;
488 unsigned char hash[20];
490 fd = open(filename, O_RDONLY);
491 if (fstat(fd, &stat) < 0)
493 p = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
497 parser = XML_ParserCreate(NULL);
499 XML_SetUserData(parser, &pctx);
500 XML_SetElementHandler(parser, start_element, end_element);
501 if (XML_Parse(parser, p, stat.st_size, 1) == XML_STATUS_ERROR) {
503 "%s at line %d, %s\n",
504 XML_ErrorString(XML_GetErrorCode(parser)),
505 XML_GetCurrentLineNumber(parser),
510 XML_ParserFree(parser);
513 SHA1_Update(&sha1, p, stat.st_size);
514 SHA1_Final(hash, &sha1);
518 snprintf(buf, sizeof buf, "set/%s", sha1_to_hex(hash));
519 if (write_to_file(buf, p, stat.st_size) < 0)
521 munmap(p, stat.st_size);
527 razor_context_write(struct razor_context *ctx, const char *filename)
529 return hashtable_write(ctx->global_ht, filename);
533 razor_context_list_packages(struct razor_context *ctx)
536 struct hashtable *ht = ctx->global_ht;
540 for (i = 0; i < ht->package_count && p->name; i++, p++) {
542 &ht->string_pool[p->name],
543 &ht->string_pool[p->version]);
548 razor_context_info(struct razor_context *ctx)
550 struct hashtable *ht = ctx->global_ht;
551 unsigned int offset, size;
554 for (i = 0; i < ht->header->sections[i].type; i++) {
555 offset = ht->header->sections[i].offset;
556 size = ht->header->sections[i + 1].offset - offset;
558 switch (ht->header->sections[i].type) {
559 case HASHTABLE_BUCKETS:
560 printf("bucket section:\t\t%dkb\n", size / 1024);
562 case HASHTABLE_STRINGS:
563 printf("string pool:\t\t%dkb\n", size / 1024);
565 case HASHTABLE_PACKAGES:
566 printf("package section:\t%dkb\n", size / 1024);
574 razor_context_destroy(struct razor_context *ctx)
576 hashtable_destroy(ctx->global_ht);
583 printf("usage: razor [ import FILES | lookup <key> | list | info ]\n");
587 static const char repo_filename[] = "system.repo";
590 main(int argc, char *argv[])
593 struct razor_context *ctx;
598 } else if (strcmp(argv[1], "import") == 0) {
599 if (stat("set", &statbuf) && mkdir("set", 0777)) {
600 fprintf(stderr, "could not create directory 'set'\n");
604 ctx = razor_context_create();
606 for (i = 2; i < argc; i++) {
607 if (razor_context_read_file(ctx, argv[i]) < 0) {
608 fprintf(stderr, "failed to import %s\n",
614 razor_context_sort(ctx);
616 printf("number of buckets: %d\n",
617 ctx->global_ht->bucket_count);
618 printf("bucket allocation: %d\n",
619 ctx->global_ht->bucket_alloc);
620 printf("pool size: %d\n", ctx->global_ht->pool_size);
621 printf("pool allocation: %d\n", ctx->global_ht->pool_alloc);
623 razor_context_write(ctx, repo_filename);
625 razor_context_destroy(ctx);
626 } else if (strcmp(argv[1], "lookup") == 0) {
627 ctx = razor_context_create_from_file(repo_filename);
628 printf("%s is %lu\n", argv[2],
629 hashtable_lookup(ctx->global_ht, argv[2]));
630 razor_context_destroy(ctx);
631 } else if (strcmp(argv[1], "list") == 0) {
632 ctx = razor_context_create_from_file(repo_filename);
633 razor_context_list_packages(ctx);
634 razor_context_destroy(ctx);
635 } else if (strcmp(argv[1], "info") == 0) {
636 ctx = razor_context_create_from_file(repo_filename);
637 razor_context_info(ctx);
638 razor_context_destroy(ctx);