Add the first bits of rpm file parser.
23 struct razor_set_section {
29 struct razor_set_header {
32 struct razor_set_section sections[0];
35 #define RAZOR_MAGIC 0x7a7a7a7a
36 #define RAZOR_VERSION 1
38 #define RAZOR_ENTRY_LAST 0x80000000ul
39 #define RAZOR_IMMEDIATE 0x80000000ul
40 #define RAZOR_ENTRY_MASK 0x00fffffful
42 #define RAZOR_STRING_POOL 0
43 #define RAZOR_PACKAGES 1
44 #define RAZOR_PROPERTIES 2
46 #define RAZOR_PACKAGE_POOL 4
47 #define RAZOR_PROPERTY_POOL 5
48 #define RAZOR_FILE_POOL 6
50 struct razor_package {
52 unsigned long version;
53 unsigned long properties;
57 struct razor_property {
59 unsigned long version;
60 unsigned long packages;
66 unsigned long packages;
70 struct array string_pool;
71 struct array packages;
72 struct array properties;
74 struct array package_pool;
75 struct array property_pool;
76 struct array file_pool;
77 struct razor_set_header *header;
81 unsigned long package;
85 struct import_directory {
86 unsigned long name, count;
88 struct array packages;
89 struct import_directory *last;
92 struct razor_importer {
93 struct razor_set *set;
95 struct razor_package *package;
96 struct array properties;
101 array_init(struct array *array)
103 memset(array, 0, sizeof *array);
107 array_release(struct array *array)
113 array_add(struct array *array, int size)
118 if (array->alloc > 0)
119 alloc = array->alloc;
123 while (alloc < array->size + size)
126 if (array->alloc < alloc) {
127 data = realloc(array->data, alloc);
131 array->alloc = alloc;
134 p = array->data + array->size;
141 write_to_fd(int fd, void *p, size_t size)
147 len = write(fd, p, rest);
167 struct razor_set_section razor_sections[] = {
168 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
169 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
170 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
171 { RAZOR_FILES, offsetof(struct razor_set, files) },
172 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
173 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
174 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
178 razor_set_create(void)
180 return zalloc(sizeof(struct razor_set));
184 razor_set_open(const char *filename)
186 struct razor_set *set;
187 struct razor_set_section *s;
192 set = zalloc(sizeof *set);
193 fd = open(filename, O_RDONLY);
194 if (fstat(fd, &stat) < 0)
196 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
197 if (set->header == MAP_FAILED) {
202 for (s = set->header->sections; ~s->type; s++) {
203 if (s->type >= ARRAY_SIZE(razor_sections))
205 if (s->type != razor_sections[s->type].type)
207 array = (void *) set + razor_sections[s->type].offset;
208 array->data = (void *) set->header + s->offset;
209 array->size = s->size;
210 array->alloc = s->size;
218 razor_set_destroy(struct razor_set *set)
225 for (i = 0; set->header->sections[i].type; i++)
227 size = set->header->sections[i].type;
228 munmap(set->header, size);
230 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
231 a = (void *) set + razor_sections[i].offset;
240 razor_set_write(struct razor_set *set, const char *filename)
243 struct razor_set_header *header = (struct razor_set_header *) data;
245 unsigned long offset;
248 memset(data, 0, sizeof data);
249 header->magic = RAZOR_MAGIC;
250 header->version = RAZOR_VERSION;
251 offset = sizeof data;
253 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
254 if (razor_sections[i].type != i)
256 a = (void *) set + razor_sections[i].offset;
257 header->sections[i].type = i;
258 header->sections[i].offset = offset;
259 header->sections[i].size = a->size;
260 offset += (a->size + 4095) & ~4095;
263 header->sections[i].type = ~0;
264 header->sections[i].offset = 0;
265 header->sections[i].size = 0;
267 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
271 write_to_fd(fd, data, sizeof data);
272 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
273 if (razor_sections[i].type != i)
275 a = (void *) set + razor_sections[i].offset;
276 write_to_fd(fd, a->data, (a->size + 4095) & ~4095);
285 hash_string(const char *key)
288 unsigned int hash = 0;
290 for (p = key; *p; p++)
291 hash = (hash * 617) ^ *p;
297 razor_importer_lookup(struct razor_importer *importer, const char *key)
299 unsigned int mask, start, i;
303 pool = importer->set->string_pool.data;
304 mask = importer->buckets.alloc - 1;
305 start = hash_string(key) * sizeof(unsigned long);
307 for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
308 b = importer->buckets.data + ((start + i) & mask);
313 if (strcmp(key, &pool[*b]) == 0)
321 add_to_string_pool(struct razor_set *set, const char *key)
326 len = strlen(key) + 1;
327 p = array_add(&set->string_pool, len);
330 return p - (char *) set->string_pool.data;
334 add_to_property_pool(struct array *pool, struct array *properties)
338 p = array_add(pool, properties->size);
339 memcpy(p, properties->data, properties->size);
340 p[properties->size / sizeof *p - 1] |= RAZOR_IMMEDIATE;
342 return p - (unsigned long *) pool->data;
346 do_insert(struct razor_importer *importer, unsigned long value)
348 unsigned int mask, start, i;
352 key = (char *) importer->set->string_pool.data + value;
353 mask = importer->buckets.alloc - 1;
354 start = hash_string(key) * sizeof(unsigned long);
356 for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
357 b = importer->buckets.data + ((start + i) & mask);
366 razor_importer_insert(struct razor_importer *importer, const char *key)
368 unsigned long value, *buckets, *b, *end;
371 alloc = importer->buckets.alloc;
372 array_add(&importer->buckets, 4 * sizeof *buckets);
373 if (alloc != importer->buckets.alloc) {
374 end = importer->buckets.data + alloc;
375 memset(end, 0, importer->buckets.alloc - alloc);
376 for (b = importer->buckets.data; b < end; b++) {
380 do_insert(importer, value);
385 value = add_to_string_pool(importer->set, key);
386 do_insert (importer, value);
392 razor_importer_tokenize(struct razor_importer *importer, const char *string)
397 return razor_importer_tokenize(importer, "");
399 token = razor_importer_lookup(importer, string);
403 return razor_importer_insert(importer, string);
407 razor_importer_begin_package(struct razor_importer *importer,
408 const char *name, const char *version)
410 struct razor_package *p;
412 p = array_add(&importer->set->packages, sizeof *p);
413 p->name = razor_importer_tokenize(importer, name);
414 p->version = razor_importer_tokenize(importer, version);
416 importer->package = p;
417 array_init(&importer->properties);
421 razor_importer_finish_package(struct razor_importer *importer)
423 struct razor_package *p;
425 p = importer->package;
426 p->properties = add_to_property_pool(&importer->set->property_pool,
427 &importer->properties);
429 array_release(&importer->properties);
433 razor_importer_add_property(struct razor_importer *importer,
434 const char *name, const char *version,
435 enum razor_property_type type)
437 struct razor_property *p;
440 p = array_add(&importer->set->properties, sizeof *p);
441 p->name = razor_importer_tokenize(importer, name) | (type << 30);
442 p->version = razor_importer_tokenize(importer, version);
443 p->packages = importer->package -
444 (struct razor_package *) importer->set->packages.data;
446 r = array_add(&importer->properties, sizeof *r);
447 *r = p - (struct razor_property *) importer->set->properties.data;
451 razor_importer_add_file(struct razor_importer *importer, const char *name)
453 struct import_entry *e;
455 e = array_add(&importer->files, sizeof *e);
457 e->package = importer->package -
458 (struct razor_package *) importer->set->packages.data;
459 e->name = strdup(name);
462 struct razor_importer *
463 razor_importer_new(void)
465 struct razor_importer *importer;
467 importer = zalloc(sizeof *importer);
468 importer->set = razor_set_create();
473 typedef int (*compare_with_data_func_t)(const void *p1,
477 struct qsort_context {
479 compare_with_data_func_t compare;
484 qsort_swap(void *p1, void *p2, size_t size)
488 memcpy(buffer, p1, size);
489 memcpy(p1, p2, size);
490 memcpy(p2, buffer, size);
494 __qsort_with_data(void *base, size_t nelem, unsigned long *map,
495 struct qsort_context *ctx)
497 void *p, *start, *end, *pivot;
498 unsigned long *mp, *mstart, *mend, tmp;
499 int left, right, result;
500 size_t size = ctx->size;
504 end = base + nelem * size;
508 pivot = base + (random() % nelem) * size;
511 result = ctx->compare(p, pivot, ctx->data);
513 qsort_swap(p, start, size);
523 } else if (result == 0) {
529 qsort_swap(p, end, size);
538 left = (start - base) / size;
539 right = (base + nelem * size - end) / size;
541 __qsort_with_data(base, left, map, ctx);
543 __qsort_with_data(end, right, mend, ctx);
547 qsort_with_data(void *base, size_t nelem, size_t size,
548 compare_with_data_func_t compare, void *data)
550 struct qsort_context ctx;
555 ctx.compare = compare;
558 map = malloc(nelem * sizeof (unsigned long));
559 for (i = 0; i < nelem; i++)
562 __qsort_with_data(base, nelem, map, &ctx);
568 versioncmp(const char *s1, const char *s2)
574 n1 = strtol(s1, (char **) &p1, 0);
575 n2 = strtol(s2, (char **) &p2, 0);
577 /* Epoch; if one but not the other has an epoch set, default
578 * the epoch-less version to 0. */
579 res = (*p1 == ':') - (*p2 == ':');
584 } else if (res > 0) {
597 if (isdigit(*p1) && isdigit(*p2))
598 return versioncmp(p1, p2);
606 compare_packages(const void *p1, const void *p2, void *data)
608 const struct razor_package *pkg1 = p1, *pkg2 = p2;
609 struct razor_set *set = data;
610 char *pool = set->string_pool.data;
612 if (pkg1->name == pkg2->name)
613 return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
615 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
619 compare_properties(const void *p1, const void *p2, void *data)
621 const struct razor_property *prop1 = p1, *prop2 = p2;
622 struct razor_set *set = data;
623 char *pool = set->string_pool.data;
625 if (prop1->name == prop2->name)
626 return versioncmp(&pool[prop1->version],
627 &pool[prop2->version]);
628 else if ((prop1->name & RAZOR_ENTRY_MASK) == (prop2->name & RAZOR_ENTRY_MASK))
629 return (prop1->name >> 30) - (prop2->name >> 30);
631 return strcmp(&pool[prop1->name & RAZOR_ENTRY_MASK],
632 &pool[prop2->name & RAZOR_ENTRY_MASK]);
635 static unsigned long *
636 uniqueify_properties(struct razor_set *set)
638 struct razor_property *rp, *up, *rp_end;
639 struct array *pkgs, *p;
640 unsigned long *map, *rmap, *r;
641 int i, count, unique;
643 count = set->properties.size / sizeof(struct razor_property);
644 map = qsort_with_data(set->properties.data,
646 sizeof(struct razor_property),
650 rp_end = set->properties.data + set->properties.size;
651 rmap = malloc(count * sizeof *map);
652 pkgs = zalloc(count * sizeof *pkgs);
653 for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
654 if (rp->name != up->name || rp->version != up->version) {
657 up->version = rp->version;
660 unique = up - (struct razor_property *) set->properties.data;
661 rmap[map[i]] = unique;
662 r = array_add(&pkgs[unique], sizeof *r);
668 set->properties.size = (void *) up - set->properties.data;
670 for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
671 if (p->size / sizeof *r == 1) {
673 rp->packages = *r | RAZOR_IMMEDIATE;
676 add_to_property_pool(&set->package_pool, p);
687 remap_links(struct array *links, unsigned long *map)
689 unsigned long *p, *end;
691 end = links->data + links->size;
692 for (p = links->data; p < end; p++)
693 *p = map[*p & RAZOR_ENTRY_MASK] | (*p & ~RAZOR_ENTRY_MASK);
697 compare_filenames(const void *p1, const void *p2, void *data)
699 const struct import_entry *e1 = p1;
700 const struct import_entry *e2 = p2;
702 return strcmp(e1->name, e2->name);
706 count_entries(struct import_directory *d)
708 struct import_directory *p, *end;
711 end = d->files.data + d->files.size;
715 d->count += p->count + 1;
721 serialize_files(struct razor_set *set,
722 struct import_directory *d, struct array *array)
724 struct import_directory *p, *end;
725 struct razor_entry *e = NULL;
729 end = d->files.data + d->files.size;
730 s = array->size / sizeof *e + d->files.size / sizeof *p;
732 e = array_add(array, sizeof *e);
734 e->start = p->count > 0 ? s : 0;
737 if (p->packages.size == 0) {
738 /* FIXME: We need to make sure this is handled
739 * correctly as the empty list. */
740 e->packages = 0 | RAZOR_IMMEDIATE;
741 } else if (p->packages.size / sizeof *r == 1) {
742 r = p->packages.data;
743 e->packages = *r | RAZOR_IMMEDIATE;
745 e->packages = add_to_property_pool(&set->package_pool,
748 array_release(&p->packages);
752 e->name |= RAZOR_ENTRY_LAST;
755 end = d->files.data + d->files.size;
757 serialize_files(set, p, array);
763 remap_property_package_links(struct array *properties, unsigned long *rmap)
765 struct razor_property *p, *end;
767 end = properties->data + properties->size;
768 for (p = properties->data; p < end; p++)
769 if (p->packages & RAZOR_IMMEDIATE)
770 p->packages = rmap[p->packages & RAZOR_ENTRY_MASK] |
775 build_file_tree(struct razor_importer *importer)
777 int count, i, length;
778 struct import_entry *filenames;
780 unsigned long name, *r;
782 struct import_directory *d, root;
783 struct razor_entry *e;
785 count = importer->files.size / sizeof (struct import_entry);
786 qsort_with_data(importer->files.data,
788 sizeof (struct import_entry),
792 root.name = razor_importer_tokenize(importer, "");
793 array_init(&root.files);
794 array_init(&root.packages);
797 filenames = importer->files.data;
798 for (i = 0; i < count; i++) {
799 f = filenames[i].name;
806 end = strchr(f, '/');
810 memcpy(dirname, f, length);
811 dirname[length] ='\0';
812 name = razor_importer_tokenize(importer, dirname);
813 if (d->last == NULL || d->last->name != name) {
814 d->last = array_add(&d->files, sizeof *d);
815 d->last->name = name;
816 d->last->last = NULL;
817 array_init(&d->last->files);
818 array_init(&d->last->packages);
826 r = array_add(&d->packages, sizeof *r);
827 *r = filenames[i].package;
828 free(filenames[i].name);
831 count_entries(&root);
832 array_init(&importer->set->files);
834 e = array_add(&importer->set->files, sizeof *e);
835 e->name = root.name | RAZOR_ENTRY_LAST;
839 serialize_files(importer->set, &root, &importer->set->files);
841 array_release(&importer->files);
845 build_package_file_lists(struct razor_set *set, unsigned long *rmap)
847 struct razor_package *p, *packages;
849 struct razor_entry *e, *end;
850 unsigned long *r, *q;
853 count = set->packages.size / sizeof *p;
854 pkgs = zalloc(count * sizeof *pkgs);
857 end = set->files.data + set->files.size;
859 if (e->packages & RAZOR_IMMEDIATE) {
860 e->packages = rmap[e->packages & RAZOR_ENTRY_MASK] |
864 r = (unsigned long *) set->package_pool.data + e->packages;
868 q = array_add(&pkgs[*r & RAZOR_ENTRY_MASK], sizeof *q);
869 *q = e - (struct razor_entry *) set->files.data;
870 if (*r++ & RAZOR_IMMEDIATE)
876 packages = set->packages.data;
877 for (i = 0; i < count; i++) {
879 add_to_property_pool(&set->file_pool, &pkgs[i]);
880 array_release(&pkgs[i]);
886 razor_importer_finish(struct razor_importer *importer)
888 struct razor_set *set;
889 unsigned long *map, *rmap;
892 map = uniqueify_properties(importer->set);
893 remap_links(&importer->set->property_pool, map);
896 count = importer->set->packages.size / sizeof(struct razor_package);
897 map = qsort_with_data(importer->set->packages.data,
899 sizeof(struct razor_package),
903 rmap = malloc(count * sizeof *rmap);
904 for (i = 0; i < count; i++)
908 build_file_tree(importer);
909 remap_links(&importer->set->package_pool, rmap);
910 build_package_file_lists(importer->set, rmap);
911 remap_property_package_links(&importer->set->properties, rmap);
915 array_release(&importer->buckets);
922 razor_set_list(struct razor_set *set, const char *pattern)
924 struct razor_package *p, *end;
925 int with_version = 0;
928 pool = set->string_pool.data;
929 end = set->packages.data + set->packages.size;
930 for (p = set->packages.data; p < end; p++) {
931 if (pattern && fnmatch(pattern, &pool[p->name], 0) != 0)
934 printf("%s-%s\n", &pool[p->name], &pool[p->version]);
936 printf("%s\n", &pool[p->name]);
940 struct razor_set *bsearch_set;
943 compare_package_name(const void *key, const void *data)
945 const struct razor_package *p = data;
948 pool = bsearch_set->string_pool.data;
950 return strcmp(key, &pool[p->name]);
953 struct razor_package *
954 razor_set_get_package(struct razor_set *set, const char *package)
957 return bsearch(package, set->packages.data,
958 set->packages.size / sizeof(struct razor_package),
959 sizeof(struct razor_package), compare_package_name);
963 compare_property_name(const void *key, const void *data)
965 const struct razor_property *p = data;
968 pool = bsearch_set->string_pool.data;
970 return strcmp(key, &pool[p->name & RAZOR_ENTRY_MASK]);
973 struct razor_property *
974 razor_set_get_property(struct razor_set *set, const char *property)
976 struct razor_property *p, *start;
979 p = bsearch(property, set->properties.data,
980 set->properties.size / sizeof(struct razor_property),
981 sizeof(struct razor_property), compare_property_name);
983 start = set->properties.data;
985 ((p - 1)->name & RAZOR_ENTRY_MASK) ==
986 (p->name & RAZOR_ENTRY_MASK))
993 razor_set_list_properties(struct razor_set *set, const char *name,
994 enum razor_property_type type)
996 struct razor_property *p, *properties, *end;
997 struct razor_package *package;
1001 pool = set->string_pool.data;
1004 package = razor_set_get_package(set, name);
1005 r = (unsigned long *) set->property_pool.data +
1006 package->properties;
1007 properties = set->properties.data;
1009 p = &properties[*r & RAZOR_ENTRY_MASK];
1010 if ((p->name >> 30) != type)
1012 if (pool[p->version] == '\0')
1014 &pool[p->name & RAZOR_ENTRY_MASK]);
1017 &pool[p->name & RAZOR_ENTRY_MASK],
1020 if (*r++ & RAZOR_IMMEDIATE)
1024 end = set->properties.data + set->properties.size;
1025 for (p = set->properties.data; p < end; p++) {
1026 if ((p->name >> 30) != type)
1028 if (pool[p->version] == '\0')
1030 &pool[p->name & RAZOR_ENTRY_MASK]);
1033 &pool[p->name & RAZOR_ENTRY_MASK],
1040 razor_set_list_property_packages(struct razor_set *set,
1042 const char *version,
1043 enum razor_property_type type)
1045 struct razor_property *property, *end;
1046 struct razor_package *p, *packages;
1053 property = razor_set_get_property(set, name);
1054 packages = set->packages.data;
1055 pool = set->string_pool.data;
1056 end = set->properties.data + set->properties.size;
1057 while (property < end &&
1058 strcmp(name, &pool[property->name & RAZOR_ENTRY_MASK]) == 0) {
1060 versioncmp(version, &pool[property->version]) != 0)
1062 if (type != (property->name >> 30))
1065 if (property->packages & RAZOR_IMMEDIATE)
1066 r = &property->packages;
1068 r = (unsigned long *)
1069 set->package_pool.data + property->packages;
1071 p = &packages[*r & RAZOR_ENTRY_MASK];
1073 &pool[p->name & RAZOR_ENTRY_MASK],
1075 if (*r++ & RAZOR_IMMEDIATE)
1083 static struct razor_entry *
1084 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
1086 struct razor_entry *e;
1087 const char *n, *pool = set->string_pool.data;
1090 e = (struct razor_entry *) set->files.data + dir->start;
1092 n = pool + (e->name & RAZOR_ENTRY_MASK);
1093 if (strcmp(pattern + 1, n) == 0)
1096 if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
1097 pattern[len + 1] == '/') {
1098 return find_entry(set, e, pattern + len + 1);
1100 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
1106 list_dir(struct razor_set *set, struct razor_entry *dir,
1107 const char *prefix, const char *pattern)
1109 struct razor_entry *e;
1110 const char *n, *pool = set->string_pool.data;
1112 e = (struct razor_entry *) set->files.data + dir->start;
1114 n = pool + (e->name & RAZOR_ENTRY_MASK);
1115 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
1117 printf("%s/%s%s\n", prefix, n, e->start > 0 ? "/" : "");
1118 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
1122 razor_set_list_files(struct razor_set *set, const char *pattern)
1124 struct razor_entry *e;
1125 char buffer[512], *p, *base;
1127 if (pattern == NULL)
1130 strcpy(buffer, pattern);
1131 e = find_entry(set, set->files.data, buffer);
1132 if (e && e->start > 0) {
1135 p = strrchr(buffer, '/');
1143 e = find_entry(set, set->files.data, buffer);
1145 list_dir(set, e, buffer, base);
1149 razor_set_list_file_packages(struct razor_set *set, const char *filename)
1151 struct razor_entry *e;
1152 struct razor_package *packages, *p;
1156 e = find_entry(set, set->files.data, filename);
1160 if (e->packages & RAZOR_IMMEDIATE)
1163 r = (unsigned long *) set->package_pool.data + e->packages;
1165 packages = set->packages.data;
1166 pool = set->string_pool.data;
1168 p = &packages[*r & RAZOR_ENTRY_MASK];
1169 printf("%s-%s\n", &pool[p->name], &pool[p->version]);
1170 if (*r++ & RAZOR_IMMEDIATE)
1175 static unsigned long *
1176 list_package_files(struct razor_set *set, unsigned long *r,
1177 struct razor_entry *dir, unsigned long end,
1180 struct razor_entry *e, *f, *entries;
1185 entries = (struct razor_entry *) set->files.data;
1186 pool = set->string_pool.data;
1188 e = entries + dir->start;
1190 if (entries + *r == e) {
1191 printf("%s/%s\n", prefix,
1192 pool + (e->name & RAZOR_ENTRY_MASK));
1197 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
1199 e = entries + dir->start;
1204 if (e->name & RAZOR_ENTRY_LAST)
1208 while (f->start == 0 && !(f->name & RAZOR_ENTRY_LAST))
1216 if (e->start <= *r && *r < next) {
1217 len = strlen(prefix);
1219 strcpy(prefix + len + 1,
1220 pool + (e->name & RAZOR_ENTRY_MASK));
1221 r = list_package_files(set, r, e, next, prefix);
1226 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
1232 razor_set_list_package_files(struct razor_set *set, const char *name)
1234 struct razor_package *package;
1235 unsigned long *r, end;
1238 package = razor_set_get_package(set, name);
1240 r = (unsigned long *) set->file_pool.data + package->files;
1241 end = set->files.size / sizeof (struct razor_entry);
1243 list_package_files(set, r, set->files.data, end, buffer);
1247 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
1249 struct razor_property *r, *p, *end;
1253 end = set->properties.data + set->properties.size;
1254 pool = set->string_pool.data;
1256 for (r = set->properties.data, p = r; r < end; r++) {
1257 if (r->name >> 30 != RAZOR_PROPERTY_REQUIRES)
1260 if ((r->name & RAZOR_ENTRY_MASK) != (p->name & RAZOR_ENTRY_MASK)) {
1262 while (p < end && p->name == r->name)
1266 /* If there is more than one version of a provides,
1267 * seek to the end for the highest version. */
1268 /* FIXME: This doesn't work if we have a series of
1269 * requires a = 1, provides a = 1, requires a = 2,
1270 * provides a = 2, as the kernel and kernel-devel
1272 while (p + 1 < end && p->name == (p + 1)->name)
1275 /* FIXME: We need to track property flags (<, <=, =
1276 * etc) to properly determine if a requires is
1277 * satisfied. The current code doesn't track that the
1278 * requires a = 1 isn't satisfied by a = 2 provides. */
1281 (p->name >> 30) != RAZOR_PROPERTY_PROVIDES ||
1282 (r->name & RAZOR_ENTRY_MASK) != (p->name & RAZOR_ENTRY_MASK) ||
1283 versioncmp(&pool[r->version], &pool[p->version]) > 0) {
1284 /* FIXME: We ignore file requires for now. */
1285 if (pool[r->name & RAZOR_ENTRY_MASK] == '/')
1287 u = array_add(unsatisfied, sizeof *u);
1288 *u = r - (struct razor_property *) set->properties.data;
1294 razor_set_list_unsatisfied(struct razor_set *set)
1296 struct array unsatisfied;
1297 struct razor_property *properties, *r;
1298 unsigned long *u, *end;
1301 array_init(&unsatisfied);
1302 razor_set_validate(set, &unsatisfied);
1304 end = unsatisfied.data + unsatisfied.size;
1305 properties = set->properties.data;
1306 pool = set->string_pool.data;
1308 for (u = unsatisfied.data; u < end; u++) {
1309 r = properties + *u;
1310 if (pool[r->version] == '\0')
1311 printf("%ss not satisfied\n",
1312 &pool[r->name & RAZOR_ENTRY_MASK]);
1314 printf("%s-%s not satisfied\n",
1315 &pool[r->name & RAZOR_ENTRY_MASK],
1319 array_release(&unsatisfied);
1322 #define UPSTREAM_SOURCE 0x80000000ul
1323 #define INDEX_MASK 0x00fffffful
1326 struct razor_set *set;
1327 unsigned long *property_map;
1331 prepare_source(struct source *source, struct razor_set *set)
1338 count = set->properties.size / sizeof (struct razor_property);
1339 size = count * sizeof *source->property_map;
1340 source->property_map = zalloc(size);
1344 add_package(struct razor_importer *importer,
1345 struct razor_package *package, struct source *source,
1346 unsigned long flags)
1350 struct razor_package *p;
1352 pool = source->set->string_pool.data;
1353 p = array_add(&importer->set->packages, sizeof *p);
1354 p->name = razor_importer_tokenize(importer, &pool[package->name]);
1356 p->version = razor_importer_tokenize(importer,
1357 &pool[package->version]);
1358 p->properties = package->properties;
1360 if (package->properties & RAZOR_IMMEDIATE)
1361 r = &package->properties;
1363 r = (unsigned long *)
1364 source->set->property_pool.data + package->properties;
1366 source->property_map[*r & RAZOR_ENTRY_MASK] = 1;
1367 if (*r++ & RAZOR_IMMEDIATE)
1373 /* Build the new package list sorted by merging the two package lists.
1374 * Build new string pool as we go. (for now we just re-use that part of
1377 merge_packages(struct razor_importer *importer,
1378 struct source *source1, struct source *source2,
1379 struct array *packages)
1381 struct razor_package *upstream_packages, *p, *s, *send;
1382 char *spool, *upool;
1383 unsigned long *u, *uend;
1386 upstream_packages = source2->set->packages.data;
1389 uend = packages->data + packages->size;
1390 upool = source2->set->string_pool.data;
1392 s = source1->set->packages.data;
1393 send = source1->set->packages.data + source1->set->packages.size;
1394 spool = source1->set->string_pool.data;
1397 p = upstream_packages + *u;
1400 cmp = strcmp(&spool[s->name], &upool[p->name]);
1401 if (u >= uend || cmp < 0) {
1402 add_package(importer, s, source1, 0);
1404 } else if (cmp == 0) {
1405 add_package(importer, p, source2, UPSTREAM_SOURCE);
1409 add_package(importer, p, source2, UPSTREAM_SOURCE);
1415 static unsigned long
1416 add_property(struct razor_importer *importer,
1417 const char *name, const char *version, int type)
1419 struct razor_property *p;
1421 p = array_add(&importer->set->properties, sizeof *p);
1422 p->name = razor_importer_tokenize(importer, name) | (type << 30);
1423 p->version = razor_importer_tokenize(importer, version);
1425 return p - (struct razor_property *) importer->set->properties.data;
1429 merge_properties(struct razor_importer *importer,
1430 struct razor_set *set1,
1431 unsigned long *map1,
1432 struct razor_set *set2,
1433 unsigned long *map2)
1435 struct razor_property *p1, *p2;
1436 int i, j, cmp, count1, count2;
1437 char *pool1, *pool2;
1441 pool1 = set1->string_pool.data;
1442 pool2 = set2->string_pool.data;
1444 count1 = set1->properties.size / sizeof *p1;
1445 count2 = set2->properties.size / sizeof *p2;
1446 while (i < count1 || j < count2) {
1447 if (i < count1 && map1[i] == 0) {
1451 if (j < count2 && map2[j] == 0) {
1455 p1 = (struct razor_property *) set1->properties.data + i;
1456 p2 = (struct razor_property *) set2->properties.data + j;
1457 if (i < count1 && j < count2)
1458 cmp = strcmp(&pool1[p1->name & RAZOR_ENTRY_MASK],
1459 &pool2[p2->name & RAZOR_ENTRY_MASK]);
1460 else if (i < count1)
1465 cmp = versioncmp(&pool1[p1->version],
1466 &pool2[p2->version]);
1468 map1[i++] = add_property(importer,
1469 &pool1[p1->name & RAZOR_ENTRY_MASK],
1470 &pool1[p1->version],
1472 } else if (cmp > 0) {
1473 map2[j++] = add_property(importer,
1474 &pool2[p2->name & RAZOR_ENTRY_MASK],
1475 &pool2[p2->version],
1478 map1[i++] = map2[j++] = add_property(importer,
1479 &pool1[p1->name & RAZOR_ENTRY_MASK],
1480 &pool1[p1->version],
1486 static unsigned long
1487 emit_properties(struct array *source_pool, unsigned long index,
1488 unsigned long *map, struct array *pool)
1490 unsigned long r, *p, *q;
1492 r = pool->size / sizeof *q;
1493 p = (unsigned long *) source_pool->data + index;
1495 q = array_add(pool, sizeof *q);
1496 *q = map[*p & RAZOR_ENTRY_MASK] | (*p & ~RAZOR_ENTRY_MASK);
1497 if (*p++ & RAZOR_ENTRY_LAST)
1504 /* Rebuild property->packages maps. We can't just remap these, as a
1505 * property may have lost or gained a number of packages. Allocate an
1506 * array per property and loop through the packages and add them to
1507 * the arrays for their properties. */
1509 rebuild_package_lists(struct razor_set *set)
1511 struct array *pkgs, *a;
1512 struct razor_package *pkg, *pkg_end;
1513 struct razor_property *prop, *prop_end;
1514 unsigned long *r, *q, *pool;
1517 count = set->properties.size / sizeof (struct razor_property);
1518 pkgs = zalloc(count * sizeof *pkgs);
1519 pkg_end = set->packages.data + set->packages.size;
1520 pool = set->property_pool.data;
1522 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1523 for (r = &pool[pkg->properties]; ; r++) {
1524 q = array_add(&pkgs[*r & RAZOR_ENTRY_MASK], sizeof *q);
1525 *q = pkg - (struct razor_package *) set->packages.data;
1526 if (*r & RAZOR_IMMEDIATE)
1531 prop_end = set->properties.data + set->properties.size;
1533 for (prop = set->properties.data; prop < prop_end; prop++, a++) {
1534 if (a->size / sizeof *r == 1) {
1536 prop->packages = *r | RAZOR_IMMEDIATE;
1539 add_to_property_pool(&set->property_pool, a);
1546 /* Add packages from 'upstream' to 'set'. The packages to add are
1547 * specified by the 'packages' array, which is a sorted list of
1548 * package indexes. Returns a newly allocated package set. Does not
1549 * enforce validity of the resulting package set.
1551 * This looks more complicated than it is. An easy way to merge two
1552 * package sets would be to just use a razor_importer, but that
1553 * requires resorting, and is thus O(n log n). We can do this in a
1554 * linear sweep, but it gets a little more complicated.
1557 razor_set_add(struct razor_set *set, struct razor_set *upstream,
1558 struct array *packages)
1560 struct razor_set *result;
1561 struct razor_importer *importer;
1562 struct razor_package *p, *pend;
1563 struct source source, upstream_source;
1565 importer = razor_importer_new();
1567 prepare_source(&upstream_source, upstream);
1568 prepare_source(&source, set);
1570 merge_packages(importer, &source, &upstream_source, packages);
1572 /* As we built the package list, we filled out a bitvector of
1573 * the properties that are referenced by the packages in the
1574 * new set. Now we do a parallel loop through the properties
1575 * and emit those marked in the bit vector to the new set. In
1576 * the process, we update the bit vector to actually map from
1577 * indices in the old property list to indices in the new
1578 * property list for both sets. */
1580 merge_properties(importer,
1581 set, source.property_map,
1582 upstream, upstream_source.property_map);
1584 /* Now we loop through the packages again and emit the
1585 * property lists, remapped to point to the new properties. */
1587 pend = importer->set->packages.data + importer->set->packages.size;
1588 for (p = importer->set->packages.data; p < pend; p++) {
1591 if (p->name & UPSTREAM_SOURCE)
1592 src = &upstream_source;
1596 p->properties = emit_properties(&src->set->property_pool,
1599 &importer->set->property_pool);
1600 p->name &= INDEX_MASK;
1603 rebuild_package_lists(importer->set);
1605 result = importer->set;
1606 array_release(&importer->buckets);
1613 razor_set_satisfy(struct razor_set *set, struct array *unsatisfied,
1614 struct razor_set *upstream, struct array *list)
1616 struct razor_property *requires, *r;
1617 struct razor_property *p, *pend;
1618 unsigned long *u, *end, *pkg, *package_pool;
1621 end = unsatisfied->data + unsatisfied->size;
1622 requires = set->properties.data;
1623 pool = set->string_pool.data;
1625 p = upstream->properties.data;
1626 pend = upstream->properties.data + upstream->properties.size;
1627 upool = upstream->string_pool.data;
1628 package_pool = upstream->package_pool.data;
1630 for (u = unsatisfied->data; u < end; u++) {
1634 strcmp(&pool[r->name & RAZOR_ENTRY_MASK],
1635 &upool[p->name & RAZOR_ENTRY_MASK]) > 0 &&
1636 (p->name >> 30) != RAZOR_PROPERTY_PROVIDES)
1638 /* If there is more than one version of a provides,
1639 * seek to the end for the highest version. */
1640 while (p + 1 < pend && p->name == (p + 1)->name)
1644 strcmp(&pool[r->name & RAZOR_ENTRY_MASK],
1645 &upool[p->name & RAZOR_ENTRY_MASK]) != 0 ||
1646 versioncmp(&pool[r->version], &upool[p->version]) > 0) {
1647 /* Do we need to track unsatisfiable requires
1648 * as we go, or should we just do a
1649 * razor_set_validate() at the end? */
1651 pkg = array_add(list, sizeof *pkg);
1652 /* We just pull in the first package that provides */
1653 if (p->packages & RAZOR_IMMEDIATE)
1654 *pkg = p->packages & RAZOR_ENTRY_MASK;
1656 *pkg = package_pool[p->packages];
1662 find_packages(struct razor_set *set,
1663 int count, const char **packages, struct array *list)
1665 struct razor_package *p;
1669 /* FIXME: Sort the packages. */
1670 for (i = 0; i < count; i++) {
1671 p = razor_set_get_package(set, packages[i]);
1672 r = array_add(list, sizeof *r);
1673 *r = p - (struct razor_package *) set->packages.data;
1678 find_all_packages(struct razor_set *set,
1679 struct razor_set *upstream, struct array *list)
1681 struct razor_package *p, *u, *pend, *uend;
1685 pend = set->packages.data + set->packages.size;
1686 pool = set->string_pool.data;
1687 u = upstream->packages.data;
1688 uend = upstream->packages.data + upstream->packages.size;
1689 upool = upstream->string_pool.data;
1691 for (p = set->packages.data; p < pend; p++) {
1692 while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0)
1694 if (strcmp(&pool[p->name], &upool[u->name]) == 0) {
1695 r = array_add(list, sizeof *r);
1696 *r = u - (struct razor_package *) upstream->packages.data;
1702 razor_set_update(struct razor_set *set, struct razor_set *upstream,
1703 int count, const char **packages)
1705 struct razor_set *new;
1706 struct razor_package *upackages;
1707 struct array list, unsatisfied;
1709 unsigned long *u, *end;
1714 find_packages(upstream, count, packages, &list);
1716 find_all_packages(set, upstream, &list);
1718 end = list.data + list.size;
1719 upackages = upstream->packages.data;
1720 pool = upstream->string_pool.data;
1721 total += list.size / sizeof *u;
1723 while (list.size > 0) {
1724 new = razor_set_add(set, upstream, &list);
1725 array_release(&list);
1726 razor_set_destroy(set);
1729 array_init(&unsatisfied);
1730 razor_set_validate(new, &unsatisfied);
1732 razor_set_satisfy(new, &unsatisfied, upstream, &list);
1733 array_release(&unsatisfied);
1735 end = list.data + list.size;
1736 upackages = upstream->packages.data;
1737 pool = upstream->string_pool.data;
1738 total += list.size / sizeof *u;
1741 array_release(&list);
1746 /* The diff order matters. We should sort the packages so that a
1747 * REMOVE of a package comes before the INSTALL, and so that all
1748 * requires for a package have been installed before the package.
1752 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
1753 razor_package_callback_t callback, void *data)
1755 struct razor_package *p, *pend, *u, *uend;
1756 char *ppool, *upool;
1759 p = set->packages.data;
1760 pend = set->packages.data + set->packages.size;
1761 ppool = set->string_pool.data;
1763 u = upstream->packages.data;
1764 uend = upstream->packages.data + upstream->packages.size;
1765 upool = upstream->string_pool.data;
1767 while (p < pend || u < uend) {
1768 if (p < pend && u < uend) {
1769 res = strcmp(&ppool[p->name], &upool[u->name]);
1771 res = versioncmp(&ppool[p->version],
1772 &upool[u->version]);
1775 if (u == uend || res < 0) {
1776 callback(&ppool[p->name], &ppool[p->version],
1780 } else if (p == pend || res > 0) {
1781 callback(&upool[u->name], NULL, &upool[u->version],