rhughes@241: /* rhughes@241: * Copyright (C) 2008 Kristian Høgsberg rhughes@241: * Copyright (C) 2008 Red Hat, Inc rhughes@241: * rhughes@241: * This program is free software; you can redistribute it and/or modify rhughes@241: * it under the terms of the GNU General Public License as published by rhughes@241: * the Free Software Foundation; either version 2 of the License, or rhughes@241: * (at your option) any later version. rhughes@241: * rhughes@241: * This program is distributed in the hope that it will be useful, rhughes@241: * but WITHOUT ANY WARRANTY; without even the implied warranty of rhughes@241: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the rhughes@241: * GNU General Public License for more details. rhughes@241: * rhughes@241: * You should have received a copy of the GNU General Public License along rhughes@241: * with this program; if not, write to the Free Software Foundation, Inc., rhughes@241: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. rhughes@241: */ rhughes@241: rhughes@241: #define _GNU_SOURCE rhughes@241: rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include richard@302: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include richard@301: #include rhughes@241: krh@253: #include "razor-internal.h" rhughes@241: #include "razor.h" rhughes@241: krh@248: void * rhughes@241: zalloc(size_t size) rhughes@241: { rhughes@241: void *p; rhughes@241: rhughes@241: p = malloc(size); rhughes@241: memset(p, 0, size); rhughes@241: rhughes@241: return p; rhughes@241: } rhughes@241: jbowes@318: struct razor_set_section_index { jbowes@318: const char *name; jbowes@318: uint32_t offset; jbowes@318: }; jbowes@318: jbowes@318: struct razor_set_section_index razor_sections[] = { rhughes@241: { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) }, rhughes@241: { RAZOR_PACKAGES, offsetof(struct razor_set, packages) }, rhughes@241: { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) }, rhughes@241: { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) }, rhughes@241: { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) }, rhughes@241: }; rhughes@241: jbowes@318: struct razor_set_section_index razor_files_sections[] = { jbowes@258: { RAZOR_FILES, offsetof(struct razor_set, files) }, jbowes@258: { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) }, jbowes@258: { RAZOR_FILE_STRING_POOL, offsetof(struct razor_set, file_string_pool) }, jbowes@258: }; jbowes@258: jbowes@318: struct razor_set_section_index razor_details_sections[] = { jbowes@258: { RAZOR_DETAILS_STRING_POOL, offsetof(struct razor_set, details_string_pool) }, jbowes@258: }; krh@262: krh@269: RAZOR_EXPORT struct razor_set * rhughes@241: razor_set_create(void) rhughes@241: { rhughes@241: struct razor_set *set; rhughes@241: struct razor_entry *e; rhughes@241: char *empty; rhughes@241: rhughes@241: set = zalloc(sizeof *set); rhughes@241: rhughes@241: e = array_add(&set->files, sizeof *e); rhughes@241: empty = array_add(&set->string_pool, 1); rhughes@241: *empty = '\0'; rhughes@241: e->name = 0; rhughes@241: e->flags = RAZOR_ENTRY_LAST; rhughes@241: e->start = 0; rhughes@241: list_set_empty(&e->packages); rhughes@241: rhughes@241: return set; rhughes@241: } rhughes@241: jbowes@318: static int jbowes@318: razor_set_bind_sections(struct razor_set *set, jbowes@318: struct razor_set_header **header, jbowes@318: size_t *header_size, jbowes@318: struct razor_set_section_index section_index[], jbowes@318: int section_index_size, jbowes@318: const char *filename) rhughes@241: { jbowes@318: struct razor_set_section *s, *sections; rhughes@241: struct array *array; jbowes@318: const char *pool; ali@322: int i; richard@301: ali@322: *header = razor_file_get_contents(filename, header_size); ali@322: if (!*header) jbowes@288: return -1; jbowes@258: jbowes@318: sections = (void *) *header + sizeof **header; jbowes@318: pool = (void *) sections + (*header)->num_sections * sizeof *sections; jbowes@318: jbowes@318: for (i = 0; i < (*header)->num_sections; i++) { jbowes@318: int j; jbowes@318: s = sections + i; jbowes@318: for (j = 0; j < section_index_size; j++) jbowes@318: if (!strcmp(section_index[j].name, jbowes@318: &pool[s->name])) jbowes@318: break; jbowes@318: if (j == section_index_size) jbowes@258: continue; jbowes@318: array = (void *) set + section_index[j].offset; jbowes@318: array->data = (void *) *header + s->offset; jbowes@258: array->size = s->size; jbowes@258: array->alloc = s->size; jbowes@258: } jbowes@288: jbowes@288: return 0; jbowes@258: } jbowes@258: jbowes@318: RAZOR_EXPORT struct razor_set * jbowes@318: razor_set_open(const char *filename) jbowes@318: { jbowes@318: struct razor_set *set; jbowes@318: jbowes@318: set = zalloc(sizeof *set); jbowes@318: if (razor_set_bind_sections(set, &set->header, &set->header_size, jbowes@318: razor_sections, ARRAY_SIZE(razor_sections), jbowes@318: filename)){ jbowes@318: free(set); jbowes@318: return NULL; jbowes@318: } jbowes@318: return set; jbowes@318: } jbowes@318: jbowes@318: RAZOR_EXPORT int jbowes@318: razor_set_open_details(struct razor_set *set, const char *filename) jbowes@318: { jbowes@318: return razor_set_bind_sections(set, &set->details_header, jbowes@318: &set->details_header_size, jbowes@318: razor_details_sections, jbowes@318: ARRAY_SIZE(razor_details_sections), jbowes@318: filename); jbowes@318: } jbowes@318: jbowes@288: RAZOR_EXPORT int jbowes@258: razor_set_open_files(struct razor_set *set, const char *filename) jbowes@258: { jbowes@318: return razor_set_bind_sections(set, &set->files_header, jbowes@318: &set->files_header_size, jbowes@318: razor_files_sections, jbowes@318: ARRAY_SIZE(razor_files_sections), jbowes@318: filename); jbowes@258: } jbowes@258: krh@269: RAZOR_EXPORT void rhughes@241: razor_set_destroy(struct razor_set *set) rhughes@241: { rhughes@241: struct array *a; rhughes@241: int i; rhughes@241: richard@301: assert (set != NULL); richard@301: rhughes@241: if (set->header) { ali@322: razor_file_free_contents(set->header, set->header_size); rhughes@241: } else { rhughes@241: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { rhughes@241: a = (void *) set + razor_sections[i].offset; rhughes@241: free(a->data); rhughes@241: } rhughes@241: } rhughes@241: jbowes@258: if (set->details_header) { ali@322: razor_file_free_contents(set->details_header, ali@322: set->details_header_size); jbowes@258: } else { jbowes@258: for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) { jbowes@258: a = (void *) set + razor_details_sections[i].offset; jbowes@258: free(a->data); jbowes@258: } jbowes@258: } jbowes@258: jbowes@258: if (set->files_header) { ali@322: razor_file_free_contents(set->files_header, ali@322: set->files_header_size); jbowes@258: } else { jbowes@258: for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) { jbowes@258: a = (void *) set + razor_files_sections[i].offset; jbowes@258: free(a->data); jbowes@258: } jbowes@258: } jbowes@258: rhughes@241: free(set); rhughes@241: } rhughes@241: jbowes@258: static int jbowes@318: razor_set_write_sections_to_fd(struct razor_set *set, int fd, jbowes@318: struct razor_set_section_index *sections, jbowes@258: size_t array_size) rhughes@241: { jbowes@318: struct razor_set_header header; jbowes@318: struct razor_set_section *out_sections = jbowes@318: malloc(array_size * sizeof *out_sections); jbowes@318: struct hashtable table; jbowes@318: struct array *a, pool; rhughes@241: uint32_t offset; rhughes@241: int i; rhughes@241: jbowes@318: header.magic = RAZOR_MAGIC; jbowes@318: header.version = RAZOR_VERSION; jbowes@318: header.num_sections = array_size; jbowes@318: offset = sizeof header + array_size * sizeof *out_sections; jbowes@318: jbowes@318: array_init(&pool); jbowes@318: hashtable_init(&table, &pool); jbowes@318: jbowes@318: for (i = 0; i < array_size; i++) jbowes@318: out_sections[i].name = jbowes@318: hashtable_tokenize(&table, sections[i].name); jbowes@318: jbowes@318: offset += pool.size; rhughes@241: jbowes@258: for (i = 0; i < array_size; i++) { jbowes@258: a = (void *) set + sections[i].offset; jbowes@318: out_sections[i].offset = offset; jbowes@318: out_sections[i].size = a->size; jbowes@318: offset += a->size; rhughes@241: } rhughes@241: jbowes@318: razor_write(fd, &header, sizeof header); jbowes@318: razor_write(fd, out_sections, array_size * sizeof *out_sections); jbowes@318: razor_write(fd, pool.data, pool.size); rhughes@241: jbowes@258: for (i = 0; i < array_size; i++) { jbowes@258: a = (void *) set + sections[i].offset; rhughes@241: razor_write(fd, a->data, a->size); rhughes@241: } rhughes@241: jbowes@318: free(out_sections); jbowes@318: rhughes@241: return 0; rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT int jbowes@258: razor_set_write_to_fd(struct razor_set *set, int fd, jbowes@258: enum razor_repo_file_type type) jbowes@258: { jbowes@258: switch (type) { jbowes@258: case RAZOR_REPO_FILE_MAIN: jbowes@318: return razor_set_write_sections_to_fd(set, fd, jbowes@258: razor_sections, jbowes@258: ARRAY_SIZE(razor_sections)); jbowes@258: jbowes@258: case RAZOR_REPO_FILE_DETAILS: jbowes@318: return razor_set_write_sections_to_fd(set, fd, jbowes@258: razor_details_sections, jbowes@258: ARRAY_SIZE(razor_details_sections)); jbowes@258: case RAZOR_REPO_FILE_FILES: jbowes@318: return razor_set_write_sections_to_fd(set, fd, jbowes@258: razor_files_sections, jbowes@258: ARRAY_SIZE(razor_files_sections)); jbowes@258: default: jbowes@258: return -1; jbowes@258: } jbowes@258: } jbowes@258: krh@269: RAZOR_EXPORT int jbowes@258: razor_set_write(struct razor_set *set, const char *filename, jbowes@258: enum razor_repo_file_type type) rhughes@241: { rhughes@241: int fd, status; rhughes@241: rhughes@241: fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); rhughes@241: if (fd < 0) rhughes@241: return -1; rhughes@241: jbowes@258: status = razor_set_write_to_fd(set, fd, type); rhughes@241: if (status) { rhughes@241: close(fd); rhughes@241: return status; rhughes@241: } rhughes@241: rhughes@241: return close(fd); rhughes@241: } krh@269: krh@269: RAZOR_EXPORT void rhughes@241: razor_build_evr(char *evr_buf, int size, const char *epoch, rhughes@241: const char *version, const char *release) rhughes@241: { rhughes@241: int len; rhughes@241: rhughes@241: if (!version || !*version) { rhughes@241: *evr_buf = '\0'; rhughes@241: return; rhughes@241: } rhughes@241: rhughes@241: if (epoch && *epoch && strcmp(epoch, "0") != 0) { rhughes@241: len = snprintf(evr_buf, size, "%s:", epoch); rhughes@241: evr_buf += len; rhughes@241: size -= len; rhughes@241: } rhughes@241: len = snprintf(evr_buf, size, "%s", version); rhughes@241: evr_buf += len; rhughes@241: size -= len; rhughes@241: if (release && *release) rhughes@241: snprintf(evr_buf, size, "-%s", release); rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT int krh@248: razor_versioncmp(const char *s1, const char *s2) rhughes@241: { rhughes@241: const char *p1, *p2; rhughes@241: long n1, n2; rhughes@241: int res; rhughes@241: richard@301: assert (s1 != NULL); richard@301: assert (s2 != NULL); richard@301: rhughes@241: n1 = strtol(s1, (char **) &p1, 10); rhughes@241: n2 = strtol(s2, (char **) &p2, 10); rhughes@241: rhughes@241: /* Epoch; if one but not the other has an epoch set, default rhughes@241: * the epoch-less version to 0. */ rhughes@241: res = (*p1 == ':') - (*p2 == ':'); rhughes@241: if (res < 0) { rhughes@241: n1 = 0; rhughes@241: p1 = s1; rhughes@241: p2++; rhughes@241: } else if (res > 0) { rhughes@241: p1++; rhughes@241: n2 = 0; rhughes@241: p2 = s2; rhughes@241: } rhughes@241: rhughes@241: if (n1 != n2) rhughes@241: return n1 - n2; rhughes@241: while (*p1 && *p2) { rhughes@241: if (*p1 != *p2) rhughes@241: return *p1 - *p2; rhughes@241: p1++; rhughes@241: p2++; rhughes@241: if (isdigit(*p1) && isdigit(*p2)) krh@248: return razor_versioncmp(p1, p2); rhughes@241: } rhughes@241: rhughes@241: return *p1 - *p2; rhughes@241: } rhughes@241: richard@302: static const char * richard@302: razor_package_get_details_type(struct razor_set *set, richard@302: struct razor_package *package, richard@302: enum razor_detail_type type) richard@302: { richard@302: const char *pool; richard@302: richard@302: switch (type) { richard@302: case RAZOR_DETAIL_NAME: richard@302: pool = set->string_pool.data; richard@302: return &pool[package->name]; richard@302: richard@302: case RAZOR_DETAIL_VERSION: richard@302: pool = set->string_pool.data; richard@302: return &pool[package->version]; richard@302: richard@302: case RAZOR_DETAIL_ARCH: richard@302: pool = set->string_pool.data; richard@302: return &pool[package->arch]; richard@302: richard@302: case RAZOR_DETAIL_SUMMARY: richard@302: pool = set->details_string_pool.data; richard@302: return &pool[package->summary]; richard@302: richard@302: case RAZOR_DETAIL_DESCRIPTION: richard@302: pool = set->details_string_pool.data; richard@302: return &pool[package->description]; richard@302: richard@302: case RAZOR_DETAIL_URL: richard@302: pool = set->details_string_pool.data; richard@302: return &pool[package->url]; richard@302: richard@302: case RAZOR_DETAIL_LICENSE: richard@302: pool = set->details_string_pool.data; richard@302: return &pool[package->license]; richard@302: richard@302: default: richard@302: fprintf(stderr, "type %u not found\n", type); richard@302: return NULL; richard@302: } richard@302: } richard@302: richard@302: /** richard@302: * razor_package_get_details_varg: richard@302: * @set: a %razor_set richard@302: * @package: a %razor_package richard@302: * @args: a va_list of arguments to set richard@302: **/ richard@302: void richard@302: razor_package_get_details_varg(struct razor_set *set, richard@302: struct razor_package *package, richard@302: va_list args) richard@302: { richard@302: int i; richard@302: enum razor_detail_type type; richard@302: const char **data; richard@302: richard@302: for (i = 0;; i += 2) { richard@302: type = va_arg(args, enum razor_detail_type); richard@307: if (type == RAZOR_DETAIL_LAST) richard@302: break; richard@302: data = va_arg(args, const char **); richard@302: *data = razor_package_get_details_type(set, package, type); richard@302: } richard@302: richard@302: } richard@302: richard@302: /** richard@302: * razor_package_get_details: richard@302: * @set: a %razor_set richard@302: * @package: a %razor_package richard@302: * richard@302: * Gets details about a package using a varg interface krh@308: * The vararg must be terminated with %RAZOR_DETAIL_LAST. richard@302: * richard@307: * Example: razor_package_get_details (set, package, richard@307: * RAZOR_DETAIL_URL, &url, richard@307: * RAZOR_DETAIL_LAST); richard@302: **/ krh@269: RAZOR_EXPORT void richard@302: razor_package_get_details(struct razor_set *set, struct razor_package *package, ...) jbowes@258: { richard@302: va_list args; jbowes@258: richard@301: assert (set != NULL); richard@301: assert (package != NULL); richard@301: richard@302: va_start(args, NULL); richard@302: razor_package_get_details_varg (set, package, args); richard@302: va_end (args); jbowes@258: } jbowes@258: krh@270: RAZOR_EXPORT const char * krh@270: razor_property_relation_to_string(struct razor_property *p) krh@270: { richard@301: assert (p != NULL); richard@301: krh@270: switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) { krh@270: case RAZOR_PROPERTY_LESS: krh@270: return "<"; krh@270: krh@270: case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL: krh@270: return "<="; krh@270: krh@270: case RAZOR_PROPERTY_EQUAL: krh@270: return "="; krh@270: krh@270: case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL: krh@270: return ">="; krh@270: krh@270: case RAZOR_PROPERTY_GREATER: krh@270: return ">"; krh@270: krh@270: default: krh@270: return "?"; krh@270: } krh@270: } krh@270: krh@270: RAZOR_EXPORT const char * krh@270: razor_property_type_to_string(struct razor_property *p) krh@270: { richard@301: assert (p != NULL); richard@301: krh@270: switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) { krh@270: case RAZOR_PROPERTY_REQUIRES: krh@270: return "requires"; krh@270: case RAZOR_PROPERTY_PROVIDES: krh@270: return "provides"; krh@270: case RAZOR_PROPERTY_CONFLICTS: krh@270: return "conflicts"; krh@270: case RAZOR_PROPERTY_OBSOLETES: krh@270: return "obsoletes"; krh@270: default: krh@270: return NULL; krh@270: } krh@270: } krh@270: krh@269: RAZOR_EXPORT struct razor_entry * krh@248: razor_set_find_entry(struct razor_set *set, krh@248: struct razor_entry *dir, const char *pattern) rhughes@241: { rhughes@241: struct razor_entry *e; jbowes@264: const char *n, *pool = set->file_string_pool.data; rhughes@241: int len; rhughes@241: richard@301: assert (set != NULL); richard@301: assert (dir != NULL); richard@301: assert (pattern != NULL); richard@301: rhughes@241: e = (struct razor_entry *) set->files.data + dir->start; rhughes@241: do { rhughes@241: n = pool + e->name; rhughes@241: if (strcmp(pattern + 1, n) == 0) rhughes@241: return e; rhughes@241: len = strlen(n); rhughes@241: if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 && rhughes@241: pattern[len + 1] == '/') { krh@248: return razor_set_find_entry(set, e, pattern + len + 1); rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); rhughes@241: rhughes@241: return NULL; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: list_dir(struct razor_set *set, struct razor_entry *dir, rhughes@241: char *prefix, const char *pattern) rhughes@241: { rhughes@241: struct razor_entry *e; jbowes@274: const char *n, *pool = set->file_string_pool.data; rhughes@241: rhughes@241: e = (struct razor_entry *) set->files.data + dir->start; rhughes@241: do { rhughes@241: n = pool + e->name; rhughes@241: if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0) rhughes@241: continue; rhughes@241: printf("%s/%s\n", prefix, n); rhughes@241: if (e->start) { rhughes@241: char *sub = prefix + strlen (prefix); rhughes@241: *sub = '/'; rhughes@241: strcpy (sub + 1, n); rhughes@241: list_dir(set, e, prefix, pattern); rhughes@241: *sub = '\0'; rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT void rhughes@241: razor_set_list_files(struct razor_set *set, const char *pattern) rhughes@241: { rhughes@241: struct razor_entry *e; rhughes@241: char buffer[512], *p, *base; rhughes@241: richard@301: assert (set != NULL); richard@301: rhughes@241: if (pattern == NULL || !strcmp (pattern, "/")) { rhughes@241: buffer[0] = '\0'; rhughes@241: list_dir(set, set->files.data, buffer, NULL); rhughes@241: return; rhughes@241: } rhughes@241: rhughes@241: strcpy(buffer, pattern); krh@248: e = razor_set_find_entry(set, set->files.data, buffer); rhughes@241: if (e && e->start > 0) { rhughes@241: base = NULL; rhughes@241: } else { rhughes@241: p = strrchr(buffer, '/'); rhughes@241: if (p) { rhughes@241: *p = '\0'; rhughes@241: base = p + 1; rhughes@241: } else { rhughes@241: base = NULL; rhughes@241: } rhughes@241: } krh@248: e = razor_set_find_entry(set, set->files.data, buffer); krh@283: if (e && e->start != 0) rhughes@241: list_dir(set, e, buffer, base); rhughes@241: } rhughes@241: rhughes@241: static struct list * rhughes@241: list_package_files(struct razor_set *set, struct list *r, rhughes@241: struct razor_entry *dir, uint32_t end, rhughes@241: char *prefix) rhughes@241: { rhughes@241: struct razor_entry *e, *f, *entries; rhughes@241: uint32_t next, file; rhughes@241: char *pool; rhughes@241: int len; rhughes@241: rhughes@241: entries = (struct razor_entry *) set->files.data; jbowes@274: pool = set->file_string_pool.data; rhughes@241: rhughes@241: e = entries + dir->start; rhughes@241: do { rhughes@241: if (entries + r->data == e) { rhughes@241: printf("%s/%s\n", prefix, pool + e->name); rhughes@241: r = list_next(r); rhughes@241: if (!r) rhughes@241: return NULL; rhughes@241: if (r->data >= end) rhughes@241: return r; rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); rhughes@241: rhughes@241: e = entries + dir->start; rhughes@241: do { rhughes@241: if (e->start == 0) rhughes@241: continue; rhughes@241: rhughes@241: if (e->flags & RAZOR_ENTRY_LAST) rhughes@241: next = end; rhughes@241: else { rhughes@241: f = e + 1; rhughes@241: while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST)) rhughes@241: f++; rhughes@241: if (f->start == 0) rhughes@241: next = end; rhughes@241: else rhughes@241: next = f->start; rhughes@241: } rhughes@241: rhughes@241: file = r->data; rhughes@241: if (e->start <= file && file < next) { rhughes@241: len = strlen(prefix); rhughes@241: prefix[len] = '/'; rhughes@241: strcpy(prefix + len + 1, pool + e->name); rhughes@241: r = list_package_files(set, r, e, next, prefix); rhughes@241: prefix[len] = '\0'; rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL); rhughes@241: rhughes@241: return r; rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT void krh@306: razor_set_list_package_files(struct razor_set *set, krh@306: struct razor_package *package) rhughes@241: { rhughes@241: struct list *r; rhughes@241: uint32_t end; rhughes@241: char buffer[512]; rhughes@241: richard@301: assert (set != NULL); krh@306: assert (package != NULL); rhughes@241: rhughes@241: r = list_first(&package->files, &set->file_pool); rhughes@241: end = set->files.size / sizeof (struct razor_entry); rhughes@241: buffer[0] = '\0'; rhughes@241: list_package_files(set, r, set->files.data, end, buffer); rhughes@241: } rhughes@241: rhughes@241: /* The diff order matters. We should sort the packages so that a rhughes@241: * REMOVE of a package comes before the INSTALL, and so that all rhughes@241: * requires for a package have been installed before the package. rhughes@241: **/ rhughes@241: krh@269: RAZOR_EXPORT void rhughes@241: razor_set_diff(struct razor_set *set, struct razor_set *upstream, krh@253: razor_diff_callback_t callback, void *data) rhughes@241: { rhughes@241: struct razor_package_iterator *pi1, *pi2; rhughes@241: struct razor_package *p1, *p2; rhughes@241: const char *name1, *name2, *version1, *version2, *arch1, *arch2; rhughes@241: int res; rhughes@241: richard@301: assert (set != NULL); richard@301: assert (upstream != NULL); richard@301: rhughes@241: pi1 = razor_package_iterator_create(set); rhughes@241: pi2 = razor_package_iterator_create(upstream); rhughes@241: richard@302: razor_package_iterator_next(pi1, &p1, richard@302: RAZOR_DETAIL_NAME, &name1, richard@302: RAZOR_DETAIL_VERSION, &version1, richard@302: RAZOR_DETAIL_ARCH, &arch1, richard@307: RAZOR_DETAIL_LAST); richard@302: razor_package_iterator_next(pi2, &p2, richard@302: RAZOR_DETAIL_NAME, &name2, richard@302: RAZOR_DETAIL_VERSION, &version2, richard@302: RAZOR_DETAIL_ARCH, &arch2, richard@307: RAZOR_DETAIL_LAST); rhughes@241: rhughes@241: while (p1 || p2) { rhughes@241: if (p1 && p2) { rhughes@241: res = strcmp(name1, name2); rhughes@241: if (res == 0) krh@248: res = razor_versioncmp(version1, version2); rhughes@241: } else { rhughes@241: res = 0; rhughes@241: } rhughes@241: rhughes@241: if (p2 == NULL || res < 0) krh@253: callback(RAZOR_DIFF_ACTION_REMOVE, krh@253: p1, name1, version1, arch1, data); rhughes@241: else if (p1 == NULL || res > 0) krh@253: callback(RAZOR_DIFF_ACTION_ADD, krh@253: p2, name2, version2, arch2, data); rhughes@241: rhughes@241: if (p1 != NULL && res <= 0) rhughes@241: razor_package_iterator_next(pi1, &p1, richard@302: RAZOR_DETAIL_NAME, &name1, richard@302: RAZOR_DETAIL_VERSION, &version1, richard@302: RAZOR_DETAIL_ARCH, &arch1, richard@307: RAZOR_DETAIL_LAST); rhughes@241: if (p2 != NULL && res >= 0) rhughes@241: razor_package_iterator_next(pi2, &p2, richard@302: RAZOR_DETAIL_NAME, &name2, richard@302: RAZOR_DETAIL_VERSION, &version2, richard@302: RAZOR_DETAIL_ARCH, &arch2, richard@307: RAZOR_DETAIL_LAST); rhughes@241: } rhughes@241: rhughes@241: razor_package_iterator_destroy(pi1); rhughes@241: razor_package_iterator_destroy(pi2); rhughes@241: } krh@254: krh@316: struct install_action { krh@316: enum razor_install_action action; krh@316: struct razor_package *package; krh@316: }; krh@316: krh@316: struct razor_install_iterator { krh@316: struct razor_set *set; krh@316: struct razor_set *next; krh@316: struct array actions; krh@316: struct install_action *a, *end; krh@316: }; krh@316: krh@254: static void krh@316: add_action(enum razor_diff_action action, krh@316: struct razor_package *package, krh@316: const char *name, krh@316: const char *version, krh@316: const char *arch, krh@316: void *data) krh@254: { krh@316: struct razor_install_iterator *ii = data; krh@316: struct install_action *a; krh@316: krh@316: a = array_add(&ii->actions, sizeof *a); krh@316: a->package = package; krh@316: krh@316: switch (action) { krh@316: case RAZOR_DIFF_ACTION_ADD: krh@316: a->action = RAZOR_INSTALL_ACTION_ADD; krh@316: break; krh@316: case RAZOR_DIFF_ACTION_REMOVE: krh@316: a->action = RAZOR_INSTALL_ACTION_REMOVE; krh@316: break; krh@316: } krh@254: } krh@254: krh@316: RAZOR_EXPORT struct razor_install_iterator * krh@316: razor_set_create_install_iterator(struct razor_set *set, krh@316: struct razor_set *next) krh@254: { krh@316: struct razor_install_iterator *ii; krh@254: richard@301: assert (set != NULL); richard@301: assert (next != NULL); richard@301: krh@316: ii = zalloc(sizeof *ii); krh@316: ii->set = set; krh@316: ii->next = next; krh@316: krh@316: razor_set_diff(set, next, add_action, ii); krh@254: krh@316: ii->a = ii->actions.data; krh@316: ii->end = ii->actions.data + ii->actions.size; krh@254: krh@254: /* FIXME: We need to figure out the right install order here, krh@254: * so the post and pre scripts can run. */ krh@254: krh@316: return ii; krh@254: } krh@254: krh@316: RAZOR_EXPORT int krh@316: razor_install_iterator_next(struct razor_install_iterator *ii, krh@316: struct razor_set **set, krh@316: struct razor_package **package, krh@316: enum razor_install_action *action, krh@316: int *count) krh@254: { krh@316: if (ii->a == ii->end) krh@316: return 0; krh@254: krh@316: switch (ii->a->action) { krh@316: case RAZOR_INSTALL_ACTION_ADD: krh@316: *set = ii->next; krh@316: break; krh@316: case RAZOR_INSTALL_ACTION_REMOVE: krh@316: *set = ii->set; krh@316: break; krh@316: } richard@301: krh@316: *package = ii->a->package; krh@316: *action = ii->a->action; krh@316: *count = 0; krh@316: ii->a++; krh@254: krh@316: return 1; krh@316: } krh@254: krh@316: RAZOR_EXPORT void krh@316: razor_install_iterator_destroy(struct razor_install_iterator *ii) krh@316: { krh@316: array_release(&ii->actions); krh@316: free(ii); krh@254: }