Add a test for relocations that are valid paths but would be invalid URIs if mis-interpreted
2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
4 * Copyright (C) 2009, 2016 J. Ali Harlow <ali@juiblex.co.uk>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "razor-internal.h"
29 * razor_importer_create:
31 * Create a new %razor_importer.
33 * Returns: the new %razor_importer.
35 RAZOR_EXPORT struct razor_importer *
36 razor_importer_create(void)
38 struct razor_importer *importer;
40 importer = zalloc(sizeof *importer);
41 importer->set = razor_set_create();
42 hashtable_init(&importer->table, &importer->set->string_pool);
43 hashtable_init(&importer->details_table,
44 &importer->set->details_string_pool);
45 hashtable_init(&importer->file_table,
46 &importer->set->file_string_pool);
52 * razor_importer_destroy:
53 * @importer: the %razor_importer
55 * Destroy an importer without creating a %razor_set. Normally,
56 * %razor_importer_finish will create a new %razor_set and destroy the
57 * importer. If the import must be aborted without creating the set,
58 * just destroy the import using this function.
61 razor_importer_destroy(struct razor_importer *importer)
63 struct import_entry *e, *end;
65 razor_set_unref(importer->set);
66 hashtable_release(&importer->table);
67 hashtable_release(&importer->details_table);
68 hashtable_release(&importer->file_table);
70 e = importer->files.data;
71 end = importer->files.data + importer->files.size;
76 array_release(&importer->files);
77 array_release(&importer->file_requires);
79 if (importer->package) {
80 array_release(&importer->properties);
81 array_release(&importer->install_prefixes);
89 * razor_importer_begin_package:
90 * @importer: the %razor_importer
91 * @name: the name of the new package
92 * @version: the version of the new package
93 * @arch: the architechture of the new package.
95 * Begin describing a new package to the importer. This creates a new
96 * package and sets the %name, %version and %arch. Subsequent calls
97 * to %razor_importer_add_details, %razor_importer_add_property and
98 * %razor_importer_add_file further describe this package and
99 * %razor_importer_finish_package marks the end of meta data for this
103 razor_importer_begin_package(struct razor_importer *importer,
109 struct razor_package *p;
111 p = array_add(&importer->set->packages, sizeof *p);
112 p->name = hashtable_tokenize(&importer->table, name);
114 p->version = hashtable_tokenize(&importer->table, version);
115 p->arch = hashtable_tokenize(&importer->table, arch);
117 importer->package = p;
118 array_init(&importer->properties);
119 array_init(&importer->install_prefixes);
121 empty = hashtable_tokenize(&importer->details_table, "");
122 importer->package->preun.program = empty;
123 importer->package->preun.body = empty;
124 importer->package->postun.program = empty;
125 importer->package->postun.body = empty;
129 * razor_importer_finish_package:
130 * @importer: the %razor_importer
132 * Tells the importer that the current package is complete.
135 razor_importer_finish_package(struct razor_importer *importer)
137 list_set_array(&importer->package->properties,
138 &importer->set->property_pool,
139 &importer->properties,
142 list_set_array(&importer->package->install_prefixes,
143 &importer->set->prefix_pool,
144 &importer->install_prefixes,
147 array_release(&importer->properties);
148 array_release(&importer->install_prefixes);
150 importer->package = NULL;
154 * razor_importer_add_details:
155 * @importer: the %razor_importer
156 * @summary: the package summary
157 * @description: the package description
158 * @url: the package url
159 * @license: the package license
161 * Provide additional information for the current package.
164 razor_importer_add_details(struct razor_importer *importer,
166 const char *description,
170 importer->package->summary = hashtable_tokenize(&importer->details_table, summary);
171 importer->package->description = hashtable_tokenize(&importer->details_table, description);
172 importer->package->url = hashtable_tokenize(&importer->details_table, url);
173 importer->package->license = hashtable_tokenize(&importer->details_table, license);
177 * razor_importer_add_script:
178 * @importer: the %razor_importer
179 * @script: either %RAZOR_PROPERTY_PREUN or %RAZOR_PROPERTY_POSTUN
180 * @program: the program to run the script
181 * @body: the body of the script
183 * Provide a script to use when uninstalling the current package.
186 razor_importer_add_script(struct razor_importer *importer,
187 enum razor_property_flags script,
192 case RAZOR_PROPERTY_PREUN:
193 importer->package->preun.program =
194 hashtable_tokenize(&importer->table, program);
195 importer->package->preun.body =
196 hashtable_tokenize(&importer->table, body);
198 case RAZOR_PROPERTY_POSTUN:
199 importer->package->postun.program =
200 hashtable_tokenize(&importer->table, program);
201 importer->package->postun.body =
202 hashtable_tokenize(&importer->table, body);
210 * razor_importer_add_install_prefixes:
211 * @importer: the %razor_importer
212 * @install_prefix: the relocated prefix
214 * Adds a relocated prefix for the current package.
217 razor_importer_add_install_prefix(struct razor_importer *importer,
218 const char *install_prefix)
222 r = array_add(&importer->install_prefixes, sizeof *r);
223 *r = hashtable_tokenize(&importer->table, install_prefix);
227 * razor_importer_add_property:
228 * @importer: the %razor_importer
229 * @name: name of the property
230 * @flags: property flags
231 * @version: version of the property or %NULL
233 * Add a property for the current package. The %flags parameter
234 * determines the type of the property and optionally the relation to
235 * the specified version and the availability constraint. See
236 * %razor_property_flags for further information about the flag
240 razor_importer_add_property(struct razor_importer *importer,
245 struct razor_property *p;
248 p = array_add(&importer->set->properties, sizeof *p);
249 p->name = hashtable_tokenize(&importer->table, name);
251 p->version = hashtable_tokenize(&importer->table, version);
252 list_set_ptr(&p->packages, importer->package -
253 (struct razor_package *) importer->set->packages.data);
255 r = array_add(&importer->properties, sizeof *r);
256 *r = p - (struct razor_property *) importer->set->properties.data;
258 if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) &&
260 r = array_add(&importer->file_requires, sizeof *r);
266 * razor_importer_add_file:
267 * @importer: the %razor_importer
268 * @name: name of the file
270 * Add a file to the current package.
273 razor_importer_add_file(struct razor_importer *importer, const char *name)
275 struct import_entry *e;
277 e = array_add(&importer->files, sizeof *e);
279 e->package = importer->package -
280 (struct razor_package *) importer->set->packages.data;
281 e->name = strdup(name);
285 compare_packages(const void *p1, const void *p2, void *data)
287 const struct razor_package *pkg1 = p1, *pkg2 = p2;
288 struct razor_set *set = data;
289 char *pool = set->string_pool.data;
291 /* FIXME: what if the flags are different? */
292 if (pkg1->name == pkg2->name)
293 return razor_versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
295 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
299 compare_properties(const void *p1, const void *p2, void *data)
301 const struct razor_property *prop1 = p1, *prop2 = p2;
302 struct razor_set *set = data;
303 char *pool = set->string_pool.data;
305 if (prop1->name != prop2->name)
306 return strcmp(&pool[prop1->name], &pool[prop2->name]);
307 else if (prop1->flags != prop2->flags)
308 return prop1->flags - prop2->flags;
309 else if (prop1->version != prop2->version)
310 return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]);
312 return prop1->packages.list_ptr - prop2->packages.list_ptr;
316 uniqueify_properties(struct razor_set *set)
318 struct razor_property *rp, *up, *rp_end;
319 struct array *pkgs, *p;
321 uint32_t *map, *rmap;
322 int i, count, unique;
324 count = set->properties.size / sizeof(struct razor_property);
325 map = razor_qsort_with_data(set->properties.data,
327 sizeof(struct razor_property),
331 rp_end = set->properties.data + set->properties.size;
332 rmap = malloc(count * sizeof *map);
333 pkgs = zalloc(count * sizeof *pkgs);
334 for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
335 if (rp->name != up->name ||
336 rp->flags != up->flags ||
337 rp->version != up->version) {
340 up->flags = rp->flags;
341 up->version = rp->version;
344 unique = up - (struct razor_property *) set->properties.data;
345 rmap[map[i]] = unique;
346 r = array_add(&pkgs[unique], sizeof *r);
353 set->properties.size = (void *) up - set->properties.data;
355 for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
356 list_set_array(&rp->packages, &set->package_pool, p, 0);
366 compare_filenames(const void *p1, const void *p2, void *data)
368 const struct import_entry *e1 = p1;
369 const struct import_entry *e2 = p2;
370 const char *n1 = e1->name;
371 const char *n2 = e2->name;
373 /* Need to make sure that the contents of a directory
374 * are sorted immediately after it. So "foo/bar" has to
375 * sort before "foo.conf"
377 * FIXME: this is about 60% slower than strcmp
381 return *n2 == '/' ? 1 : -1;
383 return *n1 == '/' ? -1 : 1;
396 count_entries(struct import_directory *d)
398 struct import_directory *p, *end;
401 end = d->files.data + d->files.size;
405 d->count += p->count + 1;
411 serialize_files(struct razor_set *set,
412 struct import_directory *d, struct array *array)
414 struct import_directory *p, *end;
415 struct razor_entry *e = NULL;
419 end = d->files.data + d->files.size;
420 s = array->size / sizeof *e + d->files.size / sizeof *p;
422 e = array_add(array, sizeof *e);
425 e->start = p->count > 0 ? s : 0;
428 list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
429 array_release(&p->packages);
433 e->flags |= RAZOR_ENTRY_LAST;
436 end = d->files.data + d->files.size;
438 serialize_files(set, p, array);
442 array_release(&d->files);
446 remap_property_package_links(struct array *properties, uint32_t *rmap)
448 struct razor_property *p, *end;
450 end = properties->data + properties->size;
451 for (p = properties->data; p < end; p++)
452 list_remap_head(&p->packages, rmap);
456 build_file_tree(struct razor_importer *importer)
458 int count, i, length;
459 struct import_entry *filenames;
461 uint32_t name, *r, s;
464 struct import_directory *d, *last_root;
466 struct razor_entry *e;
468 count = importer->files.size / sizeof (struct import_entry);
469 filenames = importer->files.data;
470 map = razor_qsort_with_data(filenames,
472 sizeof (struct import_entry),
480 for (i = 0; i < count; i++) {
481 f = filenames[i].name;
484 end = strchr(f, '/');
488 memcpy(dirname, f, length);
489 dirname[length] = '\0';
490 name = hashtable_tokenize(&importer->file_table,
493 if (!last_root || last_root->name != name) {
494 d = array_add(&roots, sizeof *d);
497 array_init(&d->files);
498 array_init(&d->packages);
503 if (!d->last || d->last->name != name) {
504 d->last = array_add(&d->files,
506 d->last->name = name;
507 d->last->last = NULL;
508 array_init(&d->last->files);
509 array_init(&d->last->packages);
518 r = array_add(&d->packages, sizeof *r);
519 *r = filenames[i].package;
520 free(filenames[i].name);
523 count = roots.size / sizeof (struct import_directory);
526 for (i = 0; i < count; i++) {
529 e = array_add(&importer->set->files, sizeof *e);
531 e = importer->set->files.data;
534 e->start = d->count > 0 ? s : 0;
536 list_set_empty(&e->packages);
540 e->flags |= RAZOR_ENTRY_LAST;
543 for (i = 0; i < count; i++) {
544 serialize_files(importer->set, d, &importer->set->files);
548 array_release(&importer->files);
549 array_release(&roots);
553 list_to_array(struct list *list, struct array *array)
558 item = array_add(array, sizeof *item);
560 list = list_next(list);
565 compare_file_requires(const void *p1, const void *p2, void *data)
567 uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
568 const char *pool = data;
570 return strcmp(&pool[*f1], &pool[*f2]);
574 find_file_provides(struct razor_importer *importer)
576 struct razor_property *prop;
577 struct razor_entry *top, *entry;
578 struct razor_package *packages;
579 struct array pkgprops;
581 uint32_t *req, *req_start, *req_end;
582 uint32_t *map, *newprop;
585 pool = importer->set->string_pool.data;
586 packages = importer->set->packages.data;
587 top = importer->set->files.data;
589 req = req_start = importer->file_requires.data;
590 req_end = importer->file_requires.data + importer->file_requires.size;
591 map = razor_qsort_with_data(req, req_end - req, sizeof *req,
592 compare_file_requires, pool);
595 for (req = req_start; req < req_end; req++) {
596 if (req > req_start && req[0] == req[-1])
598 entry = razor_set_find_entry(importer->set, top, &pool[*req]);
602 for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
603 prop = array_add(&importer->set->properties, sizeof *prop);
606 RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
607 prop->version = hashtable_tokenize(&importer->table, "");
608 list_set_ptr(&prop->packages, pkg->data);
610 /* Update property list of pkg */
611 array_init(&pkgprops);
612 list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
613 newprop = array_add(&pkgprops, sizeof *newprop);
614 *newprop = prop - (struct razor_property *)importer->set->properties.data;
615 list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
616 array_release(&pkgprops);
620 array_release(&importer->file_requires);
624 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
626 struct razor_package *p, *packages;
628 struct razor_entry *e, *end;
633 count = set->packages.size / sizeof *p;
634 pkgs = zalloc(count * sizeof *pkgs);
636 end = set->files.data + set->files.size;
637 for (e = set->files.data; e < end; e++) {
638 list_remap_head(&e->packages, rmap);
639 r = list_first(&e->packages, &set->package_pool);
641 q = array_add(&pkgs[r->data], sizeof *q);
642 *q = e - (struct razor_entry *) set->files.data;
647 packages = set->packages.data;
648 for (i = 0; i < count; i++) {
649 list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
650 array_release(&pkgs[i]);
656 * razor_importer_finish:
657 * @importer: the %razor_importer
659 * Finish importing packages and create the package set. This sorts
660 * and indexes all the packages, properties and files in the importer
661 * and creates a new %razor_set. After creating the new package set,
662 * the importer is destroyed.
664 * Returns: the new %razor_set
666 RAZOR_EXPORT struct razor_set *
667 razor_importer_finish(struct razor_importer *importer)
669 struct razor_set *set;
670 uint32_t *map, *rmap;
673 build_file_tree(importer);
674 find_file_provides(importer);
676 map = uniqueify_properties(importer->set);
677 list_remap_pool(&importer->set->property_pool, map);
680 count = importer->set->packages.size / sizeof(struct razor_package);
681 map = razor_qsort_with_data(importer->set->packages.data,
683 sizeof(struct razor_package),
687 rmap = malloc(count * sizeof *rmap);
688 for (i = 0; i < count; i++)
692 list_remap_pool(&importer->set->package_pool, rmap);
693 build_package_file_lists(importer->set, rmap);
694 remap_property_package_links(&importer->set->properties, rmap);
698 hashtable_release(&importer->table);
699 hashtable_release(&importer->details_table);
700 hashtable_release(&importer->file_table);