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 razor_sections[] = {
53 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
54 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
55 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
56 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
57 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
60 struct razor_set_section razor_files_sections[] = {
61 { RAZOR_FILES, offsetof(struct razor_set, files) },
62 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
63 { RAZOR_FILE_STRING_POOL, offsetof(struct razor_set, file_string_pool) },
66 struct razor_set_section razor_details_sections[] = {
67 { RAZOR_DETAILS_STRING_POOL, offsetof(struct razor_set, details_string_pool) },
70 RAZOR_EXPORT struct razor_set *
71 razor_set_create(void)
73 struct razor_set *set;
74 struct razor_entry *e;
77 set = zalloc(sizeof *set);
79 e = array_add(&set->files, sizeof *e);
80 empty = array_add(&set->string_pool, 1);
83 e->flags = RAZOR_ENTRY_LAST;
85 list_set_empty(&e->packages);
90 RAZOR_EXPORT struct razor_set *
91 razor_set_open(const char *filename)
93 struct razor_set *set;
94 struct razor_set_section *s;
99 set = zalloc(sizeof *set);
100 fd = open(filename, O_RDONLY);
101 if (fstat(fd, &stat) < 0)
103 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
104 if (set->header == MAP_FAILED) {
109 for (s = set->header->sections; ~s->type; s++) {
110 if (s->type >= ARRAY_SIZE(razor_sections))
112 if (s->type != razor_sections[s->type].type)
114 array = (void *) set + razor_sections[s->type].offset;
115 array->data = (void *) set->header + s->offset;
116 array->size = s->size;
117 array->alloc = s->size;
125 razor_set_open_details(struct razor_set *set, const char *filename)
127 struct razor_set_section *s;
132 assert (set != NULL);
133 assert (filename != NULL);
135 fd = open(filename, O_RDONLY);
136 if (fstat(fd, &stat) < 0)
138 set->details_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
139 if (set->details_header == MAP_FAILED)
142 for (s = set->details_header->sections; ~s->type; s++) {
143 if (s->type >= ARRAY_SIZE(razor_details_sections))
145 if (s->type != razor_details_sections[s->type].type)
147 array = (void *) set + razor_details_sections[s->type].offset;
148 array->data = (void *) set->details_header + s->offset;
149 array->size = s->size;
150 array->alloc = s->size;
158 razor_set_open_files(struct razor_set *set, const char *filename)
160 struct razor_set_section *s;
165 assert (set != NULL);
166 assert (filename != NULL);
168 fd = open(filename, O_RDONLY);
169 if (fstat(fd, &stat) < 0)
171 set->files_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
172 if (set->files_header == MAP_FAILED)
175 for (s = set->files_header->sections; ~s->type; s++) {
176 if (s->type >= ARRAY_SIZE(razor_files_sections))
178 if (s->type != razor_files_sections[s->type].type)
180 array = (void *) set + razor_files_sections[s->type].offset;
181 array->data = (void *) set->files_header + s->offset;
182 array->size = s->size;
183 array->alloc = s->size;
191 razor_set_destroy(struct razor_set *set)
197 assert (set != NULL);
200 for (i = 0; set->header->sections[i].type; i++)
202 size = set->header->sections[i].type;
203 munmap(set->header, size);
205 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
206 a = (void *) set + razor_sections[i].offset;
211 if (set->details_header) {
212 for (i = 0; set->details_header->sections[i].type; i++)
214 size = set->details_header->sections[i].type;
215 munmap(set->details_header, size);
217 for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
218 a = (void *) set + razor_details_sections[i].offset;
223 if (set->files_header) {
224 for (i = 0; set->files_header->sections[i].type; i++)
226 size = set->files_header->sections[i].type;
227 munmap(set->files_header, size);
229 for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
230 a = (void *) set + razor_files_sections[i].offset;
239 razor_set_write_sections_to_fd(struct razor_set *set, int fd, int magic,
240 struct razor_set_section *sections,
244 struct razor_set_header *header = (struct razor_set_header *) data;
249 memset(data, 0, sizeof data);
250 header->magic = magic;
251 header->version = RAZOR_VERSION;
252 offset = sizeof data;
254 for (i = 0; i < array_size; i++) {
255 if (sections[i].type != i)
257 a = (void *) set + sections[i].offset;
258 header->sections[i].type = i;
259 header->sections[i].offset = offset;
260 header->sections[i].size = a->size;
261 offset += ALIGN(a->size, 4096);
264 header->sections[i].type = ~0;
265 header->sections[i].offset = 0;
266 header->sections[i].size = 0;
268 razor_write(fd, data, sizeof data);
269 memset(data, 0, sizeof data);
270 for (i = 0; i < array_size; i++) {
271 if (sections[i].type != i)
273 a = (void *) set + sections[i].offset;
274 razor_write(fd, a->data, a->size);
275 razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
282 razor_set_write_to_fd(struct razor_set *set, int fd,
283 enum razor_repo_file_type type)
286 case RAZOR_REPO_FILE_MAIN:
287 return razor_set_write_sections_to_fd(set, fd, RAZOR_MAGIC,
289 ARRAY_SIZE(razor_sections));
291 case RAZOR_REPO_FILE_DETAILS:
292 return razor_set_write_sections_to_fd(set, fd, RAZOR_DETAILS_MAGIC,
293 razor_details_sections,
294 ARRAY_SIZE(razor_details_sections));
295 case RAZOR_REPO_FILE_FILES:
296 return razor_set_write_sections_to_fd(set, fd, RAZOR_FILES_MAGIC,
297 razor_files_sections,
298 ARRAY_SIZE(razor_files_sections));
305 razor_set_write(struct razor_set *set, const char *filename,
306 enum razor_repo_file_type type)
310 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
314 status = razor_set_write_to_fd(set, fd, type);
324 razor_build_evr(char *evr_buf, int size, const char *epoch,
325 const char *version, const char *release)
329 if (!version || !*version) {
334 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
335 len = snprintf(evr_buf, size, "%s:", epoch);
339 len = snprintf(evr_buf, size, "%s", version);
342 if (release && *release)
343 snprintf(evr_buf, size, "-%s", release);
347 razor_versioncmp(const char *s1, const char *s2)
356 n1 = strtol(s1, (char **) &p1, 10);
357 n2 = strtol(s2, (char **) &p2, 10);
359 /* Epoch; if one but not the other has an epoch set, default
360 * the epoch-less version to 0. */
361 res = (*p1 == ':') - (*p2 == ':');
366 } else if (res > 0) {
379 if (isdigit(*p1) && isdigit(*p2))
380 return razor_versioncmp(p1, p2);
386 RAZOR_EXPORT struct razor_package *
387 razor_set_get_package(struct razor_set *set, const char *package)
389 struct razor_package_iterator *pi;
390 struct razor_package *p;
393 assert (set != NULL);
394 assert (package != NULL);
396 pi = razor_package_iterator_create(set);
397 while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_NAME, &name, 0)) {
398 if (strcmp(package, name) == 0)
401 razor_package_iterator_destroy(pi);
407 razor_package_get_details_type(struct razor_set *set,
408 struct razor_package *package,
409 enum razor_detail_type type)
414 case RAZOR_DETAIL_NAME:
415 pool = set->string_pool.data;
416 return &pool[package->name];
418 case RAZOR_DETAIL_VERSION:
419 pool = set->string_pool.data;
420 return &pool[package->version];
422 case RAZOR_DETAIL_ARCH:
423 pool = set->string_pool.data;
424 return &pool[package->arch];
426 case RAZOR_DETAIL_SUMMARY:
427 pool = set->details_string_pool.data;
428 return &pool[package->summary];
430 case RAZOR_DETAIL_DESCRIPTION:
431 pool = set->details_string_pool.data;
432 return &pool[package->description];
434 case RAZOR_DETAIL_URL:
435 pool = set->details_string_pool.data;
436 return &pool[package->url];
438 case RAZOR_DETAIL_LICENSE:
439 pool = set->details_string_pool.data;
440 return &pool[package->license];
443 fprintf(stderr, "type %u not found\n", type);
449 * razor_package_get_details_varg:
451 * @package: a %razor_package
452 * @args: a va_list of arguments to set
455 razor_package_get_details_varg(struct razor_set *set,
456 struct razor_package *package,
460 enum razor_detail_type type;
463 for (i = 0;; i += 2) {
464 type = va_arg(args, enum razor_detail_type);
467 data = va_arg(args, const char **);
468 *data = razor_package_get_details_type(set, package, type);
474 * razor_package_get_details:
476 * @package: a %razor_package
478 * Gets details about a package using a varg interface
479 * The vararg must be terminated with zero.
481 * Example: razor_package_get_details (set, package, RAZOR_DETAIL_URL, &url, 0);
484 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
488 assert (set != NULL);
489 assert (package != NULL);
491 va_start(args, NULL);
492 razor_package_get_details_varg (set, package, args);
496 RAZOR_EXPORT const char *
497 razor_property_relation_to_string(struct razor_property *p)
501 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
502 case RAZOR_PROPERTY_LESS:
505 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
508 case RAZOR_PROPERTY_EQUAL:
511 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
514 case RAZOR_PROPERTY_GREATER:
522 RAZOR_EXPORT const char *
523 razor_property_type_to_string(struct razor_property *p)
527 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
528 case RAZOR_PROPERTY_REQUIRES:
530 case RAZOR_PROPERTY_PROVIDES:
532 case RAZOR_PROPERTY_CONFLICTS:
534 case RAZOR_PROPERTY_OBSOLETES:
541 RAZOR_EXPORT struct razor_entry *
542 razor_set_find_entry(struct razor_set *set,
543 struct razor_entry *dir, const char *pattern)
545 struct razor_entry *e;
546 const char *n, *pool = set->file_string_pool.data;
549 assert (set != NULL);
550 assert (dir != NULL);
551 assert (pattern != NULL);
553 e = (struct razor_entry *) set->files.data + dir->start;
556 if (strcmp(pattern + 1, n) == 0)
559 if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
560 pattern[len + 1] == '/') {
561 return razor_set_find_entry(set, e, pattern + len + 1);
563 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
569 list_dir(struct razor_set *set, struct razor_entry *dir,
570 char *prefix, const char *pattern)
572 struct razor_entry *e;
573 const char *n, *pool = set->file_string_pool.data;
575 e = (struct razor_entry *) set->files.data + dir->start;
578 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
580 printf("%s/%s\n", prefix, n);
582 char *sub = prefix + strlen (prefix);
585 list_dir(set, e, prefix, pattern);
588 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
592 razor_set_list_files(struct razor_set *set, const char *pattern)
594 struct razor_entry *e;
595 char buffer[512], *p, *base;
597 assert (set != NULL);
599 if (pattern == NULL || !strcmp (pattern, "/")) {
601 list_dir(set, set->files.data, buffer, NULL);
605 strcpy(buffer, pattern);
606 e = razor_set_find_entry(set, set->files.data, buffer);
607 if (e && e->start > 0) {
610 p = strrchr(buffer, '/');
618 e = razor_set_find_entry(set, set->files.data, buffer);
619 if (e && e->start != 0)
620 list_dir(set, e, buffer, base);
624 list_package_files(struct razor_set *set, struct list *r,
625 struct razor_entry *dir, uint32_t end,
628 struct razor_entry *e, *f, *entries;
633 entries = (struct razor_entry *) set->files.data;
634 pool = set->file_string_pool.data;
636 e = entries + dir->start;
638 if (entries + r->data == e) {
639 printf("%s/%s\n", prefix, pool + e->name);
646 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
648 e = entries + dir->start;
653 if (e->flags & RAZOR_ENTRY_LAST)
657 while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
666 if (e->start <= file && file < next) {
667 len = strlen(prefix);
669 strcpy(prefix + len + 1, pool + e->name);
670 r = list_package_files(set, r, e, next, prefix);
673 } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
679 razor_set_list_package_files(struct razor_set *set, const char *name)
681 struct razor_package *package;
686 assert (set != NULL);
687 assert (name != NULL);
689 package = razor_set_get_package(set, name);
690 /* TODO: we should return the error to the caller */
694 r = list_first(&package->files, &set->file_pool);
695 end = set->files.size / sizeof (struct razor_entry);
697 list_package_files(set, r, set->files.data, end, buffer);
700 /* The diff order matters. We should sort the packages so that a
701 * REMOVE of a package comes before the INSTALL, and so that all
702 * requires for a package have been installed before the package.
706 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
707 razor_diff_callback_t callback, void *data)
709 struct razor_package_iterator *pi1, *pi2;
710 struct razor_package *p1, *p2;
711 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
714 assert (set != NULL);
715 assert (upstream != NULL);
717 pi1 = razor_package_iterator_create(set);
718 pi2 = razor_package_iterator_create(upstream);
720 razor_package_iterator_next(pi1, &p1,
721 RAZOR_DETAIL_NAME, &name1,
722 RAZOR_DETAIL_VERSION, &version1,
723 RAZOR_DETAIL_ARCH, &arch1,
725 razor_package_iterator_next(pi2, &p2,
726 RAZOR_DETAIL_NAME, &name2,
727 RAZOR_DETAIL_VERSION, &version2,
728 RAZOR_DETAIL_ARCH, &arch2,
733 res = strcmp(name1, name2);
735 res = razor_versioncmp(version1, version2);
740 if (p2 == NULL || res < 0)
741 callback(RAZOR_DIFF_ACTION_REMOVE,
742 p1, name1, version1, arch1, data);
743 else if (p1 == NULL || res > 0)
744 callback(RAZOR_DIFF_ACTION_ADD,
745 p2, name2, version2, arch2, data);
747 if (p1 != NULL && res <= 0)
748 razor_package_iterator_next(pi1, &p1,
749 RAZOR_DETAIL_NAME, &name1,
750 RAZOR_DETAIL_VERSION, &version1,
751 RAZOR_DETAIL_ARCH, &arch1,
753 if (p2 != NULL && res >= 0)
754 razor_package_iterator_next(pi2, &p2,
755 RAZOR_DETAIL_NAME, &name2,
756 RAZOR_DETAIL_VERSION, &version2,
757 RAZOR_DETAIL_ARCH, &arch2,
761 razor_package_iterator_destroy(pi1);
762 razor_package_iterator_destroy(pi2);
766 add_new_package(enum razor_diff_action action,
767 struct razor_package *package,
773 if (action == RAZOR_DIFF_ACTION_ADD)
774 razor_package_query_add_package(data, package);
777 RAZOR_EXPORT struct razor_package_iterator *
778 razor_set_create_remove_iterator(struct razor_set *set,
779 struct razor_set *next)
781 struct razor_package_query *query;
782 struct razor_package_iterator *pi;
784 assert (set != NULL);
785 assert (next != NULL);
787 query = razor_package_query_create(set);
788 razor_set_diff(next, set, add_new_package, query);
790 pi = razor_package_query_finish(query);
792 /* FIXME: We need to figure out the right install order here,
793 * so the post and pre scripts can run. */
800 RAZOR_EXPORT struct razor_package_iterator *
801 razor_set_create_install_iterator(struct razor_set *set,
802 struct razor_set *next)
804 struct razor_package_query *query;
805 struct razor_package_iterator *pi;
807 assert (set != NULL);
808 assert (next != NULL);
810 query = razor_package_query_create(next);
811 razor_set_diff(set, next, add_new_package, query);
813 pi = razor_package_query_finish(query);
815 /* FIXME: We need to figure out the right install order here,
816 * so the post and pre scripts can run. */