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.
28 #include <sys/types.h>
38 #include "razor-internal.h"
52 struct razor_set_section_index {
57 struct razor_set_section_index razor_sections[] = {
58 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
59 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
60 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
61 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
62 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
65 struct razor_set_section_index razor_files_sections[] = {
66 { RAZOR_FILES, offsetof(struct razor_set, files) },
67 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
68 { RAZOR_FILE_STRING_POOL, offsetof(struct razor_set, file_string_pool) },
71 struct razor_set_section_index razor_details_sections[] = {
72 { RAZOR_DETAILS_STRING_POOL, offsetof(struct razor_set, details_string_pool) },
75 RAZOR_EXPORT struct razor_set *
76 razor_set_create(void)
78 struct razor_set *set;
79 struct razor_entry *e;
82 set = zalloc(sizeof *set);
84 e = array_add(&set->files, sizeof *e);
85 empty = array_add(&set->string_pool, 1);
88 e->flags = RAZOR_ENTRY_LAST;
90 list_set_empty(&e->packages);
96 razor_set_bind_sections(struct razor_set *set,
97 struct razor_set_header **header,
99 struct razor_set_section_index section_index[],
100 int section_index_size,
101 const char *filename)
103 struct razor_set_section *s, *sections;
109 fd = open(filename, O_RDONLY);
110 if (fstat(fd, &stat) < 0)
112 *header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
113 if (*header == MAP_FAILED)
115 *header_size = stat.st_size;
117 sections = (void *) *header + sizeof **header;
118 pool = (void *) sections + (*header)->num_sections * sizeof *sections;
120 for (i = 0; i < (*header)->num_sections; i++) {
123 for (j = 0; j < section_index_size; j++)
124 if (!strcmp(section_index[j].name,
127 if (j == section_index_size)
129 array = (void *) set + section_index[j].offset;
130 array->data = (void *) *header + s->offset;
131 array->size = s->size;
132 array->alloc = s->size;
139 RAZOR_EXPORT struct razor_set *
140 razor_set_open(const char *filename)
142 struct razor_set *set;
144 set = zalloc(sizeof *set);
145 if (razor_set_bind_sections(set, &set->header, &set->header_size,
146 razor_sections, ARRAY_SIZE(razor_sections),
155 razor_set_open_details(struct razor_set *set, const char *filename)
157 return razor_set_bind_sections(set, &set->details_header,
158 &set->details_header_size,
159 razor_details_sections,
160 ARRAY_SIZE(razor_details_sections),
165 razor_set_open_files(struct razor_set *set, const char *filename)
167 return razor_set_bind_sections(set, &set->files_header,
168 &set->files_header_size,
169 razor_files_sections,
170 ARRAY_SIZE(razor_files_sections),
175 razor_set_destroy(struct razor_set *set)
180 assert (set != NULL);
183 munmap(set->header, set->header_size);
185 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
186 a = (void *) set + razor_sections[i].offset;
191 if (set->details_header) {
192 munmap(set->details_header, set->details_header_size);
194 for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
195 a = (void *) set + razor_details_sections[i].offset;
200 if (set->files_header) {
201 munmap(set->files_header, set->files_header_size);
203 for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
204 a = (void *) set + razor_files_sections[i].offset;
213 razor_set_write_sections_to_fd(struct razor_set *set, int fd,
214 struct razor_set_section_index *sections,
217 struct razor_set_header header;
218 struct razor_set_section *out_sections =
219 malloc(array_size * sizeof *out_sections);
220 struct hashtable table;
221 struct array *a, pool;
225 header.magic = RAZOR_MAGIC;
226 header.version = RAZOR_VERSION;
227 header.num_sections = array_size;
228 offset = sizeof header + array_size * sizeof *out_sections;
231 hashtable_init(&table, &pool);
233 for (i = 0; i < array_size; i++)
234 out_sections[i].name =
235 hashtable_tokenize(&table, sections[i].name);
239 for (i = 0; i < array_size; i++) {
240 a = (void *) set + sections[i].offset;
241 out_sections[i].offset = offset;
242 out_sections[i].size = a->size;
246 razor_write(fd, &header, sizeof header);
247 razor_write(fd, out_sections, array_size * sizeof *out_sections);
248 razor_write(fd, pool.data, pool.size);
250 for (i = 0; i < array_size; i++) {
251 a = (void *) set + sections[i].offset;
252 razor_write(fd, a->data, a->size);
261 razor_set_write_to_fd(struct razor_set *set, int fd,
262 enum razor_repo_file_type type)
265 case RAZOR_REPO_FILE_MAIN:
266 return razor_set_write_sections_to_fd(set, fd,
268 ARRAY_SIZE(razor_sections));
270 case RAZOR_REPO_FILE_DETAILS:
271 return razor_set_write_sections_to_fd(set, fd,
272 razor_details_sections,
273 ARRAY_SIZE(razor_details_sections));
274 case RAZOR_REPO_FILE_FILES:
275 return razor_set_write_sections_to_fd(set, fd,
276 razor_files_sections,
277 ARRAY_SIZE(razor_files_sections));
284 razor_set_write(struct razor_set *set, const char *filename,
285 enum razor_repo_file_type type)
289 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
293 status = razor_set_write_to_fd(set, fd, type);
303 razor_build_evr(char *evr_buf, int size, const char *epoch,
304 const char *version, const char *release)
308 if (!version || !*version) {
313 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
314 len = snprintf(evr_buf, size, "%s:", epoch);
318 len = snprintf(evr_buf, size, "%s", version);
321 if (release && *release)
322 snprintf(evr_buf, size, "-%s", release);
326 razor_versioncmp(const char *s1, const char *s2)
335 n1 = strtol(s1, (char **) &p1, 10);
336 n2 = strtol(s2, (char **) &p2, 10);
338 /* Epoch; if one but not the other has an epoch set, default
339 * the epoch-less version to 0. */
340 res = (*p1 == ':') - (*p2 == ':');
345 } else if (res > 0) {
358 if (isdigit(*p1) && isdigit(*p2))
359 return razor_versioncmp(p1, p2);
366 razor_package_get_details_type(struct razor_set *set,
367 struct razor_package *package,
368 enum razor_detail_type type)
373 case RAZOR_DETAIL_NAME:
374 pool = set->string_pool.data;
375 return &pool[package->name];
377 case RAZOR_DETAIL_VERSION:
378 pool = set->string_pool.data;
379 return &pool[package->version];
381 case RAZOR_DETAIL_ARCH:
382 pool = set->string_pool.data;
383 return &pool[package->arch];
385 case RAZOR_DETAIL_SUMMARY:
386 pool = set->details_string_pool.data;
387 return &pool[package->summary];
389 case RAZOR_DETAIL_DESCRIPTION:
390 pool = set->details_string_pool.data;
391 return &pool[package->description];
393 case RAZOR_DETAIL_URL:
394 pool = set->details_string_pool.data;
395 return &pool[package->url];
397 case RAZOR_DETAIL_LICENSE:
398 pool = set->details_string_pool.data;
399 return &pool[package->license];
402 fprintf(stderr, "type %u not found\n", type);
408 * razor_package_get_details_varg:
410 * @package: a %razor_package
411 * @args: a va_list of arguments to set
414 razor_package_get_details_varg(struct razor_set *set,
415 struct razor_package *package,
419 enum razor_detail_type type;
422 for (i = 0;; i += 2) {
423 type = va_arg(args, enum razor_detail_type);
424 if (type == RAZOR_DETAIL_LAST)
426 data = va_arg(args, const char **);
427 *data = razor_package_get_details_type(set, package, type);
433 * razor_package_get_details:
435 * @package: a %razor_package
437 * Gets details about a package using a varg interface
438 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
440 * Example: razor_package_get_details (set, package,
441 * RAZOR_DETAIL_URL, &url,
442 * RAZOR_DETAIL_LAST);
445 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
449 assert (set != NULL);
450 assert (package != NULL);
452 va_start(args, NULL);
453 razor_package_get_details_varg (set, package, args);
457 RAZOR_EXPORT const char *
458 razor_property_relation_to_string(struct razor_property *p)
462 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
463 case RAZOR_PROPERTY_LESS:
466 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
469 case RAZOR_PROPERTY_EQUAL:
472 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
475 case RAZOR_PROPERTY_GREATER:
483 RAZOR_EXPORT const char *
484 razor_property_type_to_string(struct razor_property *p)
488 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
489 case RAZOR_PROPERTY_REQUIRES:
491 case RAZOR_PROPERTY_PROVIDES:
493 case RAZOR_PROPERTY_CONFLICTS:
495 case RAZOR_PROPERTY_OBSOLETES:
502 RAZOR_EXPORT struct razor_entry *
503 razor_set_find_entry(struct razor_set *set,
504 struct razor_entry *dir, const char *pattern)
506 struct razor_entry *e;
507 const char *n, *pool = set->file_string_pool.data;
510 assert (set != NULL);
511 assert (dir != NULL);
512 assert (pattern != NULL);
514 e = (struct razor_entry *) set->files.data + dir->start;
517 if (strcmp(pattern + 1, n) == 0)
520 if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
521 pattern[len + 1] == '/') {
522 return razor_set_find_entry(set, e, pattern + len + 1);
524 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
530 list_dir(struct razor_set *set, struct razor_entry *dir,
531 char *prefix, const char *pattern)
533 struct razor_entry *e;
534 const char *n, *pool = set->file_string_pool.data;
536 e = (struct razor_entry *) set->files.data + dir->start;
539 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
541 printf("%s/%s\n", prefix, n);
543 char *sub = prefix + strlen (prefix);
546 list_dir(set, e, prefix, pattern);
549 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
553 razor_set_list_files(struct razor_set *set, const char *pattern)
555 struct razor_entry *e;
556 char buffer[512], *p, *base;
558 assert (set != NULL);
560 if (pattern == NULL || !strcmp (pattern, "/")) {
562 list_dir(set, set->files.data, buffer, NULL);
566 strcpy(buffer, pattern);
567 e = razor_set_find_entry(set, set->files.data, buffer);
568 if (e && e->start > 0) {
571 p = strrchr(buffer, '/');
579 e = razor_set_find_entry(set, set->files.data, buffer);
580 if (e && e->start != 0)
581 list_dir(set, e, buffer, base);
585 list_package_files(struct razor_set *set, struct list *r,
586 struct razor_entry *dir, uint32_t end,
589 struct razor_entry *e, *f, *entries;
594 entries = (struct razor_entry *) set->files.data;
595 pool = set->file_string_pool.data;
597 e = entries + dir->start;
599 if (entries + r->data == e) {
600 printf("%s/%s\n", prefix, pool + e->name);
607 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
609 e = entries + dir->start;
614 if (e->flags & RAZOR_ENTRY_LAST)
618 while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
627 if (e->start <= file && file < next) {
628 len = strlen(prefix);
630 strcpy(prefix + len + 1, pool + e->name);
631 r = list_package_files(set, r, e, next, prefix);
634 } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
640 razor_set_list_package_files(struct razor_set *set,
641 struct razor_package *package)
647 assert (set != NULL);
648 assert (package != NULL);
650 r = list_first(&package->files, &set->file_pool);
651 end = set->files.size / sizeof (struct razor_entry);
653 list_package_files(set, r, set->files.data, end, buffer);
656 /* The diff order matters. We should sort the packages so that a
657 * REMOVE of a package comes before the INSTALL, and so that all
658 * requires for a package have been installed before the package.
662 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
663 razor_diff_callback_t callback, void *data)
665 struct razor_package_iterator *pi1, *pi2;
666 struct razor_package *p1, *p2;
667 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
670 assert (set != NULL);
671 assert (upstream != NULL);
673 pi1 = razor_package_iterator_create(set);
674 pi2 = razor_package_iterator_create(upstream);
676 razor_package_iterator_next(pi1, &p1,
677 RAZOR_DETAIL_NAME, &name1,
678 RAZOR_DETAIL_VERSION, &version1,
679 RAZOR_DETAIL_ARCH, &arch1,
681 razor_package_iterator_next(pi2, &p2,
682 RAZOR_DETAIL_NAME, &name2,
683 RAZOR_DETAIL_VERSION, &version2,
684 RAZOR_DETAIL_ARCH, &arch2,
689 res = strcmp(name1, name2);
691 res = razor_versioncmp(version1, version2);
696 if (p2 == NULL || res < 0)
697 callback(RAZOR_DIFF_ACTION_REMOVE,
698 p1, name1, version1, arch1, data);
699 else if (p1 == NULL || res > 0)
700 callback(RAZOR_DIFF_ACTION_ADD,
701 p2, name2, version2, arch2, data);
703 if (p1 != NULL && res <= 0)
704 razor_package_iterator_next(pi1, &p1,
705 RAZOR_DETAIL_NAME, &name1,
706 RAZOR_DETAIL_VERSION, &version1,
707 RAZOR_DETAIL_ARCH, &arch1,
709 if (p2 != NULL && res >= 0)
710 razor_package_iterator_next(pi2, &p2,
711 RAZOR_DETAIL_NAME, &name2,
712 RAZOR_DETAIL_VERSION, &version2,
713 RAZOR_DETAIL_ARCH, &arch2,
717 razor_package_iterator_destroy(pi1);
718 razor_package_iterator_destroy(pi2);
721 struct install_action {
722 enum razor_install_action action;
723 struct razor_package *package;
726 struct razor_install_iterator {
727 struct razor_set *set;
728 struct razor_set *next;
729 struct array actions;
730 struct install_action *a, *end;
734 add_action(enum razor_diff_action action,
735 struct razor_package *package,
741 struct razor_install_iterator *ii = data;
742 struct install_action *a;
744 a = array_add(&ii->actions, sizeof *a);
745 a->package = package;
748 case RAZOR_DIFF_ACTION_ADD:
749 a->action = RAZOR_INSTALL_ACTION_ADD;
751 case RAZOR_DIFF_ACTION_REMOVE:
752 a->action = RAZOR_INSTALL_ACTION_REMOVE;
757 RAZOR_EXPORT struct razor_install_iterator *
758 razor_set_create_install_iterator(struct razor_set *set,
759 struct razor_set *next)
761 struct razor_install_iterator *ii;
763 assert (set != NULL);
764 assert (next != NULL);
766 ii = zalloc(sizeof *ii);
770 razor_set_diff(set, next, add_action, ii);
772 ii->a = ii->actions.data;
773 ii->end = ii->actions.data + ii->actions.size;
775 /* FIXME: We need to figure out the right install order here,
776 * so the post and pre scripts can run. */
782 razor_install_iterator_next(struct razor_install_iterator *ii,
783 struct razor_set **set,
784 struct razor_package **package,
785 enum razor_install_action *action,
788 if (ii->a == ii->end)
791 switch (ii->a->action) {
792 case RAZOR_INSTALL_ACTION_ADD:
795 case RAZOR_INSTALL_ACTION_REMOVE:
800 *package = ii->a->package;
801 *action = ii->a->action;
809 razor_install_iterator_destroy(struct razor_install_iterator *ii)
811 array_release(&ii->actions);