2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
4 * Copyright (C) 2009-2011 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"
62 struct razor_set_section_index {
68 #define MAIN(type, field) \
69 { type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
70 #define FILES(type, field) \
71 { type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
72 #define DETAILS(type, field) \
73 { type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
75 struct razor_set_section_index razor_sections[] = {
76 MAIN(RAZOR_STRING_POOL, string_pool),
77 MAIN(RAZOR_PACKAGES, packages),
78 MAIN(RAZOR_PROPERTIES, properties),
79 MAIN(RAZOR_PACKAGE_POOL, package_pool),
80 MAIN(RAZOR_PROPERTY_POOL, property_pool),
81 MAIN(RAZOR_PREFIX_POOL, prefix_pool),
82 FILES(RAZOR_FILES, files),
83 FILES(RAZOR_FILE_POOL, file_pool),
84 FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
85 DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
88 RAZOR_EXPORT struct razor_set *
89 razor_set_create_without_root(void)
91 struct razor_set *set;
94 set = zalloc(sizeof *set);
97 empty = array_add(&set->string_pool, 1);
104 set->header_version = RAZOR_HEADER_VERSION;
110 RAZOR_EXPORT struct razor_set *
111 razor_set_create(void)
113 struct razor_set *set;
114 struct razor_entry *e;
116 set = razor_set_create_without_root();
118 e = array_add(&set->files, sizeof *e);
120 e->flags = RAZOR_ENTRY_LAST;
122 list_set_empty(&e->packages);
127 RAZOR_EXPORT uint32_t
128 razor_set_get_header_version(struct razor_set *set)
130 return set->header_version;
134 razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
136 if (header_version<RAZOR_HEADER_VERSION_MIN ||
137 header_version>RAZOR_HEADER_VERSION)
140 set->header_version = header_version;
145 struct razor_mapped_file {
146 struct razor_set_header *header;
148 struct razor_mapped_file *next;
152 razor_set_bind_sections(struct razor_set *set, struct razor_atomic *atomic,
153 const char *filename)
155 struct razor_set_section *s, *sections;
156 struct razor_mapped_file *file;
157 const char *pool, *reason;
162 file = zalloc(sizeof *file);
164 razor_atomic_abort(atomic, "Not enough memory");
168 file->header = razor_file_get_contents(filename, &file->size);
170 msg = razor_concat(filename, ": ", strerror(errno), NULL);
171 razor_atomic_abort(atomic, msg);
177 if (file->size < sizeof *file->header)
178 reason = "Premature EOF";
179 else if (file->header->magic != RAZOR_MAGIC)
180 reason = "Bad magic number";
181 else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
182 file->header->version > RAZOR_HEADER_VERSION)
183 reason = "Incompatible file version";
188 msg = razor_concat(filename, ": ", reason, NULL);
189 razor_atomic_abort(atomic, msg);
191 razor_file_free_contents(file->header, file->size);
196 set->header_version = file->header->version;
198 if (set->mapped_files == NULL) {
199 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
200 array = (void *) set + razor_sections[i].offset;
201 array_release(array);
205 file->next = set->mapped_files;
206 set->mapped_files = file;
208 sections = (void *) file->header + sizeof *file->header;
209 pool = (void *) sections +
210 file->header->num_sections * sizeof *sections;
212 for (i = 0; i < file->header->num_sections; i++) {
214 for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
215 if (!strcmp(razor_sections[j].name, &pool[s->name]))
217 if (j == ARRAY_SIZE(razor_sections))
219 array = (void *) set + razor_sections[j].offset;
220 array->data = (void *) file->header + s->offset;
221 array->size = s->size;
222 array->alloc = s->size;
228 RAZOR_EXPORT struct razor_set *
229 razor_set_open(const char *filename, struct razor_atomic *atomic)
231 struct razor_set *set;
233 set = zalloc(sizeof *set);
235 razor_atomic_abort(atomic, "Not enough memory");
240 if (razor_set_bind_sections(set, atomic, filename)) {
248 razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive)
254 fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0666);
262 DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
263 OVERLAPPED lock = {0};
266 flags |= LOCKFILE_EXCLUSIVE_LOCK;
267 if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0,
272 if (set->lock_fd >= 0)
273 (void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1,
276 struct flock lock = {0};
278 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
279 lock.l_whence = SEEK_SET;
282 if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) {
286 if (set->lock_fd >= 0) {
287 lock.l_type = F_UNLCK;
288 (void)fcntl(set->lock_fd, F_SETLK, &lock);
292 if (set->lock_fd >= 0)
300 razor_set_destroy(struct razor_set *set)
302 struct razor_mapped_file *file, *next;
306 assert (set != NULL);
308 if (set->mapped_files == NULL) {
309 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
310 array = (void *) set + razor_sections[i].offset;
311 array_release(array);
314 for (file = set->mapped_files; file != NULL; file = next) {
316 razor_file_free_contents(file->header, file->size);
321 razor_set_aquire_lock(set, NULL, 0);
326 razor_set_unref(struct razor_set *set)
328 if (set && !--set->ref_count)
329 razor_set_destroy(set);
332 RAZOR_EXPORT struct razor_set *
333 razor_set_ref(struct razor_set *set)
341 razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
342 int handle, uint32_t section_mask)
344 struct razor_set_header header;
345 struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
346 struct hashtable table;
347 struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
350 static const char padding[4];
353 hashtable_init(&table, &pool);
356 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
357 if ((razor_sections[i].flags & section_mask) == 0)
360 arrays[j] = (void *) set + razor_sections[i].offset;
362 hashtable_tokenize(&table, razor_sections[i].name);
367 header.magic = RAZOR_MAGIC;
368 header.version = set->header_version;
369 header.num_sections = count;
370 offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
372 for (i = 0; i < count; i++) {
373 sections[i].offset = offset;
374 sections[i].size = arrays[i]->size;
375 offset += ALIGN(arrays[i]->size, 4);
378 razor_atomic_write(atomic, handle, &header, sizeof header);
379 razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
380 razor_atomic_write(atomic, handle, pool.data, pool.size);
381 razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
383 for (i = 0; i < count; i++) {
384 razor_atomic_write(atomic, handle, arrays[i]->data,
386 razor_atomic_write(atomic, handle, padding,
387 PADDING(arrays[i]->size, 4));
390 array_release(&pool);
391 hashtable_release(&table);
395 razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
396 const char *filename, uint32_t sections)
400 h = razor_atomic_create_file(atomic, filename,
401 S_IRWXU | S_IRWXG | S_IRWXO);
405 razor_set_write_to_handle(set, atomic, h, sections);
407 return razor_atomic_close(atomic, h);
411 razor_build_evr(char *evr_buf, int size, const char *epoch,
412 const char *version, const char *release)
416 if (!version || !*version) {
421 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
422 len = snprintf(evr_buf, size, "%s:", epoch);
426 len = snprintf(evr_buf, size, "%s", version);
429 if (release && *release)
430 snprintf(evr_buf, size, "-%s", release);
434 razor_versioncmp(const char *s1, const char *s2)
443 n1 = strtol(s1, (char **) &p1, 10);
444 n2 = strtol(s2, (char **) &p2, 10);
446 /* Epoch; if one but not the other has an epoch set, default
447 * the epoch-less version to 0. */
448 res = (*p1 == ':') - (*p2 == ':');
453 } else if (res > 0) {
466 if (isdigit(*p1) && isdigit(*p2))
467 return razor_versioncmp(p1, p2);
474 razor_package_get_details_string(struct razor_set *set,
475 struct razor_package *package,
476 enum razor_detail_type type)
481 case RAZOR_DETAIL_NAME:
482 pool = set->string_pool.data;
483 return &pool[package->name];
485 case RAZOR_DETAIL_VERSION:
486 pool = set->string_pool.data;
487 return &pool[package->version];
489 case RAZOR_DETAIL_ARCH:
490 pool = set->string_pool.data;
491 return &pool[package->arch];
493 case RAZOR_DETAIL_SUMMARY:
494 if (!set->details_string_pool.size)
496 pool = set->details_string_pool.data;
497 return &pool[package->summary];
499 case RAZOR_DETAIL_DESCRIPTION:
500 if (!set->details_string_pool.size)
502 pool = set->details_string_pool.data;
503 return &pool[package->description];
505 case RAZOR_DETAIL_URL:
506 if (!set->details_string_pool.size)
508 pool = set->details_string_pool.data;
509 return &pool[package->url];
511 case RAZOR_DETAIL_LICENSE:
512 if (!set->details_string_pool.size)
514 pool = set->details_string_pool.data;
515 return &pool[package->license];
517 case RAZOR_DETAIL_PREUNPROG:
518 pool = set->string_pool.data;
519 return &pool[package->preun.program];
521 case RAZOR_DETAIL_PREUN:
522 pool = set->string_pool.data;
523 return &pool[package->preun.body];
525 case RAZOR_DETAIL_POSTUNPROG:
526 pool = set->string_pool.data;
527 return &pool[package->postun.program];
529 case RAZOR_DETAIL_POSTUN:
530 pool = set->string_pool.data;
531 return &pool[package->postun.body];
534 fprintf(stderr, "type %u not found\n", type);
539 static const char *const *
540 razor_package_get_details_array(struct razor_set *set,
541 struct razor_package *package,
542 enum razor_detail_type type)
545 case RAZOR_DETAIL_PREFIXES:
546 /* We don't track prefixes in packages. Install prefixes
547 * are tracked, but we don't provide an API to get them.
552 fprintf(stderr, "type %u not found\n", type);
558 * razor_package_get_details_varg:
560 * @package: a %razor_package
561 * @args: a va_list of arguments to set
564 razor_package_get_details_varg(struct razor_set *set,
565 struct razor_package *package,
569 enum razor_detail_type type;
571 const char *const **array;
573 for (i = 0;; i += 2) {
574 type = va_arg(args, enum razor_detail_type);
575 if (type == RAZOR_DETAIL_LAST)
577 if (type == RAZOR_DETAIL_PREFIXES) {
578 array = va_arg(args, const char *const **);
579 *array = razor_package_get_details_array(set, package,
582 string = va_arg(args, const char **);
583 *string = razor_package_get_details_string(set, package,
591 * razor_package_get_details:
593 * @package: a %razor_package
595 * Gets details about a package using a varg interface
596 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
598 * Example: razor_package_get_details (set, package,
599 * RAZOR_DETAIL_URL, &url,
600 * RAZOR_DETAIL_LAST);
603 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
607 assert (set != NULL);
608 assert (package != NULL);
610 va_start(args, NULL);
611 razor_package_get_details_varg (set, package, args);
616 * razor_package_remove:
617 * @prev: The %razor_set before the current transaction
618 * @next: The %razor_set after the current transaction is applied
619 * @package: a %razor_package
620 * @root: the root into which the package is currently installed
621 * @install_count: the value to pass to uninstall scripts
622 * @stage: Limit the removal to just the scripts or the files
624 * Removes an installed package.
627 razor_package_remove(struct razor_set *prev, struct razor_set *next,
628 struct razor_atomic *atomic, struct razor_package *package,
629 const char *root, int install_count,
630 enum razor_stage_type stage)
632 struct razor_file_iterator *fi;
633 struct razor_package_iterator *pi;
634 struct razor_package *p;
636 const char *name, *program, *script;
638 struct environment env;
642 if (stage & RAZOR_STAGE_SCRIPTS) {
643 environment_init(&env);
644 link = list_first(&package->install_prefixes,
646 for (i = 0; link; i++) {
647 prefix = (const char *)prev->string_pool.data +
649 sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
650 environment_add_variable(&env, buffer, prefix);
651 link = list_next(link);
653 environment_set(&env);
656 if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
657 razor_package_get_details(prev, package,
658 RAZOR_DETAIL_PREUNPROG, &program,
659 RAZOR_DETAIL_PREUN, &script,
662 razor_run_script(root, RAZOR_PROPERTY_PREUN, program,
663 script, install_count);
666 if (stage & RAZOR_STAGE_FILES) {
667 fi = razor_file_iterator_create(prev, package, 1);
669 while (razor_file_iterator_next(fi, &name)) {
670 pi = razor_package_iterator_create_for_file(next, name);
672 while (razor_package_iterator_next(pi, &p,
675 razor_package_iterator_destroy(pi);
677 buffer = razor_concat(root, name, NULL);
678 razor_atomic_remove(atomic, buffer);
683 razor_file_iterator_destroy(fi);
686 if (stage & RAZOR_STAGE_SCRIPTS_POST) {
687 razor_package_get_details(prev, package,
688 RAZOR_DETAIL_POSTUNPROG, &program,
689 RAZOR_DETAIL_POSTUN, &script,
692 razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
696 if (stage & RAZOR_STAGE_SCRIPTS) {
697 environment_unset(&env);
698 environment_release(&env);
701 return razor_atomic_in_error_state(atomic);
704 RAZOR_EXPORT const char *
705 razor_property_relation_to_string(struct razor_property *p)
709 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
710 case RAZOR_PROPERTY_LESS:
713 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
716 case RAZOR_PROPERTY_EQUAL:
719 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
722 case RAZOR_PROPERTY_GREATER:
730 RAZOR_EXPORT const char *
731 razor_property_type_to_string(struct razor_property *p)
735 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
736 case RAZOR_PROPERTY_REQUIRES:
738 case RAZOR_PROPERTY_PROVIDES:
740 case RAZOR_PROPERTY_CONFLICTS:
742 case RAZOR_PROPERTY_OBSOLETES:
749 RAZOR_EXPORT struct razor_entry *
750 razor_set_find_entry(struct razor_set *set,
751 struct razor_entry *dir, const char *pattern)
753 struct razor_entry *e, *subdir;
754 const char *n, *pool = set->file_string_pool.data;
757 assert (set != NULL);
758 assert (pattern != NULL);
766 if (strcmp(pattern, n) == 0)
769 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
770 pattern[len] == '/') {
771 subdir = (struct razor_entry *) set->files.data +
773 return razor_set_find_entry(set, subdir,
776 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
782 list_dir(struct razor_set *set, struct razor_entry *dir,
783 char *prefix, const char *pattern)
785 struct razor_entry *e, *subdir;
786 const char *n, *pool = set->file_string_pool.data;
791 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
793 printf("%s/%s\n", prefix, n);
795 char *sub = prefix + strlen (prefix);
798 subdir = (struct razor_entry *) set->files.data +
800 list_dir(set, subdir, prefix, pattern);
803 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
807 razor_set_list_files(struct razor_set *set, const char *pattern)
809 struct razor_entry *root, *e;
810 char buffer[512], *p, *base;
812 assert (set != NULL);
814 root = (struct razor_entry *) set->files.data;
816 if (pattern == NULL) {
817 p = set->file_string_pool.data;
821 strcpy(buffer, p + e->name);
822 list_dir(set, root + e->start, buffer, NULL);
824 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
828 strcpy(buffer, pattern);
829 e = razor_set_find_entry(set, root, buffer);
833 p = strrchr(buffer, '/');
841 e = razor_set_find_entry(set, root, buffer);
843 list_dir(set, root + e->start, buffer, base);
847 razor_set_list_package_files(struct razor_set *set,
848 struct razor_package *package)
850 struct razor_file_iterator *fi;
853 assert (set != NULL);
854 assert (package != NULL);
856 fi = razor_file_iterator_create(set, package, 0);
858 while (razor_file_iterator_next(fi, &name))
859 printf("%s\n", name);
861 razor_file_iterator_destroy(fi);
865 * Package data can potentially come from two places. The so-called
866 * metadata (eg., from comps.xml) and from an RPM file. We consider
867 * a package which has additional data from an RPM file as "fixed".
868 * If a package needs fixing, then razor_transaction_fixup_package()
869 * will do so. When considering what packages to add and to remove
870 * we need to take this into account since we always want to add
871 * unfixed packages (otherwise we have a potential conflict between
872 * the existing package data and that present in the RPM).
875 razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
877 const char *preunprog, *preun, *postunprog, *postun;
881 razor_package_get_details(set, p,
882 RAZOR_DETAIL_PREUNPROG, &preunprog,
883 RAZOR_DETAIL_PREUN, &preun,
884 RAZOR_DETAIL_POSTUNPROG, &postunprog,
885 RAZOR_DETAIL_POSTUN, &postun,
887 return *preunprog || *preun || *postunprog || *postun;
891 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
892 razor_diff_callback_t callback, void *data)
894 struct razor_package_iterator *pi1, *pi2;
895 struct razor_package *p1, *p2;
896 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
897 int res, is_fixed1, is_fixed2;
899 assert (set != NULL);
900 assert (upstream != NULL);
902 pi1 = razor_package_iterator_create(set);
903 pi2 = razor_package_iterator_create(upstream);
905 razor_package_iterator_next(pi1, &p1,
906 RAZOR_DETAIL_NAME, &name1,
907 RAZOR_DETAIL_VERSION, &version1,
908 RAZOR_DETAIL_ARCH, &arch1,
910 is_fixed1 = razor_package_is_fixed(set, p1);
911 razor_package_iterator_next(pi2, &p2,
912 RAZOR_DETAIL_NAME, &name2,
913 RAZOR_DETAIL_VERSION, &version2,
914 RAZOR_DETAIL_ARCH, &arch2,
916 is_fixed2 = razor_package_is_fixed(upstream, p2);
920 res = strcmp(name1, name2);
922 res = razor_versioncmp(version1, version2);
924 res = is_fixed1 - is_fixed2;
929 if (p2 == NULL || res < 0)
930 callback(RAZOR_DIFF_ACTION_REMOVE,
931 p1, name1, version1, arch1, data);
932 else if (p1 == NULL || res > 0)
933 callback(RAZOR_DIFF_ACTION_ADD,
934 p2, name2, version2, arch2, data);
936 if (p1 != NULL && res <= 0) {
937 razor_package_iterator_next(pi1, &p1,
938 RAZOR_DETAIL_NAME, &name1,
939 RAZOR_DETAIL_VERSION, &version1,
940 RAZOR_DETAIL_ARCH, &arch1,
942 is_fixed1 = razor_package_is_fixed(set, p1);
944 if (p2 != NULL && res >= 0) {
945 razor_package_iterator_next(pi2, &p2,
946 RAZOR_DETAIL_NAME, &name2,
947 RAZOR_DETAIL_VERSION, &version2,
948 RAZOR_DETAIL_ARCH, &arch2,
950 is_fixed2 = razor_package_is_fixed(upstream, p2);
954 razor_package_iterator_destroy(pi1);
955 razor_package_iterator_destroy(pi2);
958 struct install_action {
959 enum razor_install_action action;
960 struct razor_package *package;
963 struct razor_install_iterator {
964 struct razor_set *set;
965 struct razor_set *next;
966 struct array actions;
967 struct deque *order, *left;
971 add_action(enum razor_diff_action action,
972 struct razor_package *package,
978 struct razor_install_iterator *ii = data;
979 struct install_action *a;
981 a = array_add(&ii->actions, sizeof *a);
982 a->package = package;
985 case RAZOR_DIFF_ACTION_ADD:
986 a->action = RAZOR_INSTALL_ACTION_ADD;
988 case RAZOR_DIFF_ACTION_REMOVE:
989 a->action = RAZOR_INSTALL_ACTION_REMOVE;
994 RAZOR_EXPORT struct razor_install_iterator *
995 razor_set_create_install_iterator(struct razor_set *set,
996 struct razor_set *next)
998 struct razor_install_iterator *ii;
999 struct razor_property *prop;
1000 /* A graph of the actions to be perfomed where
1001 * A->B means action A should follow action B.
1003 struct graph follows;
1004 struct install_action *actions, *ai, *aj;
1005 int i, j, count, vertex_added;
1007 struct razor_set *rs;
1009 assert (set != NULL);
1010 assert (next != NULL);
1012 ii = zalloc(sizeof *ii);
1016 razor_set_diff(set, next, add_action, ii);
1018 actions = ii->actions.data;
1019 count = ii->actions.size / sizeof (struct install_action);
1021 graph_init(&follows);
1023 for(i = 0; i < count; i++) {
1025 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
1027 link = list_first(&ai->package->properties, &rs->property_pool);
1028 for(; link; link = list_next(link)) {
1029 prop = rs->properties.data;
1031 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
1032 case RAZOR_PROPERTY_REQUIRES:
1033 case RAZOR_PROPERTY_CONFLICTS:
1034 for(j = 0; j < count; j++) {
1038 if (aj->package->name == prop->name) {
1040 RAZOR_INSTALL_ACTION_ADD)
1041 graph_add_edge(&follows,
1044 graph_add_edge(&follows,
1052 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
1053 for(j = 0; j < count; j++) {
1057 if (aj->package == ai->package &&
1058 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
1059 graph_add_edge(&follows, i, j);
1065 graph_add_edge(&follows, i, i);
1068 ii->order = graph_sort(&follows);
1069 ii->left = deque_dup(ii->order);
1070 graph_release(&follows);
1076 razor_install_iterator_next(struct razor_install_iterator *ii,
1077 struct razor_package **package,
1078 enum razor_install_action *action,
1081 struct install_action *a;
1082 struct razor_package_iterator *pi;
1083 struct razor_package *pkg;
1084 const char *removing, *name;
1086 if (deque_empty(ii->left))
1089 a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
1090 *package = a->package;
1091 *action = a->action;
1094 if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
1095 razor_package_get_details(ii->set, a->package,
1096 RAZOR_DETAIL_NAME, &removing,
1099 pi = razor_package_iterator_create(ii->next);
1100 while (razor_package_iterator_next(pi, &pkg,
1101 RAZOR_DETAIL_NAME, &name,
1102 RAZOR_DETAIL_LAST)) {
1103 if (!strcmp(name, removing))
1106 razor_package_iterator_destroy(pi);
1114 razor_install_iterator_rewind(struct razor_install_iterator *ii)
1116 deque_free(ii->left);
1117 ii->left=deque_dup(ii->order);
1121 razor_install_iterator_destroy(struct razor_install_iterator *ii)
1123 array_release(&ii->actions);
1124 deque_free(ii->order);
1125 deque_free(ii->left);