18 #include "razor-internal.h"
21 struct razor_set_section {
27 struct razor_set_header {
30 struct razor_set_section sections[0];
33 #define RAZOR_MAGIC 0x7a7a7a7a
34 #define RAZOR_VERSION 1
36 #define RAZOR_ENTRY_LAST 0x80000000ul
37 #define RAZOR_ENTRY_MASK 0x00fffffful
39 #define RAZOR_STRING_POOL 0
40 #define RAZOR_PACKAGES 1
41 #define RAZOR_PROPERTIES 2
43 #define RAZOR_PACKAGE_POOL 4
44 #define RAZOR_PROPERTY_POOL 5
45 #define RAZOR_FILE_POOL 6
47 struct razor_package {
54 struct razor_property {
68 struct array string_pool;
69 struct array packages;
70 struct array properties;
72 struct array package_pool;
73 struct array property_pool;
74 struct array file_pool;
75 struct razor_set_header *header;
83 struct import_directory {
86 struct array packages;
87 struct import_directory *last;
90 struct razor_importer {
91 struct razor_set *set;
92 struct hashtable table;
93 struct razor_package *package;
94 struct array properties;
109 struct razor_set_section razor_sections[] = {
110 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
111 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
112 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
113 { RAZOR_FILES, offsetof(struct razor_set, files) },
114 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
115 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
116 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
120 razor_set_create(void)
122 return zalloc(sizeof(struct razor_set));
126 razor_set_open(const char *filename)
128 struct razor_set *set;
129 struct razor_set_section *s;
134 set = zalloc(sizeof *set);
135 fd = open(filename, O_RDONLY);
136 if (fstat(fd, &stat) < 0)
138 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
139 if (set->header == MAP_FAILED) {
144 for (s = set->header->sections; ~s->type; s++) {
145 if (s->type >= ARRAY_SIZE(razor_sections))
147 if (s->type != razor_sections[s->type].type)
149 array = (void *) set + razor_sections[s->type].offset;
150 array->data = (void *) set->header + s->offset;
151 array->size = s->size;
152 array->alloc = s->size;
160 razor_set_destroy(struct razor_set *set)
167 for (i = 0; set->header->sections[i].type; i++)
169 size = set->header->sections[i].type;
170 munmap(set->header, size);
172 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
173 a = (void *) set + razor_sections[i].offset;
182 razor_set_write(struct razor_set *set, const char *filename)
185 struct razor_set_header *header = (struct razor_set_header *) data;
190 memset(data, 0, sizeof data);
191 header->magic = RAZOR_MAGIC;
192 header->version = RAZOR_VERSION;
193 offset = sizeof data;
195 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
196 if (razor_sections[i].type != i)
198 a = (void *) set + razor_sections[i].offset;
199 header->sections[i].type = i;
200 header->sections[i].offset = offset;
201 header->sections[i].size = a->size;
202 offset += ALIGN(a->size, 4096);
205 header->sections[i].type = ~0;
206 header->sections[i].offset = 0;
207 header->sections[i].size = 0;
209 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
213 razor_write(fd, data, sizeof data);
214 memset(data, 0, sizeof data);
215 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
216 if (razor_sections[i].type != i)
218 a = (void *) set + razor_sections[i].offset;
219 razor_write(fd, a->data, a->size);
220 razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
229 razor_importer_begin_package(struct razor_importer *importer,
230 const char *name, const char *version)
232 struct razor_package *p;
234 p = array_add(&importer->set->packages, sizeof *p);
235 p->name = hashtable_tokenize(&importer->table, name);
236 p->version = hashtable_tokenize(&importer->table, version);
238 importer->package = p;
239 array_init(&importer->properties);
243 razor_importer_finish_package(struct razor_importer *importer)
245 list_set (&importer->package->properties,
246 &importer->set->property_pool,
247 &importer->properties);
249 array_release(&importer->properties);
253 razor_importer_add_property(struct razor_importer *importer,
255 enum razor_version_relation relation,
257 enum razor_property_type type)
259 struct razor_property *p;
262 p = array_add(&importer->set->properties, sizeof *p);
263 p->name = hashtable_tokenize(&importer->table, name) | (type << 30);
264 p->relation = relation;
265 p->version = hashtable_tokenize(&importer->table, version);
266 p->packages = importer->package -
267 (struct razor_package *) importer->set->packages.data;
269 r = array_add(&importer->properties, sizeof *r);
270 *r = p - (struct razor_property *) importer->set->properties.data;
274 razor_importer_add_file(struct razor_importer *importer, const char *name)
276 struct import_entry *e;
278 e = array_add(&importer->files, sizeof *e);
280 e->package = importer->package -
281 (struct razor_package *) importer->set->packages.data;
282 e->name = strdup(name);
285 struct razor_importer *
286 razor_importer_new(void)
288 struct razor_importer *importer;
290 importer = zalloc(sizeof *importer);
291 importer->set = razor_set_create();
292 hashtable_init(&importer->table, &importer->set->string_pool);
297 /* Destroy an importer without creating the set. */
299 razor_importer_destroy(struct razor_importer *importer)
301 /* FIXME: write this */
305 typedef int (*compare_with_data_func_t)(const void *p1,
309 struct qsort_context {
311 compare_with_data_func_t compare;
316 qsort_swap(void *p1, void *p2, size_t size)
320 memcpy(buffer, p1, size);
321 memcpy(p1, p2, size);
322 memcpy(p2, buffer, size);
326 __qsort_with_data(void *base, size_t nelem, uint32_t *map,
327 struct qsort_context *ctx)
329 void *p, *start, *end, *pivot;
330 uint32_t *mp, *mstart, *mend, tmp;
331 int left, right, result;
332 size_t size = ctx->size;
336 end = base + nelem * size;
340 pivot = base + (random() % nelem) * size;
343 result = ctx->compare(p, pivot, ctx->data);
345 qsort_swap(p, start, size);
355 } else if (result == 0) {
361 qsort_swap(p, end, size);
370 left = (start - base) / size;
371 right = (base + nelem * size - end) / size;
373 __qsort_with_data(base, left, map, ctx);
375 __qsort_with_data(end, right, mend, ctx);
379 qsort_with_data(void *base, size_t nelem, size_t size,
380 compare_with_data_func_t compare, void *data)
382 struct qsort_context ctx;
390 ctx.compare = compare;
393 map = malloc(nelem * sizeof (uint32_t));
394 for (i = 0; i < nelem; i++)
397 __qsort_with_data(base, nelem, map, &ctx);
403 versioncmp(const char *s1, const char *s2)
409 n1 = strtol(s1, (char **) &p1, 0);
410 n2 = strtol(s2, (char **) &p2, 0);
412 /* Epoch; if one but not the other has an epoch set, default
413 * the epoch-less version to 0. */
414 res = (*p1 == ':') - (*p2 == ':');
419 } else if (res > 0) {
432 if (isdigit(*p1) && isdigit(*p2))
433 return versioncmp(p1, p2);
440 compare_packages(const void *p1, const void *p2, void *data)
442 const struct razor_package *pkg1 = p1, *pkg2 = p2;
443 struct razor_set *set = data;
444 char *pool = set->string_pool.data;
446 if (pkg1->name == pkg2->name)
447 return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
449 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
453 compare_properties(const void *p1, const void *p2, void *data)
455 const struct razor_property *prop1 = p1, *prop2 = p2;
456 struct razor_set *set = data;
457 char *pool = set->string_pool.data;
459 if (prop1->name == prop2->name) {
460 if (prop1->relation == prop2->relation)
461 return versioncmp(&pool[prop1->version],
462 &pool[prop2->version]);
464 return prop1->relation - prop2->relation;
465 } else if ((prop1->name & RAZOR_ENTRY_MASK) == (prop2->name & RAZOR_ENTRY_MASK))
466 return (prop1->name >> 30) - (prop2->name >> 30);
468 return strcmp(&pool[prop1->name & RAZOR_ENTRY_MASK],
469 &pool[prop2->name & RAZOR_ENTRY_MASK]);
473 uniqueify_properties(struct razor_set *set)
475 struct razor_property *rp, *up, *rp_end;
476 struct array *pkgs, *p;
477 uint32_t *map, *rmap, *r;
478 int i, count, unique;
480 count = set->properties.size / sizeof(struct razor_property);
481 map = qsort_with_data(set->properties.data,
483 sizeof(struct razor_property),
487 rp_end = set->properties.data + set->properties.size;
488 rmap = malloc(count * sizeof *map);
489 pkgs = zalloc(count * sizeof *pkgs);
490 for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
491 if (rp->name != up->name || rp->relation != up->relation ||
492 rp->version != up->version) {
495 up->relation = rp->relation;
496 up->version = rp->version;
499 unique = up - (struct razor_property *) set->properties.data;
500 rmap[map[i]] = unique;
501 r = array_add(&pkgs[unique], sizeof *r);
507 set->properties.size = (void *) up - set->properties.data;
509 for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
510 list_set(&rp->packages, &set->package_pool, p);
520 compare_filenames(const void *p1, const void *p2, void *data)
522 const struct import_entry *e1 = p1;
523 const struct import_entry *e2 = p2;
525 return strcmp(e1->name, e2->name);
529 count_entries(struct import_directory *d)
531 struct import_directory *p, *end;
534 end = d->files.data + d->files.size;
538 d->count += p->count + 1;
544 serialize_files(struct razor_set *set,
545 struct import_directory *d, struct array *array)
547 struct import_directory *p, *end;
548 struct razor_entry *e = NULL;
552 end = d->files.data + d->files.size;
553 s = array->size / sizeof *e + d->files.size / sizeof *p;
555 e = array_add(array, sizeof *e);
557 e->start = p->count > 0 ? s : 0;
560 list_set(&e->packages, &set->package_pool, &p->packages);
561 array_release(&p->packages);
565 e->name |= RAZOR_ENTRY_LAST;
568 end = d->files.data + d->files.size;
570 serialize_files(set, p, array);
576 remap_property_package_links(struct array *properties, uint32_t *rmap)
578 struct razor_property *p, *end;
580 end = properties->data + properties->size;
581 for (p = properties->data; p < end; p++)
582 list_remap_if_immediate(&p->packages, rmap);
586 build_file_tree(struct razor_importer *importer)
588 int count, i, length;
589 struct import_entry *filenames;
593 struct import_directory *d, root;
594 struct razor_entry *e;
596 count = importer->files.size / sizeof (struct import_entry);
597 qsort_with_data(importer->files.data,
599 sizeof (struct import_entry),
603 root.name = hashtable_tokenize(&importer->table, "");
604 array_init(&root.files);
605 array_init(&root.packages);
608 filenames = importer->files.data;
609 for (i = 0; i < count; i++) {
610 f = filenames[i].name;
617 end = strchr(f, '/');
621 memcpy(dirname, f, length);
622 dirname[length] ='\0';
623 name = hashtable_tokenize(&importer->table, dirname);
624 if (d->last == NULL || d->last->name != name) {
625 d->last = array_add(&d->files, sizeof *d);
626 d->last->name = name;
627 d->last->last = NULL;
628 array_init(&d->last->files);
629 array_init(&d->last->packages);
637 r = array_add(&d->packages, sizeof *r);
638 *r = filenames[i].package;
639 free(filenames[i].name);
642 count_entries(&root);
643 array_init(&importer->set->files);
645 e = array_add(&importer->set->files, sizeof *e);
646 e->name = root.name | RAZOR_ENTRY_LAST;
648 list_init(&e->packages);
650 serialize_files(importer->set, &root, &importer->set->files);
652 array_release(&importer->files);
656 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
658 struct razor_package *p, *packages;
660 struct razor_entry *e, *end;
664 count = set->packages.size / sizeof *p;
665 pkgs = zalloc(count * sizeof *pkgs);
667 end = set->files.data + set->files.size;
668 for (e = set->files.data; e < end; e++) {
669 list_remap_if_immediate(&e->packages, rmap);
670 r = list_first(&e->packages, &set->package_pool);
672 q = array_add(&pkgs[LIST_VALUE(r)], sizeof *q);
673 *q = e - (struct razor_entry *) set->files.data;
678 packages = set->packages.data;
679 for (i = 0; i < count; i++) {
680 list_set(&packages[i].files, &set->file_pool, &pkgs[i]);
681 array_release(&pkgs[i]);
687 razor_importer_finish(struct razor_importer *importer)
689 struct razor_set *set;
690 uint32_t *map, *rmap;
693 map = uniqueify_properties(importer->set);
694 list_remap_pool(&importer->set->property_pool, map);
697 count = importer->set->packages.size / sizeof(struct razor_package);
698 map = qsort_with_data(importer->set->packages.data,
700 sizeof(struct razor_package),
704 rmap = malloc(count * sizeof *rmap);
705 for (i = 0; i < count; i++)
709 build_file_tree(importer);
710 list_remap_pool(&importer->set->package_pool, rmap);
711 build_package_file_lists(importer->set, rmap);
712 remap_property_package_links(&importer->set->properties, rmap);
716 hashtable_release(&importer->table);
722 struct razor_package_iterator {
723 struct razor_set *set;
724 struct razor_package *package, *end;
728 struct razor_package_iterator *
729 razor_package_iterator_create_with_index(struct razor_set *set,
732 struct razor_package_iterator *pi;
734 pi = zalloc(sizeof *pi);
741 struct razor_package_iterator *
742 razor_package_iterator_create(struct razor_set *set)
744 struct razor_package_iterator *pi;
746 pi = zalloc(sizeof *pi);
748 pi->end = set->packages.data + set->packages.size;
749 pi->package = set->packages.data;
754 struct razor_package_iterator *
755 razor_package_iterator_create_for_property(struct razor_set *set,
756 struct razor_property *property)
760 index = list_first(&property->packages, &set->package_pool);
761 return razor_package_iterator_create_with_index(set, index);
765 razor_package_iterator_next(struct razor_package_iterator *pi,
766 struct razor_package **package,
767 const char **name, const char **version)
771 struct razor_package *p, *packages;
776 } else if (pi->index) {
777 packages = pi->set->packages.data;
778 p = &packages[LIST_VALUE(pi->index)];
779 pi->index = list_next(pi->index);
785 pool = pi->set->string_pool.data;
787 *name = &pool[p->name & RAZOR_ENTRY_MASK];
788 *version = &pool[p->version];
797 razor_package_iterator_destroy(struct razor_package_iterator *pi)
802 struct razor_package *
803 razor_set_get_package(struct razor_set *set, const char *package)
805 struct razor_package_iterator *pi;
806 struct razor_package *p;
807 const char *name, *version;
809 pi = razor_package_iterator_create(set);
810 while (razor_package_iterator_next(pi, &p, &name, &version)) {
811 if (strcmp(package, name) == 0)
814 razor_package_iterator_destroy(pi);
819 struct razor_property_iterator {
820 struct razor_set *set;
821 struct razor_property *property, *end;
825 struct razor_property_iterator *
826 razor_property_iterator_create(struct razor_set *set,
827 struct razor_package *package)
829 struct razor_property_iterator *pi;
831 pi = zalloc(sizeof *pi);
835 pi->index = (uint32_t *)
836 set->property_pool.data + package->properties;
838 pi->property = set->properties.data;
839 pi->end = set->properties.data + set->properties.size;
846 razor_property_iterator_next(struct razor_property_iterator *pi,
847 struct razor_property **property,
849 enum razor_version_relation *relation,
850 const char **version,
851 enum razor_property_type *type)
855 struct razor_property *p, *properties;
860 } else if (pi->index) {
861 properties = pi->set->properties.data;
862 p = &properties[LIST_VALUE(pi->index)];
863 pi->index = list_next(pi->index);
869 pool = pi->set->string_pool.data;
871 *name = &pool[p->name & RAZOR_ENTRY_MASK];
872 *relation = p->relation;
873 *version = &pool[p->version];
874 *type = p->name >> 30;
883 razor_property_iterator_destroy(struct razor_property_iterator *pi)
888 static struct razor_entry *
889 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
891 struct razor_entry *e;
892 const char *n, *pool = set->string_pool.data;
895 e = (struct razor_entry *) set->files.data + dir->start;
897 n = pool + (e->name & RAZOR_ENTRY_MASK);
898 if (strcmp(pattern + 1, n) == 0)
901 if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
902 pattern[len + 1] == '/') {
903 return find_entry(set, e, pattern + len + 1);
905 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
911 list_dir(struct razor_set *set, struct razor_entry *dir,
912 const char *prefix, const char *pattern)
914 struct razor_entry *e;
915 const char *n, *pool = set->string_pool.data;
917 e = (struct razor_entry *) set->files.data + dir->start;
919 n = pool + (e->name & RAZOR_ENTRY_MASK);
920 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
922 printf("%s/%s%s\n", prefix, n, e->start > 0 ? "/" : "");
923 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
927 razor_set_list_files(struct razor_set *set, const char *pattern)
929 struct razor_entry *e;
930 char buffer[512], *p, *base;
935 strcpy(buffer, pattern);
936 e = find_entry(set, set->files.data, buffer);
937 if (e && e->start > 0) {
940 p = strrchr(buffer, '/');
948 e = find_entry(set, set->files.data, buffer);
950 list_dir(set, e, buffer, base);
953 struct razor_package_iterator *
954 razor_package_iterator_create_for_file(struct razor_set *set,
955 const char *filename)
957 struct razor_entry *entry;
960 entry = find_entry(set, set->files.data, filename);
964 index = list_first(&entry->packages, &set->package_pool);
965 return razor_package_iterator_create_with_index(set, index);
969 list_package_files(struct razor_set *set, uint32_t *r,
970 struct razor_entry *dir, uint32_t end,
973 struct razor_entry *e, *f, *entries;
978 entries = (struct razor_entry *) set->files.data;
979 pool = set->string_pool.data;
981 e = entries + dir->start;
983 if (entries + LIST_VALUE(r) == e) {
984 printf("%s/%s\n", prefix,
985 pool + (e->name & RAZOR_ENTRY_MASK));
989 if (LIST_VALUE(r) >= end)
992 } while (!((e++)->name & RAZOR_ENTRY_LAST));
994 e = entries + dir->start;
999 if (e->name & RAZOR_ENTRY_LAST)
1003 while (f->start == 0 && !(f->name & RAZOR_ENTRY_LAST))
1011 file = LIST_VALUE(r);
1012 if (e->start <= file && file < next) {
1013 len = strlen(prefix);
1015 strcpy(prefix + len + 1,
1016 pool + (e->name & RAZOR_ENTRY_MASK));
1017 r = list_package_files(set, r, e, next, prefix);
1020 } while (!((e++)->name & RAZOR_ENTRY_LAST) && r != NULL);
1026 razor_set_list_package_files(struct razor_set *set, const char *name)
1028 struct razor_package *package;
1032 package = razor_set_get_package(set, name);
1034 r = list_first(&package->files, &set->file_pool);
1035 end = set->files.size / sizeof (struct razor_entry);
1037 list_package_files(set, r, set->files.data, end, buffer);
1041 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
1043 struct razor_property *r, *p, *end;
1047 end = set->properties.data + set->properties.size;
1048 pool = set->string_pool.data;
1050 for (r = set->properties.data, p = r; r < end; r++) {
1051 if (r->name >> 30 != RAZOR_PROPERTY_REQUIRES)
1054 if ((r->name & RAZOR_ENTRY_MASK) != (p->name & RAZOR_ENTRY_MASK)) {
1056 while (p < end && p->name == r->name)
1060 /* If there is more than one version of a provides,
1061 * seek to the end for the highest version. */
1062 /* FIXME: This doesn't work if we have a series of
1063 * requires a = 1, provides a = 1, requires a = 2,
1064 * provides a = 2, as the kernel and kernel-devel
1066 while (p + 1 < end && p->name == (p + 1)->name)
1069 /* FIXME: We need to track property flags (<, <=, =
1070 * etc) to properly determine if a requires is
1071 * satisfied. The current code doesn't track that the
1072 * requires a = 1 isn't satisfied by a = 2 provides. */
1075 (p->name >> 30) != RAZOR_PROPERTY_PROVIDES ||
1076 (r->name & RAZOR_ENTRY_MASK) != (p->name & RAZOR_ENTRY_MASK) ||
1077 versioncmp(&pool[r->version], &pool[p->version]) > 0) {
1078 /* FIXME: We ignore file requires for now. */
1079 if (pool[r->name & RAZOR_ENTRY_MASK] == '/')
1081 u = array_add(unsatisfied, sizeof *u);
1082 *u = r - (struct razor_property *) set->properties.data;
1088 razor_set_list_unsatisfied(struct razor_set *set)
1090 struct array unsatisfied;
1091 struct razor_property *properties, *r;
1095 array_init(&unsatisfied);
1096 razor_set_validate(set, &unsatisfied);
1098 end = unsatisfied.data + unsatisfied.size;
1099 properties = set->properties.data;
1100 pool = set->string_pool.data;
1102 for (u = unsatisfied.data; u < end; u++) {
1103 r = properties + *u;
1104 if (pool[r->version] == '\0')
1105 printf("%ss not satisfied\n",
1106 &pool[r->name & RAZOR_ENTRY_MASK]);
1108 printf("%s-%s not satisfied\n",
1109 &pool[r->name & RAZOR_ENTRY_MASK],
1113 array_release(&unsatisfied);
1116 #define UPSTREAM_SOURCE 0x80000000ul
1117 #define INDEX_MASK 0x00fffffful
1120 struct razor_set *set;
1121 uint32_t *property_map;
1124 struct razor_merger {
1125 struct razor_set *set;
1126 struct hashtable table;
1127 struct source source1;
1128 struct source source2;
1131 static struct razor_merger *
1132 razor_merger_create(struct razor_set *set1, struct razor_set *set2)
1134 struct razor_merger *merger;
1138 merger = zalloc(sizeof *merger);
1139 merger->set = razor_set_create();
1140 hashtable_init(&merger->table, &merger->set->string_pool);
1142 count = set1->properties.size / sizeof (struct razor_property);
1143 size = count * sizeof merger->source1.property_map[0];
1144 merger->source1.property_map = zalloc(size);
1145 merger->source1.set = set1;
1147 count = set2->properties.size / sizeof (struct razor_property);
1148 size = count * sizeof merger->source2.property_map[0];
1149 merger->source2.property_map = zalloc(size);
1150 merger->source2.set = set2;
1156 add_package(struct razor_merger *merger,
1157 struct razor_package *package, struct source *source,
1162 struct razor_package *p;
1164 pool = source->set->string_pool.data;
1165 p = array_add(&merger->set->packages, sizeof *p);
1166 p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
1168 p->version = hashtable_tokenize(&merger->table,
1169 &pool[package->version]);
1170 p->properties = package->properties;
1172 r = list_first(&package->properties, &source->set->property_pool);
1174 source->property_map[LIST_VALUE(r)] = 1;
1180 /* Build the new package list sorted by merging the two package lists.
1181 * Build new string pool as we go. */
1183 merge_packages(struct razor_merger *merger, struct array *packages)
1185 struct razor_package *upstream_packages, *p, *s, *send;
1186 struct source *source1, *source2;
1187 char *spool, *upool;
1191 source1 = &merger->source1;
1192 source2 = &merger->source2;
1193 upstream_packages = source2->set->packages.data;
1196 uend = packages->data + packages->size;
1197 upool = source2->set->string_pool.data;
1199 s = source1->set->packages.data;
1200 send = source1->set->packages.data + source1->set->packages.size;
1201 spool = source1->set->string_pool.data;
1204 p = upstream_packages + *u;
1207 cmp = strcmp(&spool[s->name], &upool[p->name]);
1208 if (u >= uend || cmp < 0) {
1209 add_package(merger, s, source1, 0);
1211 } else if (cmp == 0) {
1212 add_package(merger, p, source2, UPSTREAM_SOURCE);
1216 add_package(merger, p, source2, UPSTREAM_SOURCE);
1223 add_property(struct razor_merger *merger,
1224 const char *name, enum razor_version_relation relation,
1225 const char *version, int type)
1227 struct razor_property *p;
1229 p = array_add(&merger->set->properties, sizeof *p);
1230 p->name = hashtable_tokenize(&merger->table, name) | (type << 30);
1231 p->relation = relation;
1232 p->version = hashtable_tokenize(&merger->table, version);
1234 return p - (struct razor_property *) merger->set->properties.data;
1238 merge_properties(struct razor_merger *merger)
1240 struct razor_property *p1, *p2;
1241 struct razor_set *set1, *set2;
1242 uint32_t *map1, *map2;
1243 int i, j, cmp, count1, count2;
1244 char *pool1, *pool2;
1246 set1 = merger->source1.set;
1247 set2 = merger->source2.set;
1248 map1 = merger->source1.property_map;
1249 map2 = merger->source2.property_map;
1253 pool1 = set1->string_pool.data;
1254 pool2 = set2->string_pool.data;
1256 count1 = set1->properties.size / sizeof *p1;
1257 count2 = set2->properties.size / sizeof *p2;
1258 while (i < count1 || j < count2) {
1259 if (i < count1 && map1[i] == 0) {
1263 if (j < count2 && map2[j] == 0) {
1267 p1 = (struct razor_property *) set1->properties.data + i;
1268 p2 = (struct razor_property *) set2->properties.data + j;
1269 if (i < count1 && j < count2)
1270 cmp = strcmp(&pool1[p1->name & RAZOR_ENTRY_MASK],
1271 &pool2[p2->name & RAZOR_ENTRY_MASK]);
1272 else if (i < count1)
1277 cmp = p1->relation - p2->relation;
1279 cmp = versioncmp(&pool1[p1->version],
1280 &pool2[p2->version]);
1282 map1[i++] = add_property(merger,
1283 &pool1[p1->name & RAZOR_ENTRY_MASK],
1285 &pool1[p1->version],
1287 } else if (cmp > 0) {
1288 map2[j++] = add_property(merger,
1289 &pool2[p2->name & RAZOR_ENTRY_MASK],
1291 &pool2[p2->version],
1294 map1[i++] = map2[j++] = add_property(merger,
1295 &pool1[p1->name & RAZOR_ENTRY_MASK],
1297 &pool1[p1->version],
1304 emit_properties(uint32_t *properties, struct array *source_pool,
1305 uint32_t *map, struct array *pool)
1309 r = pool->size / sizeof *q;
1310 p = list_first(properties, source_pool);
1312 q = array_add(pool, sizeof *q);
1313 *q = map[LIST_VALUE(p)] | LIST_FLAGS(p);
1320 /* Rebuild property->packages maps. We can't just remap these, as a
1321 * property may have lost or gained a number of packages. Allocate an
1322 * array per property and loop through the packages and add them to
1323 * the arrays for their properties. */
1325 rebuild_package_lists(struct razor_set *set)
1327 struct array *pkgs, *a;
1328 struct razor_package *pkg, *pkg_end;
1329 struct razor_property *prop, *prop_end;
1334 count = set->properties.size / sizeof (struct razor_property);
1335 pkgs = zalloc(count * sizeof *pkgs);
1336 pkg_end = set->packages.data + set->packages.size;
1337 pool = &set->property_pool;
1339 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1340 r = list_first(&pkg->properties, pool);
1342 q = array_add(&pkgs[LIST_VALUE(r)], sizeof *q);
1343 *q = pkg - (struct razor_package *) set->packages.data;
1348 prop_end = set->properties.data + set->properties.size;
1350 for (prop = set->properties.data; prop < prop_end; prop++, a++) {
1351 list_set(&prop->packages, pool, a);
1358 razor_merger_finish(struct razor_merger *merger)
1360 struct razor_set *result;
1362 result = merger->set;
1363 hashtable_release(&merger->table);
1369 /* Add packages from 'upstream' to 'set'. The packages to add are
1370 * specified by the 'packages' array, which is a sorted list of
1371 * package indexes. Returns a newly allocated package set. Does not
1372 * enforce validity of the resulting package set.
1374 * This looks more complicated than it is. An easy way to merge two
1375 * package sets would be to just use a razor_importer, but that
1376 * requires resorting, and is thus O(n log n). We can do this in a
1377 * linear sweep, but it gets a little more complicated.
1380 razor_set_add(struct razor_set *set, struct razor_set *upstream,
1381 struct array *packages)
1383 struct razor_merger *merger;
1384 struct razor_package *p, *pend;
1386 merger = razor_merger_create(set, upstream);
1388 merge_packages(merger, packages);
1390 /* As we built the package list, we filled out a bitvector of
1391 * the properties that are referenced by the packages in the
1392 * new set. Now we do a parallel loop through the properties
1393 * and emit those marked in the bit vector to the new set. In
1394 * the process, we update the bit vector to actually map from
1395 * indices in the old property list to indices in the new
1396 * property list for both sets. */
1398 merge_properties(merger);
1400 /* Now we loop through the packages again and emit the
1401 * property lists, remapped to point to the new properties. */
1403 pend = merger->set->packages.data + merger->set->packages.size;
1404 for (p = merger->set->packages.data; p < pend; p++) {
1407 if (p->name & UPSTREAM_SOURCE)
1408 src = &merger->source2;
1410 src = &merger->source1;
1412 emit_properties(&p->properties,
1413 &src->set->property_pool,
1415 &merger->set->property_pool);
1416 p->name &= INDEX_MASK;
1419 rebuild_package_lists(merger->set);
1421 return razor_merger_finish(merger);
1425 razor_set_satisfy(struct razor_set *set, struct array *unsatisfied,
1426 struct razor_set *upstream, struct array *list)
1428 struct razor_property *requires, *r;
1429 struct razor_property *p, *pend;
1430 uint32_t *u, *end, *pkg;
1431 struct array *package_pool;
1434 end = unsatisfied->data + unsatisfied->size;
1435 requires = set->properties.data;
1436 pool = set->string_pool.data;
1438 p = upstream->properties.data;
1439 pend = upstream->properties.data + upstream->properties.size;
1440 upool = upstream->string_pool.data;
1441 package_pool = &upstream->package_pool;
1443 for (u = unsatisfied->data; u < end; u++) {
1447 strcmp(&pool[r->name & RAZOR_ENTRY_MASK],
1448 &upool[p->name & RAZOR_ENTRY_MASK]) > 0 &&
1449 (p->name >> 30) != RAZOR_PROPERTY_PROVIDES)
1451 /* If there is more than one version of a provides,
1452 * seek to the end for the highest version. */
1453 while (p + 1 < pend && p->name == (p + 1)->name)
1457 strcmp(&pool[r->name & RAZOR_ENTRY_MASK],
1458 &upool[p->name & RAZOR_ENTRY_MASK]) != 0 ||
1459 versioncmp(&pool[r->version], &upool[p->version]) > 0) {
1460 /* Do we need to track unsatisfiable requires
1461 * as we go, or should we just do a
1462 * razor_set_validate() at the end? */
1464 pkg = array_add(list, sizeof *pkg);
1465 /* We just pull in the first package that provides */
1466 *pkg = LIST_VALUE(list_first(&p->packages, package_pool));
1472 find_packages(struct razor_set *set,
1473 int count, const char **package_names, struct array *list)
1475 struct razor_package_iterator *pi;
1476 struct razor_package *p, *packages;
1477 const char *name, *version;
1481 packages = (struct razor_package *) set->packages.data;
1482 pi = razor_package_iterator_create(set);
1484 while (razor_package_iterator_next(pi, &p, &name, &version)) {
1485 for (i = 0; i < count; i++) {
1486 if (strcmp(name, package_names[i]) == 0) {
1487 r = array_add(list, sizeof *r);
1494 razor_package_iterator_destroy(pi);
1498 find_all_packages(struct razor_set *set,
1499 struct razor_set *upstream, struct array *list)
1501 struct razor_package *p, *u, *pend, *uend;
1505 pend = set->packages.data + set->packages.size;
1506 pool = set->string_pool.data;
1507 u = upstream->packages.data;
1508 uend = upstream->packages.data + upstream->packages.size;
1509 upool = upstream->string_pool.data;
1511 for (p = set->packages.data; p < pend; p++) {
1512 while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0)
1514 if (strcmp(&pool[p->name], &upool[u->name]) == 0) {
1515 r = array_add(list, sizeof *r);
1516 *r = u - (struct razor_package *) upstream->packages.data;
1522 razor_set_update(struct razor_set *set, struct razor_set *upstream,
1523 int count, const char **packages)
1525 struct razor_set *new;
1526 struct razor_package *upackages;
1527 struct array list, unsatisfied;
1534 find_packages(upstream, count, packages, &list);
1536 find_all_packages(set, upstream, &list);
1538 end = list.data + list.size;
1539 upackages = upstream->packages.data;
1540 pool = upstream->string_pool.data;
1541 total += list.size / sizeof *u;
1543 while (list.size > 0) {
1544 new = razor_set_add(set, upstream, &list);
1545 array_release(&list);
1546 razor_set_destroy(set);
1549 array_init(&unsatisfied);
1550 razor_set_validate(new, &unsatisfied);
1552 razor_set_satisfy(new, &unsatisfied, upstream, &list);
1553 array_release(&unsatisfied);
1555 end = list.data + list.size;
1556 upackages = upstream->packages.data;
1557 pool = upstream->string_pool.data;
1558 total += list.size / sizeof *u;
1561 array_release(&list);
1566 /* The diff order matters. We should sort the packages so that a
1567 * REMOVE of a package comes before the INSTALL, and so that all
1568 * requires for a package have been installed before the package.
1572 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
1573 razor_package_callback_t callback, void *data)
1575 struct razor_package_iterator *pi1, *pi2;
1576 struct razor_package *p1, *p2;
1577 const char *name1, *name2, *version1, *version2;
1580 pi1 = razor_package_iterator_create(set);
1581 pi2 = razor_package_iterator_create(upstream);
1583 razor_package_iterator_next(pi1, &p1, &name1, &version1);
1584 razor_package_iterator_next(pi2, &p2, &name2, &version2);
1588 res = strcmp(name1, name2);
1590 res = versioncmp(version1, version2);
1595 if (p2 == NULL || res < 0)
1596 callback(name1, version1, NULL, data);
1597 else if (p1 == NULL || res > 0)
1598 callback(name2, NULL, version2, data);
1600 if (p1 != NULL && res <= 0)
1601 razor_package_iterator_next(pi1, &p1,
1603 if (p2 != NULL && res >= 0)
1604 razor_package_iterator_next(pi2, &p2,
1608 razor_package_iterator_destroy(pi1);
1609 razor_package_iterator_destroy(pi2);