2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
4 * Copyright (C) 2009-2012 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.
31 #include <sys/types.h>
44 #include "razor-internal.h"
51 struct razor_set_section_index {
57 #define MAIN(type, field) \
58 { type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
59 #define FILES(type, field) \
60 { type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
61 #define DETAILS(type, field) \
62 { type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
64 struct razor_set_section_index razor_sections[] = {
65 MAIN(RAZOR_STRING_POOL, string_pool),
66 MAIN(RAZOR_PACKAGES, packages),
67 MAIN(RAZOR_PROPERTIES, properties),
68 MAIN(RAZOR_PACKAGE_POOL, package_pool),
69 MAIN(RAZOR_PROPERTY_POOL, property_pool),
70 MAIN(RAZOR_PREFIX_POOL, prefix_pool),
71 FILES(RAZOR_FILES, files),
72 FILES(RAZOR_FILE_POOL, file_pool),
73 FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
74 DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
77 RAZOR_EXPORT struct razor_set *
78 razor_set_create_without_root(void)
80 struct razor_set *set;
83 set = zalloc(sizeof *set);
86 empty = array_add(&set->string_pool, 1);
93 set->header_version = RAZOR_HEADER_VERSION;
95 set->flags = RAZOR_SET_PRIVATE;
101 RAZOR_EXPORT struct razor_set *
102 razor_set_create(void)
104 struct razor_set *set;
105 struct razor_entry *e;
107 set = razor_set_create_without_root();
109 e = array_add(&set->files, sizeof *e);
111 e->flags = RAZOR_ENTRY_LAST;
113 list_set_empty(&e->packages);
118 RAZOR_EXPORT uint32_t
119 razor_set_get_header_version(struct razor_set *set)
121 return set->header_version;
125 razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
127 if (header_version<RAZOR_HEADER_VERSION_MIN ||
128 header_version>RAZOR_HEADER_VERSION)
131 set->header_version = header_version;
136 struct razor_mapped_file {
137 struct razor_set_header *header;
139 struct razor_mapped_file *next;
143 razor_set_bind_sections(struct razor_set *set, const char *filename,
144 enum razor_set_flags flags, struct razor_error **error)
146 struct razor_set_section *s, *sections;
147 struct razor_mapped_file *file;
148 const char *pool, *reason;
152 file = zalloc(sizeof *file);
154 razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
155 "Not enough memory");
159 file->header = razor_file_get_contents(filename, &file->size,
160 flags & RAZOR_SET_PRIVATE,
167 if (file->size < sizeof *file->header) {
168 code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
169 reason = "Premature EOF";
170 } else if (file->header->magic != RAZOR_MAGIC) {
171 code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
172 reason = "Bad magic number";
173 } else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
174 file->header->version > RAZOR_HEADER_VERSION) {
175 code = RAZOR_GENERAL_ERROR_DATABASE_INCOMPATIBLE;
176 reason = "Incompatible file version";
181 razor_set_error(error, RAZOR_GENERAL_ERROR, code, filename,
183 razor_file_free_contents(file->header, file->size);
188 set->flags = flags & RAZOR_SET_PRIVATE;
190 set->header_version = file->header->version;
192 if (set->mapped_files == NULL) {
193 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
194 array = (void *) set + razor_sections[i].offset;
195 array_release(array);
199 file->next = set->mapped_files;
200 set->mapped_files = file;
202 sections = (void *) file->header + sizeof *file->header;
203 pool = (void *) sections +
204 file->header->num_sections * sizeof *sections;
206 for (i = 0; i < file->header->num_sections; i++) {
208 for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
209 if (!strcmp(razor_sections[j].name, &pool[s->name]))
211 if (j == ARRAY_SIZE(razor_sections))
213 array = (void *) set + razor_sections[j].offset;
214 array->data = (void *) file->header + s->offset;
215 array->size = s->size;
216 array->alloc = s->size;
222 RAZOR_EXPORT struct razor_set *
223 razor_set_open(const char *filename, enum razor_set_flags flags,
224 struct razor_error **error)
226 struct razor_set *set;
228 set = zalloc(sizeof *set);
230 razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
231 "Not enough memory");
237 if (razor_set_bind_sections(set, filename, flags, error)) {
245 razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive)
251 fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0666);
259 DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
260 OVERLAPPED lock = {0};
263 flags |= LOCKFILE_EXCLUSIVE_LOCK;
264 if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0,
269 if (set->lock_fd >= 0)
270 (void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1,
273 struct flock lock = {0};
275 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
276 lock.l_whence = SEEK_SET;
279 if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) {
283 if (set->lock_fd >= 0) {
284 lock.l_type = F_UNLCK;
285 (void)fcntl(set->lock_fd, F_SETLK, &lock);
289 if (set->lock_fd >= 0)
297 razor_set_destroy(struct razor_set *set)
299 struct razor_mapped_file *file, *next;
303 assert (set != NULL);
305 if (set->mapped_files == NULL) {
306 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
307 array = (void *) set + razor_sections[i].offset;
308 array_release(array);
311 for (file = set->mapped_files; file != NULL; file = next) {
313 razor_file_free_contents(file->header, file->size);
318 razor_set_aquire_lock(set, NULL, 0);
323 razor_set_unref(struct razor_set *set)
325 if (set && !--set->ref_count)
326 razor_set_destroy(set);
329 RAZOR_EXPORT struct razor_set *
330 razor_set_ref(struct razor_set *set)
338 razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
339 int handle, uint32_t section_mask)
341 struct razor_set_header header;
342 struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
343 struct hashtable table;
344 struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
347 static const char padding[4];
350 hashtable_init(&table, &pool);
353 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
354 if ((razor_sections[i].flags & section_mask) == 0)
357 arrays[j] = (void *) set + razor_sections[i].offset;
359 hashtable_tokenize(&table, razor_sections[i].name);
364 header.magic = RAZOR_MAGIC;
365 header.version = set->header_version;
366 header.num_sections = count;
367 offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
369 for (i = 0; i < count; i++) {
370 sections[i].offset = offset;
371 sections[i].size = arrays[i]->size;
372 offset += ALIGN(arrays[i]->size, 4);
375 razor_atomic_write(atomic, handle, &header, sizeof header);
376 razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
377 razor_atomic_write(atomic, handle, pool.data, pool.size);
378 razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
380 for (i = 0; i < count; i++) {
381 razor_atomic_write(atomic, handle, arrays[i]->data,
383 razor_atomic_write(atomic, handle, padding,
384 PADDING(arrays[i]->size, 4));
387 array_release(&pool);
388 hashtable_release(&table);
392 razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
393 const char *filename, uint32_t sections)
397 h = razor_atomic_create_file(atomic, filename,
398 S_IRWXU | S_IRWXG | S_IRWXO);
402 razor_set_write_to_handle(set, atomic, h, sections);
404 return razor_atomic_close(atomic, h);
408 razor_build_evr(char *evr_buf, int size, const char *epoch,
409 const char *version, const char *release)
413 if (!version || !*version) {
418 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
419 len = snprintf(evr_buf, size, "%s:", epoch);
423 len = snprintf(evr_buf, size, "%s", version);
426 if (release && *release)
427 snprintf(evr_buf, size, "-%s", release);
431 razor_versioncmp(const char *s1, const char *s2)
440 n1 = strtol(s1, (char **) &p1, 10);
441 n2 = strtol(s2, (char **) &p2, 10);
443 /* Epoch; if one but not the other has an epoch set, default
444 * the epoch-less version to 0. */
445 res = (*p1 == ':') - (*p2 == ':');
450 } else if (res > 0) {
463 if (isdigit(*p1) && isdigit(*p2))
464 return razor_versioncmp(p1, p2);
471 razor_package_get_details_string(struct razor_set *set,
472 struct razor_package *package,
473 enum razor_detail_type type)
478 case RAZOR_DETAIL_NAME:
479 pool = set->string_pool.data;
480 return &pool[package->name];
482 case RAZOR_DETAIL_VERSION:
483 pool = set->string_pool.data;
484 return &pool[package->version];
486 case RAZOR_DETAIL_ARCH:
487 pool = set->string_pool.data;
488 return &pool[package->arch];
490 case RAZOR_DETAIL_SUMMARY:
491 if (!set->details_string_pool.size)
493 pool = set->details_string_pool.data;
494 return &pool[package->summary];
496 case RAZOR_DETAIL_DESCRIPTION:
497 if (!set->details_string_pool.size)
499 pool = set->details_string_pool.data;
500 return &pool[package->description];
502 case RAZOR_DETAIL_URL:
503 if (!set->details_string_pool.size)
505 pool = set->details_string_pool.data;
506 return &pool[package->url];
508 case RAZOR_DETAIL_LICENSE:
509 if (!set->details_string_pool.size)
511 pool = set->details_string_pool.data;
512 return &pool[package->license];
514 case RAZOR_DETAIL_PREUNPROG:
515 pool = set->string_pool.data;
516 return &pool[package->preun.program];
518 case RAZOR_DETAIL_PREUN:
519 pool = set->string_pool.data;
520 return &pool[package->preun.body];
522 case RAZOR_DETAIL_POSTUNPROG:
523 pool = set->string_pool.data;
524 return &pool[package->postun.program];
526 case RAZOR_DETAIL_POSTUN:
527 pool = set->string_pool.data;
528 return &pool[package->postun.body];
531 fprintf(stderr, "type %u not found\n", type);
536 static const char *const *
537 razor_package_get_details_array(struct razor_set *set,
538 struct razor_package *package,
539 enum razor_detail_type type)
542 case RAZOR_DETAIL_PREFIXES:
543 /* We don't track prefixes in packages. Install prefixes
544 * are tracked, but we don't provide an API to get them.
549 fprintf(stderr, "type %u not found\n", type);
555 * razor_package_get_details_varg:
557 * @package: a %razor_package
558 * @args: a va_list of arguments to set
561 razor_package_get_details_varg(struct razor_set *set,
562 struct razor_package *package,
566 enum razor_detail_type type;
568 const char *const **array;
570 for (i = 0;; i += 2) {
571 type = va_arg(args, enum razor_detail_type);
572 if (type == RAZOR_DETAIL_LAST)
574 if (type == RAZOR_DETAIL_PREFIXES) {
575 array = va_arg(args, const char *const **);
576 *array = razor_package_get_details_array(set, package,
579 string = va_arg(args, const char **);
580 *string = razor_package_get_details_string(set, package,
588 * razor_package_get_details:
590 * @package: a %razor_package
592 * Gets details about a package using a varg interface
593 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
595 * Example: razor_package_get_details (set, package,
596 * RAZOR_DETAIL_URL, &url,
597 * RAZOR_DETAIL_LAST);
600 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
604 assert (set != NULL);
605 assert (package != NULL);
607 va_start(args, NULL);
608 razor_package_get_details_varg (set, package, args);
613 * razor_package_remove:
614 * @prev: The %razor_set before the current transaction
615 * @next: The %razor_set after the current transaction is applied
616 * @package: a %razor_package
617 * @root: the root into which the package is currently installed
618 * @install_count: the value to pass to uninstall scripts
619 * @stage: Limit the removal to just the scripts or the files
621 * Removes an installed package.
624 razor_package_remove(struct razor_set *prev, struct razor_set *next,
625 struct razor_atomic *atomic, struct razor_package *package,
626 const char *root, int install_count,
627 enum razor_stage_type stage)
629 struct razor_file_iterator *fi;
630 struct razor_package_iterator *pi;
631 struct razor_package *p;
632 char *buffer, buf[32];
633 const char *name, *program, *script;
634 int i, count, retval = 0;
635 struct environment env;
639 if (stage & RAZOR_STAGE_SCRIPTS) {
640 environment_init(&env);
641 link = list_first(&package->install_prefixes,
643 for (i = 0; link; i++) {
644 prefix = (const char *)prev->string_pool.data +
646 sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
647 environment_add_variable(&env, buf, prefix);
648 link = list_next(link);
650 environment_set(&env);
653 if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
654 razor_package_get_details(prev, package,
655 RAZOR_DETAIL_PREUNPROG, &program,
656 RAZOR_DETAIL_PREUN, &script,
659 retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program,
660 script, install_count);
663 if (!retval && (stage & RAZOR_STAGE_FILES)) {
664 fi = razor_file_iterator_create(prev, package, 1);
666 while (razor_file_iterator_next(fi, &name)) {
667 pi = razor_package_iterator_create_for_file(next, name);
669 while (razor_package_iterator_next(pi, &p,
672 razor_package_iterator_destroy(pi);
674 buffer = razor_concat(root, name, NULL);
675 razor_atomic_remove(atomic, buffer);
680 razor_file_iterator_destroy(fi);
682 retval = razor_atomic_in_error_state(atomic);
685 if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) {
686 razor_package_get_details(prev, package,
687 RAZOR_DETAIL_POSTUNPROG, &program,
688 RAZOR_DETAIL_POSTUN, &script,
691 retval |= razor_run_script(root, RAZOR_PROPERTY_POSTUN, program,
692 script, install_count);
695 if (stage & RAZOR_STAGE_SCRIPTS) {
696 environment_unset(&env);
697 environment_release(&env);
703 RAZOR_EXPORT const char *
704 razor_property_relation_to_string(struct razor_property *p)
708 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
709 case RAZOR_PROPERTY_LESS:
712 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
715 case RAZOR_PROPERTY_EQUAL:
718 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
721 case RAZOR_PROPERTY_GREATER:
729 RAZOR_EXPORT const char *
730 razor_property_type_to_string(struct razor_property *p)
734 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
735 case RAZOR_PROPERTY_REQUIRES:
737 case RAZOR_PROPERTY_PROVIDES:
739 case RAZOR_PROPERTY_CONFLICTS:
741 case RAZOR_PROPERTY_OBSOLETES:
748 RAZOR_EXPORT struct razor_entry *
749 razor_set_find_entry(struct razor_set *set,
750 struct razor_entry *dir, const char *pattern)
752 struct razor_entry *e, *subdir;
753 const char *n, *pool = set->file_string_pool.data;
756 assert (set != NULL);
757 assert (pattern != NULL);
765 if (strcmp(pattern, n) == 0)
768 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
769 pattern[len] == '/') {
770 subdir = (struct razor_entry *) set->files.data +
772 return razor_set_find_entry(set, subdir,
775 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
781 list_dir(struct razor_set *set, struct razor_entry *dir,
782 char *prefix, const char *pattern)
784 struct razor_entry *e, *subdir;
785 const char *n, *pool = set->file_string_pool.data;
790 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
792 printf("%s/%s\n", prefix, n);
794 char *sub = prefix + strlen (prefix);
797 subdir = (struct razor_entry *) set->files.data +
799 list_dir(set, subdir, prefix, pattern);
802 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
806 razor_set_list_files(struct razor_set *set, const char *pattern)
808 struct razor_entry *root, *e;
809 char buffer[512], *p, *base;
811 assert (set != NULL);
813 root = (struct razor_entry *) set->files.data;
815 if (pattern == NULL) {
816 p = set->file_string_pool.data;
820 strcpy(buffer, p + e->name);
821 list_dir(set, root + e->start, buffer, NULL);
823 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
827 strcpy(buffer, pattern);
828 e = razor_set_find_entry(set, root, buffer);
832 p = strrchr(buffer, '/');
840 e = razor_set_find_entry(set, root, buffer);
842 list_dir(set, root + e->start, buffer, base);
846 razor_set_list_package_files(struct razor_set *set,
847 struct razor_package *package)
849 struct razor_file_iterator *fi;
852 assert (set != NULL);
853 assert (package != NULL);
855 fi = razor_file_iterator_create(set, package, 0);
857 while (razor_file_iterator_next(fi, &name))
858 printf("%s\n", name);
860 razor_file_iterator_destroy(fi);
864 * Package data can potentially come from two places. The so-called
865 * metadata (eg., from comps.xml) and from an RPM file. We consider
866 * a package which has additional data from an RPM file as "fixed".
867 * If a package needs fixing, then razor_transaction_fixup_package()
868 * will do so. When considering what packages to add and to remove
869 * we need to take this into account since we always want to add
870 * unfixed packages (otherwise we have a potential conflict between
871 * the existing package data and that present in the RPM).
874 razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
876 const char *preunprog, *preun, *postunprog, *postun;
880 razor_package_get_details(set, p,
881 RAZOR_DETAIL_PREUNPROG, &preunprog,
882 RAZOR_DETAIL_PREUN, &preun,
883 RAZOR_DETAIL_POSTUNPROG, &postunprog,
884 RAZOR_DETAIL_POSTUN, &postun,
886 return *preunprog || *preun || *postunprog || *postun;
890 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
891 razor_diff_callback_t callback, void *data)
893 struct razor_package_iterator *pi1, *pi2;
894 struct razor_package *p1, *p2;
895 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
896 int res, is_fixed1, is_fixed2;
898 assert (set != NULL);
899 assert (upstream != NULL);
901 pi1 = razor_package_iterator_create(set);
902 pi2 = razor_package_iterator_create(upstream);
904 razor_package_iterator_next(pi1, &p1,
905 RAZOR_DETAIL_NAME, &name1,
906 RAZOR_DETAIL_VERSION, &version1,
907 RAZOR_DETAIL_ARCH, &arch1,
909 is_fixed1 = razor_package_is_fixed(set, p1);
910 razor_package_iterator_next(pi2, &p2,
911 RAZOR_DETAIL_NAME, &name2,
912 RAZOR_DETAIL_VERSION, &version2,
913 RAZOR_DETAIL_ARCH, &arch2,
915 is_fixed2 = razor_package_is_fixed(upstream, p2);
919 res = strcmp(name1, name2);
921 res = razor_versioncmp(version1, version2);
923 res = is_fixed1 - is_fixed2;
928 if (p2 == NULL || res < 0)
929 callback(RAZOR_DIFF_ACTION_REMOVE,
930 p1, name1, version1, arch1, data);
931 else if (p1 == NULL || res > 0)
932 callback(RAZOR_DIFF_ACTION_ADD,
933 p2, name2, version2, arch2, data);
935 if (p1 != NULL && res <= 0) {
936 razor_package_iterator_next(pi1, &p1,
937 RAZOR_DETAIL_NAME, &name1,
938 RAZOR_DETAIL_VERSION, &version1,
939 RAZOR_DETAIL_ARCH, &arch1,
941 is_fixed1 = razor_package_is_fixed(set, p1);
943 if (p2 != NULL && res >= 0) {
944 razor_package_iterator_next(pi2, &p2,
945 RAZOR_DETAIL_NAME, &name2,
946 RAZOR_DETAIL_VERSION, &version2,
947 RAZOR_DETAIL_ARCH, &arch2,
949 is_fixed2 = razor_package_is_fixed(upstream, p2);
953 razor_package_iterator_destroy(pi1);
954 razor_package_iterator_destroy(pi2);
957 struct install_action {
958 enum razor_install_action action;
959 struct razor_package *package;
962 struct razor_install_iterator {
963 struct razor_set *set;
964 struct razor_set *next;
965 struct array actions;
966 struct deque *order, *left;
970 add_action(enum razor_diff_action action,
971 struct razor_package *package,
977 struct razor_install_iterator *ii = data;
978 struct install_action *a;
980 a = array_add(&ii->actions, sizeof *a);
981 a->package = package;
984 case RAZOR_DIFF_ACTION_ADD:
985 a->action = RAZOR_INSTALL_ACTION_ADD;
987 case RAZOR_DIFF_ACTION_REMOVE:
988 a->action = RAZOR_INSTALL_ACTION_REMOVE;
994 * Does <package> have a requirement for <script> which is
995 * satisfied by <provider> ?
996 * Note: We already know that <provider> is to be added as part of this install
997 * so there is no need to check the relation.
1000 package_script_requires(struct razor_set *set, struct razor_package *package,
1001 enum razor_property_flags script,
1002 struct razor_package *provider)
1005 struct razor_property *prop;
1007 link = list_first(&package->properties, &set->property_pool);
1008 for(; link; link = list_next(link)) {
1009 prop = set->properties.data;
1011 if ((prop->flags & RAZOR_PROPERTY_SCRIPT_MASK) & script &&
1012 (prop->flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES &&
1013 provider->name == prop->name)
1019 RAZOR_EXPORT struct razor_install_iterator *
1020 razor_set_create_install_iterator(struct razor_set *set,
1021 struct razor_set *next)
1023 struct razor_install_iterator *ii;
1024 struct razor_property *prop;
1025 /* A graph of the actions to be perfomed where
1026 * A->B means action A should follow action B.
1028 struct graph follows;
1029 struct install_action *actions, *ai, *aj, *an;
1030 int i, j, count, vertex_added;
1032 struct razor_set *rs;
1033 struct deque *order;
1036 assert (set != NULL);
1037 assert (next != NULL);
1039 ii = zalloc(sizeof *ii);
1043 razor_set_diff(set, next, add_action, ii);
1045 actions = ii->actions.data;
1046 count = ii->actions.size / sizeof (struct install_action);
1048 graph_init(&follows);
1050 for(i = 0; i < count; i++) {
1052 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
1054 link = list_first(&ai->package->properties, &rs->property_pool);
1055 for(; link; link = list_next(link)) {
1056 prop = rs->properties.data;
1058 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
1059 case RAZOR_PROPERTY_REQUIRES:
1060 case RAZOR_PROPERTY_CONFLICTS:
1061 for(j = 0; j < count; j++) {
1065 if (aj->package->name == prop->name) {
1067 RAZOR_INSTALL_ACTION_ADD)
1068 graph_add_edge(&follows,
1071 graph_add_edge(&follows,
1079 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
1080 for(j = 0; j < count; j++) {
1084 if (aj->package == ai->package &&
1085 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
1086 graph_add_edge(&follows, i, j);
1092 graph_add_edge(&follows, i, i);
1096 * Because files are installed and removed using razor_atomic,
1097 * but scripts are run with no regard for these, we need some
1098 * means for synchronisation between the two. We support this
1099 * via transaction barriers which are points where
1100 * razor_atomic_commit() should be called so that scripts can
1101 * rely on the files they need being present.
1104 * 1) Transaction barriers never occur within a dependency
1105 * loop. Since we can't guarantee any ordering of actions
1106 * within such a loop, they make no sense.
1107 * 2) Otherwise the following table applies:
1108 * Action I Action J Barrier between I and J iff
1109 * ADD P ADD Q %pre(Q) requires P
1110 * ADD P REMOVE Q %preun(Q) requires P
1111 * REMOVE P ADD Q never
1112 * REMOVE P REMOVE Q %postun(P) requires Q
1115 * This should take account of conflicts somehow.
1117 order = graph_sort(&follows);
1118 ii->order = deque_new(0);
1119 if (!deque_empty(order)) {
1120 j = deque_pop(order);
1121 deque_unshift(ii->order, j);
1123 while (!deque_empty(order)) {
1125 j = deque_pop(order);
1128 if (graph_is_connected(&follows, i, j) &&
1129 graph_is_connected(&follows, j, i))
1131 else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
1132 aj->action == RAZOR_INSTALL_ACTION_ADD &&
1133 package_script_requires(next, aj->package,
1137 else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
1138 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
1139 package_script_requires(set, aj->package,
1140 RAZOR_PROPERTY_PREUN,
1143 else if (ai->action == RAZOR_INSTALL_ACTION_REMOVE &&
1144 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
1145 package_script_requires(set, ai->package,
1146 RAZOR_PROPERTY_POSTUN,
1151 if (barrier_needed) {
1152 an = array_add(&ii->actions, sizeof *an);
1153 actions = ii->actions.data;
1155 an->action = RAZOR_INSTALL_ACTION_COMMIT;
1156 deque_unshift(ii->order, an - actions);
1158 deque_unshift(ii->order, j);
1162 ii->left = deque_dup(ii->order);
1163 graph_release(&follows);
1169 razor_install_iterator_next(struct razor_install_iterator *ii,
1170 struct razor_package **package,
1171 enum razor_install_action *action,
1174 struct install_action *a;
1175 struct razor_package_iterator *pi;
1176 struct razor_package *pkg;
1177 const char *removing, *name;
1179 if (deque_empty(ii->left))
1182 a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
1183 *package = a->package;
1184 *action = a->action;
1187 if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
1188 razor_package_get_details(ii->set, a->package,
1189 RAZOR_DETAIL_NAME, &removing,
1192 pi = razor_package_iterator_create(ii->next);
1193 while (razor_package_iterator_next(pi, &pkg,
1194 RAZOR_DETAIL_NAME, &name,
1195 RAZOR_DETAIL_LAST)) {
1196 if (!strcmp(name, removing))
1199 razor_package_iterator_destroy(pi);
1200 } else if (a->action == RAZOR_INSTALL_ACTION_ADD)
1207 action_is_included(struct razor_install_iterator *ii, struct deque *done,
1208 struct razor_package *package,
1209 enum razor_install_action action)
1212 struct install_action *a;
1215 t = deque_dup(done);
1217 while(!deque_empty(t)) {
1218 a = (struct install_action *)ii->actions.data + deque_pop(t);
1219 if (a->package == package && a->action == action)
1222 retval = !deque_empty(t);
1229 RAZOR_EXPORT struct razor_set *
1230 razor_install_iterator_commit_set(struct razor_install_iterator *ii)
1232 struct razor_merger *merger;
1233 struct razor_set *set;
1234 struct razor_package *n, *nend, *s, *send;
1237 char *npool, *spool;
1240 done = deque_dup(ii->order);
1241 pos = razor_install_iterator_tell(ii);
1242 while(deque_length(done) > pos)
1245 s = ii->set->packages.data;
1246 send = ii->set->packages.data + ii->set->packages.size;
1247 spool = ii->set->string_pool.data;
1249 n = ii->next->packages.data;
1250 nend = ii->next->packages.data + ii->next->packages.size;
1251 npool = ii->next->string_pool.data;
1253 merger = razor_merger_create(ii->set, ii->next);
1254 while (s < send || n < nend) {
1255 if (s < send && n < nend)
1256 cmp = strcmp(&spool[s->name], &npool[n->name]);
1263 if (!action_is_included(ii, done, s,
1264 RAZOR_INSTALL_ACTION_REMOVE))
1265 razor_merger_add_package(merger, s);
1267 } else if (cmp == 0) {
1268 if (!action_is_included(ii, done, s,
1269 RAZOR_INSTALL_ACTION_REMOVE))
1270 razor_merger_add_package(merger, s);
1271 if (action_is_included(ii, done, n,
1272 RAZOR_INSTALL_ACTION_ADD))
1273 razor_merger_add_package(merger, n);
1278 if (action_is_included(ii, done, n,
1279 RAZOR_INSTALL_ACTION_ADD))
1280 razor_merger_add_package(merger, n);
1285 set = razor_merger_commit(merger);
1286 razor_merger_destroy(merger);
1293 razor_install_iterator_rewind(struct razor_install_iterator *ii)
1295 deque_free(ii->left);
1296 ii->left=deque_dup(ii->order);
1300 razor_install_iterator_tell(struct razor_install_iterator *ii)
1302 return deque_length(ii->order) - deque_length(ii->left);
1306 razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
1310 if (pos > deque_length(ii->order))
1311 pos = deque_length(ii->order);
1313 current_pos = razor_install_iterator_tell(ii);
1315 if (pos < current_pos) {
1316 razor_install_iterator_rewind(ii);
1320 while(current_pos < pos) {
1321 (void) deque_pop(ii->left);
1329 razor_install_iterator_destroy(struct razor_install_iterator *ii)
1331 array_release(&ii->actions);
1332 deque_free(ii->order);
1333 deque_free(ii->left);