2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
4 * Copyright (C) 2009-2012, 2016, 2018 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.
43 #include "types/types.h"
44 #include "razor-internal.h"
50 struct razor_set_section_index {
56 #define MAIN(type, field) \
57 { type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
58 #define FILES(type, field) \
59 { type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
60 #define DETAILS(type, field) \
61 { type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
63 struct razor_set_section_index razor_sections[] = {
64 MAIN(RAZOR_STRING_POOL, string_pool),
65 MAIN(RAZOR_PACKAGES, packages),
66 MAIN(RAZOR_PROPERTIES, properties),
67 MAIN(RAZOR_PACKAGE_POOL, package_pool),
68 MAIN(RAZOR_PROPERTY_POOL, property_pool),
69 MAIN(RAZOR_PREFIX_POOL, prefix_pool),
70 FILES(RAZOR_FILES, files),
71 FILES(RAZOR_FILE_POOL, file_pool),
72 FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
73 DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
76 RAZOR_EXPORT struct razor_set *
77 razor_set_create_without_root(void)
79 struct razor_set *set;
82 set = zalloc(sizeof *set);
85 empty = array_add(&set->string_pool, 1);
92 set->header_version = RAZOR_HEADER_VERSION;
94 set->flags = RAZOR_SET_PRIVATE;
100 RAZOR_EXPORT struct razor_set *
101 razor_set_create(void)
103 struct razor_set *set;
104 struct razor_entry *e;
106 set = razor_set_create_without_root();
108 e = array_add(&set->files, sizeof *e);
110 e->flags = RAZOR_ENTRY_LAST;
112 list_set_empty(&e->packages);
117 RAZOR_EXPORT uint32_t
118 razor_set_get_header_version(struct razor_set *set)
120 return set->header_version;
124 razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
126 if (header_version<RAZOR_HEADER_VERSION_MIN ||
127 header_version>RAZOR_HEADER_VERSION)
130 set->header_version = header_version;
135 struct razor_mapped_file {
136 struct razor_set_header *header;
138 struct razor_mapped_file *next;
142 razor_set_bind_sections(struct razor_set *set, const char *uri,
143 enum razor_set_flags flags, struct razor_error **error)
145 struct razor_set_section *s, *sections;
146 struct razor_mapped_file *file;
147 const char *pool, *reason;
151 file = zalloc(sizeof *file);
153 razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
154 "Not enough memory");
158 file->header = razor_uri_get_contents(uri, &file->size,
159 flags & RAZOR_SET_PRIVATE,
166 if (file->size < sizeof *file->header) {
167 code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
168 reason = "Premature EOF";
169 } else if (file->header->magic != RAZOR_MAGIC) {
170 code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
171 reason = "Bad magic number";
172 } else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
173 file->header->version > RAZOR_HEADER_VERSION) {
174 code = RAZOR_GENERAL_ERROR_DATABASE_INCOMPATIBLE;
175 reason = "Incompatible file version";
180 razor_set_error(error, RAZOR_GENERAL_ERROR, code, uri, reason);
181 razor_uri_free_contents(file->header, file->size);
186 set->flags = flags & RAZOR_SET_PRIVATE;
188 set->header_version = file->header->version;
190 if (set->mapped_files == NULL) {
191 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
192 array = (void *) set + razor_sections[i].offset;
193 array_release(array);
197 file->next = set->mapped_files;
198 set->mapped_files = file;
200 sections = (void *) file->header + sizeof *file->header;
201 pool = (void *) sections +
202 file->header->num_sections * sizeof *sections;
204 for (i = 0; i < file->header->num_sections; i++) {
206 for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
207 if (!strcmp(razor_sections[j].name, &pool[s->name]))
209 if (j == ARRAY_SIZE(razor_sections))
211 array = (void *) set + razor_sections[j].offset;
212 array->data = (void *) file->header + s->offset;
213 array->size = s->size;
214 array->alloc = s->size;
220 RAZOR_EXPORT struct razor_set *
221 razor_set_open(const char *uri, enum razor_set_flags flags,
222 struct razor_error **error)
224 struct razor_set *set;
226 set = zalloc(sizeof *set);
228 razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
229 "Not enough memory");
235 if (razor_set_bind_sections(set, uri, flags, error)) {
242 struct razor_uri_lock {
248 static struct array razor_uri_locks = { 0, };
251 * The underlying locks on MS-Windows and POSIX are different. Posix locks
252 * created with fcntl(F_SETLK) only affect other processes whereas MS-Windows
253 * locks affect the locking process as well. Partly because the latter is
254 * preferable and partly because it makes testing easier if platforms behave
255 * in the same way, we implement platform independent locks which follow the
256 * MS-Windows pattern.
258 * Note that razor_set_aquire_lock() currently assumes that this is a private
259 * helper function. Should we ever want to make this a library-wide API then
260 * we should probably add a 'void *owner' parameter and add a new error code
261 * (RAZOR_GENERAL_ERROR_LOCALLY_LOCKED?) if a lock is present with a different
262 * owner so that razor_set_aquire_lock() can generate a different error message.
266 razor_uri_lock(const char *uri, int flags, mode_t mode, int exclusive,
267 struct razor_error **error)
270 struct razor_uri_lock *ulock;
272 DWORD lflags = LOCKFILE_FAIL_IMMEDIATELY, err;
273 OVERLAPPED lock = {0};
275 struct flock lock = {0};
278 fd = razor_uri_open(uri, flags, mode, error);
282 for (i = ptr_array_len(&razor_uri_locks) - 1; i >= 0; i--) {
283 ulock = ptr_array_index(&razor_uri_locks, i);
284 if (ulock && !strcmp(ulock->uri, uri)) {
285 if (!ulock->exclusive && !exclusive)
287 razor_set_error(error, RAZOR_GENERAL_ERROR,
288 RAZOR_GENERAL_ERROR_ALREADY_LOCKED,
290 "An existing lock is already held on this file");
298 lflags |= LOCKFILE_EXCLUSIVE_LOCK;
299 if (!LockFileEx((HANDLE)_get_osfhandle(fd), lflags, 0, 1, 0, &lock)) {
300 err = GetLastError();
301 if (err == ERROR_IO_PENDING)
302 razor_set_error(error, RAZOR_GENERAL_ERROR,
303 RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED,
305 "An existing lock is already held on this file");
307 razor_set_error_mswin(error, uri, err);
312 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
313 lock.l_whence = SEEK_SET;
316 if (fcntl(fd, F_SETLK, &lock) < 0) {
317 if (errno == EAGAIN || errno == EACCES)
318 razor_set_error(error, RAZOR_GENERAL_ERROR,
319 RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED,
321 "An existing lock is already held on this file");
323 razor_set_error_posix(error, uri);
329 ulock = zalloc(sizeof *ulock);
330 ulock->uri = strdup(uri);
332 ulock->exclusive = exclusive;
333 return ptr_array_add(&razor_uri_locks, ulock);
337 razor_uri_unlock(int id)
339 struct razor_uri_lock *ulock;
341 struct flock lock = {0};
344 if (id < 0 || id >= ptr_array_len(&razor_uri_locks))
347 ulock = ptr_array_index(&razor_uri_locks, id);
353 (void)UnlockFile((HANDLE)_get_osfhandle(ulock->fd), 0, 0, 1, 0);
355 lock.l_type = F_UNLCK;
356 lock.l_whence = SEEK_SET;
359 (void)fcntl(ulock->fd, F_SETLK, &lock);
362 ptr_array_remove_index(&razor_uri_locks, id);
369 razor_set_acquire_lock(struct razor_set *set, const char *uri, int exclusive,
370 struct razor_error **error)
373 const char *errstr = NULL;
377 razor_uri_unlock(set->lock);
382 lock = razor_uri_lock(uri,
383 O_CREAT | O_RDWR | O_TRUNC | O_BINARY,
384 0666, exclusive, error);
394 if (razor_error_matches(*error, RAZOR_GENERAL_ERROR,
395 RAZOR_GENERAL_ERROR_ALREADY_LOCKED)) {
397 * This represents a design flaw in the caller.
400 errstr = "Database is in use and cannot be locked";
402 errstr = "Database is being updated and cannot be locked";
403 } else if (razor_error_matches(*error, RAZOR_GENERAL_ERROR,
404 RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED)) {
406 * This is probably caused by another application holding
407 * the lock, but under MS-Windows the file could in theory
408 * be locked by this application outside of razor_set.
411 errstr = "Database is in use. Please try again later";
413 errstr = "Database is being updated. Please try again later";
417 razor_error_free(*error);
418 razor_set_error(error,
420 RAZOR_GENERAL_ERROR_DATABASE_LOCKED,
428 razor_set_destroy(struct razor_set *set)
430 struct razor_mapped_file *file, *next;
434 assert (set != NULL);
436 if (set->mapped_files == NULL) {
437 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
438 array = (void *) set + razor_sections[i].offset;
439 array_release(array);
442 for (file = set->mapped_files; file != NULL; file = next) {
444 razor_uri_free_contents(file->header, file->size);
449 razor_set_acquire_lock(set, NULL, 0, NULL);
454 razor_set_unref(struct razor_set *set)
456 if (set && !--set->ref_count)
457 razor_set_destroy(set);
460 RAZOR_EXPORT struct razor_set *
461 razor_set_ref(struct razor_set *set)
469 razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
470 int handle, uint32_t section_mask)
472 struct razor_set_header header;
473 struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
474 struct hashtable table;
475 struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
478 static const char padding[4];
481 hashtable_init(&table, &pool);
484 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
485 if ((razor_sections[i].flags & section_mask) == 0)
488 arrays[j] = (void *) set + razor_sections[i].offset;
490 hashtable_tokenize(&table, razor_sections[i].name);
495 header.magic = RAZOR_MAGIC;
496 header.version = set->header_version;
497 header.num_sections = count;
498 offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
500 for (i = 0; i < count; i++) {
501 sections[i].offset = offset;
502 sections[i].size = arrays[i]->size;
503 offset += ALIGN(arrays[i]->size, 4);
506 razor_atomic_write(atomic, handle, &header, sizeof header);
507 razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
508 razor_atomic_write(atomic, handle, pool.data, pool.size);
509 razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
511 for (i = 0; i < count; i++) {
512 razor_atomic_write(atomic, handle, arrays[i]->data,
514 razor_atomic_write(atomic, handle, padding,
515 PADDING(arrays[i]->size, 4));
518 array_release(&pool);
519 hashtable_release(&table);
523 razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
524 const char *uri, uint32_t sections)
528 h = razor_atomic_create_file(atomic, uri,
529 S_IRWXU | S_IRWXG | S_IRWXO);
533 razor_set_write_to_handle(set, atomic, h, sections);
535 return razor_atomic_close(atomic, h);
539 razor_build_evr(char *evr_buf, int size, const char *epoch,
540 const char *version, const char *release)
544 if (!version || !*version) {
549 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
550 len = snprintf(evr_buf, size, "%s:", epoch);
554 len = snprintf(evr_buf, size, "%s", version);
557 if (release && *release)
558 snprintf(evr_buf, size, "-%s", release);
562 razor_versioncmp(const char *s1, const char *s2)
571 n1 = strtol(s1, (char **) &p1, 10);
572 n2 = strtol(s2, (char **) &p2, 10);
574 /* Epoch; if one but not the other has an epoch set, default
575 * the epoch-less version to 0. */
576 res = (*p1 == ':') - (*p2 == ':');
581 } else if (res > 0) {
594 if (isdigit(*p1) && isdigit(*p2))
595 return razor_versioncmp(p1, p2);
602 razor_package_get_details_string(struct razor_set *set,
603 struct razor_package *package,
604 enum razor_detail_type type)
609 case RAZOR_DETAIL_NAME:
610 pool = set->string_pool.data;
611 return &pool[package->name];
613 case RAZOR_DETAIL_VERSION:
614 pool = set->string_pool.data;
615 return &pool[package->version];
617 case RAZOR_DETAIL_ARCH:
618 pool = set->string_pool.data;
619 return &pool[package->arch];
621 case RAZOR_DETAIL_SUMMARY:
622 if (!set->details_string_pool.size)
624 pool = set->details_string_pool.data;
625 return &pool[package->summary];
627 case RAZOR_DETAIL_DESCRIPTION:
628 if (!set->details_string_pool.size)
630 pool = set->details_string_pool.data;
631 return &pool[package->description];
633 case RAZOR_DETAIL_URL:
634 if (!set->details_string_pool.size)
636 pool = set->details_string_pool.data;
637 return &pool[package->url];
639 case RAZOR_DETAIL_LICENSE:
640 if (!set->details_string_pool.size)
642 pool = set->details_string_pool.data;
643 return &pool[package->license];
645 case RAZOR_DETAIL_PREUNPROG:
646 pool = set->string_pool.data;
647 return &pool[package->preun.program];
649 case RAZOR_DETAIL_PREUN:
650 pool = set->string_pool.data;
651 return &pool[package->preun.body];
653 case RAZOR_DETAIL_POSTUNPROG:
654 pool = set->string_pool.data;
655 return &pool[package->postun.program];
657 case RAZOR_DETAIL_POSTUN:
658 pool = set->string_pool.data;
659 return &pool[package->postun.body];
662 fprintf(stderr, "type %u not found\n", type);
667 static const char *const *
668 razor_package_get_details_array(struct razor_set *set,
669 struct razor_package *package,
670 enum razor_detail_type type)
673 case RAZOR_DETAIL_PREFIXES:
674 /* We don't track prefixes in packages. Install
675 * prefixes are tracked, and made available via
676 * razor_install_prefix_iterator_create().
681 fprintf(stderr, "type %u not found\n", type);
687 * razor_package_get_details_varg:
689 * @package: a %razor_package
690 * @args: a va_list of arguments to set
693 razor_package_get_details_varg(struct razor_set *set,
694 struct razor_package *package,
698 enum razor_detail_type type;
700 const char *const **array;
702 for (i = 0;; i += 2) {
703 type = va_arg(args, enum razor_detail_type);
704 if (type == RAZOR_DETAIL_LAST)
706 if (type == RAZOR_DETAIL_PREFIXES) {
707 array = va_arg(args, const char *const **);
708 *array = razor_package_get_details_array(set, package,
711 string = va_arg(args, const char **);
712 *string = razor_package_get_details_string(set, package,
720 * razor_package_get_details:
722 * @package: a %razor_package
724 * Gets details about a package using a varg interface
725 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
727 * Example: razor_package_get_details (set, package,
728 * RAZOR_DETAIL_URL, &url,
729 * RAZOR_DETAIL_LAST);
732 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
736 assert (set != NULL);
737 assert (package != NULL);
739 va_start(args, NULL);
740 razor_package_get_details_varg (set, package, args);
745 * razor_package_remove:
746 * @prev: The %razor_set before the current transaction
747 * @next: The %razor_set after the current transaction is applied
748 * @package: a %razor_package
749 * @root: the root into which the package is currently installed
750 * @install_count: the value to pass to uninstall scripts
751 * @stage: Limit the removal to just the scripts or the files
753 * Removes an installed package.
756 razor_package_remove(struct razor_set *prev, struct razor_set *next,
757 struct razor_atomic *atomic, struct razor_package *package,
758 const char *root_uri, int install_count,
759 enum razor_stage_type stage)
761 struct razor_file_iterator *fi;
762 struct razor_package_iterator *pi;
763 struct razor_package *p;
764 char *uri, *relative, *buffer, buf[32];
765 const char *name, *program, *script;
766 int i, count, retval = 0;
767 struct environment env;
770 struct razor_error *tmp_error = NULL;
772 if (stage & RAZOR_STAGE_SCRIPTS) {
773 environment_init(&env);
774 link = list_first(&package->install_prefixes,
776 for (i = 0; link; i++) {
777 prefix = (const char *)prev->string_pool.data +
779 sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
780 environment_add_variable(&env, buf, prefix);
781 link = list_next(link);
783 environment_set(&env);
786 if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
787 razor_package_get_details(prev, package,
788 RAZOR_DETAIL_PREUNPROG, &program,
789 RAZOR_DETAIL_PREUN, &script,
792 retval = razor_run_script(root_uri, RAZOR_PROPERTY_PREUN,
793 program, script, install_count,
797 razor_atomic_propagate_error(atomic, tmp_error, NULL);
802 if (!retval && (stage & RAZOR_STAGE_FILES)) {
803 fi = razor_file_iterator_create(prev, package, 1);
805 while (razor_file_iterator_next(fi, &name)) {
806 pi = razor_package_iterator_create_for_file(next, name);
808 while (razor_package_iterator_next(pi, &p,
811 razor_package_iterator_destroy(pi);
813 uri = razor_path_to_uri(name);
815 if (str_has_prefix(uri, "file:///"))
817 else if (str_has_prefix(uri, "file:/"))
819 else if (str_has_prefix(uri, "file:"))
821 else if (str_has_prefix(uri, "/"))
826 buffer = razor_resolve_uri_root(root_uri,
832 razor_atomic_remove(atomic, buffer);
835 razor_atomic_propagate_error(atomic,
844 razor_file_iterator_destroy(fi);
846 retval = razor_atomic_in_error_state(atomic);
849 if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) {
850 razor_package_get_details(prev, package,
851 RAZOR_DETAIL_POSTUNPROG, &program,
852 RAZOR_DETAIL_POSTUN, &script,
855 retval |= razor_run_script(root_uri, RAZOR_PROPERTY_POSTUN,
856 program, script, install_count,
860 razor_atomic_propagate_error(atomic, tmp_error, NULL);
865 if (stage & RAZOR_STAGE_SCRIPTS) {
866 environment_unset(&env);
867 environment_release(&env);
873 RAZOR_EXPORT const char *
874 razor_property_relation_to_string(struct razor_property *p)
878 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
879 case RAZOR_PROPERTY_LESS:
882 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
885 case RAZOR_PROPERTY_EQUAL:
888 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
891 case RAZOR_PROPERTY_GREATER:
899 RAZOR_EXPORT const char *
900 razor_property_type_to_string(struct razor_property *p)
904 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
905 case RAZOR_PROPERTY_REQUIRES:
907 case RAZOR_PROPERTY_PROVIDES:
909 case RAZOR_PROPERTY_CONFLICTS:
911 case RAZOR_PROPERTY_OBSOLETES:
918 RAZOR_EXPORT struct razor_entry *
919 razor_set_find_entry(struct razor_set *set,
920 struct razor_entry *dir, const char *pattern)
922 struct razor_entry *e, *subdir;
923 const char *n, *pool = set->file_string_pool.data;
926 assert (set != NULL);
927 assert (pattern != NULL);
935 if (strcmp(pattern, n) == 0)
938 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
939 pattern[len] == '/') {
940 subdir = (struct razor_entry *) set->files.data +
942 return razor_set_find_entry(set, subdir,
945 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
951 list_dir(struct razor_set *set, struct razor_entry *dir,
952 char *prefix, const char *pattern)
954 struct razor_entry *e, *subdir;
955 const char *n, *pool = set->file_string_pool.data;
960 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
962 printf("%s/%s\n", prefix, n);
964 char *sub = prefix + strlen (prefix);
967 subdir = (struct razor_entry *) set->files.data +
969 list_dir(set, subdir, prefix, pattern);
972 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
976 razor_set_list_files(struct razor_set *set, const char *pattern)
978 struct razor_entry *root, *e;
979 char buffer[512], *p, *base;
981 assert (set != NULL);
983 root = (struct razor_entry *) set->files.data;
985 if (pattern == NULL) {
986 p = set->file_string_pool.data;
990 strcpy(buffer, p + e->name);
991 list_dir(set, root + e->start, buffer, NULL);
993 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
997 strcpy(buffer, pattern);
998 e = razor_set_find_entry(set, root, buffer);
1002 p = strrchr(buffer, '/');
1010 e = razor_set_find_entry(set, root, buffer);
1012 list_dir(set, root + e->start, buffer, base);
1016 razor_set_list_package_files(struct razor_set *set,
1017 struct razor_package *package)
1019 struct razor_file_iterator *fi;
1022 assert (set != NULL);
1023 assert (package != NULL);
1025 fi = razor_file_iterator_create(set, package, 0);
1027 while (razor_file_iterator_next(fi, &name))
1028 printf("%s\n", name);
1030 razor_file_iterator_destroy(fi);
1034 * Package data can potentially come from two places. The so-called
1035 * metadata (eg., from comps.xml) and from an RPM file. We consider
1036 * a package which has additional data from an RPM file as "fixed".
1037 * If a package needs fixing, then razor_transaction_fixup_package()
1038 * will do so. When considering what packages to add and to remove
1039 * we need to take this into account since we always want to add
1040 * unfixed packages (otherwise we have a potential conflict between
1041 * the existing package data and that present in the RPM).
1044 razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
1046 const char *preunprog, *preun, *postunprog, *postun;
1050 razor_package_get_details(set, p,
1051 RAZOR_DETAIL_PREUNPROG, &preunprog,
1052 RAZOR_DETAIL_PREUN, &preun,
1053 RAZOR_DETAIL_POSTUNPROG, &postunprog,
1054 RAZOR_DETAIL_POSTUN, &postun,
1056 return *preunprog || *preun || *postunprog || *postun;
1060 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
1061 razor_diff_callback_t callback, void *data)
1063 struct razor_package_iterator *pi1, *pi2;
1064 struct razor_package *p1, *p2;
1065 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
1066 int res, is_fixed1, is_fixed2;
1068 assert (set != NULL);
1069 assert (upstream != NULL);
1071 pi1 = razor_package_iterator_create(set);
1072 pi2 = razor_package_iterator_create(upstream);
1074 razor_package_iterator_next(pi1, &p1,
1075 RAZOR_DETAIL_NAME, &name1,
1076 RAZOR_DETAIL_VERSION, &version1,
1077 RAZOR_DETAIL_ARCH, &arch1,
1079 is_fixed1 = razor_package_is_fixed(set, p1);
1080 razor_package_iterator_next(pi2, &p2,
1081 RAZOR_DETAIL_NAME, &name2,
1082 RAZOR_DETAIL_VERSION, &version2,
1083 RAZOR_DETAIL_ARCH, &arch2,
1085 is_fixed2 = razor_package_is_fixed(upstream, p2);
1089 res = strcmp(name1, name2);
1091 res = razor_versioncmp(version1, version2);
1093 res = is_fixed1 - is_fixed2;
1098 if (p2 == NULL || res < 0)
1099 callback(RAZOR_DIFF_ACTION_REMOVE,
1100 p1, name1, version1, arch1, data);
1101 else if (p1 == NULL || res > 0)
1102 callback(RAZOR_DIFF_ACTION_ADD,
1103 p2, name2, version2, arch2, data);
1105 if (p1 != NULL && res <= 0) {
1106 razor_package_iterator_next(pi1, &p1,
1107 RAZOR_DETAIL_NAME, &name1,
1108 RAZOR_DETAIL_VERSION, &version1,
1109 RAZOR_DETAIL_ARCH, &arch1,
1111 is_fixed1 = razor_package_is_fixed(set, p1);
1113 if (p2 != NULL && res >= 0) {
1114 razor_package_iterator_next(pi2, &p2,
1115 RAZOR_DETAIL_NAME, &name2,
1116 RAZOR_DETAIL_VERSION, &version2,
1117 RAZOR_DETAIL_ARCH, &arch2,
1119 is_fixed2 = razor_package_is_fixed(upstream, p2);
1123 razor_package_iterator_destroy(pi1);
1124 razor_package_iterator_destroy(pi2);
1127 struct install_action {
1128 enum razor_install_action action;
1129 struct razor_package *package;
1132 struct razor_install_iterator {
1133 struct razor_set *set;
1134 struct razor_set *next;
1135 struct array actions;
1136 struct deque *order, *left;
1140 add_action(enum razor_diff_action action,
1141 struct razor_package *package,
1143 const char *version,
1147 struct razor_install_iterator *ii = data;
1148 struct install_action *a;
1150 a = array_add(&ii->actions, sizeof *a);
1151 a->package = package;
1154 case RAZOR_DIFF_ACTION_ADD:
1155 a->action = RAZOR_INSTALL_ACTION_ADD;
1157 case RAZOR_DIFF_ACTION_REMOVE:
1158 a->action = RAZOR_INSTALL_ACTION_REMOVE;
1164 * Does <package> have a requirement for <script> which is
1165 * satisfied by <provider> ?
1166 * Note: We already know that <provider> is to be added as part of this install
1167 * so there is no need to check the relation.
1170 package_script_requires(struct razor_set *set, struct razor_package *package,
1171 enum razor_property_flags script,
1172 struct razor_package *provider)
1175 struct razor_property *prop;
1177 link = list_first(&package->properties, &set->property_pool);
1178 for(; link; link = list_next(link)) {
1179 prop = set->properties.data;
1181 if ((prop->flags & RAZOR_PROPERTY_SCRIPT_MASK) & script &&
1182 (prop->flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES &&
1183 provider->name == prop->name)
1189 RAZOR_EXPORT struct razor_install_iterator *
1190 razor_set_create_install_iterator(struct razor_set *set,
1191 struct razor_set *next)
1193 struct razor_install_iterator *ii;
1194 struct razor_property *prop;
1195 /* A graph of the actions to be perfomed where
1196 * A->B means action A should follow action B.
1198 struct graph follows;
1199 struct install_action *actions, *ai, *aj, *an;
1200 int i, j, count, vertex_added;
1202 struct razor_set *rs;
1203 struct deque *order;
1206 assert (set != NULL);
1207 assert (next != NULL);
1209 ii = zalloc(sizeof *ii);
1213 razor_set_diff(set, next, add_action, ii);
1215 actions = ii->actions.data;
1216 count = ii->actions.size / sizeof (struct install_action);
1218 graph_init(&follows);
1220 for(i = 0; i < count; i++) {
1222 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
1224 link = list_first(&ai->package->properties, &rs->property_pool);
1225 for(; link; link = list_next(link)) {
1226 prop = rs->properties.data;
1228 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
1229 case RAZOR_PROPERTY_REQUIRES:
1230 case RAZOR_PROPERTY_CONFLICTS:
1231 for(j = 0; j < count; j++) {
1235 if (aj->package->name == prop->name) {
1237 RAZOR_INSTALL_ACTION_ADD)
1238 graph_add_edge(&follows,
1241 graph_add_edge(&follows,
1249 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
1250 for(j = 0; j < count; j++) {
1254 if (aj->package == ai->package &&
1255 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
1256 graph_add_edge(&follows, i, j);
1262 graph_add_edge(&follows, i, i);
1266 * Because files are installed and removed using razor_atomic,
1267 * but scripts are run with no regard for these, we need some
1268 * means for synchronisation between the two. We support this
1269 * via transaction barriers which are points where
1270 * razor_atomic_commit() should be called so that scripts can
1271 * rely on the files they need being present.
1274 * 1) Transaction barriers never occur within a dependency
1275 * loop. Since we can't guarantee any ordering of actions
1276 * within such a loop, they make no sense.
1277 * 2) Otherwise the following table applies:
1278 * Action I Action J Barrier between I and J iff
1279 * ADD P ADD Q %pre(Q) requires P
1280 * ADD P REMOVE Q %preun(Q) requires P
1281 * REMOVE P ADD Q never
1282 * REMOVE P REMOVE Q %postun(P) requires Q
1285 * This should take account of conflicts somehow.
1287 order = graph_sort(&follows);
1288 ii->order = deque_new(0);
1289 if (!deque_empty(order)) {
1290 j = deque_pop(order);
1291 deque_unshift(ii->order, j);
1293 while (!deque_empty(order)) {
1295 j = deque_pop(order);
1298 if (graph_is_connected(&follows, i, j) &&
1299 graph_is_connected(&follows, j, i))
1301 else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
1302 aj->action == RAZOR_INSTALL_ACTION_ADD &&
1303 package_script_requires(next, aj->package,
1307 else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
1308 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
1309 package_script_requires(set, aj->package,
1310 RAZOR_PROPERTY_PREUN,
1313 else if (ai->action == RAZOR_INSTALL_ACTION_REMOVE &&
1314 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
1315 package_script_requires(set, ai->package,
1316 RAZOR_PROPERTY_POSTUN,
1321 if (barrier_needed) {
1322 an = array_add(&ii->actions, sizeof *an);
1323 actions = ii->actions.data;
1325 an->action = RAZOR_INSTALL_ACTION_COMMIT;
1326 deque_unshift(ii->order, an - actions);
1328 deque_unshift(ii->order, j);
1332 ii->left = deque_dup(ii->order);
1333 graph_release(&follows);
1339 razor_install_iterator_next(struct razor_install_iterator *ii,
1340 struct razor_package **package,
1341 enum razor_install_action *action,
1344 struct install_action *a;
1345 struct razor_package_iterator *pi;
1346 struct razor_package *pkg;
1347 const char *removing, *name;
1349 if (deque_empty(ii->left))
1352 a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
1353 *package = a->package;
1354 *action = a->action;
1357 if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
1358 razor_package_get_details(ii->set, a->package,
1359 RAZOR_DETAIL_NAME, &removing,
1362 pi = razor_package_iterator_create(ii->next);
1363 while (razor_package_iterator_next(pi, &pkg,
1364 RAZOR_DETAIL_NAME, &name,
1365 RAZOR_DETAIL_LAST)) {
1366 if (!strcmp(name, removing))
1369 razor_package_iterator_destroy(pi);
1370 } else if (a->action == RAZOR_INSTALL_ACTION_ADD)
1377 action_is_included(struct razor_install_iterator *ii, struct deque *done,
1378 struct razor_package *package,
1379 enum razor_install_action action)
1382 struct install_action *a;
1385 t = deque_dup(done);
1387 while(!deque_empty(t)) {
1388 a = (struct install_action *)ii->actions.data + deque_pop(t);
1389 if (a->package == package && a->action == action)
1392 retval = !deque_empty(t);
1399 RAZOR_EXPORT struct razor_set *
1400 razor_install_iterator_commit_set(struct razor_install_iterator *ii)
1402 struct razor_merger *merger;
1403 struct razor_set *set;
1404 struct razor_package *n, *nend, *s, *send;
1407 char *npool, *spool;
1410 done = deque_dup(ii->order);
1411 pos = razor_install_iterator_tell(ii);
1412 while(deque_length(done) > pos)
1415 s = ii->set->packages.data;
1416 send = ii->set->packages.data + ii->set->packages.size;
1417 spool = ii->set->string_pool.data;
1419 n = ii->next->packages.data;
1420 nend = ii->next->packages.data + ii->next->packages.size;
1421 npool = ii->next->string_pool.data;
1423 merger = razor_merger_create(ii->set, ii->next);
1424 while (s < send || n < nend) {
1425 if (s < send && n < nend)
1426 cmp = strcmp(&spool[s->name], &npool[n->name]);
1433 if (!action_is_included(ii, done, s,
1434 RAZOR_INSTALL_ACTION_REMOVE))
1435 razor_merger_add_package(merger, s);
1437 } else if (cmp == 0) {
1438 if (!action_is_included(ii, done, s,
1439 RAZOR_INSTALL_ACTION_REMOVE))
1440 razor_merger_add_package(merger, s);
1441 if (action_is_included(ii, done, n,
1442 RAZOR_INSTALL_ACTION_ADD))
1443 razor_merger_add_package(merger, n);
1448 if (action_is_included(ii, done, n,
1449 RAZOR_INSTALL_ACTION_ADD))
1450 razor_merger_add_package(merger, n);
1455 set = razor_merger_commit(merger);
1456 razor_merger_destroy(merger);
1463 razor_install_iterator_rewind(struct razor_install_iterator *ii)
1465 deque_free(ii->left);
1466 ii->left=deque_dup(ii->order);
1470 razor_install_iterator_tell(struct razor_install_iterator *ii)
1472 return deque_length(ii->order) - deque_length(ii->left);
1476 razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
1480 if (pos > deque_length(ii->order))
1481 pos = deque_length(ii->order);
1483 current_pos = razor_install_iterator_tell(ii);
1485 if (pos < current_pos) {
1486 razor_install_iterator_rewind(ii);
1490 while(current_pos < pos) {
1491 (void) deque_pop(ii->left);
1499 razor_install_iterator_destroy(struct razor_install_iterator *ii)
1501 array_release(&ii->actions);
1502 deque_free(ii->order);
1503 deque_free(ii->left);