Only export symbols starting with razor_ in dynamic library.
Apart from being good practice to avoid clashes with higher-level
libraries and the application, this also fixes an obscure bug: The
gnulib library is used both by librazor (the dynamic library) and
by razor (the executable). In doing so, we want to have two separate
copies of the library despite the code duplication this involves.
Without the explicit limit to export only razor_ symbols, the razor
executable under mingw64 was picking up the getopt_long function
from librazor and the optind variable from libgnu which meant that
it did not see optind changing. Hiding librazor's copy of getopt
causes the linker to find libgnu's copy and everything works.
Note that under mingw librazor-#.dll still contains undocumented
(private) razor_ symbols but these will do no harm as long as nobody
tries to use them.
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);
1292 razor_install_iterator_rewind(struct razor_install_iterator *ii)
1294 deque_free(ii->left);
1295 ii->left=deque_dup(ii->order);
1299 razor_install_iterator_tell(struct razor_install_iterator *ii)
1301 return deque_length(ii->order) - deque_length(ii->left);
1305 razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
1309 if (pos > deque_length(ii->order))
1310 pos = deque_length(ii->order);
1312 current_pos = razor_install_iterator_tell(ii);
1314 if (pos < current_pos) {
1315 razor_install_iterator_rewind(ii);
1319 while(current_pos < pos) {
1320 (void) deque_pop(ii->left);
1328 razor_install_iterator_destroy(struct razor_install_iterator *ii)
1330 array_release(&ii->actions);
1331 deque_free(ii->order);
1332 deque_free(ii->left);