razor.c
author Kristian H?gsberg <krh@redhat.com>
Fri Sep 07 00:09:18 2007 -0400 (2007-09-07)
changeset 12 71a410830f3d
parent 10 1b8f6a5022f1
child 13 6a715b310792
permissions -rw-r--r--
Sort on version as second order key for provides and requires.
     1 #include <stdlib.h>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #include <sys/types.h>
     5 #include <sys/stat.h>
     6 #include <sys/mman.h>
     7 #include <unistd.h>
     8 #include <fcntl.h>
     9 
    10 #include <expat.h>
    11 #include "sha1.h"
    12 
    13 struct array {
    14 	void *data;
    15 	int size, alloc;
    16 };
    17 
    18 static void *
    19 array_add(struct array *array, int size)
    20 {
    21 	int alloc;
    22 	void *data, *p;
    23 
    24 	if (array->alloc > 0)
    25 		alloc = array->alloc;
    26 	else
    27 		alloc = 16;
    28 
    29 	while (alloc < array->size + size)
    30 		alloc *= 2;
    31 
    32 	if (array->alloc < alloc) {
    33 		data = realloc(array->data, alloc);
    34 		if (data == NULL)
    35 			return 0;
    36 		array->data = data;
    37 		array->alloc = alloc;
    38 	}
    39 
    40 	p = array->data + array->size;
    41 	array->size += size;
    42 
    43 	return p;
    44 }
    45 
    46 static int
    47 write_to_fd(int fd, void *p, size_t size)
    48 {
    49 	int rest, len;
    50 
    51 	rest = size;
    52 	while (rest > 0) {
    53 		len = write(fd, p, rest);
    54 		if (len < 0)
    55 			return -1;
    56 		rest -= len;
    57 	}
    58 
    59 	return 0;
    60 }
    61 
    62 static int
    63 write_to_file(const char *filename, void *p, size_t size)
    64 {
    65 	int fd, err;
    66 
    67 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
    68 	if (fd < 0)
    69 		return -1;
    70 	err = write_to_fd(fd, p, size);
    71 	close(fd);
    72 
    73 	return err;
    74 }
    75 
    76 static void *
    77 zalloc(size_t size)
    78 {
    79 	void *p;
    80 
    81 	p = malloc(size);
    82 	memset(p, 0, size);
    83 
    84 	return p;
    85 }
    86 
    87 struct razor_set_header {
    88 	unsigned int magic;
    89 	unsigned int version;
    90 	struct { unsigned int type, offset; } sections[0];
    91 };
    92 
    93 #define RAZOR_MAGIC 0x7a7a7a7a
    94 #define RAZOR_VERSION 1
    95 
    96 #define RAZOR_BUCKETS 1
    97 #define RAZOR_STRINGS 2
    98 #define RAZOR_PACKAGES 3
    99 #define RAZOR_REQUIRES 4
   100 #define RAZOR_PROVIDES 5
   101 #define RAZOR_PROPERTIES 6
   102 
   103 struct razor_package {
   104 	unsigned long name;
   105 	unsigned long version;
   106 	unsigned long requires;
   107 	unsigned long provides;
   108 };
   109 
   110 struct razor_property {
   111 	unsigned long name;
   112 	unsigned long version;
   113 	unsigned long packages;
   114 };
   115 
   116 struct razor_set {
   117 	struct array buckets;
   118 	struct array string_pool;
   119 	struct array property_pool;
   120  	struct array packages;
   121  	struct array requires;
   122  	struct array provides;
   123 	struct razor_set_header *header;
   124 };
   125 
   126 struct razor_set *
   127 razor_set_create(void)
   128 {
   129 	struct razor_set *set;
   130 	char *p;
   131 
   132 	set = zalloc(sizeof(struct razor_set));
   133 	p = array_add(&set->string_pool, 1);
   134 	*p = '\0';
   135 
   136 	return set;
   137 }
   138 
   139 struct razor_set *
   140 razor_set_open(const char *filename)
   141 {
   142 	struct razor_set *set;
   143 	struct stat stat;
   144 	unsigned int size, offset;
   145 	int fd, i;
   146 
   147 	set = zalloc(sizeof *set);
   148 	fd = open(filename, O_RDONLY);
   149 	if (fstat(fd, &stat) < 0)
   150 		return NULL;
   151 	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   152 	if (set->header == MAP_FAILED) {
   153 		free(set);
   154 		return NULL;
   155 	}
   156 
   157 	for (i = 0; i < set->header->sections[i].type; i++) {
   158 		offset = set->header->sections[i].offset;
   159 		size = set->header->sections[i + 1].offset - offset;
   160 
   161 		switch (set->header->sections[i].type) {
   162 		case RAZOR_BUCKETS:
   163 			set->buckets.data = (void *) set->header + offset;
   164 			set->buckets.size = size;
   165 			set->buckets.alloc = size;
   166 			break;
   167 		case RAZOR_STRINGS:
   168 			set->string_pool.data = (void *) set->header + offset;
   169 			set->string_pool.size = size;
   170 			set->string_pool.alloc = size;
   171 			break;
   172 		case RAZOR_PACKAGES:
   173 			set->packages.data = (void *) set->header + offset;
   174 			set->packages.size = size;
   175 			set->packages.size = size;
   176 			break;
   177 		case RAZOR_REQUIRES:
   178 			set->requires.data = (void *) set->header + offset;
   179 			set->requires.size = size;
   180 			set->requires.size = size;
   181 			break;
   182 		case RAZOR_PROVIDES:
   183 			set->provides.data = (void *) set->header + offset;
   184 			set->provides.size = size;
   185 			set->provides.size = size;
   186 			break;
   187 		case RAZOR_PROPERTIES:
   188 			set->property_pool.data = (void *) set->header + offset;
   189 			set->property_pool.size = size;
   190 			set->property_pool.size = size;
   191 			break;
   192 		}
   193 	}
   194 	close(fd);
   195 
   196 	return set;
   197 }
   198 
   199 void
   200 razor_set_destroy(struct razor_set *set)
   201 {
   202 	unsigned int size;
   203 	int i;
   204 
   205 	if (set->header) {
   206 		for (i = 0; set->header->sections[i].type; i++)
   207 			;
   208 		size = set->header->sections[i].type;
   209 		munmap(set->header, size);
   210 	} else {
   211 		free(set->buckets.data);
   212 		free(set->string_pool.data);
   213 		free(set->packages.data);
   214 		free(set->requires.data);
   215 		free(set->provides.data);
   216 		free(set->property_pool.data);
   217 	}
   218 
   219 	free(set);
   220 }
   221 
   222 static int
   223 razor_set_write(struct razor_set *set, const char *filename)
   224 {
   225 	char data[4096];
   226 	struct razor_set_header *header = (struct razor_set_header *) data;
   227 	int fd, pool_size, packages_size, requires_size, provides_size;
   228 	int properties_size;
   229 
   230 	/* Align these to pages sizes */
   231 	pool_size = (set->string_pool.size + 4095) & ~4095;
   232 	packages_size = (set->packages.size + 4095) & ~4095;
   233 	requires_size = (set->requires.size + 4095) & ~4095;
   234 	provides_size = (set->provides.size + 4095) & ~4095;
   235 	properties_size = (set->property_pool.size + 4095) & ~4095;
   236 
   237 	memset(data, 0, sizeof data);
   238 	header->magic = RAZOR_MAGIC;
   239 	header->version = RAZOR_VERSION;
   240 
   241 	header->sections[0].type = RAZOR_BUCKETS;
   242 	header->sections[0].offset = sizeof data;
   243 
   244 	header->sections[1].type = RAZOR_STRINGS;
   245 	header->sections[1].offset =
   246 		header->sections[0].offset + set->buckets.alloc;
   247 
   248 	header->sections[2].type = RAZOR_PACKAGES;
   249 	header->sections[2].offset =
   250 		header->sections[1].offset + pool_size;
   251 
   252 	header->sections[3].type = RAZOR_REQUIRES;
   253 	header->sections[3].offset =
   254 		header->sections[2].offset + packages_size;
   255 
   256 	header->sections[4].type = RAZOR_PROVIDES;
   257 	header->sections[4].offset =
   258 		header->sections[3].offset + requires_size;
   259 
   260 	header->sections[5].type = RAZOR_PROPERTIES;
   261 	header->sections[5].offset =
   262 		header->sections[4].offset + provides_size;
   263 
   264 	header->sections[6].type = 0;
   265 	header->sections[6].offset =
   266 		header->sections[5].offset + properties_size;
   267 
   268 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
   269 	if (fd < 0)
   270 		return -1;
   271 
   272 	write_to_fd(fd, data, sizeof data);
   273 	write_to_fd(fd, set->buckets.data, set->buckets.alloc);
   274 	write_to_fd(fd, set->string_pool.data, pool_size);
   275 	write_to_fd(fd, set->packages.data, packages_size);
   276 	write_to_fd(fd, set->requires.data, requires_size);
   277 	write_to_fd(fd, set->provides.data, provides_size);
   278 	write_to_fd(fd, set->property_pool.data, properties_size);
   279 
   280 	return 0;
   281 }
   282 
   283 static unsigned int
   284 hash_string(const char *key)
   285 {
   286 	const char *p;
   287 	unsigned int hash = 0;
   288 
   289 	for (p = key; *p; p++)
   290 		hash = (hash * 617) ^ *p;
   291 
   292 	return hash;
   293 }
   294 
   295 unsigned long
   296 razor_set_lookup(struct razor_set *set, const char *key)
   297 {
   298 	unsigned int mask, start, i;
   299 	unsigned long *b;
   300 	char *pool;
   301 
   302 	pool = set->string_pool.data;
   303 	mask = set->buckets.alloc - 1;
   304 	start = hash_string(key) * sizeof(unsigned long);
   305 
   306 	for (i = 0; i < set->buckets.alloc; i += sizeof *b) {
   307 		b = set->buckets.data + ((start + i) & mask);
   308 
   309 		if (*b == 0)
   310 			return 0;
   311 
   312 		if (strcmp(key, &pool[*b]) == 0)
   313 			return *b;
   314 	}
   315 
   316 	return 0;
   317 }
   318 
   319 static unsigned long
   320 add_to_string_pool(struct razor_set *set, const char *key)
   321 {
   322 	int len;
   323 	char *p;
   324 
   325 	len = strlen(key) + 1;
   326 	p = array_add(&set->string_pool, len);
   327 	memcpy(p, key, len);
   328 
   329 	return p - (char *) set->string_pool.data;
   330 }
   331 
   332 static unsigned long
   333 add_to_property_pool(struct razor_set *set, struct array *properties)
   334 {
   335 	unsigned long  *p;
   336 
   337 	p = array_add(properties, sizeof *p);
   338 	*p = 0;
   339 	p = array_add(&set->property_pool, properties->size);
   340 	memcpy(p, properties->data, properties->size);
   341 
   342 	return p - (unsigned long *) set->property_pool.data;
   343 }
   344 
   345 static void
   346 do_insert(struct razor_set *set, unsigned long value)
   347 {
   348 	unsigned int mask, start, i;
   349 	unsigned long *b;
   350 	const char *key;
   351 
   352 	key = (char *) set->string_pool.data + value;
   353 	mask = set->buckets.alloc - 1;
   354 	start = hash_string(key) * sizeof(unsigned long);
   355 
   356 	for (i = 0; i < set->buckets.alloc; i += sizeof *b) {
   357 		b = set->buckets.data + ((start + i) & mask);
   358 		if (*b == 0) {
   359 			*b = value;
   360 			break;
   361 		}
   362 	}
   363 }
   364 
   365 unsigned long
   366 razor_set_insert(struct razor_set *set, const char *key)
   367 {
   368 	unsigned long value, *buckets, *b, *end;
   369 	int alloc;
   370 
   371 	alloc = set->buckets.alloc;
   372 	array_add(&set->buckets, 4 * sizeof *buckets);
   373 	if (alloc != set->buckets.alloc) {
   374 		end = set->buckets.data + alloc;
   375 		memset(end, 0, set->buckets.alloc - alloc);
   376 		for (b = set->buckets.data; b < end; b++) {
   377 			value = *b;
   378 			if (value != 0) {
   379 				*b = 0;
   380 				do_insert(set, value);
   381 			}
   382 		}
   383 	}
   384 
   385 	value = add_to_string_pool(set, key);
   386 	do_insert (set, value);
   387 
   388 	return value;
   389 }
   390 
   391 static unsigned long
   392 razor_set_add_package(struct razor_set *set,
   393 		      unsigned long name, unsigned long version)
   394 {
   395 	struct razor_package *p;
   396 
   397 	p = array_add(&set->packages, sizeof *p);
   398 
   399 	p->name = name;
   400 	p->version = version;
   401 
   402 	return p - (struct razor_package *) set->packages.data;
   403 }
   404 
   405 static unsigned long
   406 razor_set_add_requires(struct razor_set *set,
   407 		       unsigned long name, unsigned long version)
   408 {
   409 	struct razor_property *p;
   410 
   411 	p = array_add(&set->requires, sizeof *p);
   412 
   413 	p->name = name;
   414 	p->version = version;
   415 
   416 	return p - (struct razor_property *) set->requires.data;
   417 }
   418 
   419 static unsigned long
   420 razor_set_add_provides(struct razor_set *set,
   421 		       unsigned long name, unsigned long version)
   422 {
   423 	struct razor_property *p;
   424 
   425 	p = array_add(&set->provides, sizeof *p);
   426 
   427 	p->name = name;
   428 	p->version = version;
   429 
   430 	return p - (struct razor_property *) set->provides.data;
   431 }
   432 
   433 unsigned long
   434 razor_set_tokenize(struct razor_set *set, const char *string)
   435 {
   436 	unsigned long token;
   437 
   438 	token = razor_set_lookup(set, string);
   439 	if (token != 0)
   440 		return token;
   441 
   442 	return razor_set_insert(set, string);
   443 }
   444 
   445 struct property_context {
   446 	struct array all;
   447 	struct array package;
   448 };
   449 
   450 struct import_context {
   451 	struct razor_set *set;
   452 	struct property_context requires;
   453 	struct property_context provides;
   454 	unsigned long package;
   455 	unsigned long *requires_map;
   456 	unsigned long *provides_map;
   457 };
   458 
   459 struct import_property {
   460 	unsigned long name;
   461 	unsigned long version;
   462 	unsigned long package;
   463 	unsigned long index;
   464 	unsigned long unique_index;
   465 };
   466 
   467 static void
   468 parse_package(struct import_context *ctx, const char **atts, void *data)
   469 {
   470 	unsigned long name = 0, version = 0;
   471 	int i;
   472 
   473 	for (i = 0; atts[i]; i += 2) {
   474 		if (strcmp(atts[i], "name") == 0)
   475 			name = razor_set_tokenize(ctx->set, atts[i + 1]);
   476 		else if (strcmp(atts[i], "version") == 0)
   477 			version = razor_set_tokenize(ctx->set, atts[i + 1]);
   478 	}
   479 
   480 	if (name == 0 || version == 0) {
   481 		fprintf(stderr, "invalid package tag, "
   482 			"missing name or version attributes\n");
   483 		return;
   484 	}
   485 
   486 	ctx->package = razor_set_add_package(ctx->set, name, version);
   487 	memset(&ctx->requires.package, 0, sizeof ctx->requires.package);
   488 	memset(&ctx->provides.package, 0, sizeof ctx->provides.package);
   489 
   490 	return;
   491 }
   492 
   493 static void
   494 parse_property(struct import_context *ctx, const char **atts, void *data)
   495 {
   496 	unsigned long name = 0, version = 0, *r;
   497 	struct import_property *p;
   498 	struct property_context *pctx = data;
   499 	int i;
   500 
   501 	for (i = 0; atts[i]; i += 2) {
   502 		if (strcmp(atts[i], "name") == 0)
   503 			name = razor_set_tokenize(ctx->set, atts[i + 1]);
   504 		if (strcmp(atts[i], "version") == 0)
   505 			version = razor_set_tokenize(ctx->set, atts[i + 1]);
   506 	}
   507 	
   508 	if (name == 0) {
   509 		fprintf(stderr, "invalid tag, missing name attribute\n");
   510 		return;
   511 	}
   512 
   513 	p = array_add(&pctx->all, sizeof *p);
   514 	p->name = name;
   515 	p->version = version;
   516 	p->package = ctx->package;
   517 	p->index = p - (struct import_property *) pctx->all.data;
   518 
   519 	r = array_add(&pctx->package, sizeof *r);
   520 	*r = p->index;
   521 }
   522 
   523 static void
   524 start_element(void *data, const char *name, const char **atts)
   525 {
   526 	struct import_context *ctx = data;
   527 
   528 	if (strcmp(name, "package") == 0)
   529 		parse_package(ctx, atts, NULL);
   530 	else if (strcmp(name, "requires") == 0)
   531 		parse_property(ctx, atts, &ctx->requires);
   532 	else if (strcmp(name, "provides") == 0)
   533 		parse_property(ctx, atts, &ctx->provides);
   534 }
   535 
   536 static void
   537 end_element (void *data, const char *name)
   538 {
   539 	struct import_context *ctx = data;
   540 	struct razor_package *package;
   541 
   542 	if (strcmp(name, "package") == 0) {
   543 		package = (struct razor_package *) ctx->set->packages.data +
   544 			ctx->package;
   545 		package->requires =
   546 			add_to_property_pool(ctx->set, &ctx->requires.package);
   547 		package->provides =
   548 			add_to_property_pool(ctx->set, &ctx->provides.package);
   549 		free(ctx->requires.package.data);
   550 		free(ctx->provides.package.data);
   551 		ctx->package = 0;
   552 	}
   553 }
   554 
   555 static char *
   556 sha1_to_hex(const unsigned char *sha1)
   557 {
   558 	static int bufno;
   559 	static char hexbuffer[4][50];
   560 	static const char hex[] = "0123456789abcdef";
   561 	char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
   562 	int i;
   563 
   564 	for (i = 0; i < 20; i++) {
   565 		unsigned int val = *sha1++;
   566 		*buf++ = hex[val >> 4];
   567 		*buf++ = hex[val & 0xf];
   568 	}
   569 	*buf = '\0';
   570 
   571 	return buffer;
   572 }
   573 
   574 static void
   575 razor_set_prepare_import(struct razor_set *set, struct import_context *ctx)
   576 {
   577 	memset(ctx, 0, sizeof *ctx);
   578 	ctx->set = set;
   579 }
   580 
   581 static int
   582 razor_set_import(struct import_context *ctx, const char *filename)
   583 {
   584 	SHA_CTX sha1;
   585 	XML_Parser parser;
   586 	int fd;
   587 	void *p;
   588 	struct stat stat;
   589 	char buf[128];
   590 	unsigned char hash[20];
   591 
   592 	fd = open(filename, O_RDONLY);
   593 	if (fstat(fd, &stat) < 0)
   594 		return -1;
   595 	p = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   596 	if (p == MAP_FAILED)
   597 		return -1;
   598 
   599 	parser = XML_ParserCreate(NULL);
   600 	XML_SetUserData(parser, ctx);
   601 	XML_SetElementHandler(parser, start_element, end_element);
   602 	if (XML_Parse(parser, p, stat.st_size, 1) == XML_STATUS_ERROR) {
   603 		fprintf(stderr,
   604 			"%s at line %d, %s\n",
   605 			XML_ErrorString(XML_GetErrorCode(parser)),
   606 			XML_GetCurrentLineNumber(parser),
   607 			filename);
   608 		return 1;
   609 	}
   610 
   611 	XML_ParserFree(parser);
   612 
   613 	SHA1_Init(&sha1);
   614 	SHA1_Update(&sha1, p, stat.st_size);
   615 	SHA1_Final(hash, &sha1);
   616 
   617 	close(fd);
   618 
   619 	snprintf(buf, sizeof buf, "set/%s", sha1_to_hex(hash));
   620 	if (write_to_file(buf, p, stat.st_size) < 0)
   621 		return -1;
   622 	munmap(p, stat.st_size);
   623 
   624 	return 0;
   625 }
   626 
   627 static struct razor_set *qsort_set;
   628 
   629 static int
   630 compare_packages(const void *p1, const void *p2)
   631 {
   632 	const struct razor_package *pkg1 = p1, *pkg2 = p2;
   633 	char *pool = qsort_set->string_pool.data;
   634 
   635 	return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
   636 }
   637 
   638 static int
   639 compare_properties(const void *p1, const void *p2)
   640 {
   641 	const struct import_property *prop1 = p1, *prop2 = p2;
   642 	char *pool = qsort_set->string_pool.data;
   643 	int result;
   644 
   645 	result = strcmp(&pool[prop1->name], &pool[prop2->name]);
   646 	if (result == 0)
   647 		return strcmp(&pool[prop1->version], &pool[prop2->version]);
   648 	else
   649 		return result;
   650 }
   651 
   652 static unsigned long *
   653 uniqueify_properties(struct array *in, struct array *out)
   654 {
   655 	struct import_property *ip, *end;
   656 	struct razor_property *rp;
   657 	unsigned long *map;
   658 	int i, count;
   659 
   660 	count = in->size / sizeof(struct import_property);
   661 	qsort(in->data, count,
   662 	      sizeof(struct import_property), compare_properties);
   663 
   664 	rp = NULL;
   665 	end = in->data + in->size;
   666 	for (ip = in->data; ip < end; ip++) {
   667 		if (rp == NULL ||
   668 		    ip->name != rp->name || ip->version != rp->version) {
   669 			rp = array_add(out, sizeof *rp);
   670 			rp->name = ip->name;
   671 			rp->version = ip->version;
   672 		}
   673 		ip->unique_index = rp - (struct razor_property *) out->data;
   674 	}
   675 
   676 	map = malloc(count * sizeof (unsigned long));
   677 	ip = in->data;
   678 	for (i = 0; i < count; i++)
   679 		map[ip[i].index] = ip[i].unique_index;
   680 
   681 	return map;
   682 }
   683 
   684 static void
   685 sort_packages(struct import_context *ctx)
   686 {
   687 	struct razor_package *p, *end;
   688 	unsigned long *pool, *r;
   689 
   690 	pool = ctx->set->property_pool.data;
   691 	end = ctx->set->packages.data + ctx->set->packages.size;
   692 	for (p = ctx->set->packages.data; p < end; p++) {
   693 		for (r = &pool[p->requires]; *r; r++)
   694 			*r = ctx->requires_map[*r];
   695 		for (r = &pool[p->provides]; *r; r++)
   696 			*r = ctx->provides_map[*r];
   697 	}
   698 
   699 	qsort(ctx->set->packages.data,
   700 	      ctx->set->packages.size / sizeof(struct razor_package),
   701 	      sizeof(struct razor_package), compare_packages);
   702 }
   703 
   704 static void
   705 razor_set_finish_import(struct import_context *ctx)
   706 {
   707 	qsort_set = ctx->set;
   708 
   709 	ctx->requires_map =
   710 		uniqueify_properties(&ctx->requires.all, &ctx->set->requires);
   711 	ctx->provides_map =
   712 		uniqueify_properties(&ctx->provides.all, &ctx->set->provides);
   713 
   714 	sort_packages(ctx);
   715 
   716 	free(ctx->requires.all.data);
   717 	free(ctx->provides.all.data);
   718 	free(ctx->requires_map);
   719 	free(ctx->provides_map);
   720 
   721 	fprintf(stderr, "parsed %d requires, %d unique\n",
   722 		ctx->requires.all.size / sizeof(struct import_property),
   723 		ctx->set->requires.size / sizeof(struct razor_property));
   724 	fprintf(stderr, "parsed %d provides, %d unique\n",
   725 		ctx->provides.all.size / sizeof(struct import_property),
   726 		ctx->set->provides.size / sizeof(struct razor_property));
   727 }
   728 
   729 
   730 void
   731 razor_set_list(struct razor_set *set)
   732 {
   733 	struct razor_package *p, *end;
   734 	char *pool;
   735 
   736 	pool = set->string_pool.data;
   737 	end = set->packages.data + set->packages.size;
   738 	for (p = set->packages.data; p < end && p->name; p++)
   739 		printf("%s %s\n", &pool[p->name], &pool[p->version]);
   740 }
   741 
   742 struct razor_package *
   743 razor_set_get_package(struct razor_set *set, const char *package)
   744 {
   745 	unsigned long name;
   746 	struct razor_package *p, *end;
   747 
   748 	name = razor_set_lookup(set, package);
   749 	end = set->packages.data + set->packages.size;
   750 	for (p = set->packages.data; p < end && p->name; p++)
   751 		if (p->name == name)
   752 			return p;
   753 
   754 	return NULL;
   755 }
   756 
   757 static void
   758 razor_set_list_all_properties(struct razor_set *set, struct array *properties)
   759 {
   760 	struct razor_property *p, *end;
   761 	char *pool;
   762 
   763 	pool = set->string_pool.data;
   764 	end = properties->data + properties->size;
   765 	for (p = properties->data; p < end && p->name; p++)
   766 		printf("%s %s\n", &pool[p->name], &pool[p->version]);
   767 }
   768 
   769 void
   770 razor_set_list_requires(struct razor_set *set, const char *name)
   771 {
   772 	struct razor_property *p, *requires;
   773 	struct razor_package *package;
   774 	unsigned long *r;
   775 	char *pool;
   776 
   777 	if (name) {
   778 		package = razor_set_get_package(set, name);
   779 		r = (unsigned long *) set->property_pool.data +
   780 			package->requires;
   781 		requires = set->requires.data;
   782 		pool = set->string_pool.data;
   783 		while (*r) {
   784 			p = &requires[*r++];
   785 			printf("%s %s\n", &pool[p->name], &pool[p->version]);
   786 		}
   787 	} else
   788 		razor_set_list_all_properties(set, &set->requires);
   789 }
   790 
   791 void
   792 razor_set_list_provides(struct razor_set *set, const char *name)
   793 {
   794 	struct razor_property *p, *provides;
   795 	struct razor_package *package;
   796 	unsigned long *r;
   797 	char *pool;
   798 
   799 	if (name) {
   800 		package = razor_set_get_package(set, name);
   801 		r = (unsigned long *) set->property_pool.data +
   802 			package->provides;
   803 		provides = set->provides.data;
   804 		pool = set->string_pool.data;
   805 		while (*r) {
   806 			p = &provides[*r++];
   807 			printf("%s %s\n", &pool[p->name], &pool[p->version]);
   808 		}
   809 	} else 
   810 		razor_set_list_all_properties(set, &set->provides);
   811 }
   812 
   813 void
   814 razor_set_info(struct razor_set *set)
   815 {
   816 	unsigned int offset, size;
   817 	int i;
   818 
   819 	for (i = 0; i < set->header->sections[i].type; i++) {
   820 		offset = set->header->sections[i].offset;
   821 		size = set->header->sections[i + 1].offset - offset;
   822 
   823 		switch (set->header->sections[i].type) {
   824 		case RAZOR_BUCKETS:
   825 			printf("bucket section:\t\t%dkb\n", size / 1024);
   826 			break;
   827 		case RAZOR_STRINGS:
   828 			printf("string pool:\t\t%dkb\n", size / 1024);
   829 			break;
   830 		case RAZOR_PACKAGES:
   831 			printf("package section:\t%dkb\n", size / 1024);
   832 			break;
   833 		case RAZOR_REQUIRES:
   834 			printf("requires section:\t%dkb\n", size / 1024);
   835 			break;
   836 		case RAZOR_PROVIDES:
   837 			printf("provides section:\t%dkb\n", size / 1024);
   838 			break;
   839 		}
   840 	}
   841 }
   842 
   843 static int
   844 usage(void)
   845 {
   846 	printf("usage: razor [ import FILES | lookup <key> | "
   847 	       "list | list-requires | list-provides | info ]\n");
   848 	exit(1);
   849 }
   850 
   851 static const char repo_filename[] = "system.repo";
   852 
   853 int
   854 main(int argc, char *argv[])
   855 {
   856 	int i;
   857 	struct razor_set *set;
   858 	struct stat statbuf;
   859 	struct import_context ctx;
   860 
   861 	if (argc < 2) {
   862 		usage();
   863 	} else if (strcmp(argv[1], "import") == 0) {
   864 		if (stat("set", &statbuf) && mkdir("set", 0777)) {
   865 			fprintf(stderr, "could not create directory 'set'\n");
   866 			exit(-1);
   867 		}
   868 			
   869 		set = razor_set_create();
   870 
   871 		razor_set_prepare_import(set, &ctx);
   872 
   873 		for (i = 2; i < argc; i++) {
   874 			if (razor_set_import(&ctx, argv[i]) < 0) {
   875 				fprintf(stderr, "failed to import %s\n",
   876 					argv[i]);
   877 				exit(-1);
   878 			}
   879 		}
   880 
   881 		razor_set_finish_import(&ctx);
   882 
   883 		/* FIXME: We add a sentinel package here, but we
   884 		 * should probably just have a size field in the
   885 		 * header section. */
   886 		razor_set_add_package(set, 0, 0);
   887 		razor_set_add_requires(set, 0, 0);
   888 		razor_set_add_provides(set, 0, 0);
   889 
   890 		printf("bucket allocation: %d\n", set->buckets.alloc);
   891 		printf("pool size: %d\n", set->string_pool.size);
   892 		printf("pool allocation: %d\n", set->string_pool.alloc);
   893 		printf("packages: %d\n",
   894 		       set->packages.size / sizeof(struct razor_package));
   895 		printf("requires: %d\n",
   896 		       set->requires.size / sizeof(struct razor_property));
   897 		printf("provides: %d\n",
   898 		       set->provides.size / sizeof(struct razor_property));
   899 
   900 		razor_set_write(set, repo_filename);
   901 
   902 		razor_set_destroy(set);
   903 	} else if (strcmp(argv[1], "lookup") == 0) {
   904 		set = razor_set_open(repo_filename);
   905 		printf("%s is %lu\n", argv[2],
   906 		       razor_set_lookup(set, argv[2]));
   907 		razor_set_destroy(set);
   908 	} else if (strcmp(argv[1], "list") == 0) {
   909 		set = razor_set_open(repo_filename);
   910 		razor_set_list(set);
   911 		razor_set_destroy(set);
   912 	} else if (strcmp(argv[1], "list-requires") == 0) {
   913 		set = razor_set_open(repo_filename);
   914 		razor_set_list_requires(set, argv[2]);
   915 		razor_set_destroy(set);
   916 	} else if (strcmp(argv[1], "list-provides") == 0) {
   917 		set = razor_set_open(repo_filename);
   918 		razor_set_list_provides(set, argv[2]);
   919 		razor_set_destroy(set);
   920 	} else if (strcmp(argv[1], "info") == 0) {
   921 		set = razor_set_open(repo_filename);
   922 		razor_set_info(set);
   923 		razor_set_destroy(set);
   924 	} else {
   925 		usage();
   926 	}
   927 
   928 	return 0;
   929 }