Add read-only open function for razor_root and support --root in rpm wrapper.
2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <sys/types.h>
37 #include "razor-internal.h"
40 struct razor_set_section {
46 struct razor_set_header {
49 struct razor_set_section sections[0];
52 #define RAZOR_MAGIC 0x7a7a7a7a
53 #define RAZOR_VERSION 1
55 #define RAZOR_STRING_POOL 0
56 #define RAZOR_PACKAGES 1
57 #define RAZOR_PROPERTIES 2
59 #define RAZOR_PACKAGE_POOL 4
60 #define RAZOR_PROPERTY_POOL 5
61 #define RAZOR_FILE_POOL 6
63 struct razor_package {
68 struct list_head properties;
69 struct list_head files;
72 struct razor_property {
75 enum razor_property_type type : 2;
76 enum razor_version_relation relation : 32;
78 struct list_head packages;
85 struct list_head packages;
88 #define RAZOR_ENTRY_LAST 0x80
91 struct array string_pool;
92 struct array packages;
93 struct array properties;
95 struct array package_pool;
96 struct array property_pool;
97 struct array file_pool;
98 struct razor_set_header *header;
101 struct import_entry {
106 struct import_directory {
107 uint32_t name, count;
109 struct array packages;
110 struct import_directory *last;
113 struct razor_importer {
114 struct razor_set *set;
115 struct hashtable table;
116 struct razor_package *package;
117 struct array properties;
119 struct array file_requires;
133 struct razor_set_section razor_sections[] = {
134 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
135 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
136 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
137 { RAZOR_FILES, offsetof(struct razor_set, files) },
138 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
139 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
140 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
144 razor_set_create(void)
146 struct razor_set *set;
147 struct razor_entry *e;
150 set = zalloc(sizeof *set);
152 e = array_add(&set->files, sizeof *e);
153 empty = array_add(&set->string_pool, 1);
156 e->flags = RAZOR_ENTRY_LAST;
158 list_set_empty(&e->packages);
164 razor_set_open(const char *filename)
166 struct razor_set *set;
167 struct razor_set_section *s;
172 set = zalloc(sizeof *set);
173 fd = open(filename, O_RDONLY);
174 if (fstat(fd, &stat) < 0)
176 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
177 if (set->header == MAP_FAILED) {
182 for (s = set->header->sections; ~s->type; s++) {
183 if (s->type >= ARRAY_SIZE(razor_sections))
185 if (s->type != razor_sections[s->type].type)
187 array = (void *) set + razor_sections[s->type].offset;
188 array->data = (void *) set->header + s->offset;
189 array->size = s->size;
190 array->alloc = s->size;
198 razor_set_destroy(struct razor_set *set)
205 for (i = 0; set->header->sections[i].type; i++)
207 size = set->header->sections[i].type;
208 munmap(set->header, size);
210 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
211 a = (void *) set + razor_sections[i].offset;
220 razor_set_write_to_fd(struct razor_set *set, int fd)
223 struct razor_set_header *header = (struct razor_set_header *) data;
228 memset(data, 0, sizeof data);
229 header->magic = RAZOR_MAGIC;
230 header->version = RAZOR_VERSION;
231 offset = sizeof data;
233 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
234 if (razor_sections[i].type != i)
236 a = (void *) set + razor_sections[i].offset;
237 header->sections[i].type = i;
238 header->sections[i].offset = offset;
239 header->sections[i].size = a->size;
240 offset += ALIGN(a->size, 4096);
243 header->sections[i].type = ~0;
244 header->sections[i].offset = 0;
245 header->sections[i].size = 0;
247 razor_write(fd, data, sizeof data);
248 memset(data, 0, sizeof data);
249 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
250 if (razor_sections[i].type != i)
252 a = (void *) set + razor_sections[i].offset;
253 razor_write(fd, a->data, a->size);
254 razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
261 razor_set_write(struct razor_set *set, const char *filename)
265 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
269 status = razor_set_write_to_fd(set, fd);
279 razor_build_evr(char *evr_buf, int size, const char *epoch,
280 const char *version, const char *release)
284 if (!version || !*version) {
289 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
290 len = snprintf(evr_buf, size, "%s:", epoch);
294 len = snprintf(evr_buf, size, "%s", version);
297 if (release && *release)
298 snprintf(evr_buf, size, "-%s", release);
302 razor_importer_begin_package(struct razor_importer *importer,
307 struct razor_package *p;
309 p = array_add(&importer->set->packages, sizeof *p);
310 p->name = hashtable_tokenize(&importer->table, name);
312 p->version = hashtable_tokenize(&importer->table, version);
313 p->arch = hashtable_tokenize(&importer->table, arch);
315 importer->package = p;
316 array_init(&importer->properties);
320 razor_importer_finish_package(struct razor_importer *importer)
322 list_set_array(&importer->package->properties,
323 &importer->set->property_pool,
324 &importer->properties,
327 array_release(&importer->properties);
331 razor_importer_add_property(struct razor_importer *importer,
333 enum razor_version_relation relation,
335 enum razor_property_type type)
337 struct razor_property *p;
340 p = array_add(&importer->set->properties, sizeof *p);
341 p->name = hashtable_tokenize(&importer->table, name);
344 p->relation = relation;
345 p->version = hashtable_tokenize(&importer->table, version);
346 list_set_ptr(&p->packages, importer->package -
347 (struct razor_package *) importer->set->packages.data);
349 r = array_add(&importer->properties, sizeof *r);
350 *r = p - (struct razor_property *) importer->set->properties.data;
352 if (type == RAZOR_PROPERTY_REQUIRES && *name == '/') {
353 r = array_add(&importer->file_requires, sizeof *r);
359 razor_importer_add_file(struct razor_importer *importer, const char *name)
361 struct import_entry *e;
363 e = array_add(&importer->files, sizeof *e);
365 e->package = importer->package -
366 (struct razor_package *) importer->set->packages.data;
367 e->name = strdup(name);
370 struct razor_importer *
371 razor_importer_new(void)
373 struct razor_importer *importer;
375 importer = zalloc(sizeof *importer);
376 importer->set = razor_set_create();
377 hashtable_init(&importer->table, &importer->set->string_pool);
382 /* Destroy an importer without creating the set. */
384 razor_importer_destroy(struct razor_importer *importer)
386 /* FIXME: write this */
390 versioncmp(const char *s1, const char *s2)
396 n1 = strtol(s1, (char **) &p1, 10);
397 n2 = strtol(s2, (char **) &p2, 10);
399 /* Epoch; if one but not the other has an epoch set, default
400 * the epoch-less version to 0. */
401 res = (*p1 == ':') - (*p2 == ':');
406 } else if (res > 0) {
419 if (isdigit(*p1) && isdigit(*p2))
420 return versioncmp(p1, p2);
427 compare_packages(const void *p1, const void *p2, void *data)
429 const struct razor_package *pkg1 = p1, *pkg2 = p2;
430 struct razor_set *set = data;
431 char *pool = set->string_pool.data;
433 /* FIXME: what if the flags are different? */
434 if (pkg1->name == pkg2->name)
435 return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
437 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
441 compare_properties(const void *p1, const void *p2, void *data)
443 const struct razor_property *prop1 = p1, *prop2 = p2;
444 struct razor_set *set = data;
445 char *pool = set->string_pool.data;
447 if (prop1->name != prop2->name)
448 return strcmp(&pool[prop1->name], &pool[prop2->name]);
449 else if (prop1->type != prop2->type)
450 return prop1->type - prop2->type;
451 else if (prop1->relation != prop2->relation)
452 return prop1->relation - prop2->relation;
454 return versioncmp(&pool[prop1->version], &pool[prop2->version]);
458 uniqueify_properties(struct razor_set *set)
460 struct razor_property *rp, *up, *rp_end;
461 struct array *pkgs, *p;
463 uint32_t *map, *rmap;
464 int i, count, unique;
466 count = set->properties.size / sizeof(struct razor_property);
467 map = razor_qsort_with_data(set->properties.data,
469 sizeof(struct razor_property),
473 rp_end = set->properties.data + set->properties.size;
474 rmap = malloc(count * sizeof *map);
475 pkgs = zalloc(count * sizeof *pkgs);
476 for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
477 if (rp->name != up->name || rp->type != up->type ||
478 rp->relation != up->relation || rp->version != up->version) {
483 up->relation = rp->relation;
484 up->version = rp->version;
487 unique = up - (struct razor_property *) set->properties.data;
488 rmap[map[i]] = unique;
489 r = array_add(&pkgs[unique], sizeof *r);
496 set->properties.size = (void *) up - set->properties.data;
498 for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
499 list_set_array(&rp->packages, &set->package_pool, p, 0);
509 compare_filenames(const void *p1, const void *p2, void *data)
511 const struct import_entry *e1 = p1;
512 const struct import_entry *e2 = p2;
513 const char *n1 = e1->name;
514 const char *n2 = e2->name;
516 /* Need to make sure that the contents of a directory
517 * are sorted immediately after it. So "foo/bar" has to
518 * sort before "foo.conf"
520 * FIXME: this is about 60% slower than strcmp
524 return *n2 == '/' ? 1 : -1;
526 return *n1 == '/' ? -1 : 1;
539 count_entries(struct import_directory *d)
541 struct import_directory *p, *end;
544 end = d->files.data + d->files.size;
548 d->count += p->count + 1;
554 serialize_files(struct razor_set *set,
555 struct import_directory *d, struct array *array)
557 struct import_directory *p, *end;
558 struct razor_entry *e = NULL;
562 end = d->files.data + d->files.size;
563 s = array->size / sizeof *e + d->files.size / sizeof *p;
565 e = array_add(array, sizeof *e);
568 e->start = p->count > 0 ? s : 0;
571 list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
572 array_release(&p->packages);
576 e->flags |= RAZOR_ENTRY_LAST;
579 end = d->files.data + d->files.size;
581 serialize_files(set, p, array);
587 remap_property_package_links(struct array *properties, uint32_t *rmap)
589 struct razor_property *p, *end;
591 end = properties->data + properties->size;
592 for (p = properties->data; p < end; p++)
593 list_remap_head(&p->packages, rmap);
597 build_file_tree(struct razor_importer *importer)
599 int count, i, length;
600 struct import_entry *filenames;
604 struct import_directory *d, root;
605 struct razor_entry *e;
607 count = importer->files.size / sizeof (struct import_entry);
608 razor_qsort_with_data(importer->files.data,
610 sizeof (struct import_entry),
614 root.name = hashtable_tokenize(&importer->table, "");
615 array_init(&root.files);
616 array_init(&root.packages);
619 filenames = importer->files.data;
620 for (i = 0; i < count; i++) {
621 f = filenames[i].name;
628 end = strchr(f, '/');
632 memcpy(dirname, f, length);
633 dirname[length] ='\0';
634 name = hashtable_tokenize(&importer->table, dirname);
635 if (d->last == NULL || d->last->name != name) {
636 d->last = array_add(&d->files, sizeof *d);
637 d->last->name = name;
638 d->last->last = NULL;
639 array_init(&d->last->files);
640 array_init(&d->last->packages);
648 r = array_add(&d->packages, sizeof *r);
649 *r = filenames[i].package;
650 free(filenames[i].name);
653 count_entries(&root);
654 e = importer->set->files.data;
656 e->flags = RAZOR_ENTRY_LAST;
657 e->start = importer->files.size ? 1 : 0;
658 list_set_empty(&e->packages);
660 serialize_files(importer->set, &root, &importer->set->files);
662 array_release(&importer->files);
665 static struct razor_entry *
666 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern);
669 list_to_array(struct list *list, struct array *array)
674 item = array_add(array, sizeof *item);
676 list = list_next(list);
681 compare_file_requires(const void *p1, const void *p2, void *data)
683 uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
684 const char *pool = data;
686 return strcmp(&pool[*f1], &pool[*f2]);
690 find_file_provides(struct razor_importer *importer)
692 struct razor_property *prop;
693 struct razor_entry *top, *entry;
694 struct razor_package *packages;
695 struct array pkgprops;
697 uint32_t *req, *req_start, *req_end;
698 uint32_t *map, *newprop;
701 pool = importer->set->string_pool.data;
702 packages = importer->set->packages.data;
703 top = importer->set->files.data;
705 req = req_start = importer->file_requires.data;
706 req_end = importer->file_requires.data + importer->file_requires.size;
707 map = razor_qsort_with_data(req, req_end - req, sizeof *req,
708 compare_file_requires, pool);
711 for (req = req_start; req < req_end; req++) {
712 if (req > req_start && req[0] == req[-1])
714 entry = find_entry(importer->set, top, &pool[*req]);
718 for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
719 prop = array_add(&importer->set->properties, sizeof *prop);
721 prop->type = RAZOR_PROPERTY_PROVIDES;
722 prop->relation = RAZOR_VERSION_EQUAL;
723 prop->version = hashtable_tokenize(&importer->table, "");
724 list_set_ptr(&prop->packages, pkg->data);
726 /* Update property list of pkg */
727 array_init(&pkgprops);
728 list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
729 newprop = array_add(&pkgprops, sizeof *newprop);
730 *newprop = prop - (struct razor_property *)importer->set->properties.data;
731 list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
732 array_release(&pkgprops);
736 array_release(&importer->file_requires);
740 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
742 struct razor_package *p, *packages;
744 struct razor_entry *e, *end;
749 count = set->packages.size / sizeof *p;
750 pkgs = zalloc(count * sizeof *pkgs);
752 end = set->files.data + set->files.size;
753 for (e = set->files.data; e < end; e++) {
754 list_remap_head(&e->packages, rmap);
755 r = list_first(&e->packages, &set->package_pool);
757 q = array_add(&pkgs[r->data], sizeof *q);
758 *q = e - (struct razor_entry *) set->files.data;
763 packages = set->packages.data;
764 for (i = 0; i < count; i++) {
765 list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
766 array_release(&pkgs[i]);
772 razor_importer_finish(struct razor_importer *importer)
774 struct razor_set *set;
775 uint32_t *map, *rmap;
778 build_file_tree(importer);
779 find_file_provides(importer);
781 map = uniqueify_properties(importer->set);
782 list_remap_pool(&importer->set->property_pool, map);
785 count = importer->set->packages.size / sizeof(struct razor_package);
786 map = razor_qsort_with_data(importer->set->packages.data,
788 sizeof(struct razor_package),
792 rmap = malloc(count * sizeof *rmap);
793 for (i = 0; i < count; i++)
797 list_remap_pool(&importer->set->package_pool, rmap);
798 build_package_file_lists(importer->set, rmap);
799 remap_property_package_links(&importer->set->properties, rmap);
803 hashtable_release(&importer->table);
809 struct razor_package_iterator {
810 struct razor_set *set;
811 struct razor_package *package, *end;
816 static struct razor_package_iterator *
817 razor_package_iterator_create_with_index(struct razor_set *set,
820 struct razor_package_iterator *pi;
822 pi = zalloc(sizeof *pi);
829 struct razor_package_iterator *
830 razor_package_iterator_create(struct razor_set *set)
832 struct razor_package_iterator *pi;
834 pi = zalloc(sizeof *pi);
836 pi->end = set->packages.data + set->packages.size;
837 pi->package = set->packages.data;
843 razor_package_iterator_init_for_property(struct razor_package_iterator *pi,
844 struct razor_set *set,
845 struct razor_property *property)
847 memset(pi, 0, sizeof *pi);
849 pi->index = list_first(&property->packages, &set->package_pool);
852 struct razor_package_iterator *
853 razor_package_iterator_create_for_property(struct razor_set *set,
854 struct razor_property *property)
858 index = list_first(&property->packages, &set->package_pool);
859 return razor_package_iterator_create_with_index(set, index);
863 razor_package_iterator_next(struct razor_package_iterator *pi,
864 struct razor_package **package,
866 const char **version,
871 struct razor_package *p, *packages;
876 } else if (pi->index) {
877 packages = pi->set->packages.data;
878 p = &packages[pi->index->data];
879 pi->index = list_next(pi->index);
885 pool = pi->set->string_pool.data;
887 *name = &pool[p->name];
888 *version = &pool[p->version];
889 *arch = &pool[p->arch];
898 razor_package_iterator_destroy(struct razor_package_iterator *pi)
906 struct razor_package *
907 razor_set_get_package(struct razor_set *set, const char *package)
909 struct razor_package_iterator *pi;
910 struct razor_package *p;
911 const char *name, *version, *arch;
913 pi = razor_package_iterator_create(set);
914 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
915 if (strcmp(package, name) == 0)
918 razor_package_iterator_destroy(pi);
923 struct razor_property_iterator {
924 struct razor_set *set;
925 struct razor_property *property, *end;
929 struct razor_property_iterator *
930 razor_property_iterator_create(struct razor_set *set,
931 struct razor_package *package)
933 struct razor_property_iterator *pi;
935 pi = zalloc(sizeof *pi);
939 pi->index = list_first(&package->properties,
940 &set->property_pool);
942 pi->property = set->properties.data;
943 pi->end = set->properties.data + set->properties.size;
950 razor_property_iterator_next(struct razor_property_iterator *pi,
951 struct razor_property **property,
953 enum razor_version_relation *relation,
954 const char **version,
955 enum razor_property_type *type)
959 struct razor_property *p, *properties;
964 } else if (pi->index) {
965 properties = pi->set->properties.data;
966 p = &properties[pi->index->data];
967 pi->index = list_next(pi->index);
973 pool = pi->set->string_pool.data;
975 *name = &pool[p->name];
976 *relation = p->relation;
977 *version = &pool[p->version];
987 razor_property_iterator_destroy(struct razor_property_iterator *pi)
992 static struct razor_entry *
993 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
995 struct razor_entry *e;
996 const char *n, *pool = set->string_pool.data;
999 e = (struct razor_entry *) set->files.data + dir->start;
1002 if (strcmp(pattern + 1, n) == 0)
1005 if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
1006 pattern[len + 1] == '/') {
1007 return find_entry(set, e, pattern + len + 1);
1009 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1015 list_dir(struct razor_set *set, struct razor_entry *dir,
1016 char *prefix, const char *pattern)
1018 struct razor_entry *e;
1019 const char *n, *pool = set->string_pool.data;
1021 e = (struct razor_entry *) set->files.data + dir->start;
1024 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
1026 printf("%s/%s\n", prefix, n);
1028 char *sub = prefix + strlen (prefix);
1030 strcpy (sub + 1, n);
1031 list_dir(set, e, prefix, pattern);
1034 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1038 razor_set_list_files(struct razor_set *set, const char *pattern)
1040 struct razor_entry *e;
1041 char buffer[512], *p, *base;
1043 if (pattern == NULL || !strcmp (pattern, "/")) {
1045 list_dir(set, set->files.data, buffer, NULL);
1049 strcpy(buffer, pattern);
1050 e = find_entry(set, set->files.data, buffer);
1051 if (e && e->start > 0) {
1054 p = strrchr(buffer, '/');
1062 e = find_entry(set, set->files.data, buffer);
1064 list_dir(set, e, buffer, base);
1067 struct razor_package_iterator *
1068 razor_package_iterator_create_for_file(struct razor_set *set,
1069 const char *filename)
1071 struct razor_entry *entry;
1074 entry = find_entry(set, set->files.data, filename);
1078 index = list_first(&entry->packages, &set->package_pool);
1079 return razor_package_iterator_create_with_index(set, index);
1082 static struct list *
1083 list_package_files(struct razor_set *set, struct list *r,
1084 struct razor_entry *dir, uint32_t end,
1087 struct razor_entry *e, *f, *entries;
1088 uint32_t next, file;
1092 entries = (struct razor_entry *) set->files.data;
1093 pool = set->string_pool.data;
1095 e = entries + dir->start;
1097 if (entries + r->data == e) {
1098 printf("%s/%s\n", prefix, pool + e->name);
1105 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1107 e = entries + dir->start;
1112 if (e->flags & RAZOR_ENTRY_LAST)
1116 while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
1125 if (e->start <= file && file < next) {
1126 len = strlen(prefix);
1128 strcpy(prefix + len + 1, pool + e->name);
1129 r = list_package_files(set, r, e, next, prefix);
1132 } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
1138 razor_set_list_package_files(struct razor_set *set, const char *name)
1140 struct razor_package *package;
1145 package = razor_set_get_package(set, name);
1147 r = list_first(&package->files, &set->file_pool);
1148 end = set->files.size / sizeof (struct razor_entry);
1150 list_package_files(set, r, set->files.data, end, buffer);
1153 #define UPSTREAM_SOURCE 0x80
1156 struct razor_set *set;
1157 uint32_t *property_map;
1161 struct razor_merger {
1162 struct razor_set *set;
1163 struct hashtable table;
1164 struct source source1;
1165 struct source source2;
1168 static struct razor_merger *
1169 razor_merger_create(struct razor_set *set1, struct razor_set *set2)
1171 struct razor_merger *merger;
1175 merger = zalloc(sizeof *merger);
1176 merger->set = razor_set_create();
1177 hashtable_init(&merger->table, &merger->set->string_pool);
1179 merger->source1.set = set1;
1180 count = set1->properties.size / sizeof (struct razor_property);
1181 size = count * sizeof merger->source1.property_map[0];
1182 merger->source1.property_map = zalloc(size);
1183 count = set1->files.size / sizeof (struct razor_entry);
1184 size = count * sizeof merger->source1.file_map[0];
1185 merger->source1.file_map = zalloc(size);
1187 merger->source2.set = set2;
1188 count = set2->properties.size / sizeof (struct razor_property);
1189 size = count * sizeof merger->source2.property_map[0];
1190 merger->source2.property_map = zalloc(size);
1191 count = set2->files.size / sizeof (struct razor_entry);
1192 size = count * sizeof merger->source2.file_map[0];
1193 merger->source2.file_map = zalloc(size);
1199 razor_merger_add_package(struct razor_merger *merger,
1200 struct razor_package *package)
1204 struct razor_package *p;
1205 struct razor_set *set1;
1206 struct source *source;
1209 set1 = merger->source1.set;
1210 if (set1->packages.data <= (void *) package &&
1211 (void *) package < set1->packages.data + set1->packages.size) {
1212 source = &merger->source1;
1215 source = &merger->source2;
1216 flags = UPSTREAM_SOURCE;
1219 pool = source->set->string_pool.data;
1220 p = array_add(&merger->set->packages, sizeof *p);
1221 p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
1223 p->version = hashtable_tokenize(&merger->table,
1224 &pool[package->version]);
1225 p->arch = hashtable_tokenize(&merger->table,
1226 &pool[package->arch]);
1228 p->properties = package->properties;
1229 r = list_first(&package->properties, &source->set->property_pool);
1231 source->property_map[r->data] = 1;
1235 p->files = package->files;
1236 r = list_first(&package->files, &source->set->file_pool);
1238 source->file_map[r->data] = 1;
1244 add_property(struct razor_merger *merger,
1245 const char *name, enum razor_version_relation relation,
1246 const char *version, int type)
1248 struct razor_property *p;
1250 p = array_add(&merger->set->properties, sizeof *p);
1251 p->name = hashtable_tokenize(&merger->table, name);
1254 p->relation = relation;
1255 p->version = hashtable_tokenize(&merger->table, version);
1257 return p - (struct razor_property *) merger->set->properties.data;
1261 merge_properties(struct razor_merger *merger)
1263 struct razor_property *p1, *p2;
1264 struct razor_set *set1, *set2;
1265 uint32_t *map1, *map2;
1266 int i, j, cmp, count1, count2;
1267 char *pool1, *pool2;
1269 set1 = merger->source1.set;
1270 set2 = merger->source2.set;
1271 map1 = merger->source1.property_map;
1272 map2 = merger->source2.property_map;
1276 pool1 = set1->string_pool.data;
1277 pool2 = set2->string_pool.data;
1279 count1 = set1->properties.size / sizeof *p1;
1280 count2 = set2->properties.size / sizeof *p2;
1281 while (i < count1 || j < count2) {
1282 if (i < count1 && map1[i] == 0) {
1286 if (j < count2 && map2[j] == 0) {
1290 p1 = (struct razor_property *) set1->properties.data + i;
1291 p2 = (struct razor_property *) set2->properties.data + j;
1292 if (i < count1 && j < count2)
1293 cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
1294 else if (i < count1)
1299 cmp = p1->type - p2->type;
1301 cmp = p1->relation - p2->relation;
1303 cmp = versioncmp(&pool1[p1->version],
1304 &pool2[p2->version]);
1306 map1[i++] = add_property(merger,
1309 &pool1[p1->version],
1311 } else if (cmp > 0) {
1312 map2[j++] = add_property(merger,
1315 &pool2[p2->version],
1318 map1[i++] = map2[j++] = add_property(merger,
1321 &pool1[p1->version],
1328 emit_properties(struct list_head *properties, struct array *source_pool,
1329 uint32_t *map, struct array *pool)
1334 r = pool->size / sizeof *q;
1335 p = list_first(properties, source_pool);
1337 q = array_add(pool, sizeof *q);
1338 q->data = map[p->data];
1339 q->flags = p->flags;
1343 list_set_ptr(properties, r);
1347 add_file(struct razor_merger *merger, const char *name)
1349 struct razor_entry *e;
1351 e = array_add(&merger->set->files, sizeof *e);
1352 e->name = hashtable_tokenize(&merger->table, name);
1356 return e - (struct razor_entry *)merger->set->files.data;
1361 fix_file_map(uint32_t *map,
1362 struct razor_entry *files,
1363 struct razor_entry *top)
1371 fix_file_map(map, files, &files[e]);
1374 } while (!(files[e++].flags & RAZOR_ENTRY_LAST));
1377 map[top - files] = 1;
1381 struct merge_directory {
1382 uint32_t merged, dir1, dir2;
1386 merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
1388 struct razor_entry *root1, *root2, *mroot, *e1, *e2;
1389 struct razor_set *set1, *set2;
1390 struct array merge_stack;
1391 struct merge_directory *child_md, *end_md;
1392 uint32_t *map1, *map2, start, last;
1394 char *pool1, *pool2;
1396 set1 = merger->source1.set;
1397 set2 = merger->source2.set;
1398 map1 = merger->source1.file_map;
1399 map2 = merger->source2.file_map;
1400 pool1 = set1->string_pool.data;
1401 pool2 = set2->string_pool.data;
1402 root1 = (struct razor_entry *) set1->files.data;
1403 root2 = (struct razor_entry *) set2->files.data;
1405 array_init(&merge_stack);
1407 start = merger->set->files.size / sizeof (struct razor_entry);
1409 e1 = md->dir1 ? root1 + md->dir1 : NULL;
1410 e2 = md->dir2 ? root2 + md->dir2 : NULL;
1412 if (!e2 && !map1[e1 - root1]) {
1413 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1417 if (!e1 && !map2[e2 - root2]) {
1418 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1422 if (e1 && !map1[e1 - root1] &&
1423 e2 && !map1[e2 - root2]) {
1424 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1426 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1436 cmp = strcmp (&pool1[e1->name],
1441 if (map1[e1 - root1]) {
1442 map1[e1 - root1] = last =
1443 add_file(merger, &pool1[e1->name]);
1445 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1446 child_md->merged = last;
1447 child_md->dir1 = e1->start;
1451 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1453 } else if (cmp > 0) {
1454 if (map2[e2 - root2]) {
1455 map2[e2 - root2] = last =
1456 add_file(merger, &pool2[e2->name]);
1458 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1459 child_md->merged = last;
1461 child_md->dir2 = e2->start;
1464 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1467 map1[e1 - root1] = map2[e2- root2] = last =
1468 add_file(merger, &pool1[e1->name]);
1469 if (e1->start || e2->start) {
1470 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1471 child_md->merged = last;
1472 child_md->dir1 = e1->start;
1473 child_md->dir2 = e2->start;
1475 if ((e1++)->flags & RAZOR_ENTRY_LAST)
1477 if ((e2++)->flags & RAZOR_ENTRY_LAST)
1482 mroot = (struct razor_entry *)merger->set->files.data;
1484 mroot[last].flags = RAZOR_ENTRY_LAST;
1485 mroot[md->merged].start = start;
1487 mroot[md->merged].start = 0;
1489 end_md = merge_stack.data + merge_stack.size;
1490 for (child_md = merge_stack.data; child_md < end_md; child_md++)
1491 merge_one_directory(merger, child_md);
1492 array_release(&merge_stack);
1496 merge_files(struct razor_merger *merger)
1498 struct razor_entry *root;
1499 struct merge_directory md;
1500 uint32_t *map1, *map2;
1502 map1 = merger->source1.file_map;
1503 map2 = merger->source2.file_map;
1507 if (merger->source1.set->files.size) {
1508 root = (struct razor_entry *) merger->source1.set->files.data;
1510 fix_file_map(map1, root, root);
1511 md.dir1 = root->start;
1515 if (merger->source2.set->files.size) {
1516 root = (struct razor_entry *) merger->source2.set->files.data;
1518 fix_file_map(map2, root, root);
1519 md.dir2 = root->start;
1523 merge_one_directory(merger, &md);
1527 emit_files(struct list_head *files, struct array *source_pool,
1528 uint32_t *map, struct array *pool)
1533 r = pool->size / sizeof *q;
1534 p = list_first(files, source_pool);
1536 q = array_add(pool, sizeof *q);
1537 q->data = map[p->data];
1538 q->flags = p->flags;
1542 list_set_ptr(files, r);
1545 /* Rebuild property->packages maps. We can't just remap these, as a
1546 * property may have lost or gained a number of packages. Allocate an
1547 * array per property and loop through the packages and add them to
1548 * the arrays for their properties. */
1550 rebuild_property_package_lists(struct razor_set *set)
1552 struct array *pkgs, *a;
1553 struct razor_package *pkg, *pkg_end;
1554 struct razor_property *prop, *prop_end;
1559 count = set->properties.size / sizeof (struct razor_property);
1560 pkgs = zalloc(count * sizeof *pkgs);
1561 pkg_end = set->packages.data + set->packages.size;
1563 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1564 r = list_first(&pkg->properties, &set->property_pool);
1566 q = array_add(&pkgs[r->data], sizeof *q);
1567 *q = pkg - (struct razor_package *) set->packages.data;
1572 prop_end = set->properties.data + set->properties.size;
1574 for (prop = set->properties.data; prop < prop_end; prop++, a++) {
1575 list_set_array(&prop->packages, &set->package_pool, a, 0);
1582 rebuild_file_package_lists(struct razor_set *set)
1584 struct array *pkgs, *a;
1585 struct razor_package *pkg, *pkg_end;
1586 struct razor_entry *entry, *entry_end;
1591 count = set->files.size / sizeof (struct razor_entry);
1592 pkgs = zalloc(count * sizeof *pkgs);
1593 pkg_end = set->packages.data + set->packages.size;
1595 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1596 r = list_first(&pkg->files, &set->file_pool);
1598 q = array_add(&pkgs[r->data], sizeof *q);
1599 *q = pkg - (struct razor_package *) set->packages.data;
1604 entry_end = set->files.data + set->files.size;
1606 for (entry = set->files.data; entry < entry_end; entry++, a++) {
1607 list_set_array(&entry->packages, &set->package_pool, a, 0);
1613 static struct razor_set *
1614 razor_merger_finish(struct razor_merger *merger)
1616 struct razor_set *result;
1617 struct razor_package *p, *pend;
1619 /* As we built the package list, we filled out a bitvector of
1620 * the properties that are referenced by the packages in the
1621 * new set. Now we do a parallel loop through the properties
1622 * and emit those marked in the bit vector to the new set. In
1623 * the process, we update the bit vector to actually map from
1624 * indices in the old property list to indices in the new
1625 * property list for both sets. */
1627 merge_properties(merger);
1628 merge_files(merger);
1630 /* Now we loop through the packages again and emit the
1631 * property lists, remapped to point to the new properties. */
1633 pend = merger->set->packages.data + merger->set->packages.size;
1634 for (p = merger->set->packages.data; p < pend; p++) {
1637 if (p->flags & UPSTREAM_SOURCE)
1638 src = &merger->source2;
1640 src = &merger->source1;
1642 emit_properties(&p->properties,
1643 &src->set->property_pool,
1645 &merger->set->property_pool);
1646 emit_files(&p->files,
1647 &src->set->file_pool,
1649 &merger->set->file_pool);
1650 p->flags &= ~UPSTREAM_SOURCE;
1653 rebuild_property_package_lists(merger->set);
1654 rebuild_file_package_lists(merger->set);
1656 result = merger->set;
1657 hashtable_release(&merger->table);
1663 /* The diff order matters. We should sort the packages so that a
1664 * REMOVE of a package comes before the INSTALL, and so that all
1665 * requires for a package have been installed before the package.
1669 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
1670 razor_package_callback_t callback, void *data)
1672 struct razor_package_iterator *pi1, *pi2;
1673 struct razor_package *p1, *p2;
1674 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
1677 pi1 = razor_package_iterator_create(set);
1678 pi2 = razor_package_iterator_create(upstream);
1680 razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
1681 razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
1685 res = strcmp(name1, name2);
1687 res = versioncmp(version1, version2);
1692 if (p2 == NULL || res < 0)
1693 callback(name1, version1, NULL, arch1, data);
1694 else if (p1 == NULL || res > 0)
1695 callback(name2, NULL, version2, arch2, data);
1697 if (p1 != NULL && res <= 0)
1698 razor_package_iterator_next(pi1, &p1,
1699 &name1, &version1, &arch1);
1700 if (p2 != NULL && res >= 0)
1701 razor_package_iterator_next(pi2, &p2,
1702 &name2, &version2, &arch2);
1705 razor_package_iterator_destroy(pi1);
1706 razor_package_iterator_destroy(pi2);
1710 provider_satisfies_requirement(struct razor_property *provider,
1711 const char *provider_strings,
1712 enum razor_version_relation relation,
1713 const char *required)
1716 const char *provided = &provider_strings[provider->version];
1721 if (relation >= RAZOR_VERSION_EQUAL)
1727 cmp = versioncmp(provided, required);
1730 case RAZOR_VERSION_LESS:
1733 case RAZOR_VERSION_LESS_OR_EQUAL:
1736 /* fall through: FIXME, make sure this is correct */
1738 case RAZOR_VERSION_EQUAL:
1742 /* "foo == 1.1" is satisfied by "foo 1.1-2" */
1743 len = strlen(required);
1744 if (!strncmp(required, provided, len) && provided[len] == '-')
1748 case RAZOR_VERSION_GREATER_OR_EQUAL:
1751 case RAZOR_VERSION_GREATER:
1755 /* shouldn't happen */
1759 #define TRANS_PACKAGE_PRESENT 1
1760 #define TRANS_PACKAGE_UPDATE 2
1761 #define TRANS_PROPERTY_SATISFIED 0x80000000
1763 struct transaction_set {
1764 struct razor_set *set;
1766 uint32_t *properties;
1769 struct razor_transaction {
1770 int package_count, errors;
1771 struct transaction_set system, upstream;
1776 transaction_set_init(struct transaction_set *ts, struct razor_set *set)
1781 count = set->packages.size / sizeof (struct razor_package);
1782 ts->packages = zalloc(count * sizeof *ts->packages);
1783 count = set->properties.size / sizeof (struct razor_property);
1784 ts->properties = zalloc(count * sizeof *ts->properties);
1788 transaction_set_release(struct transaction_set *ts)
1791 free(ts->properties);
1795 transaction_set_install_package(struct transaction_set *ts,
1796 struct razor_package *package)
1798 struct razor_package *pkgs;
1802 pkgs = ts->set->packages.data;
1804 if (ts->packages[i] == TRANS_PACKAGE_PRESENT)
1807 ts->packages[i] = TRANS_PACKAGE_PRESENT;
1809 prop = list_first(&package->properties, &ts->set->property_pool);
1811 ts->properties[prop->data]++;
1812 prop = list_next(prop);
1817 transaction_set_remove_package(struct transaction_set *ts,
1818 struct razor_package *package)
1820 struct razor_package *pkgs;
1824 pkgs = ts->set->packages.data;
1826 if (ts->packages[i] == 0)
1829 ts->packages[i] = 0;
1831 prop = list_first(&package->properties, &ts->set->property_pool);
1833 ts->properties[prop->data]--;
1834 prop = list_next(prop);
1838 struct razor_transaction *
1839 razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
1841 struct razor_transaction *trans;
1842 struct razor_package *p, *spkgs, *pend;
1844 trans = zalloc(sizeof *trans);
1845 transaction_set_init(&trans->system, system);
1846 transaction_set_init(&trans->upstream, upstream);
1848 spkgs = trans->system.set->packages.data;
1849 pend = trans->system.set->packages.data +
1850 trans->system.set->packages.size;
1851 for (p = spkgs; p < pend; p++)
1852 transaction_set_install_package(&trans->system, p);
1858 razor_transaction_install_package(struct razor_transaction *trans,
1859 struct razor_package *package)
1861 transaction_set_install_package(&trans->upstream, package);
1866 razor_transaction_remove_package(struct razor_transaction *trans,
1867 struct razor_package *package)
1869 transaction_set_remove_package(&trans->system, package);
1874 razor_transaction_update_package(struct razor_transaction *trans,
1875 struct razor_package *package)
1877 struct razor_package *spkgs;
1879 spkgs = trans->system.set->packages.data;
1880 trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
1884 struct razor_property *p, *start, *end;
1890 prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
1892 pi->p = ts->set->properties.data;
1893 pi->start = ts->set->properties.data;
1894 pi->end = ts->set->properties.data + ts->set->properties.size;
1895 pi->pool = ts->set->string_pool.data;
1896 pi->present = ts->properties;
1900 prop_iter_next(struct prop_iter *pi,
1901 enum razor_property_type type, struct razor_property **p)
1903 while (pi->p < pi->end) {
1904 if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
1905 pi->p->type == type) {
1915 static struct razor_property *
1916 prop_iter_seek_to(struct prop_iter *pi,
1917 enum razor_property_type type, const char *match)
1921 while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
1924 if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
1928 while (pi->p < pi->end &&
1929 pi->p->name == name &&
1930 pi->p->type != type)
1933 if (pi->p == pi->end || pi->p->name != name)
1939 /* Remove packages from set that provide any of the matching (same
1940 * name and type) providers from ppi onwards that match the
1941 * requirement that rpi points to. */
1943 remove_matching_providers(struct razor_transaction *trans,
1944 struct prop_iter *ppi,
1945 enum razor_version_relation relation,
1946 const char *version)
1948 struct razor_property *p;
1949 struct razor_package *pkg, *pkgs;
1950 struct razor_package_iterator pkg_iter;
1951 struct razor_set *set;
1952 const char *n, *v, *a;
1954 if (ppi->present == trans->system.properties)
1955 set = trans->system.set;
1957 set = trans->upstream.set;
1959 pkgs = (struct razor_package *) set->packages.data;
1962 p->name == ppi->p->name &&
1963 p->type == ppi->p->type;
1965 if (!ppi->present[p - ppi->start])
1967 if (!provider_satisfies_requirement(p, ppi->pool,
1971 razor_package_iterator_init_for_property(&pkg_iter, set, p);
1972 while (razor_package_iterator_next(&pkg_iter,
1973 &pkg, &n, &v, &a)) {
1974 fprintf(stderr, "removing %s-%s\n", n, v);
1975 razor_transaction_remove_package(trans, pkg);
1981 flag_matching_providers(struct razor_transaction *trans,
1982 struct prop_iter *ppi,
1983 struct razor_property *r,
1984 struct prop_iter *rpi,
1987 struct razor_property *p;
1988 struct razor_package *pkg, *pkgs;
1989 struct razor_package_iterator pkg_iter;
1990 struct razor_set *set;
1991 const char *name, *version, *arch;
1994 if (ppi->present == trans->system.properties) {
1995 set = trans->system.set;
1996 flags = trans->system.packages;
1998 set = trans->upstream.set;
1999 flags = trans->upstream.packages;
2002 pkgs = (struct razor_package *) set->packages.data;
2005 p->name == ppi->p->name &&
2006 p->type == ppi->p->type;
2008 if (!ppi->present[p - ppi->start])
2010 if (!provider_satisfies_requirement(p, ppi->pool,
2012 &rpi->pool[r->version]))
2015 razor_package_iterator_init_for_property(&pkg_iter, set, p);
2016 while (razor_package_iterator_next(&pkg_iter, &pkg,
2017 &name, &version, &arch)) {
2019 fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
2021 ppi->pool + p->name,
2022 rpi->pool + r->name,
2023 rpi->pool + r->version);
2024 flags[pkg - pkgs] |= flag;
2029 static struct razor_package *
2030 pick_matching_provider(struct razor_set *set,
2031 struct prop_iter *ppi,
2032 enum razor_version_relation relation,
2033 const char *version)
2035 struct razor_property *p;
2036 struct razor_package *pkgs;
2039 /* This is where we decide which pkgs to pull in to satisfy a
2040 * requirement. There may be several different providers
2041 * (different versions) and each version of a provider may
2042 * come from a number of packages. We pick the first package
2043 * from the first provider that matches. */
2045 pkgs = set->packages.data;
2048 p->name == ppi->p->name &&
2049 p->type == ppi->p->type &&
2050 ppi->present[p - ppi->start] == 0;
2052 if (!provider_satisfies_requirement(p, ppi->pool,
2056 i = list_first(&p->packages, &set->package_pool);
2058 return &pkgs[i->data];
2065 remove_obsoleted_packages(struct razor_transaction *trans)
2067 struct razor_property *up;
2068 struct razor_package *spkgs;
2069 struct prop_iter spi, upi;
2071 spkgs = trans->system.set->packages.data;
2072 prop_iter_init(&spi, &trans->system);
2073 prop_iter_init(&upi, &trans->upstream);
2075 while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
2076 if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
2077 &upi.pool[up->name]))
2079 remove_matching_providers(trans, &spi, up->relation,
2080 &upi.pool[up->version]);
2085 any_provider_satisfies_requirement(struct prop_iter *ppi,
2086 enum razor_version_relation relation,
2087 const char *version)
2089 struct razor_property *p;
2093 p->name == ppi->p->name &&
2094 p->type == ppi->p->type;
2096 if (ppi->present[p - ppi->start] > 0 &&
2097 provider_satisfies_requirement(p, ppi->pool,
2106 clear_requires_flags(struct transaction_set *ts)
2108 struct razor_property *p;
2112 count = ts->set->properties.size / sizeof *p;
2113 p = ts->set->properties.data;
2114 pool = ts->set->string_pool.data;
2115 for (i = 0; i < count; i++) {
2116 ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
2117 if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
2118 ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
2123 mark_satisfied_requires(struct razor_transaction *trans,
2124 struct transaction_set *rts,
2125 struct transaction_set *pts)
2127 struct prop_iter rpi, ppi;
2128 struct razor_property *rp;
2130 prop_iter_init(&rpi, rts);
2131 prop_iter_init(&ppi, pts);
2133 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
2134 if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
2135 &rpi.pool[rp->name]))
2138 if (any_provider_satisfies_requirement(&ppi, rp->relation,
2139 &rpi.pool[rp->version]))
2140 rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
2144 static const char *relation_string[] = { "<", "<=", "=", ">=", ">" };
2147 mark_all_satisfied_requires(struct razor_transaction *trans)
2149 struct razor_property *sp;
2150 struct prop_iter spi;
2152 clear_requires_flags(&trans->system);
2153 clear_requires_flags(&trans->upstream);
2154 mark_satisfied_requires(trans, &trans->system, &trans->system);
2155 mark_satisfied_requires(trans, &trans->system, &trans->upstream);
2156 mark_satisfied_requires(trans, &trans->upstream, &trans->system);
2157 mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
2159 prop_iter_init(&spi, &trans->system);
2160 while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
2161 if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
2163 fprintf(stderr, "unsatisfied system requires: %s %s %s\n",
2164 spi.pool + sp->name,
2165 relation_string[sp->relation],
2166 spi.pool + sp->version);
2169 prop_iter_init(&spi, &trans->upstream);
2170 while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
2171 if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
2173 fprintf(stderr, "unsatisfied upstream requires: %s %s %s\n",
2174 spi.pool + sp->name,
2175 relation_string[sp->relation],
2176 spi.pool + sp->version);
2181 update_unsatisfied_packages(struct razor_transaction *trans)
2183 struct razor_package *spkgs, *pkg;
2184 struct razor_property *sp;
2185 struct prop_iter spi;
2186 struct razor_package_iterator pkg_iter;
2187 const char *name, *version, *arch;
2189 spkgs = trans->system.set->packages.data;
2190 prop_iter_init(&spi, &trans->system);
2192 while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
2193 if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
2196 razor_package_iterator_init_for_property(&pkg_iter,
2199 while (razor_package_iterator_next(&pkg_iter, &pkg,
2200 &name, &version, &arch)) {
2201 fprintf(stderr, "updating %s because %s %s %s "
2202 "isn't satisfied\n",
2203 name, spi.pool + sp->name,
2204 relation_string[sp->relation],
2205 spi.pool + sp->version);
2206 trans->system.packages[pkg - spkgs] |=
2207 TRANS_PACKAGE_UPDATE;
2213 razor_transaction_update_all(struct razor_transaction *trans)
2215 struct razor_package *p;
2218 count = trans->system.set->packages.size / sizeof *p;
2219 for (i = 0; i < count; i++)
2220 trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
2224 update_conflicted_packages(struct razor_transaction *trans)
2226 struct razor_package *pkg, *spkgs;
2227 struct razor_property *up, *sp;
2228 struct prop_iter spi, upi;
2229 struct razor_package_iterator pkg_iter;
2230 const char *name, *version, *arch;
2232 spkgs = trans->system.set->packages.data;
2233 prop_iter_init(&spi, &trans->system);
2234 prop_iter_init(&upi, &trans->upstream);
2236 while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
2237 if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
2238 &spi.pool[sp->name]))
2241 if (!any_provider_satisfies_requirement(&upi, sp->relation,
2242 &spi.pool[sp->version]))
2245 razor_package_iterator_init_for_property(&pkg_iter,
2248 while (razor_package_iterator_next(&pkg_iter, &pkg,
2249 &name, &version, &arch)) {
2250 fprintf(stderr, "updating %s %s because it conflicts with %s",
2251 name, version, spi.pool + sp->name);
2252 trans->system.packages[pkg - spkgs] |=
2253 TRANS_PACKAGE_UPDATE;
2257 prop_iter_init(&spi, &trans->system);
2258 prop_iter_init(&upi, &trans->upstream);
2260 while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
2261 sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
2262 &upi.pool[upi.p->name]);
2265 flag_matching_providers(trans, &spi, up, &upi,
2266 TRANS_PACKAGE_UPDATE);
2271 pull_in_requirements(struct razor_transaction *trans,
2272 struct prop_iter *rpi, struct prop_iter *ppi)
2274 struct razor_property *rp, *pp;
2275 struct razor_package *pkg, *upkgs;
2277 upkgs = trans->upstream.set->packages.data;
2278 while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
2279 if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
2282 pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
2283 &rpi->pool[rp->name]);
2286 pkg = pick_matching_provider(trans->upstream.set,
2288 &rpi->pool[rp->version]);
2292 rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
2294 fprintf(stderr, "pulling in %s which provides %s %s %s "
2295 "to satisfy %s %s %s\n",
2296 ppi->pool + pkg->name,
2297 ppi->pool + pp->name,
2298 relation_string[pp->relation],
2299 ppi->pool + pp->version,
2300 &rpi->pool[rp->name],
2301 relation_string[rp->relation],
2302 &rpi->pool[rp->version]);
2304 trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
2309 pull_in_all_requirements(struct razor_transaction *trans)
2311 struct prop_iter rpi, ppi;
2312 struct razor_property *rp;
2314 prop_iter_init(&rpi, &trans->system);
2315 prop_iter_init(&ppi, &trans->upstream);
2316 pull_in_requirements(trans, &rpi, &ppi);
2318 prop_iter_init(&rpi, &trans->upstream);
2319 prop_iter_init(&ppi, &trans->upstream);
2320 pull_in_requirements(trans, &rpi, &ppi);
2322 prop_iter_init(&rpi, &trans->system);
2323 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
2324 if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED))
2325 fprintf(stderr, "could not satisfy req %s %s %s\n",
2326 &rpi.pool[rp->name],
2327 relation_string[rp->relation],
2328 &rpi.pool[rp->version]);
2331 prop_iter_init(&rpi, &trans->upstream);
2332 while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
2333 if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED))
2334 fprintf(stderr, "could not satisfy req %s %s %s\n",
2335 &rpi.pool[rp->name],
2336 relation_string[rp->relation],
2337 &rpi.pool[rp->version]);
2342 flush_scheduled_system_updates(struct razor_transaction *trans)
2344 struct razor_package_iterator *pi;
2345 struct razor_package *p, *pkg, *spkgs;
2346 struct prop_iter ppi;
2347 const char *name, *version, *arch;
2349 spkgs = trans->system.set->packages.data;
2350 pi = razor_package_iterator_create(trans->system.set);
2351 prop_iter_init(&ppi, &trans->upstream);
2353 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
2354 if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
2357 if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name)) {
2358 fprintf(stderr, "nothing provides %s\n", name);
2362 pkg = pick_matching_provider(trans->upstream.set, &ppi,
2363 RAZOR_VERSION_GREATER, version);
2366 "no newer version of %s available\n", name);
2370 fprintf(stderr, "updating %s from %s to %s\n",
2371 name, version, &ppi.pool[pkg->version]);
2373 razor_transaction_remove_package(trans, p);
2374 razor_transaction_install_package(trans, pkg);
2377 razor_package_iterator_destroy(pi);
2381 flush_scheduled_upstream_updates(struct razor_transaction *trans)
2383 struct razor_package_iterator *pi;
2384 struct razor_package *p, *upkgs;
2385 struct prop_iter spi;
2386 const char *name, *version, *arch;
2388 upkgs = trans->upstream.set->packages.data;
2389 pi = razor_package_iterator_create(trans->upstream.set);
2390 prop_iter_init(&spi, &trans->system);
2392 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
2393 if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
2396 if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
2398 remove_matching_providers(trans, &spi,
2399 RAZOR_VERSION_LESS, version);
2400 razor_transaction_install_package(trans, p);
2401 fprintf(stderr, "installing %s-%s\n", name, version);
2406 razor_transaction_resolve(struct razor_transaction *trans)
2410 flush_scheduled_system_updates(trans);
2412 while (last < trans->changes) {
2413 last = trans->changes;
2414 remove_obsoleted_packages(trans);
2415 mark_all_satisfied_requires(trans);
2416 update_unsatisfied_packages(trans);
2417 update_conflicted_packages(trans);
2418 pull_in_all_requirements(trans);
2419 flush_scheduled_system_updates(trans);
2420 flush_scheduled_upstream_updates(trans);
2423 return trans->changes;
2427 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
2429 enum razor_version_relation rel,
2430 const char *version,
2431 enum razor_property_type type)
2433 struct prop_iter pi;
2434 struct razor_property *p;
2436 prop_iter_init(&pi, &trans->system);
2437 while (prop_iter_next(&pi, type, &p)) {
2438 if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
2439 p->relation == rel &&
2440 strcmp(&pi.pool[p->name], name) == 0 &&
2441 strcmp(&pi.pool[p->version], version) == 0)
2446 prop_iter_init(&pi, &trans->upstream);
2447 while (prop_iter_next(&pi, type, &p)) {
2448 if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
2449 p->relation == rel &&
2450 strcmp(&pi.pool[p->name], name) == 0 &&
2451 strcmp(&pi.pool[p->version], version) == 0)
2460 razor_transaction_finish(struct razor_transaction *trans)
2462 struct razor_merger *merger;
2463 struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
2464 char *upool, *spool;
2467 s = trans->system.set->packages.data;
2468 spkgs = trans->system.set->packages.data;
2469 send = trans->system.set->packages.data +
2470 trans->system.set->packages.size;
2471 spool = trans->system.set->string_pool.data;
2473 u = trans->upstream.set->packages.data;
2474 upkgs = trans->upstream.set->packages.data;
2475 uend = trans->upstream.set->packages.data +
2476 trans->upstream.set->packages.size;
2477 upool = trans->upstream.set->string_pool.data;
2479 merger = razor_merger_create(trans->system.set, trans->upstream.set);
2480 while (s < send || u < uend) {
2481 if (s < send && u < uend)
2482 cmp = strcmp(&spool[s->name], &upool[u->name]);
2489 if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
2490 razor_merger_add_package(merger, s);
2492 } else if (cmp == 0) {
2493 if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
2494 razor_merger_add_package(merger, s);
2495 if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
2496 razor_merger_add_package(merger, u);
2501 if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
2502 razor_merger_add_package(merger, u);
2507 razor_transaction_destroy(trans);
2509 return razor_merger_finish(merger);
2513 razor_transaction_destroy(struct razor_transaction *trans)
2515 transaction_set_release(&trans->system);
2516 transaction_set_release(&trans->upstream);
2519 /* FIXME: free upstream if it was created as an empty set */
2522 struct razor_package_query {
2523 struct razor_set *set;
2528 struct razor_package_query *
2529 razor_package_query_create(struct razor_set *set)
2531 struct razor_package_query *pq;
2534 pq = zalloc(sizeof *pq);
2536 count = set->packages.size / sizeof(struct razor_package);
2537 pq->vector = zalloc(count * sizeof(char));
2543 razor_package_query_add_package(struct razor_package_query *pq,
2544 struct razor_package *p)
2546 struct razor_package *packages;
2548 packages = pq->set->packages.data;
2549 pq->count += pq->vector[p - packages] ^ 1;
2550 pq->vector[p - packages] = 1;
2554 razor_package_query_add_iterator(struct razor_package_query *pq,
2555 struct razor_package_iterator *pi)
2557 struct razor_package *packages, *p;
2558 const char *name, *version, *arch;
2560 packages = pq->set->packages.data;
2561 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
2562 pq->count += pq->vector[p - packages] ^ 1;
2563 pq->vector[p - packages] = 1;
2567 struct razor_package_iterator *
2568 razor_package_query_finish(struct razor_package_query *pq)
2570 struct razor_package_iterator *pi;
2571 struct razor_set *set;
2576 count = set->packages.size / sizeof(struct razor_package);
2577 index = zalloc(pq->count * sizeof *index);
2579 for (i = 0, j = 0; i < count; i++) {
2584 if (j == pq->count - 1)
2585 index[j].flags = 0x80;
2591 pi = razor_package_iterator_create_with_index(set, index);