Use strings to identify section types in the on-disk repo format.
Previously, a given razor file type had a fixed number of sections in a
fixed order, identified by an integer type. Now, sections are identified
by a named string (stored in a string pool after the section lists).
This will allow for razor files to contain arbitrary sections.
For bonus points, also drop the 4k section alignment and change the
magic byte string to "RZDB".
committer: Kristian H?gsberg <krh@redhat.com>
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);