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-2012, 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.
42 #include "razor-internal.h"
49 struct razor_set_section_index {
55 #define MAIN(type, field) \
56 { type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
57 #define FILES(type, field) \
58 { type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
59 #define DETAILS(type, field) \
60 { type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
62 struct razor_set_section_index razor_sections[] = {
63 MAIN(RAZOR_STRING_POOL, string_pool),
64 MAIN(RAZOR_PACKAGES, packages),
65 MAIN(RAZOR_PROPERTIES, properties),
66 MAIN(RAZOR_PACKAGE_POOL, package_pool),
67 MAIN(RAZOR_PROPERTY_POOL, property_pool),
68 MAIN(RAZOR_PREFIX_POOL, prefix_pool),
69 FILES(RAZOR_FILES, files),
70 FILES(RAZOR_FILE_POOL, file_pool),
71 FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
72 DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
75 RAZOR_EXPORT struct razor_set *
76 razor_set_create_without_root(void)
78 struct razor_set *set;
81 set = zalloc(sizeof *set);
84 empty = array_add(&set->string_pool, 1);
91 set->header_version = RAZOR_HEADER_VERSION;
93 set->flags = RAZOR_SET_PRIVATE;
99 RAZOR_EXPORT struct razor_set *
100 razor_set_create(void)
102 struct razor_set *set;
103 struct razor_entry *e;
105 set = razor_set_create_without_root();
107 e = array_add(&set->files, sizeof *e);
109 e->flags = RAZOR_ENTRY_LAST;
111 list_set_empty(&e->packages);
116 RAZOR_EXPORT uint32_t
117 razor_set_get_header_version(struct razor_set *set)
119 return set->header_version;
123 razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
125 if (header_version<RAZOR_HEADER_VERSION_MIN ||
126 header_version>RAZOR_HEADER_VERSION)
129 set->header_version = header_version;
134 struct razor_mapped_file {
135 struct razor_set_header *header;
137 struct razor_mapped_file *next;
141 razor_set_bind_sections(struct razor_set *set, const char *uri,
142 enum razor_set_flags flags, struct razor_error **error)
144 struct razor_set_section *s, *sections;
145 struct razor_mapped_file *file;
146 const char *pool, *reason;
150 file = zalloc(sizeof *file);
152 razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
153 "Not enough memory");
157 file->header = razor_uri_get_contents(uri, &file->size,
158 flags & RAZOR_SET_PRIVATE,
165 if (file->size < sizeof *file->header) {
166 code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
167 reason = "Premature EOF";
168 } else if (file->header->magic != RAZOR_MAGIC) {
169 code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
170 reason = "Bad magic number";
171 } else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
172 file->header->version > RAZOR_HEADER_VERSION) {
173 code = RAZOR_GENERAL_ERROR_DATABASE_INCOMPATIBLE;
174 reason = "Incompatible file version";
179 razor_set_error(error, RAZOR_GENERAL_ERROR, code, uri, reason);
180 razor_uri_free_contents(file->header, file->size);
185 set->flags = flags & RAZOR_SET_PRIVATE;
187 set->header_version = file->header->version;
189 if (set->mapped_files == NULL) {
190 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
191 array = (void *) set + razor_sections[i].offset;
192 array_release(array);
196 file->next = set->mapped_files;
197 set->mapped_files = file;
199 sections = (void *) file->header + sizeof *file->header;
200 pool = (void *) sections +
201 file->header->num_sections * sizeof *sections;
203 for (i = 0; i < file->header->num_sections; i++) {
205 for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
206 if (!strcmp(razor_sections[j].name, &pool[s->name]))
208 if (j == ARRAY_SIZE(razor_sections))
210 array = (void *) set + razor_sections[j].offset;
211 array->data = (void *) file->header + s->offset;
212 array->size = s->size;
213 array->alloc = s->size;
219 RAZOR_EXPORT struct razor_set *
220 razor_set_open(const char *uri, enum razor_set_flags flags,
221 struct razor_error **error)
223 struct razor_set *set;
225 set = zalloc(sizeof *set);
227 razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
228 "Not enough memory");
234 if (razor_set_bind_sections(set, uri, flags, error)) {
242 razor_set_acquire_lock(struct razor_set *set, const char *uri, int exclusive)
248 fd = razor_uri_open(uri, O_CREAT | O_RDWR | O_TRUNC | O_BINARY,
256 DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
257 OVERLAPPED lock = {0};
260 flags |= LOCKFILE_EXCLUSIVE_LOCK;
261 if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0,
266 if (set->lock_fd >= 0)
267 (void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1,
270 struct flock lock = {0};
272 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
273 lock.l_whence = SEEK_SET;
276 if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) {
280 if (set->lock_fd >= 0) {
281 lock.l_type = F_UNLCK;
282 (void)fcntl(set->lock_fd, F_SETLK, &lock);
286 if (set->lock_fd >= 0)
294 razor_set_destroy(struct razor_set *set)
296 struct razor_mapped_file *file, *next;
300 assert (set != NULL);
302 if (set->mapped_files == NULL) {
303 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
304 array = (void *) set + razor_sections[i].offset;
305 array_release(array);
308 for (file = set->mapped_files; file != NULL; file = next) {
310 razor_uri_free_contents(file->header, file->size);
315 razor_set_acquire_lock(set, NULL, 0);
320 razor_set_unref(struct razor_set *set)
322 if (set && !--set->ref_count)
323 razor_set_destroy(set);
326 RAZOR_EXPORT struct razor_set *
327 razor_set_ref(struct razor_set *set)
335 razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
336 int handle, uint32_t section_mask)
338 struct razor_set_header header;
339 struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
340 struct hashtable table;
341 struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
344 static const char padding[4];
347 hashtable_init(&table, &pool);
350 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
351 if ((razor_sections[i].flags & section_mask) == 0)
354 arrays[j] = (void *) set + razor_sections[i].offset;
356 hashtable_tokenize(&table, razor_sections[i].name);
361 header.magic = RAZOR_MAGIC;
362 header.version = set->header_version;
363 header.num_sections = count;
364 offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
366 for (i = 0; i < count; i++) {
367 sections[i].offset = offset;
368 sections[i].size = arrays[i]->size;
369 offset += ALIGN(arrays[i]->size, 4);
372 razor_atomic_write(atomic, handle, &header, sizeof header);
373 razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
374 razor_atomic_write(atomic, handle, pool.data, pool.size);
375 razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
377 for (i = 0; i < count; i++) {
378 razor_atomic_write(atomic, handle, arrays[i]->data,
380 razor_atomic_write(atomic, handle, padding,
381 PADDING(arrays[i]->size, 4));
384 array_release(&pool);
385 hashtable_release(&table);
389 razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
390 const char *uri, uint32_t sections)
394 h = razor_atomic_create_file(atomic, uri,
395 S_IRWXU | S_IRWXG | S_IRWXO);
399 razor_set_write_to_handle(set, atomic, h, sections);
401 return razor_atomic_close(atomic, h);
405 razor_build_evr(char *evr_buf, int size, const char *epoch,
406 const char *version, const char *release)
410 if (!version || !*version) {
415 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
416 len = snprintf(evr_buf, size, "%s:", epoch);
420 len = snprintf(evr_buf, size, "%s", version);
423 if (release && *release)
424 snprintf(evr_buf, size, "-%s", release);
428 razor_versioncmp(const char *s1, const char *s2)
437 n1 = strtol(s1, (char **) &p1, 10);
438 n2 = strtol(s2, (char **) &p2, 10);
440 /* Epoch; if one but not the other has an epoch set, default
441 * the epoch-less version to 0. */
442 res = (*p1 == ':') - (*p2 == ':');
447 } else if (res > 0) {
460 if (isdigit(*p1) && isdigit(*p2))
461 return razor_versioncmp(p1, p2);
468 razor_package_get_details_string(struct razor_set *set,
469 struct razor_package *package,
470 enum razor_detail_type type)
475 case RAZOR_DETAIL_NAME:
476 pool = set->string_pool.data;
477 return &pool[package->name];
479 case RAZOR_DETAIL_VERSION:
480 pool = set->string_pool.data;
481 return &pool[package->version];
483 case RAZOR_DETAIL_ARCH:
484 pool = set->string_pool.data;
485 return &pool[package->arch];
487 case RAZOR_DETAIL_SUMMARY:
488 if (!set->details_string_pool.size)
490 pool = set->details_string_pool.data;
491 return &pool[package->summary];
493 case RAZOR_DETAIL_DESCRIPTION:
494 if (!set->details_string_pool.size)
496 pool = set->details_string_pool.data;
497 return &pool[package->description];
499 case RAZOR_DETAIL_URL:
500 if (!set->details_string_pool.size)
502 pool = set->details_string_pool.data;
503 return &pool[package->url];
505 case RAZOR_DETAIL_LICENSE:
506 if (!set->details_string_pool.size)
508 pool = set->details_string_pool.data;
509 return &pool[package->license];
511 case RAZOR_DETAIL_PREUNPROG:
512 pool = set->string_pool.data;
513 return &pool[package->preun.program];
515 case RAZOR_DETAIL_PREUN:
516 pool = set->string_pool.data;
517 return &pool[package->preun.body];
519 case RAZOR_DETAIL_POSTUNPROG:
520 pool = set->string_pool.data;
521 return &pool[package->postun.program];
523 case RAZOR_DETAIL_POSTUN:
524 pool = set->string_pool.data;
525 return &pool[package->postun.body];
528 fprintf(stderr, "type %u not found\n", type);
533 static const char *const *
534 razor_package_get_details_array(struct razor_set *set,
535 struct razor_package *package,
536 enum razor_detail_type type)
539 case RAZOR_DETAIL_PREFIXES:
540 /* We don't track prefixes in packages. Install
541 * prefixes are tracked, and made available via
542 * razor_install_prefix_iterator_create().
547 fprintf(stderr, "type %u not found\n", type);
553 * razor_package_get_details_varg:
555 * @package: a %razor_package
556 * @args: a va_list of arguments to set
559 razor_package_get_details_varg(struct razor_set *set,
560 struct razor_package *package,
564 enum razor_detail_type type;
566 const char *const **array;
568 for (i = 0;; i += 2) {
569 type = va_arg(args, enum razor_detail_type);
570 if (type == RAZOR_DETAIL_LAST)
572 if (type == RAZOR_DETAIL_PREFIXES) {
573 array = va_arg(args, const char *const **);
574 *array = razor_package_get_details_array(set, package,
577 string = va_arg(args, const char **);
578 *string = razor_package_get_details_string(set, package,
586 * razor_package_get_details:
588 * @package: a %razor_package
590 * Gets details about a package using a varg interface
591 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
593 * Example: razor_package_get_details (set, package,
594 * RAZOR_DETAIL_URL, &url,
595 * RAZOR_DETAIL_LAST);
598 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
602 assert (set != NULL);
603 assert (package != NULL);
605 va_start(args, NULL);
606 razor_package_get_details_varg (set, package, args);
611 * razor_package_remove:
612 * @prev: The %razor_set before the current transaction
613 * @next: The %razor_set after the current transaction is applied
614 * @package: a %razor_package
615 * @root: the root into which the package is currently installed
616 * @install_count: the value to pass to uninstall scripts
617 * @stage: Limit the removal to just the scripts or the files
619 * Removes an installed package.
622 razor_package_remove(struct razor_set *prev, struct razor_set *next,
623 struct razor_atomic *atomic, struct razor_package *package,
624 const char *root_uri, int install_count,
625 enum razor_stage_type stage)
627 struct razor_file_iterator *fi;
628 struct razor_package_iterator *pi;
629 struct razor_package *p;
630 char *uri, *relative, *buffer, buf[32];
631 const char *name, *program, *script;
632 int i, count, retval = 0;
633 struct environment env;
636 struct razor_error *tmp_error = NULL;
638 if (stage & RAZOR_STAGE_SCRIPTS) {
639 environment_init(&env);
640 link = list_first(&package->install_prefixes,
642 for (i = 0; link; i++) {
643 prefix = (const char *)prev->string_pool.data +
645 sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
646 environment_add_variable(&env, buf, prefix);
647 link = list_next(link);
649 environment_set(&env);
652 if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
653 razor_package_get_details(prev, package,
654 RAZOR_DETAIL_PREUNPROG, &program,
655 RAZOR_DETAIL_PREUN, &script,
658 retval = razor_run_script(root_uri, RAZOR_PROPERTY_PREUN,
659 program, script, install_count,
663 razor_atomic_propagate_error(atomic, tmp_error, NULL);
668 if (!retval && (stage & RAZOR_STAGE_FILES)) {
669 fi = razor_file_iterator_create(prev, package, 1);
671 while (razor_file_iterator_next(fi, &name)) {
672 pi = razor_package_iterator_create_for_file(next, name);
674 while (razor_package_iterator_next(pi, &p,
677 razor_package_iterator_destroy(pi);
679 uri = razor_path_to_uri(name);
681 if (str_has_prefix(uri, "file:///"))
683 else if (str_has_prefix(uri, "file:/"))
685 else if (str_has_prefix(uri, "file:"))
687 else if (str_has_prefix(uri, "/"))
692 buffer = razor_resolve_uri_root(root_uri,
698 razor_atomic_remove(atomic, buffer);
701 razor_atomic_propagate_error(atomic,
710 razor_file_iterator_destroy(fi);
712 retval = razor_atomic_in_error_state(atomic);
715 if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) {
716 razor_package_get_details(prev, package,
717 RAZOR_DETAIL_POSTUNPROG, &program,
718 RAZOR_DETAIL_POSTUN, &script,
721 retval |= razor_run_script(root_uri, RAZOR_PROPERTY_POSTUN,
722 program, script, install_count,
726 razor_atomic_propagate_error(atomic, tmp_error, NULL);
731 if (stage & RAZOR_STAGE_SCRIPTS) {
732 environment_unset(&env);
733 environment_release(&env);
739 RAZOR_EXPORT const char *
740 razor_property_relation_to_string(struct razor_property *p)
744 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
745 case RAZOR_PROPERTY_LESS:
748 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
751 case RAZOR_PROPERTY_EQUAL:
754 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
757 case RAZOR_PROPERTY_GREATER:
765 RAZOR_EXPORT const char *
766 razor_property_type_to_string(struct razor_property *p)
770 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
771 case RAZOR_PROPERTY_REQUIRES:
773 case RAZOR_PROPERTY_PROVIDES:
775 case RAZOR_PROPERTY_CONFLICTS:
777 case RAZOR_PROPERTY_OBSOLETES:
784 RAZOR_EXPORT struct razor_entry *
785 razor_set_find_entry(struct razor_set *set,
786 struct razor_entry *dir, const char *pattern)
788 struct razor_entry *e, *subdir;
789 const char *n, *pool = set->file_string_pool.data;
792 assert (set != NULL);
793 assert (pattern != NULL);
801 if (strcmp(pattern, n) == 0)
804 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
805 pattern[len] == '/') {
806 subdir = (struct razor_entry *) set->files.data +
808 return razor_set_find_entry(set, subdir,
811 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
817 list_dir(struct razor_set *set, struct razor_entry *dir,
818 char *prefix, const char *pattern)
820 struct razor_entry *e, *subdir;
821 const char *n, *pool = set->file_string_pool.data;
826 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
828 printf("%s/%s\n", prefix, n);
830 char *sub = prefix + strlen (prefix);
833 subdir = (struct razor_entry *) set->files.data +
835 list_dir(set, subdir, prefix, pattern);
838 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
842 razor_set_list_files(struct razor_set *set, const char *pattern)
844 struct razor_entry *root, *e;
845 char buffer[512], *p, *base;
847 assert (set != NULL);
849 root = (struct razor_entry *) set->files.data;
851 if (pattern == NULL) {
852 p = set->file_string_pool.data;
856 strcpy(buffer, p + e->name);
857 list_dir(set, root + e->start, buffer, NULL);
859 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
863 strcpy(buffer, pattern);
864 e = razor_set_find_entry(set, root, buffer);
868 p = strrchr(buffer, '/');
876 e = razor_set_find_entry(set, root, buffer);
878 list_dir(set, root + e->start, buffer, base);
882 razor_set_list_package_files(struct razor_set *set,
883 struct razor_package *package)
885 struct razor_file_iterator *fi;
888 assert (set != NULL);
889 assert (package != NULL);
891 fi = razor_file_iterator_create(set, package, 0);
893 while (razor_file_iterator_next(fi, &name))
894 printf("%s\n", name);
896 razor_file_iterator_destroy(fi);
900 * Package data can potentially come from two places. The so-called
901 * metadata (eg., from comps.xml) and from an RPM file. We consider
902 * a package which has additional data from an RPM file as "fixed".
903 * If a package needs fixing, then razor_transaction_fixup_package()
904 * will do so. When considering what packages to add and to remove
905 * we need to take this into account since we always want to add
906 * unfixed packages (otherwise we have a potential conflict between
907 * the existing package data and that present in the RPM).
910 razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
912 const char *preunprog, *preun, *postunprog, *postun;
916 razor_package_get_details(set, p,
917 RAZOR_DETAIL_PREUNPROG, &preunprog,
918 RAZOR_DETAIL_PREUN, &preun,
919 RAZOR_DETAIL_POSTUNPROG, &postunprog,
920 RAZOR_DETAIL_POSTUN, &postun,
922 return *preunprog || *preun || *postunprog || *postun;
926 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
927 razor_diff_callback_t callback, void *data)
929 struct razor_package_iterator *pi1, *pi2;
930 struct razor_package *p1, *p2;
931 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
932 int res, is_fixed1, is_fixed2;
934 assert (set != NULL);
935 assert (upstream != NULL);
937 pi1 = razor_package_iterator_create(set);
938 pi2 = razor_package_iterator_create(upstream);
940 razor_package_iterator_next(pi1, &p1,
941 RAZOR_DETAIL_NAME, &name1,
942 RAZOR_DETAIL_VERSION, &version1,
943 RAZOR_DETAIL_ARCH, &arch1,
945 is_fixed1 = razor_package_is_fixed(set, p1);
946 razor_package_iterator_next(pi2, &p2,
947 RAZOR_DETAIL_NAME, &name2,
948 RAZOR_DETAIL_VERSION, &version2,
949 RAZOR_DETAIL_ARCH, &arch2,
951 is_fixed2 = razor_package_is_fixed(upstream, p2);
955 res = strcmp(name1, name2);
957 res = razor_versioncmp(version1, version2);
959 res = is_fixed1 - is_fixed2;
964 if (p2 == NULL || res < 0)
965 callback(RAZOR_DIFF_ACTION_REMOVE,
966 p1, name1, version1, arch1, data);
967 else if (p1 == NULL || res > 0)
968 callback(RAZOR_DIFF_ACTION_ADD,
969 p2, name2, version2, arch2, data);
971 if (p1 != NULL && res <= 0) {
972 razor_package_iterator_next(pi1, &p1,
973 RAZOR_DETAIL_NAME, &name1,
974 RAZOR_DETAIL_VERSION, &version1,
975 RAZOR_DETAIL_ARCH, &arch1,
977 is_fixed1 = razor_package_is_fixed(set, p1);
979 if (p2 != NULL && res >= 0) {
980 razor_package_iterator_next(pi2, &p2,
981 RAZOR_DETAIL_NAME, &name2,
982 RAZOR_DETAIL_VERSION, &version2,
983 RAZOR_DETAIL_ARCH, &arch2,
985 is_fixed2 = razor_package_is_fixed(upstream, p2);
989 razor_package_iterator_destroy(pi1);
990 razor_package_iterator_destroy(pi2);
993 struct install_action {
994 enum razor_install_action action;
995 struct razor_package *package;
998 struct razor_install_iterator {
999 struct razor_set *set;
1000 struct razor_set *next;
1001 struct array actions;
1002 struct deque *order, *left;
1006 add_action(enum razor_diff_action action,
1007 struct razor_package *package,
1009 const char *version,
1013 struct razor_install_iterator *ii = data;
1014 struct install_action *a;
1016 a = array_add(&ii->actions, sizeof *a);
1017 a->package = package;
1020 case RAZOR_DIFF_ACTION_ADD:
1021 a->action = RAZOR_INSTALL_ACTION_ADD;
1023 case RAZOR_DIFF_ACTION_REMOVE:
1024 a->action = RAZOR_INSTALL_ACTION_REMOVE;
1030 * Does <package> have a requirement for <script> which is
1031 * satisfied by <provider> ?
1032 * Note: We already know that <provider> is to be added as part of this install
1033 * so there is no need to check the relation.
1036 package_script_requires(struct razor_set *set, struct razor_package *package,
1037 enum razor_property_flags script,
1038 struct razor_package *provider)
1041 struct razor_property *prop;
1043 link = list_first(&package->properties, &set->property_pool);
1044 for(; link; link = list_next(link)) {
1045 prop = set->properties.data;
1047 if ((prop->flags & RAZOR_PROPERTY_SCRIPT_MASK) & script &&
1048 (prop->flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES &&
1049 provider->name == prop->name)
1055 RAZOR_EXPORT struct razor_install_iterator *
1056 razor_set_create_install_iterator(struct razor_set *set,
1057 struct razor_set *next)
1059 struct razor_install_iterator *ii;
1060 struct razor_property *prop;
1061 /* A graph of the actions to be perfomed where
1062 * A->B means action A should follow action B.
1064 struct graph follows;
1065 struct install_action *actions, *ai, *aj, *an;
1066 int i, j, count, vertex_added;
1068 struct razor_set *rs;
1069 struct deque *order;
1072 assert (set != NULL);
1073 assert (next != NULL);
1075 ii = zalloc(sizeof *ii);
1079 razor_set_diff(set, next, add_action, ii);
1081 actions = ii->actions.data;
1082 count = ii->actions.size / sizeof (struct install_action);
1084 graph_init(&follows);
1086 for(i = 0; i < count; i++) {
1088 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
1090 link = list_first(&ai->package->properties, &rs->property_pool);
1091 for(; link; link = list_next(link)) {
1092 prop = rs->properties.data;
1094 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
1095 case RAZOR_PROPERTY_REQUIRES:
1096 case RAZOR_PROPERTY_CONFLICTS:
1097 for(j = 0; j < count; j++) {
1101 if (aj->package->name == prop->name) {
1103 RAZOR_INSTALL_ACTION_ADD)
1104 graph_add_edge(&follows,
1107 graph_add_edge(&follows,
1115 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
1116 for(j = 0; j < count; j++) {
1120 if (aj->package == ai->package &&
1121 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
1122 graph_add_edge(&follows, i, j);
1128 graph_add_edge(&follows, i, i);
1132 * Because files are installed and removed using razor_atomic,
1133 * but scripts are run with no regard for these, we need some
1134 * means for synchronisation between the two. We support this
1135 * via transaction barriers which are points where
1136 * razor_atomic_commit() should be called so that scripts can
1137 * rely on the files they need being present.
1140 * 1) Transaction barriers never occur within a dependency
1141 * loop. Since we can't guarantee any ordering of actions
1142 * within such a loop, they make no sense.
1143 * 2) Otherwise the following table applies:
1144 * Action I Action J Barrier between I and J iff
1145 * ADD P ADD Q %pre(Q) requires P
1146 * ADD P REMOVE Q %preun(Q) requires P
1147 * REMOVE P ADD Q never
1148 * REMOVE P REMOVE Q %postun(P) requires Q
1151 * This should take account of conflicts somehow.
1153 order = graph_sort(&follows);
1154 ii->order = deque_new(0);
1155 if (!deque_empty(order)) {
1156 j = deque_pop(order);
1157 deque_unshift(ii->order, j);
1159 while (!deque_empty(order)) {
1161 j = deque_pop(order);
1164 if (graph_is_connected(&follows, i, j) &&
1165 graph_is_connected(&follows, j, i))
1167 else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
1168 aj->action == RAZOR_INSTALL_ACTION_ADD &&
1169 package_script_requires(next, aj->package,
1173 else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
1174 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
1175 package_script_requires(set, aj->package,
1176 RAZOR_PROPERTY_PREUN,
1179 else if (ai->action == RAZOR_INSTALL_ACTION_REMOVE &&
1180 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
1181 package_script_requires(set, ai->package,
1182 RAZOR_PROPERTY_POSTUN,
1187 if (barrier_needed) {
1188 an = array_add(&ii->actions, sizeof *an);
1189 actions = ii->actions.data;
1191 an->action = RAZOR_INSTALL_ACTION_COMMIT;
1192 deque_unshift(ii->order, an - actions);
1194 deque_unshift(ii->order, j);
1198 ii->left = deque_dup(ii->order);
1199 graph_release(&follows);
1205 razor_install_iterator_next(struct razor_install_iterator *ii,
1206 struct razor_package **package,
1207 enum razor_install_action *action,
1210 struct install_action *a;
1211 struct razor_package_iterator *pi;
1212 struct razor_package *pkg;
1213 const char *removing, *name;
1215 if (deque_empty(ii->left))
1218 a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
1219 *package = a->package;
1220 *action = a->action;
1223 if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
1224 razor_package_get_details(ii->set, a->package,
1225 RAZOR_DETAIL_NAME, &removing,
1228 pi = razor_package_iterator_create(ii->next);
1229 while (razor_package_iterator_next(pi, &pkg,
1230 RAZOR_DETAIL_NAME, &name,
1231 RAZOR_DETAIL_LAST)) {
1232 if (!strcmp(name, removing))
1235 razor_package_iterator_destroy(pi);
1236 } else if (a->action == RAZOR_INSTALL_ACTION_ADD)
1243 action_is_included(struct razor_install_iterator *ii, struct deque *done,
1244 struct razor_package *package,
1245 enum razor_install_action action)
1248 struct install_action *a;
1251 t = deque_dup(done);
1253 while(!deque_empty(t)) {
1254 a = (struct install_action *)ii->actions.data + deque_pop(t);
1255 if (a->package == package && a->action == action)
1258 retval = !deque_empty(t);
1265 RAZOR_EXPORT struct razor_set *
1266 razor_install_iterator_commit_set(struct razor_install_iterator *ii)
1268 struct razor_merger *merger;
1269 struct razor_set *set;
1270 struct razor_package *n, *nend, *s, *send;
1273 char *npool, *spool;
1276 done = deque_dup(ii->order);
1277 pos = razor_install_iterator_tell(ii);
1278 while(deque_length(done) > pos)
1281 s = ii->set->packages.data;
1282 send = ii->set->packages.data + ii->set->packages.size;
1283 spool = ii->set->string_pool.data;
1285 n = ii->next->packages.data;
1286 nend = ii->next->packages.data + ii->next->packages.size;
1287 npool = ii->next->string_pool.data;
1289 merger = razor_merger_create(ii->set, ii->next);
1290 while (s < send || n < nend) {
1291 if (s < send && n < nend)
1292 cmp = strcmp(&spool[s->name], &npool[n->name]);
1299 if (!action_is_included(ii, done, s,
1300 RAZOR_INSTALL_ACTION_REMOVE))
1301 razor_merger_add_package(merger, s);
1303 } else if (cmp == 0) {
1304 if (!action_is_included(ii, done, s,
1305 RAZOR_INSTALL_ACTION_REMOVE))
1306 razor_merger_add_package(merger, s);
1307 if (action_is_included(ii, done, n,
1308 RAZOR_INSTALL_ACTION_ADD))
1309 razor_merger_add_package(merger, n);
1314 if (action_is_included(ii, done, n,
1315 RAZOR_INSTALL_ACTION_ADD))
1316 razor_merger_add_package(merger, n);
1321 set = razor_merger_commit(merger);
1322 razor_merger_destroy(merger);
1329 razor_install_iterator_rewind(struct razor_install_iterator *ii)
1331 deque_free(ii->left);
1332 ii->left=deque_dup(ii->order);
1336 razor_install_iterator_tell(struct razor_install_iterator *ii)
1338 return deque_length(ii->order) - deque_length(ii->left);
1342 razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
1346 if (pos > deque_length(ii->order))
1347 pos = deque_length(ii->order);
1349 current_pos = razor_install_iterator_tell(ii);
1351 if (pos < current_pos) {
1352 razor_install_iterator_rewind(ii);
1356 while(current_pos < pos) {
1357 (void) deque_pop(ii->left);
1365 razor_install_iterator_destroy(struct razor_install_iterator *ii)
1367 array_release(&ii->actions);
1368 deque_free(ii->order);
1369 deque_free(ii->left);