krh@15: #define _GNU_SOURCE krh@15: krh@0: #include krh@19: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@15: #include krh@35: #include krh@0: krh@27: #include "razor.h" krh@6: krh@30: #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) krh@30: krh@30: struct array { krh@30: void *data; krh@30: int size, alloc; krh@30: }; krh@30: krh@30: struct razor_set_section { krh@30: unsigned int type; krh@30: unsigned int offset; krh@30: unsigned int size; krh@30: }; krh@30: krh@30: struct razor_set_header { krh@30: unsigned int magic; krh@30: unsigned int version; krh@30: struct razor_set_section sections[0]; krh@30: }; krh@30: krh@30: #define RAZOR_MAGIC 0x7a7a7a7a krh@30: #define RAZOR_VERSION 1 krh@30: krh@30: #define RAZOR_PACKAGES 0 krh@30: #define RAZOR_REQUIRES 1 krh@30: #define RAZOR_PROVIDES 2 krh@30: #define RAZOR_STRING_POOL 3 krh@39: #define RAZOR_PACKAGE_POOL 4 krh@39: #define RAZOR_REQUIRES_POOL 5 krh@39: #define RAZOR_PROVIDES_POOL 6 krh@30: krh@30: struct razor_package { krh@30: unsigned long name; krh@30: unsigned long version; krh@30: unsigned long requires; krh@30: unsigned long provides; krh@30: }; krh@30: krh@30: struct razor_property { krh@30: unsigned long name; krh@30: unsigned long version; krh@30: unsigned long packages; krh@30: }; krh@30: krh@30: struct razor_set { krh@30: struct array string_pool; krh@30: struct array packages; krh@39: struct array package_pool; krh@30: struct array requires; krh@30: struct array provides; krh@39: struct array requires_pool; krh@39: struct array provides_pool; krh@30: struct razor_set_header *header; krh@30: }; krh@30: krh@30: struct import_property_context { krh@30: struct array *all; krh@30: struct array package; krh@30: }; krh@30: krh@30: struct razor_importer { krh@30: struct razor_set *set; krh@32: struct array buckets; krh@30: struct import_property_context requires; krh@30: struct import_property_context provides; krh@30: struct razor_package *package; krh@30: unsigned long *requires_map; krh@30: unsigned long *provides_map; krh@30: }; krh@30: krh@13: static void krh@13: array_init(struct array *array) krh@13: { krh@13: memset(array, 0, sizeof *array); krh@13: } krh@13: krh@13: static void krh@13: array_release(struct array *array) krh@13: { krh@13: free(array->data); krh@13: } krh@13: krh@6: static void * krh@6: array_add(struct array *array, int size) krh@6: { krh@6: int alloc; krh@6: void *data, *p; krh@6: krh@6: if (array->alloc > 0) krh@6: alloc = array->alloc; krh@6: else krh@10: alloc = 16; krh@6: krh@6: while (alloc < array->size + size) krh@6: alloc *= 2; krh@6: krh@6: if (array->alloc < alloc) { krh@6: data = realloc(array->data, alloc); krh@6: if (data == NULL) krh@6: return 0; krh@6: array->data = data; krh@6: array->alloc = alloc; krh@6: } krh@6: krh@6: p = array->data + array->size; krh@6: array->size += size; krh@6: krh@6: return p; krh@6: } krh@6: krh@0: static int krh@0: write_to_fd(int fd, void *p, size_t size) krh@0: { krh@0: int rest, len; krh@0: krh@0: rest = size; krh@0: while (rest > 0) { krh@0: len = write(fd, p, rest); krh@0: if (len < 0) krh@0: return -1; krh@0: rest -= len; krh@0: } krh@0: krh@0: return 0; krh@0: } krh@0: krh@0: static void * krh@0: zalloc(size_t size) krh@0: { krh@0: void *p; krh@0: krh@0: p = malloc(size); krh@0: memset(p, 0, size); krh@0: krh@0: return p; krh@0: } krh@0: krh@19: struct razor_set_section razor_sections[] = { krh@19: { RAZOR_PACKAGES, offsetof(struct razor_set, packages) }, krh@19: { RAZOR_REQUIRES, offsetof(struct razor_set, requires) }, krh@19: { RAZOR_PROVIDES, offsetof(struct razor_set, provides) }, krh@19: { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) }, krh@39: { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) }, krh@39: { RAZOR_REQUIRES_POOL, offsetof(struct razor_set, requires_pool) }, krh@39: { RAZOR_PROVIDES_POOL, offsetof(struct razor_set, provides_pool) }, krh@19: }; krh@19: krh@4: struct razor_set * krh@4: razor_set_create(void) krh@0: { krh@18: return zalloc(sizeof(struct razor_set)); krh@0: } krh@0: krh@4: struct razor_set * krh@4: razor_set_open(const char *filename) krh@0: { krh@4: struct razor_set *set; krh@19: struct razor_set_section *s; krh@0: struct stat stat; krh@19: struct array *array; krh@19: int fd; krh@0: krh@4: set = zalloc(sizeof *set); krh@0: fd = open(filename, O_RDONLY); krh@0: if (fstat(fd, &stat) < 0) krh@0: return NULL; krh@4: set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); krh@4: if (set->header == MAP_FAILED) { krh@4: free(set); krh@0: return NULL; krh@0: } krh@0: krh@19: for (s = set->header->sections; ~s->type; s++) { krh@19: if (s->type >= ARRAY_SIZE(razor_sections)) krh@19: continue; krh@19: if (s->type != razor_sections[s->type].type) krh@19: continue; krh@19: array = (void *) set + razor_sections[s->type].offset; krh@19: array->data = (void *) set->header + s->offset; krh@19: array->size = s->size; krh@19: array->alloc = s->size; krh@0: } krh@0: close(fd); krh@0: krh@4: return set; krh@0: } krh@0: krh@0: void krh@4: razor_set_destroy(struct razor_set *set) krh@0: { krh@0: unsigned int size; krh@19: struct array *a; krh@0: int i; krh@0: krh@4: if (set->header) { krh@4: for (i = 0; set->header->sections[i].type; i++) krh@0: ; krh@4: size = set->header->sections[i].type; krh@4: munmap(set->header, size); krh@0: } else { krh@19: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@19: a = (void *) set + razor_sections[i].offset; krh@19: free(a->data); krh@19: } krh@0: } krh@0: krh@4: free(set); krh@0: } krh@0: krh@0: static int krh@4: razor_set_write(struct razor_set *set, const char *filename) krh@0: { krh@0: char data[4096]; krh@4: struct razor_set_header *header = (struct razor_set_header *) data; krh@19: struct array *a; krh@17: unsigned long offset; krh@17: int i, fd; krh@0: krh@0: memset(data, 0, sizeof data); krh@4: header->magic = RAZOR_MAGIC; krh@4: header->version = RAZOR_VERSION; krh@17: offset = sizeof data; krh@0: krh@19: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@19: if (razor_sections[i].type != i) krh@19: continue; krh@19: a = (void *) set + razor_sections[i].offset; krh@19: header->sections[i].type = i; krh@17: header->sections[i].offset = offset; krh@19: header->sections[i].size = a->size; krh@19: offset += (a->size + 4095) & ~4095; krh@17: } krh@0: krh@19: header->sections[i].type = ~0; krh@17: header->sections[i].offset = 0; krh@17: header->sections[i].size = 0; krh@10: krh@0: fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); krh@0: if (fd < 0) krh@0: return -1; krh@0: krh@0: write_to_fd(fd, data, sizeof data); krh@19: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@19: if (razor_sections[i].type != i) krh@19: continue; krh@19: a = (void *) set + razor_sections[i].offset; krh@19: write_to_fd(fd, a->data, (a->size + 4095) & ~4095); krh@19: } krh@17: krh@17: close(fd); krh@0: krh@0: return 0; krh@0: } krh@0: krh@0: static unsigned int krh@0: hash_string(const char *key) krh@0: { krh@0: const char *p; krh@0: unsigned int hash = 0; krh@0: krh@0: for (p = key; *p; p++) krh@9: hash = (hash * 617) ^ *p; krh@0: krh@0: return hash; krh@0: } krh@0: krh@32: static unsigned long krh@32: razor_importer_lookup(struct razor_importer *importer, const char *key) krh@0: { krh@6: unsigned int mask, start, i; krh@6: unsigned long *b; krh@6: char *pool; krh@0: krh@32: pool = importer->set->string_pool.data; krh@32: mask = importer->buckets.alloc - 1; krh@6: start = hash_string(key) * sizeof(unsigned long); krh@0: krh@32: for (i = 0; i < importer->buckets.alloc; i += sizeof *b) { krh@32: b = importer->buckets.data + ((start + i) & mask); krh@6: krh@6: if (*b == 0) krh@0: return 0; krh@0: krh@6: if (strcmp(key, &pool[*b]) == 0) krh@6: return *b; krh@6: } krh@0: krh@0: return 0; krh@0: } krh@0: krh@0: static unsigned long krh@4: add_to_string_pool(struct razor_set *set, const char *key) krh@0: { krh@6: int len; krh@6: char *p; krh@0: krh@0: len = strlen(key) + 1; krh@6: p = array_add(&set->string_pool, len); krh@6: memcpy(p, key, len); krh@0: krh@6: return p - (char *) set->string_pool.data; krh@0: } krh@0: krh@10: static unsigned long krh@39: add_to_property_pool(struct array *pool, struct array *properties) krh@10: { krh@10: unsigned long *p; krh@10: krh@10: p = array_add(properties, sizeof *p); krh@18: *p = ~0ul; krh@39: p = array_add(pool, properties->size); krh@10: memcpy(p, properties->data, properties->size); krh@10: krh@39: return p - (unsigned long *) pool->data; krh@10: } krh@10: krh@0: static void krh@32: do_insert(struct razor_importer *importer, unsigned long value) krh@0: { krh@6: unsigned int mask, start, i; krh@6: unsigned long *b; krh@0: const char *key; krh@0: krh@32: key = (char *) importer->set->string_pool.data + value; krh@32: mask = importer->buckets.alloc - 1; krh@6: start = hash_string(key) * sizeof(unsigned long); krh@6: krh@32: for (i = 0; i < importer->buckets.alloc; i += sizeof *b) { krh@32: b = importer->buckets.data + ((start + i) & mask); krh@6: if (*b == 0) { krh@6: *b = value; krh@0: break; krh@0: } krh@6: } krh@0: } krh@0: krh@32: static unsigned long krh@32: razor_importer_insert(struct razor_importer *importer, const char *key) krh@0: { krh@6: unsigned long value, *buckets, *b, *end; krh@6: int alloc; krh@0: krh@32: alloc = importer->buckets.alloc; krh@32: array_add(&importer->buckets, 4 * sizeof *buckets); krh@32: if (alloc != importer->buckets.alloc) { krh@32: end = importer->buckets.data + alloc; krh@32: memset(end, 0, importer->buckets.alloc - alloc); krh@32: for (b = importer->buckets.data; b < end; b++) { krh@6: value = *b; krh@6: if (value != 0) { krh@6: *b = 0; krh@32: do_insert(importer, value); krh@6: } krh@0: } krh@0: } krh@0: krh@32: value = add_to_string_pool(importer->set, key); krh@32: do_insert (importer, value); krh@0: krh@0: return value; krh@0: } krh@0: krh@30: static unsigned long krh@32: razor_importer_tokenize(struct razor_importer *importer, const char *string) krh@0: { krh@0: unsigned long token; krh@0: krh@13: if (string == NULL) krh@32: return razor_importer_tokenize(importer, ""); krh@13: krh@32: token = razor_importer_lookup(importer, string); krh@0: if (token != 0) krh@0: return token; krh@0: krh@32: return razor_importer_insert(importer, string); krh@0: } krh@0: krh@27: void krh@30: razor_importer_begin_package(struct razor_importer *importer, krh@30: const char *name, const char *version) krh@13: { krh@25: struct razor_package *p; krh@13: krh@30: p = array_add(&importer->set->packages, sizeof *p); krh@32: p->name = razor_importer_tokenize(importer, name); krh@32: p->version = razor_importer_tokenize(importer, version); krh@13: krh@30: importer->package = p; krh@30: array_init(&importer->requires.package); krh@30: array_init(&importer->provides.package); krh@13: } krh@13: krh@13: void krh@30: razor_importer_finish_package(struct razor_importer *importer) krh@13: { krh@25: struct razor_package *p; krh@13: krh@30: p = importer->package; krh@39: p->requires = add_to_property_pool(&importer->set->requires_pool, krh@30: &importer->requires.package); krh@39: p->provides = add_to_property_pool(&importer->set->provides_pool, krh@30: &importer->provides.package); krh@13: krh@30: array_release(&importer->requires.package); krh@30: array_release(&importer->provides.package); krh@13: } krh@13: krh@30: static void krh@30: razor_importer_add_property(struct razor_importer *importer, krh@13: struct import_property_context *pctx, krh@13: const char *name, const char *version) krh@13: { krh@25: struct razor_property *p; krh@13: unsigned long *r; krh@13: krh@25: p = array_add(pctx->all, sizeof *p); krh@32: p->name = razor_importer_tokenize(importer, name); krh@32: p->version = razor_importer_tokenize(importer, version); krh@30: p->packages = importer->package - krh@30: (struct razor_package *) importer->set->packages.data; krh@13: krh@13: r = array_add(&pctx->package, sizeof *r); krh@25: *r = p - (struct razor_property *) pctx->all->data; krh@13: } krh@13: krh@27: void krh@30: razor_importer_add_requires(struct razor_importer *importer, krh@30: const char *name, const char *version) krh@9: { krh@30: razor_importer_add_property(importer, krh@30: &importer->requires, name, version); krh@30: } krh@30: krh@30: void krh@30: razor_importer_add_provides(struct razor_importer *importer, krh@30: const char *name, const char *version) krh@30: { krh@30: razor_importer_add_property(importer, krh@30: &importer->provides, name, version); krh@30: } krh@30: krh@30: struct razor_importer * krh@30: razor_importer_new(void) krh@30: { krh@30: struct razor_importer *importer; krh@30: krh@30: importer = zalloc(sizeof *importer); krh@30: importer->set = razor_set_create(); krh@30: importer->requires.all = &importer->set->requires; krh@30: importer->provides.all = &importer->set->provides; krh@30: krh@30: return importer; krh@9: } krh@9: krh@22: typedef int (*compare_with_data_func_t)(const void *p1, krh@22: const void *p, krh@22: void *data); krh@22: krh@25: struct qsort_context { krh@25: size_t size; krh@25: compare_with_data_func_t compare; krh@25: void *data; krh@25: }; krh@25: krh@22: static void krh@22: qsort_swap(void *p1, void *p2, size_t size) krh@22: { krh@22: char buffer[size]; krh@22: krh@22: memcpy(buffer, p1, size); krh@22: memcpy(p1, p2, size); krh@22: memcpy(p2, buffer, size); krh@22: } krh@22: krh@25: static void krh@25: __qsort_with_data(void *base, size_t nelem, unsigned long *map, krh@25: struct qsort_context *ctx) krh@22: { krh@22: void *p, *start, *end, *pivot; krh@25: unsigned long *mp, *mstart, *mend, tmp; krh@22: int left, right, result; krh@25: size_t size = ctx->size; krh@22: krh@22: p = base; krh@22: start = base; krh@22: end = base + nelem * size; krh@25: mp = map; krh@25: mstart = map; krh@25: mend = map + nelem; krh@22: pivot = base + (random() % nelem) * size; krh@25: krh@22: while (p < end) { krh@25: result = ctx->compare(p, pivot, ctx->data); krh@22: if (result < 0) { krh@22: qsort_swap(p, start, size); krh@25: tmp = *mp; krh@25: *mp = *mstart; krh@25: *mstart = tmp; krh@22: if (start == pivot) krh@22: pivot = p; krh@22: start += size; krh@25: mstart++; krh@22: p += size; krh@29: mp++; krh@22: } else if (result == 0) { krh@22: p += size; krh@25: mp++; krh@22: } else { krh@22: end -= size; krh@25: mend--; krh@22: qsort_swap(p, end, size); krh@25: tmp = *mp; krh@29: *mp = *mend; krh@29: *mend = tmp; krh@22: if (end == pivot) krh@22: pivot = p; krh@22: } krh@22: } krh@22: krh@22: left = (start - base) / size; krh@22: right = (base + nelem * size - end) / size; krh@22: if (left > 1) krh@25: __qsort_with_data(base, left, map, ctx); krh@22: if (right > 1) krh@25: __qsort_with_data(end, right, mend, ctx); krh@25: } krh@25: krh@25: unsigned long * krh@25: qsort_with_data(void *base, size_t nelem, size_t size, krh@25: compare_with_data_func_t compare, void *data) krh@25: { krh@25: struct qsort_context ctx; krh@25: unsigned long *map; krh@25: int i; krh@25: krh@25: ctx.size = size; krh@25: ctx.compare = compare; krh@25: ctx.data = data; krh@25: krh@25: map = malloc(nelem * sizeof (unsigned long)); krh@25: for (i = 0; i < nelem; i++) krh@25: map[i] = i; krh@25: krh@25: __qsort_with_data(base, nelem, map, &ctx); krh@25: krh@25: return map; krh@22: } krh@9: krh@9: static int krh@35: versioncmp(const char *s1, const char *s2) krh@35: { krh@35: const char *p1, *p2; krh@35: long n1, n2; krh@35: int res; krh@35: krh@35: n1 = strtol(s1, (char **) &p1, 0); krh@35: n2 = strtol(s2, (char **) &p2, 0); krh@35: krh@35: /* Epoch; if one but not the other has an epoch set, default krh@35: * the epoch-less version to 0. */ krh@35: res = (*p1 == ':') - (*p2 == ':'); krh@35: if (res < 0) { krh@35: n1 = 0; krh@35: p1 = s1; krh@35: p2++; krh@35: } else if (res > 0) { krh@35: p1++; krh@35: n2 = 0; krh@35: p2 = s2; krh@35: } krh@35: krh@35: if (n1 != n2) krh@35: return n1 - n2; krh@35: while (*p1 && *p2) { krh@35: if (*p1 != *p2) krh@35: return *p1 - *p2; krh@35: p1++; krh@35: p2++; krh@35: if (isdigit(*p1) && isdigit(*p2)) krh@35: return versioncmp(p1, p2); krh@35: } krh@35: krh@35: return *p1 - *p2; krh@35: } krh@35: krh@35: krh@35: static int krh@22: compare_packages(const void *p1, const void *p2, void *data) krh@9: { krh@25: const struct razor_package *pkg1 = p1, *pkg2 = p2; krh@22: struct razor_set *set = data; krh@22: char *pool = set->string_pool.data; krh@9: krh@23: if (pkg1->name == pkg2->name) krh@35: return versioncmp(&pool[pkg1->version], &pool[pkg2->version]); krh@23: else krh@23: return strcmp(&pool[pkg1->name], &pool[pkg2->name]); krh@9: } krh@9: krh@9: static int krh@22: compare_properties(const void *p1, const void *p2, void *data) krh@9: { krh@25: const struct razor_property *prop1 = p1, *prop2 = p2; krh@22: struct razor_set *set = data; krh@22: char *pool = set->string_pool.data; krh@9: krh@23: if (prop1->name == prop2->name) krh@35: return versioncmp(&pool[prop1->version], &pool[prop2->version]); krh@12: else krh@23: return strcmp(&pool[prop1->name], &pool[prop2->name]); krh@9: } krh@9: krh@10: static unsigned long * krh@25: uniqueify_properties(struct razor_set *set, struct array *properties) krh@9: { krh@25: struct razor_property *rp, *up, *rp_end; krh@18: struct array *pkgs, *p; krh@25: unsigned long *map, *rmap, *r; krh@18: int i, count, unique; krh@9: krh@25: count = properties->size / sizeof(struct razor_property); krh@25: map = qsort_with_data(properties->data, krh@25: count, krh@25: sizeof(struct razor_property), krh@25: compare_properties, krh@25: set); krh@9: krh@25: rp_end = properties->data + properties->size; krh@25: rmap = malloc(count * sizeof *map); krh@25: pkgs = zalloc(count * sizeof *pkgs); krh@25: for (rp = properties->data, up = rp, i = 0; rp < rp_end; rp++, i++) { krh@25: if (rp->name != up->name || rp->version != up->version) { krh@25: up++; krh@25: up->name = rp->name; krh@25: up->version = rp->version; krh@10: } krh@25: krh@25: unique = up - (struct razor_property *) properties->data; krh@25: rmap[map[i]] = unique; krh@25: r = array_add(&pkgs[unique], sizeof *r); krh@25: *r = rp->packages; krh@10: } krh@25: free(map); krh@9: krh@25: up++; krh@25: properties->size = (void *) up - properties->data; krh@25: rp_end = up; krh@25: for (rp = properties->data, p = pkgs; rp < rp_end; rp++, p++) { krh@39: rp->packages = add_to_property_pool(&set->package_pool, p); krh@25: array_release(p); krh@18: } krh@18: krh@18: free(pkgs); krh@18: krh@25: return rmap; krh@10: } krh@10: krh@10: static void krh@39: remap_links(struct array *links, unsigned long *map) krh@10: { krh@39: unsigned long *p, *end; krh@10: krh@39: end = links->data + links->size; krh@39: for (p = links->data; p < end; p++) krh@39: if (*p != ~0) krh@39: *p = map[*p]; krh@9: } krh@9: krh@27: struct razor_set * krh@30: razor_importer_finish(struct razor_importer *importer) krh@9: { krh@30: struct razor_set *set; krh@39: unsigned long *map, *rmap; krh@39: int i, count; krh@18: krh@39: map = uniqueify_properties(importer->set, &importer->set->requires); krh@39: remap_links(&importer->set->requires_pool, map); krh@39: free(map); krh@39: krh@39: map = uniqueify_properties(importer->set, &importer->set->provides); krh@39: remap_links(&importer->set->provides_pool, map); krh@39: free(map); krh@25: krh@30: count = importer->set->packages.size / sizeof(struct razor_package); krh@30: map = qsort_with_data(importer->set->packages.data, krh@25: count, krh@25: sizeof(struct razor_package), krh@25: compare_packages, krh@30: importer->set); krh@39: krh@39: rmap = malloc(count * sizeof *rmap); krh@39: for (i = 0; i < count; i++) krh@39: rmap[map[i]] = i; krh@39: krh@39: remap_links(&importer->set->package_pool, rmap); krh@25: free(map); krh@39: free(rmap); krh@13: krh@30: set = importer->set; krh@32: array_release(&importer->buckets); krh@30: free(importer); krh@30: krh@30: return set; krh@9: } krh@9: krh@0: void krh@4: razor_set_list(struct razor_set *set) krh@3: { krh@6: struct razor_package *p, *end; krh@6: char *pool; krh@3: krh@6: pool = set->string_pool.data; krh@6: end = set->packages.data + set->packages.size; krh@14: for (p = set->packages.data; p < end; p++) krh@6: printf("%s %s\n", &pool[p->name], &pool[p->version]); krh@3: } krh@3: krh@16: struct razor_set *bsearch_set; krh@16: krh@16: static int krh@16: compare_package_name(const void *key, const void *data) krh@16: { krh@16: const struct razor_package *p = data; krh@16: char *pool; krh@16: krh@16: pool = bsearch_set->string_pool.data; krh@16: krh@16: return strcmp(key, &pool[p->name]); krh@16: } krh@16: krh@10: struct razor_package * krh@10: razor_set_get_package(struct razor_set *set, const char *package) krh@10: { krh@16: bsearch_set = set; krh@16: return bsearch(package, set->packages.data, krh@16: set->packages.size / sizeof(struct razor_package), krh@16: sizeof(struct razor_package), compare_package_name); krh@10: } krh@10: krh@18: static int krh@18: compare_property_name(const void *key, const void *data) krh@18: { krh@18: const struct razor_property *p = data; krh@18: char *pool; krh@18: krh@18: pool = bsearch_set->string_pool.data; krh@18: krh@18: return strcmp(key, &pool[p->name]); krh@18: } krh@18: krh@18: struct razor_property * krh@18: razor_set_get_property(struct razor_set *set, krh@18: struct array *properties, krh@18: const char *property) krh@18: { krh@18: struct razor_property *p, *start; krh@18: krh@18: bsearch_set = set; krh@18: p = bsearch(property, properties->data, krh@18: properties->size / sizeof(struct razor_property), krh@18: sizeof(struct razor_property), compare_property_name); krh@18: krh@18: start = properties->data; krh@18: while (p > start && (p - 1)->name == p->name) krh@18: p--; krh@18: krh@18: return p; krh@18: } krh@18: krh@10: static void krh@10: razor_set_list_all_properties(struct razor_set *set, struct array *properties) krh@8: { krh@8: struct razor_property *p, *end; krh@8: char *pool; krh@8: krh@8: pool = set->string_pool.data; krh@10: end = properties->data + properties->size; krh@14: for (p = properties->data; p < end; p++) krh@8: printf("%s %s\n", &pool[p->name], &pool[p->version]); krh@8: } krh@8: krh@8: void krh@10: razor_set_list_requires(struct razor_set *set, const char *name) krh@7: { krh@10: struct razor_property *p, *requires; krh@10: struct razor_package *package; krh@10: unsigned long *r; krh@7: char *pool; krh@7: krh@10: if (name) { krh@10: package = razor_set_get_package(set, name); krh@39: r = (unsigned long *) set->requires_pool.data + krh@10: package->requires; krh@10: requires = set->requires.data; krh@10: pool = set->string_pool.data; krh@18: while (~*r) { krh@10: p = &requires[*r++]; krh@10: printf("%s %s\n", &pool[p->name], &pool[p->version]); krh@10: } krh@10: } else krh@10: razor_set_list_all_properties(set, &set->requires); krh@10: } krh@10: krh@10: void krh@10: razor_set_list_provides(struct razor_set *set, const char *name) krh@10: { krh@10: struct razor_property *p, *provides; krh@10: struct razor_package *package; krh@10: unsigned long *r; krh@10: char *pool; krh@10: krh@10: if (name) { krh@10: package = razor_set_get_package(set, name); krh@39: r = (unsigned long *) set->provides_pool.data + krh@10: package->provides; krh@10: provides = set->provides.data; krh@10: pool = set->string_pool.data; krh@18: while (~*r) { krh@10: p = &provides[*r++]; krh@10: printf("%s %s\n", &pool[p->name], &pool[p->version]); krh@10: } krh@10: } else krh@10: razor_set_list_all_properties(set, &set->provides); krh@7: } krh@7: krh@7: void krh@18: razor_set_list_property_packages(struct razor_set *set, krh@18: struct array *properties, krh@20: const char *name, krh@20: const char *version) krh@18: { krh@18: struct razor_property *property, *end; krh@18: struct razor_package *p, *packages; krh@18: unsigned long *r; krh@18: char *pool; krh@18: krh@18: if (name == NULL) krh@18: return; krh@18: krh@18: property = razor_set_get_property(set, properties, name); krh@18: packages = set->packages.data; krh@18: pool = set->string_pool.data; krh@18: end = properties->data + properties->size; krh@18: while (property < end && strcmp(name, &pool[property->name]) == 0) { krh@35: if (version && versioncmp(version, &pool[property->version]) != 0) krh@20: goto next; krh@18: r = (unsigned long *) krh@39: set->package_pool.data + property->packages; krh@18: while (~*r) { krh@18: p = &packages[*r++]; krh@18: printf("%s %s\n", krh@18: &pool[p->name], &pool[p->version]); krh@18: } krh@20: next: krh@18: property++; krh@18: } krh@18: } krh@18: krh@18: void krh@21: razor_set_validate(struct razor_set *set, struct array *unsatisfied) krh@21: { krh@21: struct razor_property *r, *p, *rend, *pend; krh@21: unsigned long *u; krh@21: char *pool; krh@21: krh@21: p = set->provides.data; krh@21: rend = set->requires.data + set->requires.size; krh@21: pend = set->provides.data + set->provides.size; krh@21: pool = set->string_pool.data; krh@21: krh@35: for (r = set->requires.data; r < rend; r++) { krh@21: while (p < pend && strcmp(&pool[r->name], &pool[p->name]) > 0) krh@21: p++; krh@37: krh@35: /* If there is more than one version of a provides, krh@35: * seek to the end for the highest version. */ krh@35: while (p + 1 < pend && p->name == (p + 1)->name) krh@35: p++; krh@37: krh@37: /* FIXME: We need to track property flags (<, <=, = krh@37: * etc) to properly determine if a requires is krh@37: * satisfied. The current code doesn't track that the krh@37: * requires a = 1 isn't satisfied by a = 2 provides. */ krh@37: krh@35: if (p == pend || strcmp(&pool[r->name], &pool[p->name]) != 0 || krh@35: versioncmp(&pool[r->version], &pool[p->version]) > 0) { krh@35: /* FIXME: We ignore file requires for now. */ krh@35: if (pool[r->name] == '/') krh@35: continue; krh@21: u = array_add(unsatisfied, sizeof *u); krh@21: *u = r - (struct razor_property *) set->requires.data; krh@21: } krh@21: } krh@21: } krh@21: krh@21: void krh@21: razor_set_list_unsatisfied(struct razor_set *set) krh@21: { krh@21: struct array unsatisfied; krh@21: struct razor_property *requires, *r; krh@21: unsigned long *u, *end; krh@21: char *pool; krh@21: krh@21: array_init(&unsatisfied); krh@21: razor_set_validate(set, &unsatisfied); krh@21: krh@21: end = unsatisfied.data + unsatisfied.size; krh@21: requires = set->requires.data; krh@21: pool = set->string_pool.data; krh@21: krh@21: for (u = unsatisfied.data; u < end; u++) { krh@21: r = requires + *u; krh@21: printf("%s %s not satisfied\n", krh@21: &pool[r->name], &pool[r->version]); krh@21: } krh@21: krh@21: array_release(&unsatisfied); krh@21: } krh@21: krh@33: static void krh@33: add_package(struct razor_importer *importer, krh@33: struct razor_package *package, struct razor_set *set) krh@33: { krh@33: char *pool; krh@33: unsigned long *r; krh@33: struct razor_property *p, *properties; krh@33: krh@33: pool = set->string_pool.data; krh@33: razor_importer_begin_package(importer, krh@33: &pool[package->name], krh@33: &pool[package->version]); krh@33: krh@39: r = (unsigned long *) set->requires_pool.data + package->requires; krh@33: properties = set->requires.data; krh@33: while (~*r) { krh@33: p = &properties[*r++]; krh@33: razor_importer_add_requires(importer, krh@33: &pool[p->name], &pool[p->version]); krh@33: } krh@33: krh@39: r = (unsigned long *) set->provides_pool.data + package->provides; krh@33: properties = set->provides.data; krh@33: while (~*r) { krh@33: p = &properties[*r++]; krh@33: razor_importer_add_provides(importer, krh@33: &pool[p->name], &pool[p->version]); krh@33: } krh@33: krh@33: razor_importer_finish_package(importer); krh@33: } krh@33: krh@33: /* Add packages from 'upstream' to 'set'. The packages to add are krh@33: * specified by the 'packages' array, which is a sorted list of krh@33: * package indexes. Returns a newly allocated package set. Does not krh@33: * enforce validity of the resulting package set. */ krh@33: krh@36: /* FIXME: We can do this in a linear sweep instead of using an krh@36: * importer and the sorting that incurs: build the new package list krh@36: * sorted, build up a map from package index in old set to package krh@36: * index in new set for both sets. ~0 means 'not in new set'. build krh@36: * new string pool as we go, probably just re-use that part of the krh@36: * importer. as we build the package list, fill out a bitvector of krh@36: * the properties that are referenced by the pacakges in the new krh@36: * set. then do a parallel loop through the properties and emit them krh@36: * to the new set and build a map from indices in the old set to krh@36: * indices in the new set. then loop through the packages again and krh@36: * emit the property lists. */ krh@36: krh@33: struct razor_set * krh@33: razor_set_add(struct razor_set *set, struct razor_set *upstream, krh@33: struct array *packages) krh@33: { krh@33: struct razor_importer *importer; krh@33: struct razor_package *upstream_packages, *p, *s, *send; krh@33: char *spool, *upool; krh@33: unsigned long *u, *uend; krh@33: int cmp; krh@33: krh@33: importer = razor_importer_new(); krh@33: upstream_packages = upstream->packages.data; krh@33: u = packages->data; krh@33: uend = packages->data + packages->size; krh@33: upool = upstream->string_pool.data; krh@33: s = set->packages.data; krh@33: send = set->packages.data + set->packages.size; krh@33: spool = set->string_pool.data; krh@33: krh@33: while (s < send) { krh@33: p = upstream_packages + *u; krh@37: if (u < uend) krh@37: cmp = strcmp(&spool[s->name], &upool[p->name]); krh@37: if (u >= uend || cmp < 0) { krh@33: add_package(importer, s, set); krh@33: s++; krh@33: } else if (cmp == 0) { krh@33: add_package(importer, p, upstream); krh@33: s++; krh@33: u++; krh@33: } else { krh@33: add_package(importer, p, upstream); krh@33: u++; krh@33: } krh@33: } krh@33: krh@33: return razor_importer_finish(importer); krh@33: } krh@33: krh@37: void krh@37: razor_set_satisfy(struct razor_set *set, struct array *unsatisfied, krh@37: struct razor_set *upstream, struct array *list) krh@37: { krh@37: struct razor_property *requires, *r; krh@37: struct razor_property *p, *pend; krh@39: unsigned long *u, *end, *pkg, *package_pool; krh@37: char *pool, *upool; krh@37: krh@37: end = unsatisfied->data + unsatisfied->size; krh@37: requires = set->requires.data; krh@37: pool = set->string_pool.data; krh@37: krh@37: p = upstream->provides.data; krh@37: pend = upstream->provides.data + upstream->provides.size; krh@37: upool = upstream->string_pool.data; krh@39: package_pool = upstream->package_pool.data; krh@37: krh@37: for (u = unsatisfied->data; u < end; u++) { krh@37: r = requires + *u; krh@37: krh@37: while (p < pend && strcmp(&pool[r->name], &upool[p->name]) > 0) krh@37: p++; krh@37: /* If there is more than one version of a provides, krh@37: * seek to the end for the highest version. */ krh@37: while (p + 1 < pend && p->name == (p + 1)->name) krh@37: p++; krh@37: krh@37: if (p == pend || krh@37: strcmp(&pool[r->name], &upool[p->name]) != 0 || krh@37: versioncmp(&pool[r->version], &upool[p->version]) > 0) { krh@37: /* Do we need to track unsatisfiable requires krh@37: * as we go, or should we just do a krh@37: * razor_set_validate() at the end? */ krh@37: } else { krh@37: pkg = array_add(list, sizeof *pkg); krh@37: /* We just pull in the first package that provides */ krh@39: *pkg = package_pool[p->packages]; krh@37: } krh@37: } krh@37: } krh@37: krh@38: static void krh@38: find_packages(struct razor_set *set, krh@38: int count, const char **packages, struct array *list) krh@38: { krh@38: struct razor_package *p; krh@38: unsigned long *r; krh@38: int i; krh@38: krh@38: /* FIXME: Sort the packages. */ krh@38: for (i = 0; i < count; i++) { krh@38: p = razor_set_get_package(set, packages[i]); krh@38: r = array_add(list, sizeof *r); krh@38: *r = p - (struct razor_package *) set->packages.data; krh@38: } krh@38: } krh@38: krh@38: static void krh@38: find_all_packages(struct razor_set *set, krh@38: struct razor_set *upstream, struct array *list) krh@38: { krh@38: struct razor_package *p, *u, *pend, *uend; krh@38: unsigned long *r; krh@38: char *pool, *upool; krh@38: krh@38: pend = set->packages.data + set->packages.size; krh@38: pool = set->string_pool.data; krh@38: u = upstream->packages.data; krh@38: uend = upstream->packages.data + upstream->packages.size; krh@38: upool = upstream->string_pool.data; krh@38: krh@38: for (p = set->packages.data; p < pend; p++) { krh@38: while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0) krh@38: u++; krh@38: if (strcmp(&pool[p->name], &upool[u->name]) == 0) { krh@38: r = array_add(list, sizeof *r); krh@38: *r = u - (struct razor_package *) upstream->packages.data; krh@38: } krh@38: } krh@38: } krh@38: krh@33: struct razor_set * krh@33: razor_set_update(struct razor_set *set, struct razor_set *upstream, krh@33: int count, const char **packages) krh@33: { krh@37: struct razor_set *new; krh@37: struct razor_package *p, *upackages; krh@37: struct array list, unsatisfied; krh@37: char *pool; krh@38: unsigned long *u, *end; krh@38: int total = 0; krh@33: krh@33: array_init(&list); krh@38: if (count > 0) krh@38: find_packages(upstream, count, packages, &list); krh@38: else krh@38: find_all_packages(set, upstream, &list); krh@33: krh@37: end = list.data + list.size; krh@37: upackages = upstream->packages.data; krh@37: pool = upstream->string_pool.data; krh@37: for (u = list.data; u < end; u++) { krh@37: p = upackages + *u; krh@37: printf("package %s-%s set to be updated\n", krh@37: &pool[p->name], &pool[p->version]); krh@37: } krh@38: total += list.size / sizeof *u; krh@37: krh@37: while (list.size > 0) { krh@37: printf(" -- satisfying new requires\n"); krh@37: krh@37: new = razor_set_add(set, upstream, &list); krh@37: array_release(&list); krh@37: razor_set_destroy(set); krh@37: set = new; krh@37: krh@37: array_init(&unsatisfied); krh@37: razor_set_validate(new, &unsatisfied); krh@37: array_init(&list); krh@37: razor_set_satisfy(new, &unsatisfied, upstream, &list); krh@37: array_release(&unsatisfied); krh@37: krh@37: end = list.data + list.size; krh@37: upackages = upstream->packages.data; krh@37: pool = upstream->string_pool.data; krh@37: for (u = list.data; u < end; u++) { krh@37: p = upackages + *u; krh@37: printf("package %s-%s set to be updated\n", krh@37: &pool[p->name], &pool[p->version]); krh@37: } krh@38: total += list.size / sizeof *u; krh@37: } krh@37: krh@37: array_release(&list); krh@37: krh@38: printf("total of %d packages set to be updated\n", total); krh@38: krh@37: return set; krh@33: } krh@33: krh@21: void krh@4: razor_set_info(struct razor_set *set) krh@3: { krh@3: unsigned int offset, size; krh@3: int i; krh@3: krh@4: for (i = 0; i < set->header->sections[i].type; i++) { krh@4: offset = set->header->sections[i].offset; krh@18: size = set->header->sections[i].size; krh@3: krh@4: switch (set->header->sections[i].type) { krh@4: case RAZOR_PACKAGES: krh@3: printf("package section:\t%dkb\n", size / 1024); krh@3: break; krh@8: case RAZOR_REQUIRES: krh@8: printf("requires section:\t%dkb\n", size / 1024); krh@8: break; krh@7: case RAZOR_PROVIDES: krh@7: printf("provides section:\t%dkb\n", size / 1024); krh@7: break; krh@19: case RAZOR_STRING_POOL: krh@19: printf("string pool:\t\t%dkb\n", size / 1024); krh@19: break; krh@3: } krh@3: } krh@0: } krh@0: krh@0: static int krh@0: usage(void) krh@0: { krh@7: printf("usage: razor [ import FILES | lookup | " krh@15: "list | list-requires | list-provides | eat-yum | info ]\n"); krh@0: exit(1); krh@0: } krh@0: krh@15: static const char *repo_filename = "system.repo"; krh@15: static const char rawhide_repo_filename[] = "rawhide.repo"; krh@0: krh@0: int krh@27: main(int argc, const char *argv[]) krh@0: { krh@37: struct razor_set *set, *upstream; krh@0: struct stat statbuf; krh@15: char *repo; krh@15: krh@15: repo = getenv("RAZOR_REPO"); krh@15: if (repo != NULL) krh@15: repo_filename = repo; krh@0: krh@3: if (argc < 2) { krh@0: usage(); krh@0: } else if (strcmp(argv[1], "import") == 0) { krh@0: if (stat("set", &statbuf) && mkdir("set", 0777)) { krh@0: fprintf(stderr, "could not create directory 'set'\n"); krh@0: exit(-1); krh@0: } krh@0: krh@27: set = razor_import_rzr_files(argc - 2, argv + 2); krh@6: krh@6: printf("pool size: %d\n", set->string_pool.size); krh@6: printf("pool allocation: %d\n", set->string_pool.alloc); krh@7: printf("packages: %d\n", krh@7: set->packages.size / sizeof(struct razor_package)); krh@8: printf("requires: %d\n", krh@8: set->requires.size / sizeof(struct razor_property)); krh@7: printf("provides: %d\n", krh@8: set->provides.size / sizeof(struct razor_property)); krh@0: krh@4: razor_set_write(set, repo_filename); krh@0: krh@4: razor_set_destroy(set); krh@3: } else if (strcmp(argv[1], "list") == 0) { krh@4: set = razor_set_open(repo_filename); krh@4: razor_set_list(set); krh@4: razor_set_destroy(set); krh@8: } else if (strcmp(argv[1], "list-requires") == 0) { krh@8: set = razor_set_open(repo_filename); krh@10: razor_set_list_requires(set, argv[2]); krh@8: razor_set_destroy(set); krh@7: } else if (strcmp(argv[1], "list-provides") == 0) { krh@7: set = razor_set_open(repo_filename); krh@10: razor_set_list_provides(set, argv[2]); krh@7: razor_set_destroy(set); krh@18: } else if (strcmp(argv[1], "what-requires") == 0) { krh@18: set = razor_set_open(repo_filename); krh@20: razor_set_list_property_packages(set, &set->requires, krh@20: argv[2], argv[3]); krh@18: razor_set_destroy(set); krh@18: } else if (strcmp(argv[1], "what-provides") == 0) { krh@18: set = razor_set_open(repo_filename); krh@20: razor_set_list_property_packages(set, &set->provides, krh@20: argv[2], argv[3]); krh@18: razor_set_destroy(set); krh@3: } else if (strcmp(argv[1], "info") == 0) { krh@4: set = razor_set_open(repo_filename); krh@4: razor_set_info(set); krh@4: razor_set_destroy(set); krh@15: } else if (strcmp(argv[1], "eat-yum") == 0) { krh@15: set = razor_set_create_from_yum_filelist(STDIN_FILENO); krh@15: if (set == NULL) krh@15: return 1; krh@15: razor_set_write(set, rawhide_repo_filename); krh@15: razor_set_destroy(set); krh@18: printf("wrote %s\n", rawhide_repo_filename); krh@28: } else if (strcmp(argv[1], "import-rpmdb") == 0) { krh@28: set = razor_set_create_from_rpmdb(); krh@28: if (set == NULL) krh@28: return 1; krh@28: razor_set_write(set, repo_filename); krh@28: razor_set_destroy(set); krh@28: printf("wrote %s\n", repo_filename); krh@21: } else if (strcmp(argv[1], "validate") == 0) { krh@21: set = razor_set_open(repo_filename); krh@21: if (set == NULL) krh@21: return 1; krh@21: razor_set_list_unsatisfied(set); krh@21: razor_set_destroy(set); krh@33: } else if (strcmp(argv[1], "update") == 0) { krh@33: set = razor_set_open(repo_filename); krh@33: upstream = razor_set_open(rawhide_repo_filename); krh@33: if (set == NULL || upstream == NULL) krh@33: return 1; krh@37: set = razor_set_update(set, upstream, argc - 2, argv + 2); krh@37: razor_set_write(set, "system-updated.repo"); krh@33: razor_set_destroy(set); krh@33: razor_set_destroy(upstream); krh@37: printf("wrote system-updated.repo\n"); krh@0: } else { krh@0: usage(); krh@0: } krh@0: krh@0: return 0; krh@0: }