Use the cpio headers instead of the rpm headers when unpacking.
The files in the cpio payload doesn't actually follow the file order
in the rpm headers, so we need to decode the cpio header and use the
information there.
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_STRING_POOL 0
37 #define RAZOR_PACKAGES 1
38 #define RAZOR_PROPERTIES 2
40 #define RAZOR_PACKAGE_POOL 4
41 #define RAZOR_PROPERTY_POOL 5
42 #define RAZOR_FILE_POOL 6
44 struct razor_package {
49 struct list_head properties;
50 struct list_head files;
53 struct razor_property {
56 enum razor_property_type type : 2;
57 enum razor_version_relation relation : 32;
59 struct list_head packages;
66 struct list_head packages;
69 #define RAZOR_ENTRY_LAST 0x80
72 struct array string_pool;
73 struct array packages;
74 struct array properties;
76 struct array package_pool;
77 struct array property_pool;
78 struct array file_pool;
79 struct razor_set_header *header;
87 struct import_directory {
90 struct array packages;
91 struct import_directory *last;
94 struct razor_importer {
95 struct razor_set *set;
96 struct hashtable table;
97 struct razor_package *package;
98 struct array properties;
100 struct array file_requires;
114 struct razor_set_section razor_sections[] = {
115 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
116 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
117 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
118 { RAZOR_FILES, offsetof(struct razor_set, files) },
119 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
120 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
121 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
125 razor_set_create(void)
127 struct razor_set *set;
128 struct razor_entry *e;
131 set = zalloc(sizeof *set);
133 e = array_add(&set->files, sizeof *e);
134 empty = array_add(&set->string_pool, 1);
137 e->flags = RAZOR_ENTRY_LAST;
139 list_set_empty(&e->packages);
145 razor_set_open(const char *filename)
147 struct razor_set *set;
148 struct razor_set_section *s;
153 set = zalloc(sizeof *set);
154 fd = open(filename, O_RDONLY);
155 if (fstat(fd, &stat) < 0)
157 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
158 if (set->header == MAP_FAILED) {
163 for (s = set->header->sections; ~s->type; s++) {
164 if (s->type >= ARRAY_SIZE(razor_sections))
166 if (s->type != razor_sections[s->type].type)
168 array = (void *) set + razor_sections[s->type].offset;
169 array->data = (void *) set->header + s->offset;
170 array->size = s->size;
171 array->alloc = s->size;
179 razor_set_destroy(struct razor_set *set)
186 for (i = 0; set->header->sections[i].type; i++)
188 size = set->header->sections[i].type;
189 munmap(set->header, size);
191 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
192 a = (void *) set + razor_sections[i].offset;
201 razor_set_write_to_fd(struct razor_set *set, int fd)
204 struct razor_set_header *header = (struct razor_set_header *) data;
209 memset(data, 0, sizeof data);
210 header->magic = RAZOR_MAGIC;
211 header->version = RAZOR_VERSION;
212 offset = sizeof data;
214 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
215 if (razor_sections[i].type != i)
217 a = (void *) set + razor_sections[i].offset;
218 header->sections[i].type = i;
219 header->sections[i].offset = offset;
220 header->sections[i].size = a->size;
221 offset += ALIGN(a->size, 4096);
224 header->sections[i].type = ~0;
225 header->sections[i].offset = 0;
226 header->sections[i].size = 0;
228 razor_write(fd, data, sizeof data);
229 memset(data, 0, sizeof data);
230 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
231 if (razor_sections[i].type != i)
233 a = (void *) set + razor_sections[i].offset;
234 razor_write(fd, a->data, a->size);
235 razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
242 razor_set_write(struct razor_set *set, const char *filename)
246 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
250 status = razor_set_write_to_fd(set, fd);
260 razor_build_evr(char *evr_buf, int size, const char *epoch,
261 const char *version, const char *release)
265 if (!version || !*version) {
270 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
271 len = snprintf(evr_buf, size, "%s:", epoch);
275 len = snprintf(evr_buf, size, "%s", version);
278 if (release && *release)
279 snprintf(evr_buf, size, "-%s", release);
283 razor_importer_begin_package(struct razor_importer *importer,
288 struct razor_package *p;
290 p = array_add(&importer->set->packages, sizeof *p);
291 p->name = hashtable_tokenize(&importer->table, name);
293 p->version = hashtable_tokenize(&importer->table, version);
294 p->arch = hashtable_tokenize(&importer->table, arch);
296 importer->package = p;
297 array_init(&importer->properties);
301 razor_importer_finish_package(struct razor_importer *importer)
303 list_set_array(&importer->package->properties,
304 &importer->set->property_pool,
305 &importer->properties,
308 array_release(&importer->properties);
312 razor_importer_add_property(struct razor_importer *importer,
314 enum razor_version_relation relation,
316 enum razor_property_type type)
318 struct razor_property *p;
321 p = array_add(&importer->set->properties, sizeof *p);
322 p->name = hashtable_tokenize(&importer->table, name);
325 p->relation = relation;
326 p->version = hashtable_tokenize(&importer->table, version);
327 list_set_ptr(&p->packages, importer->package -
328 (struct razor_package *) importer->set->packages.data);
330 r = array_add(&importer->properties, sizeof *r);
331 *r = p - (struct razor_property *) importer->set->properties.data;
333 if (type == RAZOR_PROPERTY_REQUIRES && *name == '/') {
334 r = array_add(&importer->file_requires, sizeof *r);
340 razor_importer_add_file(struct razor_importer *importer, const char *name)
342 struct import_entry *e;
344 e = array_add(&importer->files, sizeof *e);
346 e->package = importer->package -
347 (struct razor_package *) importer->set->packages.data;
348 e->name = strdup(name);
351 struct razor_importer *
352 razor_importer_new(void)
354 struct razor_importer *importer;
356 importer = zalloc(sizeof *importer);
357 importer->set = razor_set_create();
358 hashtable_init(&importer->table, &importer->set->string_pool);
363 /* Destroy an importer without creating the set. */
365 razor_importer_destroy(struct razor_importer *importer)
367 /* FIXME: write this */
371 versioncmp(const char *s1, const char *s2)
377 n1 = strtol(s1, (char **) &p1, 10);
378 n2 = strtol(s2, (char **) &p2, 10);
380 /* Epoch; if one but not the other has an epoch set, default
381 * the epoch-less version to 0. */
382 res = (*p1 == ':') - (*p2 == ':');
387 } else if (res > 0) {
400 if (isdigit(*p1) && isdigit(*p2))
401 return versioncmp(p1, p2);
408 compare_packages(const void *p1, const void *p2, void *data)
410 const struct razor_package *pkg1 = p1, *pkg2 = p2;
411 struct razor_set *set = data;
412 char *pool = set->string_pool.data;
414 /* FIXME: what if the flags are different? */
415 if (pkg1->name == pkg2->name)
416 return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
418 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
422 compare_properties(const void *p1, const void *p2, void *data)
424 const struct razor_property *prop1 = p1, *prop2 = p2;
425 struct razor_set *set = data;
426 char *pool = set->string_pool.data;
428 if (prop1->name != prop2->name)
429 return strcmp(&pool[prop1->name], &pool[prop2->name]);
430 else if (prop1->type != prop2->type)
431 return prop1->type - prop2->type;
432 else if (prop1->relation != prop2->relation)
433 return prop1->relation - prop2->relation;
435 return versioncmp(&pool[prop1->version], &pool[prop2->version]);
439 uniqueify_properties(struct razor_set *set)
441 struct razor_property *rp, *up, *rp_end;
442 struct array *pkgs, *p;
444 uint32_t *map, *rmap;
445 int i, count, unique;
447 count = set->properties.size / sizeof(struct razor_property);
448 map = razor_qsort_with_data(set->properties.data,
450 sizeof(struct razor_property),
454 rp_end = set->properties.data + set->properties.size;
455 rmap = malloc(count * sizeof *map);
456 pkgs = zalloc(count * sizeof *pkgs);
457 for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
458 if (rp->name != up->name || rp->type != up->type ||
459 rp->relation != up->relation || rp->version != up->version) {
464 up->relation = rp->relation;
465 up->version = rp->version;
468 unique = up - (struct razor_property *) set->properties.data;
469 rmap[map[i]] = unique;
470 r = array_add(&pkgs[unique], sizeof *r);
477 set->properties.size = (void *) up - set->properties.data;
479 for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
480 list_set_array(&rp->packages, &set->package_pool, p, 0);
490 compare_filenames(const void *p1, const void *p2, void *data)
492 const struct import_entry *e1 = p1;
493 const struct import_entry *e2 = p2;
494 const char *n1 = e1->name;
495 const char *n2 = e2->name;
497 /* Need to make sure that the contents of a directory
498 * are sorted immediately after it. So "foo/bar" has to
499 * sort before "foo.conf"
501 * FIXME: this is about 60% slower than strcmp
505 return *n2 == '/' ? 1 : -1;
507 return *n1 == '/' ? -1 : 1;
520 count_entries(struct import_directory *d)
522 struct import_directory *p, *end;
525 end = d->files.data + d->files.size;
529 d->count += p->count + 1;
535 serialize_files(struct razor_set *set,
536 struct import_directory *d, struct array *array)
538 struct import_directory *p, *end;
539 struct razor_entry *e = NULL;
543 end = d->files.data + d->files.size;
544 s = array->size / sizeof *e + d->files.size / sizeof *p;
546 e = array_add(array, sizeof *e);
549 e->start = p->count > 0 ? s : 0;
552 list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
553 array_release(&p->packages);
557 e->flags |= RAZOR_ENTRY_LAST;
560 end = d->files.data + d->files.size;
562 serialize_files(set, p, array);
568 remap_property_package_links(struct array *properties, uint32_t *rmap)
570 struct razor_property *p, *end;
572 end = properties->data + properties->size;
573 for (p = properties->data; p < end; p++)
574 list_remap_head(&p->packages, rmap);
578 build_file_tree(struct razor_importer *importer)
580 int count, i, length;
581 struct import_entry *filenames;
585 struct import_directory *d, root;
586 struct razor_entry *e;
588 count = importer->files.size / sizeof (struct import_entry);
589 razor_qsort_with_data(importer->files.data,
591 sizeof (struct import_entry),
595 root.name = hashtable_tokenize(&importer->table, "");
596 array_init(&root.files);
597 array_init(&root.packages);
600 filenames = importer->files.data;
601 for (i = 0; i < count; i++) {
602 f = filenames[i].name;
609 end = strchr(f, '/');
613 memcpy(dirname, f, length);
614 dirname[length] ='\0';
615 name = hashtable_tokenize(&importer->table, dirname);
616 if (d->last == NULL || d->last->name != name) {
617 d->last = array_add(&d->files, sizeof *d);
618 d->last->name = name;
619 d->last->last = NULL;
620 array_init(&d->last->files);
621 array_init(&d->last->packages);
629 r = array_add(&d->packages, sizeof *r);
630 *r = filenames[i].package;
631 free(filenames[i].name);
634 count_entries(&root);
635 e = importer->set->files.data;
637 e->flags = RAZOR_ENTRY_LAST;
638 e->start = importer->files.size ? 1 : 0;
639 list_set_empty(&e->packages);
641 serialize_files(importer->set, &root, &importer->set->files);
643 array_release(&importer->files);
646 static struct razor_entry *
647 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern);
650 list_to_array(struct list *list, struct array *array)
655 item = array_add(array, sizeof *item);
657 list = list_next(list);
662 compare_file_requires(const void *p1, const void *p2, void *data)
664 uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
665 const char *pool = data;
667 return strcmp(&pool[*f1], &pool[*f2]);
671 find_file_provides(struct razor_importer *importer)
673 struct razor_property *prop;
674 struct razor_entry *top, *entry;
675 struct razor_package *packages;
676 struct array pkgprops;
678 uint32_t *req, *req_start, *req_end;
679 uint32_t *map, *newprop;
682 pool = importer->set->string_pool.data;
683 packages = importer->set->packages.data;
684 top = importer->set->files.data;
686 req = req_start = importer->file_requires.data;
687 req_end = importer->file_requires.data + importer->file_requires.size;
688 map = razor_qsort_with_data(req, req_end - req, sizeof *req,
689 compare_file_requires, pool);
692 for (req = req_start; req < req_end; req++) {
693 if (req > req_start && req[0] == req[-1])
695 entry = find_entry(importer->set, top, &pool[*req]);
699 for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
700 prop = array_add(&importer->set->properties, sizeof *prop);
702 prop->type = RAZOR_PROPERTY_PROVIDES;
703 prop->relation = RAZOR_VERSION_EQUAL;
704 prop->version = hashtable_tokenize(&importer->table, "");
705 list_set_ptr(&prop->packages, pkg->data);
707 /* Update property list of pkg */
708 array_init(&pkgprops);
709 list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
710 newprop = array_add(&pkgprops, sizeof *newprop);
711 *newprop = prop - (struct razor_property *)importer->set->properties.data;
712 list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
713 array_release(&pkgprops);
717 array_release(&importer->file_requires);
721 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
723 struct razor_package *p, *packages;
725 struct razor_entry *e, *end;
730 count = set->packages.size / sizeof *p;
731 pkgs = zalloc(count * sizeof *pkgs);
733 end = set->files.data + set->files.size;
734 for (e = set->files.data; e < end; e++) {
735 list_remap_head(&e->packages, rmap);
736 r = list_first(&e->packages, &set->package_pool);
738 q = array_add(&pkgs[r->data], sizeof *q);
739 *q = e - (struct razor_entry *) set->files.data;
744 packages = set->packages.data;
745 for (i = 0; i < count; i++) {
746 list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
747 array_release(&pkgs[i]);
753 razor_importer_finish(struct razor_importer *importer)
755 struct razor_set *set;
756 uint32_t *map, *rmap;
759 build_file_tree(importer);
760 find_file_provides(importer);
762 map = uniqueify_properties(importer->set);
763 list_remap_pool(&importer->set->property_pool, map);
766 count = importer->set->packages.size / sizeof(struct razor_package);
767 map = razor_qsort_with_data(importer->set->packages.data,
769 sizeof(struct razor_package),
773 rmap = malloc(count * sizeof *rmap);
774 for (i = 0; i < count; i++)
778 list_remap_pool(&importer->set->package_pool, rmap);
779 build_package_file_lists(importer->set, rmap);
780 remap_property_package_links(&importer->set->properties, rmap);
784 hashtable_release(&importer->table);
790 struct razor_package_iterator {
791 struct razor_set *set;
792 struct razor_package *package, *end;
796 static struct razor_package_iterator *
797 razor_package_iterator_create_with_index(struct razor_set *set,
800 struct razor_package_iterator *pi;
802 pi = zalloc(sizeof *pi);
809 struct razor_package_iterator *
810 razor_package_iterator_create(struct razor_set *set)
812 struct razor_package_iterator *pi;
814 pi = zalloc(sizeof *pi);
816 pi->end = set->packages.data + set->packages.size;
817 pi->package = set->packages.data;
822 struct razor_package_iterator *
823 razor_package_iterator_create_for_property(struct razor_set *set,
824 struct razor_property *property)
828 index = list_first(&property->packages, &set->package_pool);
829 return razor_package_iterator_create_with_index(set, index);
833 razor_package_iterator_next(struct razor_package_iterator *pi,
834 struct razor_package **package,
836 const char **version,
841 struct razor_package *p, *packages;
846 } else if (pi->index) {
847 packages = pi->set->packages.data;
848 p = &packages[pi->index->data];
849 pi->index = list_next(pi->index);
855 pool = pi->set->string_pool.data;
857 *name = &pool[p->name];
858 *version = &pool[p->version];
859 *arch = &pool[p->arch];
868 razor_package_iterator_destroy(struct razor_package_iterator *pi)
873 struct razor_package *
874 razor_set_get_package(struct razor_set *set, const char *package)
876 struct razor_package_iterator *pi;
877 struct razor_package *p;
878 const char *name, *version, *arch;
880 pi = razor_package_iterator_create(set);
881 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
882 if (strcmp(package, name) == 0)
885 razor_package_iterator_destroy(pi);
890 struct razor_property_iterator {
891 struct razor_set *set;
892 struct razor_property *property, *end;
896 struct razor_property_iterator *
897 razor_property_iterator_create(struct razor_set *set,
898 struct razor_package *package)
900 struct razor_property_iterator *pi;
902 pi = zalloc(sizeof *pi);
906 pi->index = list_first(&package->properties,
907 &set->property_pool);
909 pi->property = set->properties.data;
910 pi->end = set->properties.data + set->properties.size;
917 razor_property_iterator_next(struct razor_property_iterator *pi,
918 struct razor_property **property,
920 enum razor_version_relation *relation,
921 const char **version,
922 enum razor_property_type *type)
926 struct razor_property *p, *properties;
931 } else if (pi->index) {
932 properties = pi->set->properties.data;
933 p = &properties[pi->index->data];
934 pi->index = list_next(pi->index);
940 pool = pi->set->string_pool.data;
942 *name = &pool[p->name];
943 *relation = p->relation;
944 *version = &pool[p->version];
954 razor_property_iterator_destroy(struct razor_property_iterator *pi)
959 static struct razor_entry *
960 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
962 struct razor_entry *e;
963 const char *n, *pool = set->string_pool.data;
966 e = (struct razor_entry *) set->files.data + dir->start;
969 if (strcmp(pattern + 1, n) == 0)
972 if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
973 pattern[len + 1] == '/') {
974 return find_entry(set, e, pattern + len + 1);
976 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
982 list_dir(struct razor_set *set, struct razor_entry *dir,
983 char *prefix, const char *pattern)
985 struct razor_entry *e;
986 const char *n, *pool = set->string_pool.data;
988 e = (struct razor_entry *) set->files.data + dir->start;
991 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
993 printf("%s/%s\n", prefix, n);
995 char *sub = prefix + strlen (prefix);
998 list_dir(set, e, prefix, pattern);
1001 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1005 razor_set_list_files(struct razor_set *set, const char *pattern)
1007 struct razor_entry *e;
1008 char buffer[512], *p, *base;
1010 if (pattern == NULL || !strcmp (pattern, "/")) {
1012 list_dir(set, set->files.data, buffer, NULL);
1016 strcpy(buffer, pattern);
1017 e = find_entry(set, set->files.data, buffer);
1018 if (e && e->start > 0) {
1021 p = strrchr(buffer, '/');
1029 e = find_entry(set, set->files.data, buffer);
1031 list_dir(set, e, buffer, base);
1034 struct razor_package_iterator *
1035 razor_package_iterator_create_for_file(struct razor_set *set,
1036 const char *filename)
1038 struct razor_entry *entry;
1041 entry = find_entry(set, set->files.data, filename);
1045 index = list_first(&entry->packages, &set->package_pool);
1046 return razor_package_iterator_create_with_index(set, index);
1049 static struct list *
1050 list_package_files(struct razor_set *set, struct list *r,
1051 struct razor_entry *dir, uint32_t end,
1054 struct razor_entry *e, *f, *entries;
1055 uint32_t next, file;
1059 entries = (struct razor_entry *) set->files.data;
1060 pool = set->string_pool.data;
1062 e = entries + dir->start;
1064 if (entries + r->data == e) {
1065 printf("%s/%s\n", prefix, pool + e->name);
1072 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1074 e = entries + dir->start;
1079 if (e->flags & RAZOR_ENTRY_LAST)
1083 while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
1092 if (e->start <= file && file < next) {
1093 len = strlen(prefix);
1095 strcpy(prefix + len + 1, pool + e->name);
1096 r = list_package_files(set, r, e, next, prefix);
1099 } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
1105 razor_set_list_package_files(struct razor_set *set, const char *name)
1107 struct razor_package *package;
1112 package = razor_set_get_package(set, name);
1114 r = list_first(&package->files, &set->file_pool);
1115 end = set->files.size / sizeof (struct razor_entry);
1117 list_package_files(set, r, set->files.data, end, buffer);
1121 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
1123 struct razor_property *r, *p, *end;
1127 end = set->properties.data + set->properties.size;
1128 pool = set->string_pool.data;
1130 for (r = set->properties.data, p = r; r < end; r++) {
1131 if (r->type != RAZOR_PROPERTY_REQUIRES)
1135 while (p < end && p->name == r->name &&
1139 /* If there is more than one version of a provides,
1140 * seek to the end for the highest version. */
1141 /* FIXME: This doesn't work if we have a series of
1142 * requires a = 1, provides a = 1, requires a = 2,
1143 * provides a = 2, as the kernel and kernel-devel
1145 while (p + 1 < end && p->name == (p + 1)->name &&
1146 p->type == (p + 1)->type)
1149 /* FIXME: We need to track property flags (<, <=, =
1150 * etc) to properly determine if a requires is
1151 * satisfied. The current code doesn't track that the
1152 * requires a = 1 isn't satisfied by a = 2 provides. */
1155 p->type != RAZOR_PROPERTY_PROVIDES ||
1156 r->name != p->name ||
1157 versioncmp(&pool[r->version], &pool[p->version]) > 0) {
1158 /* FIXME: We ignore file requires for now. */
1159 if (pool[r->name] == '/')
1161 u = array_add(unsatisfied, sizeof *u);
1162 *u = r - (struct razor_property *) set->properties.data;
1168 razor_set_list_unsatisfied(struct razor_set *set)
1170 struct array unsatisfied;
1171 struct razor_property *properties, *r;
1175 array_init(&unsatisfied);
1176 razor_set_validate(set, &unsatisfied);
1178 end = unsatisfied.data + unsatisfied.size;
1179 properties = set->properties.data;
1180 pool = set->string_pool.data;
1182 for (u = unsatisfied.data; u < end; u++) {
1183 r = properties + *u;
1184 if (pool[r->version] == '\0')
1185 printf("%ss not satisfied\n",
1188 printf("%s-%s not satisfied\n",
1193 array_release(&unsatisfied);
1196 #define UPSTREAM_SOURCE 0x80
1199 struct razor_set *set;
1200 uint32_t *property_map;
1204 struct razor_merger {
1205 struct razor_set *set;
1206 struct hashtable table;
1207 struct source source1;
1208 struct source source2;
1211 static struct razor_merger *
1212 razor_merger_create(struct razor_set *set1, struct razor_set *set2)
1214 struct razor_merger *merger;
1218 merger = zalloc(sizeof *merger);
1219 merger->set = razor_set_create();
1220 hashtable_init(&merger->table, &merger->set->string_pool);
1222 merger->source1.set = set1;
1223 count = set1->properties.size / sizeof (struct razor_property);
1224 size = count * sizeof merger->source1.property_map[0];
1225 merger->source1.property_map = zalloc(size);
1226 count = set1->files.size / sizeof (struct razor_entry);
1227 size = count * sizeof merger->source1.file_map[0];
1228 merger->source1.file_map = zalloc(size);
1230 merger->source2.set = set2;
1231 count = set2->properties.size / sizeof (struct razor_property);
1232 size = count * sizeof merger->source2.property_map[0];
1233 merger->source2.property_map = zalloc(size);
1234 count = set2->files.size / sizeof (struct razor_entry);
1235 size = count * sizeof merger->source2.file_map[0];
1236 merger->source2.file_map = zalloc(size);
1242 add_package(struct razor_merger *merger,
1243 struct razor_package *package, struct source *source,
1248 struct razor_package *p;
1250 pool = source->set->string_pool.data;
1251 p = array_add(&merger->set->packages, sizeof *p);
1252 p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
1254 p->version = hashtable_tokenize(&merger->table,
1255 &pool[package->version]);
1256 p->arch = hashtable_tokenize(&merger->table,
1257 &pool[package->arch]);
1259 p->properties = package->properties;
1260 r = list_first(&package->properties, &source->set->property_pool);
1262 source->property_map[r->data] = 1;
1266 p->files = package->files;
1267 r = list_first(&package->files, &source->set->file_pool);
1269 source->file_map[r->data] = 1;
1275 add_property(struct razor_merger *merger,
1276 const char *name, enum razor_version_relation relation,
1277 const char *version, int type)
1279 struct razor_property *p;
1281 p = array_add(&merger->set->properties, sizeof *p);
1282 p->name = hashtable_tokenize(&merger->table, name);
1285 p->relation = relation;
1286 p->version = hashtable_tokenize(&merger->table, version);
1288 return p - (struct razor_property *) merger->set->properties.data;
1292 merge_properties(struct razor_merger *merger)
1294 struct razor_property *p1, *p2;
1295 struct razor_set *set1, *set2;
1296 uint32_t *map1, *map2;
1297 int i, j, cmp, count1, count2;
1298 char *pool1, *pool2;
1300 set1 = merger->source1.set;
1301 set2 = merger->source2.set;
1302 map1 = merger->source1.property_map;
1303 map2 = merger->source2.property_map;
1307 pool1 = set1->string_pool.data;
1308 pool2 = set2->string_pool.data;
1310 count1 = set1->properties.size / sizeof *p1;
1311 count2 = set2->properties.size / sizeof *p2;
1312 while (i < count1 || j < count2) {
1313 if (i < count1 && map1[i] == 0) {
1317 if (j < count2 && map2[j] == 0) {
1321 p1 = (struct razor_property *) set1->properties.data + i;
1322 p2 = (struct razor_property *) set2->properties.data + j;
1323 if (i < count1 && j < count2)
1324 cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
1325 else if (i < count1)
1330 cmp = p1->type - p2->type;
1332 cmp = p1->relation - p2->relation;
1334 cmp = versioncmp(&pool1[p1->version],
1335 &pool2[p2->version]);
1337 map1[i++] = add_property(merger,
1340 &pool1[p1->version],
1342 } else if (cmp > 0) {
1343 map2[j++] = add_property(merger,
1346 &pool2[p2->version],
1349 map1[i++] = map2[j++] = add_property(merger,
1352 &pool1[p1->version],
1359 emit_properties(struct list_head *properties, struct array *source_pool,
1360 uint32_t *map, struct array *pool)
1365 r = pool->size / sizeof *q;
1366 p = list_first(properties, source_pool);
1368 q = array_add(pool, sizeof *q);
1369 q->data = map[p->data];
1370 q->flags = p->flags;
1374 list_set_ptr(properties, r);
1378 add_file(struct razor_merger *merger, const char *name)
1380 struct razor_entry *e;
1382 e = array_add(&merger->set->files, sizeof *e);
1383 e->name = hashtable_tokenize(&merger->table, name);
1387 return e - (struct razor_entry *)merger->set->files.data;
1392 fix_file_map(uint32_t *map,
1393 struct razor_entry *files,
1394 struct razor_entry *top)
1402 fix_file_map(map, files, &files[e]);
1405 } while (!(files[e++].flags & RAZOR_ENTRY_LAST));
1408 map[top - files] = 1;
1412 struct merge_directory {
1413 uint32_t merged, dir1, dir2;
1417 merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
1419 struct razor_entry *root1, *root2, *mroot, *e1, *e2;
1420 struct razor_set *set1, *set2;
1421 struct array merge_stack;
1422 struct merge_directory *child_md, *end_md;
1423 uint32_t *map1, *map2, start, last;
1425 char *pool1, *pool2;
1427 set1 = merger->source1.set;
1428 set2 = merger->source2.set;
1429 map1 = merger->source1.file_map;
1430 map2 = merger->source2.file_map;
1431 pool1 = set1->string_pool.data;
1432 pool2 = set2->string_pool.data;
1433 root1 = (struct razor_entry *) set1->files.data;
1434 root2 = (struct razor_entry *) set2->files.data;
1436 array_init(&merge_stack);
1438 start = merger->set->files.size / sizeof (struct razor_entry);
1440 e1 = md->dir1 ? root1 + md->dir1 : NULL;
1441 e2 = md->dir2 ? root2 + md->dir2 : NULL;
1443 if (!e2 && !map1[e1 - root1]) {
1444 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1448 if (!e1 && !map2[e2 - root2]) {
1449 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1453 if (e1 && !map1[e1 - root1] &&
1454 e2 && !map1[e2 - root2]) {
1455 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1457 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1467 cmp = strcmp (&pool1[e1->name],
1472 if (map1[e1 - root1]) {
1473 map1[e1 - root1] = last =
1474 add_file(merger, &pool1[e1->name]);
1476 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1477 child_md->merged = last;
1478 child_md->dir1 = e1->start;
1482 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1484 } else if (cmp > 0) {
1485 if (map2[e2 - root2]) {
1486 map2[e2 - root2] = last =
1487 add_file(merger, &pool2[e2->name]);
1489 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1490 child_md->merged = last;
1492 child_md->dir2 = e2->start;
1495 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1498 map1[e1 - root1] = map2[e2- root2] = last =
1499 add_file(merger, &pool1[e1->name]);
1500 if (e1->start || e2->start) {
1501 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1502 child_md->merged = last;
1503 child_md->dir1 = e1->start;
1504 child_md->dir2 = e2->start;
1506 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1508 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1513 mroot = (struct razor_entry *)merger->set->files.data;
1515 mroot[last].flags = RAZOR_ENTRY_LAST;
1516 mroot[md->merged].start = start;
1518 mroot[md->merged].start = 0;
1520 end_md = merge_stack.data + merge_stack.size;
1521 for (child_md = merge_stack.data; child_md < end_md; child_md++)
1522 merge_one_directory(merger, child_md);
1523 array_release(&merge_stack);
1527 merge_files(struct razor_merger *merger)
1529 struct razor_entry *root;
1530 struct merge_directory md;
1531 uint32_t *map1, *map2;
1533 map1 = merger->source1.file_map;
1534 map2 = merger->source2.file_map;
1538 if (merger->source1.set->files.size) {
1539 root = (struct razor_entry *) merger->source1.set->files.data;
1541 fix_file_map(map1, root, root);
1542 md.dir1 = root->start;
1546 if (merger->source2.set->files.size) {
1547 root = (struct razor_entry *) merger->source2.set->files.data;
1549 fix_file_map(map2, root, root);
1550 md.dir2 = root->start;
1554 merge_one_directory(merger, &md);
1558 emit_files(struct list_head *files, struct array *source_pool,
1559 uint32_t *map, struct array *pool)
1564 r = pool->size / sizeof *q;
1565 p = list_first(files, source_pool);
1567 q = array_add(pool, sizeof *q);
1568 q->data = map[p->data];
1569 q->flags = p->flags;
1573 list_set_ptr(files, r);
1576 /* Rebuild property->packages maps. We can't just remap these, as a
1577 * property may have lost or gained a number of packages. Allocate an
1578 * array per property and loop through the packages and add them to
1579 * the arrays for their properties. */
1581 rebuild_property_package_lists(struct razor_set *set)
1583 struct array *pkgs, *a;
1584 struct razor_package *pkg, *pkg_end;
1585 struct razor_property *prop, *prop_end;
1590 count = set->properties.size / sizeof (struct razor_property);
1591 pkgs = zalloc(count * sizeof *pkgs);
1592 pkg_end = set->packages.data + set->packages.size;
1594 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1595 r = list_first(&pkg->properties, &set->property_pool);
1597 q = array_add(&pkgs[r->data], sizeof *q);
1598 *q = pkg - (struct razor_package *) set->packages.data;
1603 prop_end = set->properties.data + set->properties.size;
1605 for (prop = set->properties.data; prop < prop_end; prop++, a++) {
1606 list_set_array(&prop->packages, &set->package_pool, a, 0);
1613 rebuild_file_package_lists(struct razor_set *set)
1615 struct array *pkgs, *a;
1616 struct razor_package *pkg, *pkg_end;
1617 struct razor_entry *entry, *entry_end;
1622 count = set->files.size / sizeof (struct razor_entry);
1623 pkgs = zalloc(count * sizeof *pkgs);
1624 pkg_end = set->packages.data + set->packages.size;
1626 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1627 r = list_first(&pkg->files, &set->file_pool);
1629 q = array_add(&pkgs[r->data], sizeof *q);
1630 *q = pkg - (struct razor_package *) set->packages.data;
1635 entry_end = set->files.data + set->files.size;
1637 for (entry = set->files.data; entry < entry_end; entry++, a++) {
1638 list_set_array(&entry->packages, &set->package_pool, a, 0);
1644 static struct razor_set *
1645 razor_merger_finish(struct razor_merger *merger)
1647 struct razor_set *result;
1648 struct razor_package *p, *pend;
1650 /* As we built the package list, we filled out a bitvector of
1651 * the properties that are referenced by the packages in the
1652 * new set. Now we do a parallel loop through the properties
1653 * and emit those marked in the bit vector to the new set. In
1654 * the process, we update the bit vector to actually map from
1655 * indices in the old property list to indices in the new
1656 * property list for both sets. */
1658 merge_properties(merger);
1659 merge_files(merger);
1661 /* Now we loop through the packages again and emit the
1662 * property lists, remapped to point to the new properties. */
1664 pend = merger->set->packages.data + merger->set->packages.size;
1665 for (p = merger->set->packages.data; p < pend; p++) {
1668 if (p->flags & UPSTREAM_SOURCE)
1669 src = &merger->source2;
1671 src = &merger->source1;
1673 emit_properties(&p->properties,
1674 &src->set->property_pool,
1676 &merger->set->property_pool);
1677 emit_files(&p->files,
1678 &src->set->file_pool,
1680 &merger->set->file_pool);
1681 p->flags &= ~UPSTREAM_SOURCE;
1684 rebuild_property_package_lists(merger->set);
1685 rebuild_file_package_lists(merger->set);
1687 result = merger->set;
1688 hashtable_release(&merger->table);
1694 /* The diff order matters. We should sort the packages so that a
1695 * REMOVE of a package comes before the INSTALL, and so that all
1696 * requires for a package have been installed before the package.
1700 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
1701 razor_package_callback_t callback, void *data)
1703 struct razor_package_iterator *pi1, *pi2;
1704 struct razor_package *p1, *p2;
1705 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
1708 pi1 = razor_package_iterator_create(set);
1709 pi2 = razor_package_iterator_create(upstream);
1711 razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
1712 razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
1716 res = strcmp(name1, name2);
1718 res = versioncmp(version1, version2);
1723 if (p2 == NULL || res < 0)
1724 callback(name1, version1, NULL, arch1, data);
1725 else if (p1 == NULL || res > 0)
1726 callback(name2, NULL, version2, arch2, data);
1728 if (p1 != NULL && res <= 0)
1729 razor_package_iterator_next(pi1, &p1,
1730 &name1, &version1, &arch1);
1731 if (p2 != NULL && res >= 0)
1732 razor_package_iterator_next(pi2, &p2,
1733 &name2, &version2, &arch2);
1736 razor_package_iterator_destroy(pi1);
1737 razor_package_iterator_destroy(pi2);
1740 struct razor_transaction;
1741 struct razor_transaction_package;
1742 struct razor_transaction_resolver;
1744 struct razor_transaction {
1745 int package_count, errors;
1746 struct razor_set *system, *upstream;
1748 struct bitarray syspkgs, uppkgs;
1749 struct array packages;
1752 struct razor_transaction_package {
1753 const char *name, *old_version, *new_version;
1754 struct razor_package *old_package, *new_package;
1755 enum razor_transaction_package_state state;
1757 /* dep_package is the name of the package that resulted in
1758 * this entry being created (or NULL if the user requested the
1759 * install/remove), with the other dep_ fields providing
1760 * additional information.
1762 * For INSTALL, if dep_type is REQUIRES, then dep_package
1763 * required something that this package provides. If dep_type
1764 * is CONFLICTS, then dep_package is a package that conflicted
1765 * with an older version of this package, forcing an upgrade.
1767 * For REMOVE, if dep_type is REQUIRES, then dep_package is a
1768 * package that is being removed. If dep_type is OBSOLETES,
1769 * then dep_package is a package that obsoletes this one.
1771 * For OLD_CONFLICT or NEW_CONFLICT, dep_package is an
1772 * existing package that conflicts with this one. The
1773 * conflicting property comes from the already-installed
1774 * package for OLD_CONFLICT, or the to-be-installed package
1777 * For UNSATISFIABLE, the dep_ fields are as for an INSTALL,
1778 * but the name field will be NULL.
1780 const char *dep_package;
1781 enum razor_property_type dep_type;
1782 const char *dep_property;
1783 enum razor_version_relation dep_relation;
1784 const char *dep_version;
1788 package_in_set(void *package, struct razor_set *set)
1790 return package >= set->packages.data &&
1791 package < set->packages.data + set->packages.size;
1795 property_in_set(void *property, struct razor_set *set)
1797 return property >= set->properties.data &&
1798 property < set->properties.data + set->properties.size;
1801 static struct razor_package *
1802 property_provider_package(struct razor_transaction *trans,
1803 struct razor_property *prop,
1806 struct razor_set *set;
1807 struct bitarray *pkgbits;
1808 struct razor_package *pkgs;
1811 if (installed && prop->type != RAZOR_PROPERTY_PROVIDES)
1813 else if (!installed &&
1814 prop->type != RAZOR_PROPERTY_PROVIDES &&
1815 prop->type != RAZOR_PROPERTY_OBSOLETES)
1818 if (property_in_set(prop, trans->system)) {
1819 set = trans->system;
1820 pkgbits = &trans->syspkgs;
1822 set = trans->upstream;
1823 pkgbits = &trans->uppkgs;
1825 pkgs = set->packages.data;
1827 for (p = list_first(&prop->packages, &set->package_pool); p; p = list_next(p)) {
1828 if (bitarray_get(pkgbits, p->data) != installed)
1830 if (prop->type == RAZOR_PROPERTY_OBSOLETES ||
1831 pkgs[p->data].name == prop->name)
1832 return &pkgs[p->data];
1838 compare_transaction_packages(const void *one, const void *two)
1840 struct razor_transaction_package **tp1 = (void *)one;
1841 struct razor_transaction_package **tp2 = (void *)two;
1845 else if (!(*tp2)->name)
1848 return strcmp((*tp1)->name, (*tp2)->name);
1851 /* FIXME: merge this into the other property loop in razor_transaction_satisfy */
1853 resolve_new_packages(struct razor_transaction *trans,
1856 struct razor_property *sp, *up, *sp_end, *up_end;
1857 struct razor_package *spkg, *spkgs, *upkg, *upkgs;
1858 struct razor_transaction_package **packages;
1859 const char *spool, *upool;
1862 sp_end = trans->system->properties.data + trans->system->properties.size;
1863 spool = trans->system->string_pool.data;
1864 spkgs = trans->system->packages.data;
1865 up_end = trans->upstream->properties.data + trans->upstream->properties.size;
1866 upool = trans->upstream->string_pool.data;
1867 upkgs = trans->upstream->packages.data;
1869 /* FIXME, check if sorting the packages directly (rather than
1870 * sorting pointers-to-packages) still results in confusing
1873 packages = calloc(end - start, sizeof *packages);
1874 for (i = start; i < end; i++)
1875 packages[i - start] = ((struct razor_transaction_package *)trans->packages.data) + i;
1876 qsort(packages, end - start, sizeof *packages,
1877 compare_transaction_packages);
1879 sp = trans->system->properties.data;
1880 up = trans->upstream->properties.data;
1881 for (i = 0; i < end - start; i++) {
1882 if (!packages[i]->name ||
1883 packages[i]->state >= RAZOR_PACKAGE_FIRST_ERROR_STATE)
1887 while (sp < sp_end &&
1888 strcmp(&spool[sp->name], packages[i]->name) < 0)
1890 while (sp < sp_end &&
1891 strcmp(&spool[sp->name], packages[i]->name) == 0 &&
1892 !(spkg = property_provider_package(trans, sp, 1)))
1896 while (up < up_end &&
1897 strcmp(&upool[up->name], packages[i]->name) < 0)
1899 while (up < up_end &&
1900 strcmp(&upool[up->name], packages[i]->name) == 0 &&
1901 !(upkg = property_provider_package(trans, up, 0)))
1904 if (packages[i]->state == RAZOR_PACKAGE_REMOVE ||
1905 packages[i]->state == RAZOR_PACKAGE_OBSOLETED) {
1907 packages[i]->old_package = spkg;
1908 packages[i]->name = &spool[spkg->name];
1909 packages[i]->old_version = &spool[spkg->version];
1910 bitarray_set(&trans->syspkgs, spkg - spkgs, 0);
1912 if (!packages[i]->old_package) {
1913 packages[i]->name = strdup(packages[i]->name);
1914 packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG;
1919 packages[i]->new_package = upkg;
1920 packages[i]->name = &upool[upkg->name];
1921 packages[i]->new_version = &upool[upkg->version];
1923 if (up->name != upkg->name) {
1924 packages[i]->dep_package = &upool[upkg->name];
1925 packages[i]->dep_type = up->type;
1926 packages[i]->dep_property = &upool[up->name];
1927 packages[i]->dep_relation = up->relation;
1928 packages[i]->dep_version = &upool[up->version];
1932 packages[i]->old_package = spkg;
1933 packages[i]->old_version = &spool[spkg->version];
1934 if (versioncmp(&spool[spkg->version], &upool[up->version]) >= 0) {
1935 packages[i]->state = RAZOR_PACKAGE_UP_TO_DATE;
1939 bitarray_set(&trans->syspkgs, spkg - spkgs, 0);
1941 bitarray_set(&trans->uppkgs, upkg - upkgs, 1);
1943 if (!packages[i]->new_package) {
1944 packages[i]->name = strdup(packages[i]->name);
1945 packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG;
1953 provider_satisfies_requirement(struct razor_property *provider,
1954 const char *provider_strings,
1955 struct razor_property *requirement,
1956 const char *requirement_strings)
1959 const char *provided = &provider_strings[provider->version];
1960 const char *required = &requirement_strings[requirement->version];
1965 if (requirement->relation >= RAZOR_VERSION_EQUAL)
1971 cmp = versioncmp(provided, required);
1973 switch (requirement->relation) {
1974 case RAZOR_VERSION_LESS:
1977 case RAZOR_VERSION_LESS_OR_EQUAL:
1980 /* fall through: FIXME, make sure this is correct */
1982 case RAZOR_VERSION_EQUAL:
1986 /* "foo == 1.1" is satisfied by "foo 1.1-2" */
1987 len = strlen(required);
1988 if (!strncmp(required, provided, len) && provided[len] == '-')
1992 case RAZOR_VERSION_GREATER_OR_EQUAL:
1995 case RAZOR_VERSION_GREATER:
1999 /* shouldn't happen */
2003 static struct razor_package *
2004 find_package_for_file(struct razor_set *set, struct bitarray *pkgbits,
2005 const char *filename, int installed)
2007 struct razor_package *pkgs = set->packages.data;
2008 struct razor_entry *entry;
2011 if (filename[0] != '/')
2014 entry = find_entry(set, set->files.data, filename);
2018 for (p = list_first(&entry->packages, &set->package_pool); p; p = list_next(p)) {
2019 if (bitarray_get(pkgbits, p->data) == installed)
2020 return &pkgs[p->data];
2025 static struct razor_package *
2026 find_installed_package_for_file(struct razor_transaction *trans,
2027 const char *filename)
2029 struct razor_package *pkg;
2031 pkg = find_package_for_file(trans->system, &trans->syspkgs,
2034 pkg = find_package_for_file(trans->upstream, &trans->uppkgs,
2039 static struct razor_package *
2040 find_uninstalled_package_for_file(struct razor_transaction *trans,
2041 const char *filename)
2043 struct razor_package *pkg;
2045 pkg = find_package_for_file(trans->upstream, &trans->uppkgs,
2048 pkg = find_package_for_file(trans->system, &trans->syspkgs,
2053 static struct razor_property *
2054 skip_to_matching_property(struct razor_transaction *trans,
2055 struct razor_property *match,
2056 struct razor_property *prop)
2058 struct razor_set *mset, *pset;
2059 const char *ppool, *mpool;
2060 struct razor_property *prop_end;
2062 if (property_in_set(match, trans->system))
2063 mset = trans->system;
2065 mset = trans->upstream;
2067 if (property_in_set(prop, trans->system))
2068 pset = trans->system;
2069 else if (property_in_set(prop, trans->upstream))
2070 pset = trans->upstream;
2074 prop_end = pset->properties.data + pset->properties.size;
2075 ppool = pset->string_pool.data;
2076 mpool = mset->string_pool.data;
2078 while (prop < prop_end &&
2079 strcmp(&ppool[prop->name], &mpool[match->name]) < 0)
2084 static struct razor_package *
2085 find_package_matching(struct razor_transaction *trans, int installed,
2086 struct razor_property *prop,
2087 struct razor_property *req,
2088 struct razor_set *req_set)
2090 struct razor_set *set;
2091 struct bitarray *pkgbits;
2092 struct razor_package *pkgs;
2093 struct razor_property *props, *prop_end;
2094 enum razor_property_type match_type;
2097 int match_name = (req->type == RAZOR_PROPERTY_OBSOLETES);
2100 if (property_in_set(prop, trans->system)) {
2101 set = trans->system;
2102 pkgbits = &trans->syspkgs;
2103 } else if (property_in_set(prop, trans->upstream)) {
2104 set = trans->upstream;
2105 pkgbits = &trans->uppkgs;
2110 if (property_in_set(req, trans->system))
2111 req_set = trans->system;
2113 req_set = trans->upstream;
2115 rpool = req_set->string_pool.data;
2117 if (req->type == RAZOR_PROPERTY_PROVIDES)
2118 match_type = RAZOR_PROPERTY_CONFLICTS;
2120 match_type = RAZOR_PROPERTY_PROVIDES;
2122 pkgs = set->packages.data;
2123 props = set->properties.data;
2124 prop_end = set->properties.data + set->properties.size;
2125 pool = set->string_pool.data;
2127 /* Find first matching property */
2128 while (prop < prop_end &&
2129 strcmp(&pool[prop->name], &rpool[req->name]) < 0)
2131 if (prop == prop_end ||
2132 strcmp(&pool[prop->name], &rpool[req->name]) > 0)
2135 if (prop->type < match_type) {
2136 while (prop < prop_end && prop->type != match_type)
2139 while (prop >= props && prop->type != match_type)
2141 while (prop > props + 1 && (prop - 1)->name == prop->name &&
2142 (prop - 1)->type == match_type)
2146 /* Scan matching properties */
2147 while (prop < prop_end && prop->type == match_type &&
2148 strcmp(&pool[prop->name], &rpool[req->name]) == 0) {
2149 if (match_type == RAZOR_PROPERTY_PROVIDES)
2150 match = provider_satisfies_requirement(prop, pool, req, rpool);
2152 match = provider_satisfies_requirement(req, rpool, prop, pool);
2156 for (pkg = list_first(&prop->packages, &set->package_pool); pkg; pkg = list_next(pkg)) {
2157 if (bitarray_get(pkgbits, pkg->data) != installed)
2160 strcmp(&pool[pkgs[pkg->data].name],
2161 &rpool[req->name]) == 0)
2162 return &pkgs[pkg->data];
2171 static struct razor_package *
2172 find_installed_package_for_property(struct razor_transaction *trans,
2173 struct razor_property *sys_start,
2174 struct razor_property *up_start,
2175 struct razor_property *req)
2177 struct razor_package *pkg;
2179 pkg = find_package_matching(trans, 1, sys_start, req, NULL);
2181 pkg = find_package_matching(trans, 1, up_start, req, NULL);
2185 static struct razor_package *
2186 find_uninstalled_package_for_property(struct razor_transaction *trans,
2187 struct razor_property *sys_start,
2188 struct razor_property *up_start,
2189 struct razor_property *req)
2191 struct razor_package *pkg;
2193 pkg = find_package_matching(trans, 0, up_start, req, NULL);
2195 pkg = find_package_matching(trans, 0, sys_start, req, NULL);
2199 static struct razor_transaction_package *
2200 find_transaction_package(struct razor_transaction *trans, const char *name)
2202 struct razor_transaction_package *packages;
2205 packages = trans->packages.data;
2206 count = trans->packages.size / sizeof *packages;
2207 for (i = 0; i < count; i++) {
2208 if (packages[i].name && !strcmp(packages[i].name, name))
2209 return &packages[i];
2216 prop_is_being_installed(struct razor_transaction *trans,
2217 struct razor_property *prop)
2221 for (pkg = list_first(&prop->packages, &trans->upstream->package_pool); pkg; pkg = list_next(pkg)) {
2222 if (bitarray_get(&trans->uppkgs, pkg->data))
2229 prop_is_being_removed(struct razor_transaction *trans,
2230 struct razor_property *prop)
2234 for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) {
2235 if (bitarray_get(&trans->syspkgs, pkg->data))
2242 prop_is_being_updated(struct razor_transaction *trans,
2243 struct razor_property *prop)
2245 struct razor_package *packages = trans->system->packages.data;
2246 const char *pool = trans->system->string_pool.data;
2247 struct razor_transaction_package *tp;
2250 /* Assumes prop_is_being_removed returns true */
2252 for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) {
2253 tp = find_transaction_package(trans, &pool[packages[pkg->data].name]);
2254 if (tp && tp->state == RAZOR_PACKAGE_REMOVE)
2261 add_transaction_package(struct razor_transaction *trans,
2262 struct razor_package *new_package,
2263 struct razor_package *old_package,
2264 enum razor_transaction_package_state state,
2265 const char *req_package,
2266 struct razor_property *req_prop)
2268 struct razor_set *new_package_set, *old_package_set, *req_set;
2269 struct bitarray *reqpkgbits;
2270 struct razor_transaction_package *tp, *already;
2272 struct razor_package *pkgs;
2274 int contradiction = 0;
2276 if (package_in_set(new_package, trans->system))
2277 new_package_set = trans->system;
2279 new_package_set = trans->upstream;
2280 if (package_in_set(old_package, trans->system))
2281 old_package_set = trans->system;
2283 old_package_set = trans->upstream;
2284 if (property_in_set(req_prop, trans->system)) {
2285 req_set = trans->system;
2286 reqpkgbits = &trans->syspkgs;
2288 req_set = trans->upstream;
2289 reqpkgbits = &trans->uppkgs;
2293 pool = new_package_set->string_pool.data;
2294 already = find_transaction_package(trans, &pool[new_package->name]);
2296 if (already->new_package == new_package) {
2297 /* Already taken care of */
2299 } else if (new_package_set == trans->upstream &&
2300 already->state == RAZOR_PACKAGE_FORCED_UPDATE) {
2301 already->new_package = new_package;
2303 } else if (new_package_set == trans->upstream) {
2308 if (state != RAZOR_PACKAGE_CONTRADICTION)
2311 } else if (old_package) {
2312 pool = old_package_set->string_pool.data;
2313 already = find_transaction_package(trans, &pool[old_package->name]);
2315 if (already->old_package == old_package) {
2316 /* Already taken care of */
2318 } else if (old_package_set == trans->system) {
2319 already->old_package = old_package;
2324 if (state != RAZOR_PACKAGE_CONTRADICTION)
2328 state = RAZOR_PACKAGE_UNSATISFIABLE;
2330 tp = array_add(&trans->packages, sizeof *tp);
2331 memset(tp, 0, sizeof *tp);
2334 pool = new_package_set->string_pool.data;
2335 tp->new_package = new_package;
2336 tp->name = &pool[new_package->name];
2337 tp->new_version = &pool[new_package->version];
2339 pkgs = new_package_set->packages.data;
2342 pool = old_package_set->string_pool.data;
2343 tp->old_package = old_package;
2344 tp->name = &pool[old_package->name];
2345 tp->old_version = &pool[old_package->version];
2347 pkgs = old_package_set->packages.data;
2351 if (state != RAZOR_PACKAGE_INSTALL &&
2352 state != RAZOR_PACKAGE_FORCED_UPDATE &&
2353 state != RAZOR_PACKAGE_REMOVE &&
2354 state != RAZOR_PACKAGE_OBSOLETED)
2357 if (contradiction) {
2358 /* Do this now, after adding tp, so that it ends up
2359 * after both the INSTALL and the REMOVE in the array.
2361 add_transaction_package(trans, new_package, old_package,
2362 RAZOR_PACKAGE_CONTRADICTION,
2367 tp->dep_package = req_package;
2371 pool = req_set->string_pool.data;
2372 pkgs = req_set->packages.data;
2374 for (pkg = list_first(&req_prop->packages, &req_set->package_pool); pkg; pkg = list_next(pkg)) {
2375 if (bitarray_get(reqpkgbits, pkg->data))
2379 tp->dep_package = &pool[pkgs[pkg->data].name];
2382 tp->dep_type = req_prop->type;
2383 tp->dep_property = &pool[req_prop->name];
2384 tp->dep_relation = req_prop->relation;
2385 tp->dep_version = &pool[req_prop->version];
2389 razor_transaction_satisfy(struct razor_transaction *trans)
2391 struct razor_package *spkgs, *upkgs, *pkg;
2392 struct razor_property *sp, *sprops, *sprop_end;
2393 struct razor_property *up, *uprops, *uprop_end;
2394 struct razor_property *sr, *ur, *first_up;
2395 const char *spool, *upool, *removed_package;
2396 struct list *reqpkg;
2398 spkgs = trans->system->packages.data;
2399 sprops = trans->system->properties.data;
2400 sprop_end = trans->system->properties.data + trans->system->properties.size;
2401 spool = trans->system->string_pool.data;
2402 upkgs = trans->upstream->packages.data;
2403 uprops = trans->upstream->properties.data;
2404 uprop_end = trans->upstream->properties.data + trans->upstream->properties.size;
2405 upool = trans->upstream->string_pool.data;
2408 for (up = uprops; up < uprop_end; up++) {
2409 /* Skip 'up' ahead to a property of a package which is
2412 while (up < uprop_end &&
2413 !prop_is_being_installed(trans, up))
2415 if (up == uprop_end)
2417 sp = skip_to_matching_property(trans, up, sp);
2420 case RAZOR_PROPERTY_REQUIRES:
2421 if (!strncmp(&upool[up->name], "rpmlib(", 7))
2424 if (find_installed_package_for_property(trans, sp, up, up) ||
2425 find_installed_package_for_file(trans, &upool[up->name])) {
2426 /* Requires something that is either installed
2427 * or to-be-installed.
2432 /* See if we can install a new upstream provider */
2433 pkg = find_uninstalled_package_for_property(trans, sp, up, up);
2435 pkg = find_uninstalled_package_for_file(trans, &upool[up->name]);
2436 add_transaction_package(trans, pkg, NULL,
2437 RAZOR_PACKAGE_INSTALL,
2441 case RAZOR_PROPERTY_PROVIDES:
2442 /* find_installed_package_for_property works backwards
2443 * here, finding a *conflicting* installed package.
2445 pkg = find_installed_package_for_property(trans, sp, up, up);
2449 if (package_in_set(pkg, trans->system)) {
2450 /* pkg CONFLICTS with what 'up' PROVIDES. Try
2451 * finding an upgrade
2453 add_transaction_package(trans, NULL, pkg,
2454 RAZOR_PACKAGE_FORCED_UPDATE,
2455 &upool[up->name], sp);
2457 add_transaction_package(trans, NULL, pkg,
2458 RAZOR_PACKAGE_CONTRADICTION,
2463 case RAZOR_PROPERTY_CONFLICTS:
2464 pkg = find_installed_package_for_property(trans, sp, up, up);
2468 if (package_in_set(pkg, trans->system)) {
2469 /* Conflicts with something already installed.
2470 * Try to upgrade out.
2472 add_transaction_package(trans, NULL, pkg,
2473 RAZOR_PACKAGE_FORCED_UPDATE,
2476 add_transaction_package(trans, pkg, NULL,
2477 RAZOR_PACKAGE_CONTRADICTION,
2482 case RAZOR_PROPERTY_OBSOLETES:
2483 pkg = find_installed_package_for_property(trans, sp, up, up);
2485 /* If pkg is to-be-installed, this
2486 * will add a CONTRADICTION error as well.
2488 add_transaction_package(trans, NULL, pkg,
2489 RAZOR_PACKAGE_OBSOLETED,
2501 for (sp = sprops; sp < sprop_end; sp++) {
2502 /* Skip 'sp' ahead to a PROVIDES of a package which is
2505 while (sp < sprop_end &&
2506 (sp->type != RAZOR_PROPERTY_PROVIDES ||
2507 !prop_is_being_removed(trans, sp)))
2509 if (sp == sprop_end)
2512 removed_package = &spool[spkgs[list_first(&sp->packages, &trans->system->package_pool)->data].name];
2514 /* Skip 'up' to match */
2515 up = skip_to_matching_property(trans, sp, up);
2518 /* If the package is just being upgraded, we may
2519 * already be installing an identical PROVIDES, so
2522 while (up < uprop_end &&
2523 strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
2524 (up->type != RAZOR_PROPERTY_PROVIDES ||
2525 sp->relation != up->relation ||
2526 strcmp(&spool[sp->name], &upool[up->name]) != 0))
2528 if (up < uprop_end &&
2529 up->type == RAZOR_PROPERTY_PROVIDES &&
2530 strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
2531 sp->relation == up->relation &&
2532 strcmp(&spool[sp->version], &upool[up->version]) == 0 &&
2533 prop_is_being_installed(trans, up)) {
2539 /* For all still-installed packages that require
2540 * sp->name, see if they are satisfied by any other
2541 * still-installed or to-be-installed property. If
2542 * not, either remove or attempt to update the
2543 * package, depending on why the required property has
2547 while (sr > sprops + 1 && (sr - 1)->name == sr->name)
2549 for (; sr->type == RAZOR_PROPERTY_REQUIRES; sr++) {
2550 if (prop_is_being_removed(trans, sr))
2552 if (find_installed_package_for_property(trans, sp, up, sr))
2555 for (reqpkg = list_first(&sr->packages, &trans->system->package_pool); reqpkg; reqpkg = list_next(reqpkg)) {
2556 if (!bitarray_get(&trans->syspkgs, reqpkg->data))
2558 pkg = &spkgs[reqpkg->data];
2559 if (prop_is_being_updated(trans, sp)) {
2560 add_transaction_package(trans, NULL, pkg,
2561 RAZOR_PACKAGE_FORCED_UPDATE,
2562 removed_package, NULL);
2564 add_transaction_package(trans, NULL, pkg,
2565 RAZOR_PACKAGE_REMOVE,
2566 removed_package, sr);
2574 razor_transaction_install_package(struct razor_transaction *transaction,
2575 struct razor_package *package)
2577 add_transaction_package(transaction, package, NULL,
2578 RAZOR_PACKAGE_INSTALL, NULL, NULL);
2582 razor_transaction_remove_package(struct razor_transaction *transaction,
2583 struct razor_package *package)
2585 add_transaction_package(transaction, NULL, package,
2586 RAZOR_PACKAGE_REMOVE, NULL, NULL);
2590 razor_transaction_update_all(struct razor_transaction *trans)
2592 struct razor_package *sp, *spkgs, *send, *up, *upkgs, *uend;
2593 const char *spool, *upool;
2595 spkgs = trans->system->packages.data;
2596 send = trans->system->packages.data + trans->system->packages.size;
2597 spool = trans->system->string_pool.data;
2598 up = upkgs = trans->upstream->packages.data;
2599 uend = trans->upstream->packages.data + trans->upstream->packages.size;
2600 upool = trans->upstream->string_pool.data;
2602 for (sp = spkgs; sp < send; sp++) {
2603 while (up < uend && strcmp(&spool[sp->name], &upool[up->name]) > 0)
2605 if (strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
2606 versioncmp(&spool[sp->version], &upool[up->version]) < 0) {
2607 add_transaction_package(trans, up, sp,
2608 RAZOR_PACKAGE_INSTALL,
2614 struct razor_transaction *
2615 razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
2617 struct razor_transaction *trans;
2620 trans = zalloc(sizeof *trans);
2622 trans->system = system;
2623 trans->upstream = upstream ? upstream : razor_set_create();
2624 array_init(&trans->packages);
2625 count = trans->system->packages.size / sizeof (struct razor_package);
2626 bitarray_init(&trans->syspkgs, count, 1);
2627 count = trans->upstream->packages.size / sizeof (struct razor_package);
2628 bitarray_init(&trans->uppkgs, count, 0);
2634 resolve_transaction(struct razor_transaction *trans)
2638 if (trans->package_count > 0)
2639 /* Already did this, return. */
2643 end = trans->packages.size / sizeof (struct razor_transaction_package);
2645 while (start != end) {
2646 resolve_new_packages(trans, start, end);
2650 razor_transaction_satisfy(trans);
2653 end = trans->packages.size / sizeof (struct razor_transaction_package);
2656 trans->package_count = end;
2659 const char * const razor_version_relations[] = {
2660 /* same order as enum razor_version_relation */
2661 "<", "<=", "=", ">=", ">"
2664 const char * const razor_property_types[] = {
2665 /* same order as enum razor_property_type */
2666 "requires", "provides", "conflicts with", "obsoletes"
2670 print_requirement(struct razor_transaction_package *p)
2672 if (p->dep_type == RAZOR_PROPERTY_CONFLICTS &&
2673 !strcmp(p->dep_package, p->name)) {
2674 printf(" because %s %s conflicts with %s",
2675 p->name, p->old_version, p->dep_property);
2676 if (*p->dep_version) {
2678 razor_version_relations[p->dep_relation],
2682 if (strcmp(p->name, p->dep_package) != 0)
2683 printf(" for %s", p->dep_package);
2684 if (*p->dep_version) {
2685 printf(", which %s %s %s %s",
2686 razor_property_types[p->dep_type],
2688 razor_version_relations[p->dep_relation],
2690 } else if (strcmp(p->dep_property, p->name) != 0) {
2691 printf(", which %s %s",
2692 razor_property_types[p->dep_type],
2699 razor_transaction_resolve(struct razor_transaction *trans)
2701 struct razor_transaction_package *p, *pend, *tps;
2702 int errors_only = 0;
2704 resolve_transaction(trans);
2706 tps = trans->packages.data;
2707 pend = trans->packages.data + trans->packages.size;
2708 for (p = trans->packages.data; p < pend; p++) {
2710 case RAZOR_PACKAGE_INSTALL:
2714 printf("Installing %s %s", p->name, p->new_version);
2716 print_requirement(p);
2720 case RAZOR_PACKAGE_FORCED_UPDATE:
2724 printf("Updating %s to %s due to update of %s\n",
2725 p->name, p->new_version, p->dep_package);
2728 case RAZOR_PACKAGE_REMOVE:
2731 printf("Removing %s %s", p->name, p->old_version);
2732 if (p->dep_package) {
2733 printf(" which required %s",
2735 if (strcmp(p->dep_property, p->dep_package) != 0)
2736 printf(" for %s", p->dep_property);
2741 case RAZOR_PACKAGE_OBSOLETED:
2744 printf("Removing %s %s", p->name, p->old_version);
2745 if (p->dep_package) {
2746 printf(" which is obsoleted by %s",
2752 case RAZOR_PACKAGE_INSTALL_UNAVAILABLE:
2753 printf("Error: can't find %s", p->name);
2754 if (p->dep_package) {
2755 printf(" (which is required");
2756 print_requirement(p);
2763 case RAZOR_PACKAGE_UPDATE_UNAVAILABLE:
2764 printf("Error: can't find an updated version of %s (which must be updated due to update of %s)\n",
2765 p->name, p->dep_package);
2769 case RAZOR_PACKAGE_REMOVE_NOT_INSTALLED:
2770 printf("Error: can't remove %s: not installed\n", p->name);
2774 case RAZOR_PACKAGE_UP_TO_DATE:
2775 printf("Error: can't update %s", p->name);
2777 printf(" (which must be updated due to update of %s)", p->dep_package);
2778 printf(": %s is most recent version\n", p->old_version);
2782 case RAZOR_PACKAGE_CONTRADICTION:
2783 printf("Error: package %s is marked for both installation and removal\n", p->name);
2787 case RAZOR_PACKAGE_OLD_CONFLICT:
2788 printf("Error: can't install %s, because installed package %s conflicts with ",
2789 p->name, p->dep_package);
2790 if (*p->dep_version) {
2793 razor_version_relations[p->dep_relation],
2802 case RAZOR_PACKAGE_NEW_CONFLICT:
2803 printf("Error: can't install %s, because it conflicts with %s",
2804 p->name, p->dep_package);
2805 if (*p->dep_version) {
2807 razor_version_relations[p->dep_relation],
2815 case RAZOR_PACKAGE_UNSATISFIABLE:
2816 printf("Error: can't find package for %s", p->dep_property);
2817 if (*p->dep_version) {
2819 razor_version_relations[p->dep_relation],
2822 printf(" which is required by %s\n",
2828 /* Shouldn't actually happen */
2833 return trans->errors;
2837 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
2839 enum razor_version_relation rel,
2840 const char *version)
2842 struct razor_transaction_package *p, *end;
2844 end = trans->packages.data + trans->packages.size;
2845 for (p = trans->packages.data; p < end; p++) {
2846 if (p->state != RAZOR_PACKAGE_UNSATISFIABLE)
2848 if (strcmp(name, p->dep_property) != 0 ||
2849 rel != p->dep_relation ||
2850 strcmp(version, p->dep_version) != 0)
2860 razor_transaction_finish(struct razor_transaction *trans)
2862 struct array install_packages, remove_packages;
2863 struct razor_merger *merger;
2864 struct razor_package *pkg, *i, *iend, *r, *rend, *s, *send;
2865 struct razor_set *set;
2866 struct source *source1, *source2;
2867 char *spool, *ipool, *rpool;
2869 struct razor_transaction_package *p, *end;
2876 /* Sort the transaction packages into two arrays */
2877 array_init(&install_packages);
2878 array_init(&remove_packages);
2880 end = trans->packages.data + trans->packages.size;
2881 for (p = trans->packages.data; p < end; p++) {
2882 if (p->new_package) {
2883 pkg = array_add(&install_packages, sizeof *pkg);
2884 *pkg = *p->new_package;
2886 pkg = array_add(&remove_packages, sizeof *pkg);
2887 *pkg = *p->old_package;
2890 map = razor_qsort_with_data(install_packages.data,
2891 install_packages.size / sizeof *pkg,
2896 map = razor_qsort_with_data(remove_packages.data,
2897 remove_packages.size / sizeof *pkg,
2903 merger = razor_merger_create(trans->system, trans->upstream);
2905 source1 = &merger->source1;
2906 source2 = &merger->source2;
2908 i = install_packages.data;
2909 iend = install_packages.data + install_packages.size;
2910 ipool = trans->upstream->string_pool.data;
2912 r = remove_packages.data;
2913 rend = remove_packages.data + remove_packages.size;
2914 rpool = trans->system->string_pool.data;
2916 s = trans->system->packages.data;
2917 send = trans->system->packages.data + trans->system->packages.size;
2918 spool = trans->system->string_pool.data;
2920 while (s < send || i < iend) {
2921 /* Check if s is being removed */
2922 if (s < send && r < rend &&
2923 s->name == r->name && s->version && r->version) {
2929 if (s < send && i < iend)
2930 cmp = strcmp(&spool[s->name], &ipool[i->name]);
2936 add_package(merger, s, source1, 0);
2938 } else if (cmp == 0) {
2939 add_package(merger, i, source2, UPSTREAM_SOURCE);
2943 add_package(merger, i, source2, UPSTREAM_SOURCE);
2948 array_release(&install_packages);
2949 array_release(&remove_packages);
2951 set = razor_merger_finish(merger);
2952 razor_transaction_destroy(trans);
2958 razor_transaction_destroy(struct razor_transaction *trans)
2960 struct razor_transaction_package *p, *end;
2962 end = trans->packages.data + trans->packages.size;
2963 for (p = trans->packages.data; p < end; p++) {
2964 if (!p->dep_package &&
2965 (p->state == RAZOR_PACKAGE_INSTALL_UNAVAILABLE ||
2966 p->state == RAZOR_PACKAGE_REMOVE_NOT_INSTALLED))
2967 free((char *)p->name);
2970 array_release(&trans->packages);
2971 bitarray_release(&trans->syspkgs);
2972 bitarray_release(&trans->uppkgs);
2975 /* FIXME: free upstream if it was created as an empty set */