2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <sys/types.h>
39 #include "razor-internal.h"
57 struct razor_set_section_index {
62 struct razor_set_section_index razor_sections[] = {
63 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
64 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
65 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
66 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
67 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
70 struct razor_set_section_index razor_files_sections[] = {
71 { RAZOR_FILES, offsetof(struct razor_set, files) },
72 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
73 { RAZOR_FILE_STRING_POOL, offsetof(struct razor_set, file_string_pool) },
76 struct razor_set_section_index razor_details_sections[] = {
77 { RAZOR_DETAILS_STRING_POOL, offsetof(struct razor_set, details_string_pool) },
80 RAZOR_EXPORT struct razor_set *
81 razor_set_create_without_root(void)
83 struct razor_set *set;
86 set = zalloc(sizeof *set);
88 empty = array_add(&set->string_pool, 1);
94 RAZOR_EXPORT struct razor_set *
95 razor_set_create(void)
97 struct razor_set *set;
98 struct razor_entry *e;
100 set = razor_set_create_without_root();
102 e = array_add(&set->files, sizeof *e);
104 e->flags = RAZOR_ENTRY_LAST;
106 list_set_empty(&e->packages);
112 razor_set_bind_sections(struct razor_set *set,
113 struct razor_set_header **header,
115 struct razor_set_section_index section_index[],
116 int section_index_size,
117 const char *filename)
119 struct razor_set_section *s, *sections;
124 *header = razor_file_get_contents(filename, header_size);
128 sections = (void *) *header + sizeof **header;
129 pool = (void *) sections + (*header)->num_sections * sizeof *sections;
131 for (i = 0; i < (*header)->num_sections; i++) {
134 for (j = 0; j < section_index_size; j++)
135 if (!strcmp(section_index[j].name,
138 if (j == section_index_size)
140 array = (void *) set + section_index[j].offset;
141 array->data = (void *) *header + s->offset;
142 array->size = s->size;
143 array->alloc = s->size;
149 RAZOR_EXPORT struct razor_set *
150 razor_set_open(const char *filename)
152 struct razor_set *set;
154 set = zalloc(sizeof *set);
155 if (razor_set_bind_sections(set, &set->header, &set->header_size,
156 razor_sections, ARRAY_SIZE(razor_sections),
165 razor_set_open_details(struct razor_set *set, const char *filename)
167 return razor_set_bind_sections(set, &set->details_header,
168 &set->details_header_size,
169 razor_details_sections,
170 ARRAY_SIZE(razor_details_sections),
175 razor_set_open_files(struct razor_set *set, const char *filename)
177 return razor_set_bind_sections(set, &set->files_header,
178 &set->files_header_size,
179 razor_files_sections,
180 ARRAY_SIZE(razor_files_sections),
185 razor_set_destroy(struct razor_set *set)
190 assert (set != NULL);
193 razor_file_free_contents(set->header, set->header_size);
195 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
196 a = (void *) set + razor_sections[i].offset;
201 if (set->details_header) {
202 razor_file_free_contents(set->details_header,
203 set->details_header_size);
205 for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
206 a = (void *) set + razor_details_sections[i].offset;
211 if (set->files_header) {
212 razor_file_free_contents(set->files_header,
213 set->files_header_size);
215 for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
216 a = (void *) set + razor_files_sections[i].offset;
225 razor_set_write_sections_to_fd(struct razor_set *set, int fd,
226 struct razor_set_section_index *sections,
229 struct razor_set_header header;
230 struct razor_set_section *out_sections =
231 malloc(array_size * sizeof *out_sections);
232 struct hashtable table;
233 struct array *a, pool;
237 header.magic = RAZOR_MAGIC;
238 header.version = RAZOR_VERSION;
239 header.num_sections = array_size;
240 offset = sizeof header + array_size * sizeof *out_sections;
243 hashtable_init(&table, &pool);
245 for (i = 0; i < array_size; i++)
246 out_sections[i].name =
247 hashtable_tokenize(&table, sections[i].name);
251 for (i = 0; i < array_size; i++) {
252 a = (void *) set + sections[i].offset;
253 out_sections[i].offset = offset;
254 out_sections[i].size = a->size;
258 razor_write(fd, &header, sizeof header);
259 razor_write(fd, out_sections, array_size * sizeof *out_sections);
260 razor_write(fd, pool.data, pool.size);
262 for (i = 0; i < array_size; i++) {
263 a = (void *) set + sections[i].offset;
264 razor_write(fd, a->data, a->size);
273 razor_set_write_to_fd(struct razor_set *set, int fd,
274 enum razor_repo_file_type type)
277 case RAZOR_REPO_FILE_MAIN:
278 return razor_set_write_sections_to_fd(set, fd,
280 ARRAY_SIZE(razor_sections));
282 case RAZOR_REPO_FILE_DETAILS:
283 return razor_set_write_sections_to_fd(set, fd,
284 razor_details_sections,
285 ARRAY_SIZE(razor_details_sections));
286 case RAZOR_REPO_FILE_FILES:
287 return razor_set_write_sections_to_fd(set, fd,
288 razor_files_sections,
289 ARRAY_SIZE(razor_files_sections));
296 razor_set_write(struct razor_set *set, const char *filename,
297 enum razor_repo_file_type type)
301 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
305 status = razor_set_write_to_fd(set, fd, type);
315 razor_build_evr(char *evr_buf, int size, const char *epoch,
316 const char *version, const char *release)
320 if (!version || !*version) {
325 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
326 len = snprintf(evr_buf, size, "%s:", epoch);
330 len = snprintf(evr_buf, size, "%s", version);
333 if (release && *release)
334 snprintf(evr_buf, size, "-%s", release);
338 razor_versioncmp(const char *s1, const char *s2)
347 n1 = strtol(s1, (char **) &p1, 10);
348 n2 = strtol(s2, (char **) &p2, 10);
350 /* Epoch; if one but not the other has an epoch set, default
351 * the epoch-less version to 0. */
352 res = (*p1 == ':') - (*p2 == ':');
357 } else if (res > 0) {
370 if (isdigit(*p1) && isdigit(*p2))
371 return razor_versioncmp(p1, p2);
378 razor_package_get_details_type(struct razor_set *set,
379 struct razor_package *package,
380 enum razor_detail_type type)
385 case RAZOR_DETAIL_NAME:
386 pool = set->string_pool.data;
387 return &pool[package->name];
389 case RAZOR_DETAIL_VERSION:
390 pool = set->string_pool.data;
391 return &pool[package->version];
393 case RAZOR_DETAIL_ARCH:
394 pool = set->string_pool.data;
395 return &pool[package->arch];
397 case RAZOR_DETAIL_SUMMARY:
398 pool = set->details_string_pool.data;
399 return &pool[package->summary];
401 case RAZOR_DETAIL_DESCRIPTION:
402 pool = set->details_string_pool.data;
403 return &pool[package->description];
405 case RAZOR_DETAIL_URL:
406 pool = set->details_string_pool.data;
407 return &pool[package->url];
409 case RAZOR_DETAIL_LICENSE:
410 pool = set->details_string_pool.data;
411 return &pool[package->license];
414 fprintf(stderr, "type %u not found\n", type);
420 * razor_package_get_details_varg:
422 * @package: a %razor_package
423 * @args: a va_list of arguments to set
426 razor_package_get_details_varg(struct razor_set *set,
427 struct razor_package *package,
431 enum razor_detail_type type;
434 for (i = 0;; i += 2) {
435 type = va_arg(args, enum razor_detail_type);
436 if (type == RAZOR_DETAIL_LAST)
438 data = va_arg(args, const char **);
439 *data = razor_package_get_details_type(set, package, type);
445 * razor_package_get_details:
447 * @package: a %razor_package
449 * Gets details about a package using a varg interface
450 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
452 * Example: razor_package_get_details (set, package,
453 * RAZOR_DETAIL_URL, &url,
454 * RAZOR_DETAIL_LAST);
457 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
461 assert (set != NULL);
462 assert (package != NULL);
464 va_start(args, NULL);
465 razor_package_get_details_varg (set, package, args);
469 RAZOR_EXPORT const char *
470 razor_property_relation_to_string(struct razor_property *p)
474 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
475 case RAZOR_PROPERTY_LESS:
478 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
481 case RAZOR_PROPERTY_EQUAL:
484 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
487 case RAZOR_PROPERTY_GREATER:
495 RAZOR_EXPORT const char *
496 razor_property_type_to_string(struct razor_property *p)
500 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
501 case RAZOR_PROPERTY_REQUIRES:
503 case RAZOR_PROPERTY_PROVIDES:
505 case RAZOR_PROPERTY_CONFLICTS:
507 case RAZOR_PROPERTY_OBSOLETES:
514 RAZOR_EXPORT struct razor_entry *
515 razor_set_find_entry(struct razor_set *set,
516 struct razor_entry *dir, const char *pattern)
518 struct razor_entry *e, *subdir;
519 const char *n, *pool = set->file_string_pool.data;
522 assert (set != NULL);
523 assert (dir != NULL);
524 assert (pattern != NULL);
529 if (strcmp(pattern, n) == 0)
532 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
533 pattern[len] == '/') {
534 subdir = (struct razor_entry *) set->files.data +
536 return razor_set_find_entry(set, subdir,
539 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
545 list_dir(struct razor_set *set, struct razor_entry *dir,
546 char *prefix, const char *pattern)
548 struct razor_entry *e, *subdir;
549 const char *n, *pool = set->file_string_pool.data;
554 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
556 printf("%s/%s\n", prefix, n);
558 char *sub = prefix + strlen (prefix);
561 subdir = (struct razor_entry *) set->files.data +
563 list_dir(set, subdir, prefix, pattern);
566 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
570 razor_set_list_files(struct razor_set *set, const char *pattern)
572 struct razor_entry *root, *e;
573 char buffer[512], *p, *base;
575 assert (set != NULL);
577 root = (struct razor_entry *) set->files.data;
579 if (pattern == NULL) {
580 p = set->file_string_pool.data;
584 strcpy(buffer, p + e->name);
585 list_dir(set, root + e->start, buffer, NULL);
587 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
591 strcpy(buffer, pattern);
592 e = razor_set_find_entry(set, root, buffer);
596 p = strrchr(buffer, '/');
604 e = razor_set_find_entry(set, root, buffer);
606 list_dir(set, root + e->start, buffer, base);
610 razor_set_list_package_files(struct razor_set *set,
611 struct razor_package *package)
613 struct razor_file_iterator *fi;
616 assert (set != NULL);
617 assert (package != NULL);
619 fi = razor_file_iterator_create(set, package);
621 while (razor_file_iterator_next(fi, &name))
622 printf("%s\n", name);
624 razor_file_iterator_destroy(fi);
627 /* The diff order matters. We should sort the packages so that a
628 * REMOVE of a package comes before the INSTALL, and so that all
629 * requires for a package have been installed before the package.
633 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
634 razor_diff_callback_t callback, void *data)
636 struct razor_package_iterator *pi1, *pi2;
637 struct razor_package *p1, *p2;
638 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
641 assert (set != NULL);
642 assert (upstream != NULL);
644 pi1 = razor_package_iterator_create(set);
645 pi2 = razor_package_iterator_create(upstream);
647 razor_package_iterator_next(pi1, &p1,
648 RAZOR_DETAIL_NAME, &name1,
649 RAZOR_DETAIL_VERSION, &version1,
650 RAZOR_DETAIL_ARCH, &arch1,
652 razor_package_iterator_next(pi2, &p2,
653 RAZOR_DETAIL_NAME, &name2,
654 RAZOR_DETAIL_VERSION, &version2,
655 RAZOR_DETAIL_ARCH, &arch2,
660 res = strcmp(name1, name2);
662 res = razor_versioncmp(version1, version2);
667 if (p2 == NULL || res < 0)
668 callback(RAZOR_DIFF_ACTION_REMOVE,
669 p1, name1, version1, arch1, data);
670 else if (p1 == NULL || res > 0)
671 callback(RAZOR_DIFF_ACTION_ADD,
672 p2, name2, version2, arch2, data);
674 if (p1 != NULL && res <= 0)
675 razor_package_iterator_next(pi1, &p1,
676 RAZOR_DETAIL_NAME, &name1,
677 RAZOR_DETAIL_VERSION, &version1,
678 RAZOR_DETAIL_ARCH, &arch1,
680 if (p2 != NULL && res >= 0)
681 razor_package_iterator_next(pi2, &p2,
682 RAZOR_DETAIL_NAME, &name2,
683 RAZOR_DETAIL_VERSION, &version2,
684 RAZOR_DETAIL_ARCH, &arch2,
688 razor_package_iterator_destroy(pi1);
689 razor_package_iterator_destroy(pi2);
692 struct install_action {
693 enum razor_install_action action;
694 struct razor_package *package;
697 struct razor_install_iterator {
698 struct razor_set *set;
699 struct razor_set *next;
700 struct array actions;
701 struct install_action *a, *end;
705 add_action(enum razor_diff_action action,
706 struct razor_package *package,
712 struct razor_install_iterator *ii = data;
713 struct install_action *a;
715 a = array_add(&ii->actions, sizeof *a);
716 a->package = package;
719 case RAZOR_DIFF_ACTION_ADD:
720 a->action = RAZOR_INSTALL_ACTION_ADD;
722 case RAZOR_DIFF_ACTION_REMOVE:
723 a->action = RAZOR_INSTALL_ACTION_REMOVE;
728 RAZOR_EXPORT struct razor_install_iterator *
729 razor_set_create_install_iterator(struct razor_set *set,
730 struct razor_set *next)
732 struct razor_install_iterator *ii;
734 assert (set != NULL);
735 assert (next != NULL);
737 ii = zalloc(sizeof *ii);
741 razor_set_diff(set, next, add_action, ii);
743 ii->a = ii->actions.data;
744 ii->end = ii->actions.data + ii->actions.size;
746 /* FIXME: We need to figure out the right install order here,
747 * so the post and pre scripts can run. */
753 razor_install_iterator_next(struct razor_install_iterator *ii,
754 struct razor_set **set,
755 struct razor_package **package,
756 enum razor_install_action *action,
759 if (ii->a == ii->end)
762 switch (ii->a->action) {
763 case RAZOR_INSTALL_ACTION_ADD:
766 case RAZOR_INSTALL_ACTION_REMOVE:
771 *package = ii->a->package;
772 *action = ii->a->action;
780 razor_install_iterator_destroy(struct razor_install_iterator *ii)
782 array_release(&ii->actions);