diff -r 7538f8dc4425 -r 48b0adfe3059 librazor/rpm.c --- a/librazor/rpm.c Tue Jan 13 17:04:51 2009 +0000 +++ b/librazor/rpm.c Thu Jan 22 22:54:45 2009 +0000 @@ -1,6 +1,7 @@ /* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc + * Copyright (C) 2009 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -248,12 +249,144 @@ struct rpm_header *signature; struct rpm_header *header; const char **dirs; + unsigned int n_prefixes; + const char **prefixes; const char *pool; void *map; size_t size; void *payload; + struct razor_relocations *relocations; }; +enum razor_relocation_flags { + RAZOR_RELOCATION_ACTIVE = 1 << 0, +}; + +struct razor_relocation { + enum razor_relocation_flags flags; + size_t oldlen; + size_t newlen; + char *oldpath; + char *newpath; +}; + +struct razor_relocations { + /* Ordered such that if oldpath 1 starts with oldpath 2, then + * oldpath 1 is listed first (ie., /usr/bin comes before /usr) + * and terminated with a NULL oldpath. + */ + struct razor_relocation *relocations; + int n_relocations; + char *path; +}; + +RAZOR_EXPORT struct razor_relocations *razor_relocations_create(void) +{ + return calloc(1, sizeof(struct razor_relocations)); +} + +RAZOR_EXPORT void razor_relocations_add(struct razor_relocations *rr, + const char *oldpath, const char *newpath) +{ + int i, found = 0; + size_t len; + + if (newpath && !strcmp(oldpath, newpath)) + newpath = NULL; + + for (i = 0; i < rr->n_relocations; i++) { + len = rr->relocations[i].oldlen; + if (!strncmp(rr->relocations[i].oldpath, oldpath, len)) { + found = !strcmp(rr->relocations[i].oldpath, oldpath); + break; + } + } + + if (!newpath) { + if (found) { + free(rr->relocations[i].oldpath); + free(rr->relocations[i].newpath); + do { + rr->relocations[i] = rr->relocations[i + 1]; + } while (rr->relocations[++i].oldpath); + } + return; + } + + if (found) { + free(rr->relocations[i].newpath); + rr->relocations[i].newpath = strdup(newpath); + rr->relocations[i].newlen = strlen(newpath); + return; + } + + if (!rr->n_relocations++) + rr->relocations = calloc(1, sizeof *rr->relocations); + else { + rr->relocations = realloc(rr->relocations, + rr->n_relocations * sizeof *rr->relocations); + memmove(rr->relocations + i + 1, rr->relocations + i, + (rr->n_relocations - i - 1) * sizeof *rr->relocations); + } + + rr->relocations[i].flags = 0; + rr->relocations[i].oldpath = strdup(oldpath); + rr->relocations[i].newpath = strdup(newpath); + rr->relocations[i].oldlen = strlen(oldpath); + rr->relocations[i].newlen = strlen(newpath); +} + +RAZOR_EXPORT void +razor_relocations_set_rpm(struct razor_relocations *rr, struct razor_rpm *rpm) +{ + int i, j; + + for (i = 0; i < rr->n_relocations; i++) { + rr->relocations[i].flags &= ~RAZOR_RELOCATION_ACTIVE; + for (j = 0; j < rpm->n_prefixes; j++) + if (!strcmp(rpm->prefixes[j], + rr->relocations[i].oldpath)) { + rr->relocations[i].flags |= RAZOR_RELOCATION_ACTIVE; + break; + } + } +} + +RAZOR_EXPORT const char * +razor_relocations_apply(struct razor_relocations *rr, const char *path) +{ + int i; + size_t len; + + for (i = 0; i < rr->n_relocations; i++) + if (rr->relocations[i].flags & RAZOR_RELOCATION_ACTIVE && + !strncmp(path, rr->relocations[i].oldpath, + rr->relocations[i].oldlen)) + break; + + if (i < rr->n_relocations) { + free(rr->path); + len = strlen(path + rr->relocations[i].oldlen) + + rr->relocations[i].newlen; + rr->path = malloc(len + 1); + memcpy(rr->path, rr->relocations[i].newpath, + rr->relocations[i].newlen); + strcpy(rr->path + rr->relocations[i].newlen, + path + rr->relocations[i].oldlen); + return rr->path; + } else + return path; +} + +RAZOR_EXPORT void razor_relocations_destroy(struct razor_relocations *rr) +{ + printf("razor_relocations_destroy(rr=%p): path=%p, rel=%p\n", + rr,rr->path,rr->relocations); + free(rr->path); + free(rr->relocations); + free(rr); +} + static struct rpm_header_index * razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag) { @@ -366,7 +499,7 @@ struct razor_rpm *rpm; struct rpm_header_index *base, *index; unsigned int count, i, nindex, hsize; - const char *name; + const char *name, *prefix; assert (filename != NULL); @@ -412,9 +545,34 @@ } } + prefix = razor_rpm_get_indirect(rpm, RPMTAG_PREFIXES, &count); + if (prefix) { + rpm->prefixes = calloc(count, sizeof *rpm->prefixes); + for (i = 0; i < count; i++) { + rpm->prefixes[i] = prefix; + prefix += strlen(prefix) + 1; + } + rpm->n_prefixes = count; + } else { + prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX, + &count); + if (prefix) { + fprintf(stderr, "default prefix not supported\n"); + return NULL; + } + } + return rpm; } +RAZOR_EXPORT void razor_rpm_set_relocations(struct razor_rpm *rpm, + struct razor_relocations *rr) +{ + assert (rpm != NULL); + + rpm->relocations = rr; +} + struct cpio_file_header { char magic[6]; char inode[8]; @@ -744,7 +902,7 @@ struct cpio_file_header *header; struct stat buf; unsigned int mode; - char *path; + const char *path; size_t filesize; assert (rpm != NULL); @@ -761,6 +919,9 @@ return -1; } + if (rpm->relocations) + razor_relocations_set_rpm(rpm->relocations, rpm); + if (installer_init(&installer)) return -1; @@ -783,13 +944,16 @@ installer_align(&installer, 4)) return -1; - path = (char *) installer.buffer; + path = (const char *) installer.buffer; /* This convention is so lame... */ if (strcmp(path, "TRAILER!!!") == 0) break; installer.rest = filesize; - if (create_path(&installer, path + 1, mode) < 0) + path++; + if (rpm->relocations) + path = razor_relocations_apply(rpm->relocations, path); + if (create_path(&installer, path, mode) < 0) return -1; if (installer_align(&installer, 4)) return -1; @@ -811,6 +975,7 @@ assert (rpm != NULL); free(rpm->dirs); + free(rpm->prefixes); err = razor_file_free_contents(rpm->map, rpm->size); free(rpm);