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.
27 #include <sys/types.h>
37 #include "razor-internal.h"
51 struct razor_set_section razor_sections[] = {
52 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
53 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
54 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
55 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
56 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
59 struct razor_set_section razor_files_sections[] = {
60 { RAZOR_FILES, offsetof(struct razor_set, files) },
61 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
62 { RAZOR_FILE_STRING_POOL, offsetof(struct razor_set, file_string_pool) },
65 struct razor_set_section razor_details_sections[] = {
66 { RAZOR_DETAILS_STRING_POOL, offsetof(struct razor_set, details_string_pool) },
69 RAZOR_EXPORT struct razor_set *
70 razor_set_create(void)
72 struct razor_set *set;
73 struct razor_entry *e;
76 set = zalloc(sizeof *set);
78 e = array_add(&set->files, sizeof *e);
79 empty = array_add(&set->string_pool, 1);
82 e->flags = RAZOR_ENTRY_LAST;
84 list_set_empty(&e->packages);
89 RAZOR_EXPORT struct razor_set *
90 razor_set_open(const char *filename)
92 struct razor_set *set;
93 struct razor_set_section *s;
98 set = zalloc(sizeof *set);
99 fd = open(filename, O_RDONLY);
100 if (fstat(fd, &stat) < 0)
102 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
103 if (set->header == MAP_FAILED) {
108 for (s = set->header->sections; ~s->type; s++) {
109 if (s->type >= ARRAY_SIZE(razor_sections))
111 if (s->type != razor_sections[s->type].type)
113 array = (void *) set + razor_sections[s->type].offset;
114 array->data = (void *) set->header + s->offset;
115 array->size = s->size;
116 array->alloc = s->size;
124 razor_set_open_details(struct razor_set *set, const char *filename)
126 struct razor_set_section *s;
131 assert (set != NULL);
132 assert (filename != NULL);
134 fd = open(filename, O_RDONLY);
135 if (fstat(fd, &stat) < 0)
137 set->details_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
138 if (set->details_header == MAP_FAILED)
141 for (s = set->details_header->sections; ~s->type; s++) {
142 if (s->type >= ARRAY_SIZE(razor_details_sections))
144 if (s->type != razor_details_sections[s->type].type)
146 array = (void *) set + razor_details_sections[s->type].offset;
147 array->data = (void *) set->details_header + s->offset;
148 array->size = s->size;
149 array->alloc = s->size;
157 razor_set_open_files(struct razor_set *set, const char *filename)
159 struct razor_set_section *s;
164 assert (set != NULL);
165 assert (filename != NULL);
167 fd = open(filename, O_RDONLY);
168 if (fstat(fd, &stat) < 0)
170 set->files_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
171 if (set->files_header == MAP_FAILED)
174 for (s = set->files_header->sections; ~s->type; s++) {
175 if (s->type >= ARRAY_SIZE(razor_files_sections))
177 if (s->type != razor_files_sections[s->type].type)
179 array = (void *) set + razor_files_sections[s->type].offset;
180 array->data = (void *) set->files_header + s->offset;
181 array->size = s->size;
182 array->alloc = s->size;
190 razor_set_destroy(struct razor_set *set)
196 assert (set != NULL);
199 for (i = 0; set->header->sections[i].type; i++)
201 size = set->header->sections[i].type;
202 munmap(set->header, size);
204 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
205 a = (void *) set + razor_sections[i].offset;
210 if (set->details_header) {
211 for (i = 0; set->details_header->sections[i].type; i++)
213 size = set->details_header->sections[i].type;
214 munmap(set->details_header, size);
216 for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
217 a = (void *) set + razor_details_sections[i].offset;
222 if (set->files_header) {
223 for (i = 0; set->files_header->sections[i].type; i++)
225 size = set->files_header->sections[i].type;
226 munmap(set->files_header, size);
228 for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
229 a = (void *) set + razor_files_sections[i].offset;
238 razor_set_write_sections_to_fd(struct razor_set *set, int fd, int magic,
239 struct razor_set_section *sections,
243 struct razor_set_header *header = (struct razor_set_header *) data;
248 memset(data, 0, sizeof data);
249 header->magic = magic;
250 header->version = RAZOR_VERSION;
251 offset = sizeof data;
253 for (i = 0; i < array_size; i++) {
254 if (sections[i].type != i)
256 a = (void *) set + sections[i].offset;
257 header->sections[i].type = i;
258 header->sections[i].offset = offset;
259 header->sections[i].size = a->size;
260 offset += ALIGN(a->size, 4096);
263 header->sections[i].type = ~0;
264 header->sections[i].offset = 0;
265 header->sections[i].size = 0;
267 razor_write(fd, data, sizeof data);
268 memset(data, 0, sizeof data);
269 for (i = 0; i < array_size; i++) {
270 if (sections[i].type != i)
272 a = (void *) set + sections[i].offset;
273 razor_write(fd, a->data, a->size);
274 razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
281 razor_set_write_to_fd(struct razor_set *set, int fd,
282 enum razor_repo_file_type type)
285 case RAZOR_REPO_FILE_MAIN:
286 return razor_set_write_sections_to_fd(set, fd, RAZOR_MAGIC,
288 ARRAY_SIZE(razor_sections));
290 case RAZOR_REPO_FILE_DETAILS:
291 return razor_set_write_sections_to_fd(set, fd, RAZOR_DETAILS_MAGIC,
292 razor_details_sections,
293 ARRAY_SIZE(razor_details_sections));
294 case RAZOR_REPO_FILE_FILES:
295 return razor_set_write_sections_to_fd(set, fd, RAZOR_FILES_MAGIC,
296 razor_files_sections,
297 ARRAY_SIZE(razor_files_sections));
304 razor_set_write(struct razor_set *set, const char *filename,
305 enum razor_repo_file_type type)
309 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
313 status = razor_set_write_to_fd(set, fd, type);
323 razor_build_evr(char *evr_buf, int size, const char *epoch,
324 const char *version, const char *release)
328 if (!version || !*version) {
333 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
334 len = snprintf(evr_buf, size, "%s:", epoch);
338 len = snprintf(evr_buf, size, "%s", version);
341 if (release && *release)
342 snprintf(evr_buf, size, "-%s", release);
346 razor_versioncmp(const char *s1, const char *s2)
355 n1 = strtol(s1, (char **) &p1, 10);
356 n2 = strtol(s2, (char **) &p2, 10);
358 /* Epoch; if one but not the other has an epoch set, default
359 * the epoch-less version to 0. */
360 res = (*p1 == ':') - (*p2 == ':');
365 } else if (res > 0) {
378 if (isdigit(*p1) && isdigit(*p2))
379 return razor_versioncmp(p1, p2);
385 RAZOR_EXPORT struct razor_package *
386 razor_set_get_package(struct razor_set *set, const char *package)
388 struct razor_package_iterator *pi;
389 struct razor_package *p;
390 const char *name, *version, *arch;
392 assert (set != NULL);
393 assert (package != NULL);
395 pi = razor_package_iterator_create(set);
396 while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
397 if (strcmp(package, name) == 0)
400 razor_package_iterator_destroy(pi);
406 razor_package_get_details(struct razor_set *set,
407 struct razor_package *package,
408 const char **summary, const char **description,
409 const char **url, const char **license)
411 const char *pool = set->details_string_pool.data;
413 assert (set != NULL);
414 assert (package != NULL);
417 *summary = &pool[package->summary];
418 if (description != NULL)
419 *description = &pool[package->description];
421 *url = &pool[package->url];
423 *license = &pool[package->license];
426 RAZOR_EXPORT const char *
427 razor_property_relation_to_string(struct razor_property *p)
431 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
432 case RAZOR_PROPERTY_LESS:
435 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
438 case RAZOR_PROPERTY_EQUAL:
441 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
444 case RAZOR_PROPERTY_GREATER:
452 RAZOR_EXPORT const char *
453 razor_property_type_to_string(struct razor_property *p)
457 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
458 case RAZOR_PROPERTY_REQUIRES:
460 case RAZOR_PROPERTY_PROVIDES:
462 case RAZOR_PROPERTY_CONFLICTS:
464 case RAZOR_PROPERTY_OBSOLETES:
471 RAZOR_EXPORT struct razor_entry *
472 razor_set_find_entry(struct razor_set *set,
473 struct razor_entry *dir, const char *pattern)
475 struct razor_entry *e;
476 const char *n, *pool = set->file_string_pool.data;
479 assert (set != NULL);
480 assert (dir != NULL);
481 assert (pattern != NULL);
483 e = (struct razor_entry *) set->files.data + dir->start;
486 if (strcmp(pattern + 1, n) == 0)
489 if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
490 pattern[len + 1] == '/') {
491 return razor_set_find_entry(set, e, pattern + len + 1);
493 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
499 list_dir(struct razor_set *set, struct razor_entry *dir,
500 char *prefix, const char *pattern)
502 struct razor_entry *e;
503 const char *n, *pool = set->file_string_pool.data;
505 e = (struct razor_entry *) set->files.data + dir->start;
508 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
510 printf("%s/%s\n", prefix, n);
512 char *sub = prefix + strlen (prefix);
515 list_dir(set, e, prefix, pattern);
518 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
522 razor_set_list_files(struct razor_set *set, const char *pattern)
524 struct razor_entry *e;
525 char buffer[512], *p, *base;
527 assert (set != NULL);
529 if (pattern == NULL || !strcmp (pattern, "/")) {
531 list_dir(set, set->files.data, buffer, NULL);
535 strcpy(buffer, pattern);
536 e = razor_set_find_entry(set, set->files.data, buffer);
537 if (e && e->start > 0) {
540 p = strrchr(buffer, '/');
548 e = razor_set_find_entry(set, set->files.data, buffer);
549 if (e && e->start != 0)
550 list_dir(set, e, buffer, base);
554 list_package_files(struct razor_set *set, struct list *r,
555 struct razor_entry *dir, uint32_t end,
558 struct razor_entry *e, *f, *entries;
563 entries = (struct razor_entry *) set->files.data;
564 pool = set->file_string_pool.data;
566 e = entries + dir->start;
568 if (entries + r->data == e) {
569 printf("%s/%s\n", prefix, pool + e->name);
576 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
578 e = entries + dir->start;
583 if (e->flags & RAZOR_ENTRY_LAST)
587 while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
596 if (e->start <= file && file < next) {
597 len = strlen(prefix);
599 strcpy(prefix + len + 1, pool + e->name);
600 r = list_package_files(set, r, e, next, prefix);
603 } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
609 razor_set_list_package_files(struct razor_set *set, const char *name)
611 struct razor_package *package;
616 assert (set != NULL);
617 assert (name != NULL);
619 package = razor_set_get_package(set, name);
620 /* TODO: we should return the error to the caller */
624 r = list_first(&package->files, &set->file_pool);
625 end = set->files.size / sizeof (struct razor_entry);
627 list_package_files(set, r, set->files.data, end, buffer);
630 /* The diff order matters. We should sort the packages so that a
631 * REMOVE of a package comes before the INSTALL, and so that all
632 * requires for a package have been installed before the package.
636 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
637 razor_diff_callback_t callback, void *data)
639 struct razor_package_iterator *pi1, *pi2;
640 struct razor_package *p1, *p2;
641 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
644 assert (set != NULL);
645 assert (upstream != NULL);
647 pi1 = razor_package_iterator_create(set);
648 pi2 = razor_package_iterator_create(upstream);
650 razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
651 razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
655 res = strcmp(name1, name2);
657 res = razor_versioncmp(version1, version2);
662 if (p2 == NULL || res < 0)
663 callback(RAZOR_DIFF_ACTION_REMOVE,
664 p1, name1, version1, arch1, data);
665 else if (p1 == NULL || res > 0)
666 callback(RAZOR_DIFF_ACTION_ADD,
667 p2, name2, version2, arch2, data);
669 if (p1 != NULL && res <= 0)
670 razor_package_iterator_next(pi1, &p1,
671 &name1, &version1, &arch1);
672 if (p2 != NULL && res >= 0)
673 razor_package_iterator_next(pi2, &p2,
674 &name2, &version2, &arch2);
677 razor_package_iterator_destroy(pi1);
678 razor_package_iterator_destroy(pi2);
682 add_new_package(enum razor_diff_action action,
683 struct razor_package *package,
689 if (action == RAZOR_DIFF_ACTION_ADD)
690 razor_package_query_add_package(data, package);
693 RAZOR_EXPORT struct razor_package_iterator *
694 razor_set_create_remove_iterator(struct razor_set *set,
695 struct razor_set *next)
697 struct razor_package_query *query;
698 struct razor_package_iterator *pi;
700 assert (set != NULL);
701 assert (next != NULL);
703 query = razor_package_query_create(set);
704 razor_set_diff(next, set, add_new_package, query);
706 pi = razor_package_query_finish(query);
708 /* FIXME: We need to figure out the right install order here,
709 * so the post and pre scripts can run. */
716 RAZOR_EXPORT struct razor_package_iterator *
717 razor_set_create_install_iterator(struct razor_set *set,
718 struct razor_set *next)
720 struct razor_package_query *query;
721 struct razor_package_iterator *pi;
723 assert (set != NULL);
724 assert (next != NULL);
726 query = razor_package_query_create(next);
727 razor_set_diff(set, next, add_new_package, query);
729 pi = razor_package_query_finish(query);
731 /* FIXME: We need to figure out the right install order here,
732 * so the post and pre scripts can run. */