Extend rpm dumper into an rpm importer.
authorKristian Høgsberg <krh@redhat.com>
Thu, 8 Nov 2007 22:14:19 +0000 (17:14 -0500)
committerKristian Høgsberg <krh@redhat.com>
Thu, 8 Nov 2007 22:14:19 +0000 (17:14 -0500)
TODO
main.c
razor.c
razor.h
rpm.c

diff --git a/TODO b/TODO
index 746d240..69c8175 100644 (file)
--- a/TODO
+++ b/TODO
@@ -94,3 +94,5 @@ Misc ideas:
 
 - use hash tables for dirs when importing files to avoid qsorting all
   files in rawhide.
+
+- corner cases such as no files/properties in repo etc segfault.
diff --git a/main.c b/main.c
index 00ce88a..5a47b5f 100644 (file)
--- a/main.c
+++ b/main.c
@@ -5,7 +5,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
-
+#include <dirent.h>
 #include <curl/curl.h>
 #include "razor.h"
 
@@ -292,9 +292,51 @@ command_diff(int argc, const char *argv[])
 }
 
 static int
-command_dump_rpm(int argc, const char *argv[])
+command_import_rpms(int argc, const char *argv[])
 {
-       razor_rpm_dump(argv[0]);
+       DIR *dir;
+       struct dirent *de;
+       struct razor_importer *importer;
+       struct razor_set *set;
+       int len;
+       char filename[256];
+       const char *dirname = argv[0];
+
+       if (dirname == NULL) {
+               fprintf(stderr, "usage: razor import-rpms DIR\n");
+               return -1;
+       }
+
+       dir = opendir(dirname);
+       if (dir == NULL) {
+               fprintf(stderr, "couldn't read dir %s\n", dirname);
+               return -1;
+       }
+
+       importer = razor_importer_new();
+
+       while (de = readdir(dir), de != NULL) {
+               len = strlen(de->d_name);
+               if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
+                   continue;
+               snprintf(filename, sizeof filename,
+                        "%s/%s", dirname, de->d_name);
+               if (razor_importer_add_rpm(importer, filename)) {
+                       fprintf(stderr, "couldn't import %s\n", filename);
+                       break;
+               }
+       }
+
+       if (de != NULL) {
+               razor_importer_destroy(importer);
+               return -1;
+       }
+
+       set = razor_importer_finish(importer);
+
+       razor_set_write(set, repo_filename);
+       razor_set_destroy(set);
+       printf("wrote %s\n", repo_filename);
 
        return 0;
 }
@@ -306,20 +348,20 @@ static struct {
 } razor_commands[] = {
        { "list", "list all packages", command_list },
        { "list-requires", "list all requires for the given package", command_list_requires },
-       { "list-provides", "list all provides for the give package", command_list_provides },
-       { "list-obsoletes", "list all obsoletes for the give package", command_list_obsoletes },
-       { "list-conflicts", "list all conflicts for the give package", command_list_conflicts },
+       { "list-provides", "list all provides for the given package", command_list_provides },
+       { "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
+       { "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
        { "list-files", "list files for package set", command_list_files },
        { "list-file-packages", "list packages owning file", command_list_file_packages },
        { "list-package-files", "list files in package", command_list_package_files },
        { "what-requires", "list the packages that have the given requires", command_what_requires },
        { "what-provides", "list the packages that have the given provides", command_what_provides },
-       { "import-yum", "import yum filelist.xml on stdin", command_import_yum },
+       { "import-yum", "import yum metadata files", command_import_yum },
        { "import-rpmdb", "import the system rpm database", command_import_rpmdb },
+       { "import-rpms", "import rpms from the given directory", command_import_rpms },
        { "validate", "validate a package set", command_validate },
        { "update", "update all or specified packages", command_update },
-       { "diff", "show diff between two package sets", command_diff },
-       { "dump", "dump rpm file contents", command_dump_rpm }
+       { "diff", "show diff between two package sets", command_diff }
 };
 
 static int
diff --git a/razor.c b/razor.c
index 8f90dcc..b6e25f6 100644 (file)
--- a/razor.c
+++ b/razor.c
@@ -470,6 +470,14 @@ razor_importer_new(void)
        return importer;
 }
 
+/* Destroy an importer without creating the set. */
+void
+razor_importer_destroy(struct razor_importer *importer)
+{
+       /* FIXME: write this */
+}
+
+
 typedef int (*compare_with_data_func_t)(const void *p1,
                                        const void *p,
                                        void *data);
@@ -551,6 +559,9 @@ qsort_with_data(void *base, size_t nelem, size_t size,
        unsigned long *map;
        int i;
 
+       if (nelem == 0)
+               return NULL;
+
        ctx.size = size;
        ctx.compare = compare;
        ctx.data = data;
diff --git a/razor.h b/razor.h
index 44872d6..17f6fef 100644 (file)
--- a/razor.h
+++ b/razor.h
@@ -47,6 +47,7 @@ razor_set_diff(struct razor_set *set, struct razor_set *upstream,
 struct razor_importer;
 
 struct razor_importer *razor_importer_new(void);
+void razor_importer_destroy(struct razor_importer *importer);
 void razor_importer_begin_package(struct razor_importer *importer,
                                const char *name, const char *version);
 void razor_importer_add_property(struct razor_importer *importer,
@@ -55,6 +56,10 @@ void razor_importer_add_property(struct razor_importer *importer,
 void razor_importer_add_file(struct razor_importer *importer,
                             const char *name);
 void razor_importer_finish_package(struct razor_importer *importer);
+
+int razor_importer_add_rpm(struct razor_importer *importer,
+                          const char *filename);
+
 struct razor_set *razor_importer_finish(struct razor_importer *importer);
 
 struct razor_set *razor_import_rzr_files(int count, const char **files);
diff --git a/rpm.c b/rpm.c
index 4424fd1..614f957 100644 (file)
--- a/rpm.c
+++ b/rpm.c
@@ -7,6 +7,8 @@
 #include <arpa/inet.h>
 #include <rpm/rpmlib.h>
 
+#include "razor.h"
+
 #define        RPM_LEAD_SIZE 96
 
 struct rpm_lead {
@@ -35,92 +37,229 @@ struct rpm_header_index {
        int count;
 };
 
+struct properties {
+       struct rpm_header_index *name;
+       struct rpm_header_index *version;
+       struct rpm_header_index *flags;
+};
+
+struct rpm {
+       struct rpm_header *signature;
+       struct rpm_header *header;
+
+       struct rpm_header_index *name;
+       struct rpm_header_index *version;
+       struct rpm_header_index *release;
+
+       struct rpm_header_index *dirnames;
+       struct rpm_header_index *dirindexes;
+       struct rpm_header_index *basenames;
+
+       struct properties provides;
+       struct properties requires;
+       struct properties obsoletes;
+       struct properties conflicts;
+
+       const char *pool;
+       void *map;
+       size_t size;
+};
+
 #define ALIGN(value, base) (((value) + (base - 1)) & ~((base) - 1))
 
-static void dump_header(struct rpm_header *header)
+static void
+import_properties(struct razor_importer *importer,
+                 struct properties *properties,
+                 const char *pool, unsigned long type)
+{
+       const char *name, *version;
+       int i, count;
+
+       /* assert: count is the same for all arrays */
+
+       if (properties->name == NULL)
+               return;
+
+       count = ntohl(properties->name->count);
+       name = pool + ntohl(properties->name->offset);
+       version = pool + ntohl(properties->version->offset);
+       for (i = 0; i < count; i++) {
+               razor_importer_add_property(importer, name, version, type);
+               name += strlen(name) + 1;
+               version += strlen(version) + 1;
+       }
+}
+
+static void
+import_files(struct razor_importer *importer, struct rpm *rpm)
+{
+       const char *name, **dir;
+       unsigned long *index;
+       int i, count;
+       char buffer[256];
+
+       /* assert: count is the same for all arrays */
+
+       if (rpm->dirnames == NULL)
+               return;
+
+       count = ntohl(rpm->dirnames->count);
+       dir = calloc(count, sizeof *dir);
+       name = rpm->pool + ntohl(rpm->dirnames->offset);
+       for (i = 0; i < count; i++) {
+               dir[i] = name;
+               name += strlen(name) + 1;
+       }
+
+       count = ntohl(rpm->basenames->count);
+       index = (unsigned long *) (rpm->pool + ntohl(rpm->dirindexes->offset));
+       name = rpm->pool + ntohl(rpm->basenames->offset);
+       for (i = 0; i < count; i++) {
+               snprintf(buffer, sizeof buffer,
+                        "%s%s", dir[ntohl(*index)], name);
+               razor_importer_add_file(importer, buffer);
+               name += strlen(name) + 1;
+               index++;
+       }
+}
+
+static int
+razor_rpm_open(struct rpm *rpm, const char *filename)
 {
        struct rpm_header_index *base, *index;
-       int i, j, nindex, tag, offset, type, count;
-       char *pool, *name;
+       struct stat buf;
+       int fd, nindex, hsize, i;
+
+       memset(rpm, 0, sizeof *rpm);
+       if (stat(filename, &buf) < 0) {
+               fprintf(stderr, "no such file %s (%m)\n", filename);
+               return -1;
+       }
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "couldn't open %s\n", filename);
+               return -1;
+       }
+       rpm->size = buf.st_size;
+       rpm->map = mmap(NULL, rpm->size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (rpm->map == MAP_FAILED) {
+               fprintf(stderr, "couldn't mmap %s\n", filename);
+               return -1;
+       }
+       close(fd);
 
-       nindex = ntohl(header->nindex);
-       printf("header index records: %d\n", nindex);
-       printf("header storage size: %d\n", ntohl(header->hsize));
-       base = (struct rpm_header_index *) (header + 1);
-       pool = (void *) (header + 1) + nindex * sizeof *index;
+       rpm->signature = rpm->map + RPM_LEAD_SIZE;
+       nindex = ntohl(rpm->signature->nindex);
+       hsize = ntohl(rpm->signature->hsize);
+       rpm->header = (void *) (rpm->signature + 1) +
+               ALIGN(nindex * sizeof *index + hsize, 8);
+
+       nindex = ntohl(rpm->header->nindex);
+       base = (struct rpm_header_index *) (rpm->header + 1);
+       rpm->pool = (void *) base + nindex * sizeof *index;
 
-       printf("headers:\n");
        for (i = 0; i < nindex; i++) {
                index = base + i;
-               tag = ntohl(index->tag);
-               offset = ntohl(index->offset);
-               type = ntohl(index->type);
-               count = ntohl(index->count);
-               printf("  0x%08x 0x%08x 0x%08x 0x%08x\n",
-                      tag, type, offset, count);
-
-               switch (tag) {
+               switch (ntohl(index->tag)) {
                case RPMTAG_NAME:
-                       name = "name";
+                       rpm->name = index;
                        break;
                case RPMTAG_VERSION:
-                       name = "version";
+                       rpm->version = index;
                        break;
                case RPMTAG_RELEASE:
-                       name = "release";
+                       rpm->release = index;
                        break;
+
                case RPMTAG_REQUIRENAME:
-                       name = "requires";
+                       rpm->requires.name = index;
                        break;
-               default:
-                       name = "unknown";
+               case RPMTAG_REQUIREVERSION:
+                       rpm->requires.version = index;
+                       break;
+               case RPMTAG_REQUIREFLAGS:
+                       rpm->requires.flags = index;
+                       break;
+
+               case RPMTAG_PROVIDENAME:
+                       rpm->provides.name = index;
+                       break;
+               case RPMTAG_PROVIDEVERSION:
+                       rpm->provides.version = index;
+                       break;
+               case RPMTAG_PROVIDEFLAGS:
+                       rpm->provides.flags = index;
+                       break;
+
+               case RPMTAG_OBSOLETENAME:
+                       rpm->obsoletes.name = index;
+                       break;
+               case RPMTAG_OBSOLETEVERSION:
+                       rpm->obsoletes.version = index;
+                       break;
+               case RPMTAG_OBSOLETEFLAGS:
+                       rpm->obsoletes.flags = index;
+                       break;
+
+               case RPMTAG_CONFLICTNAME:
+                       rpm->conflicts.name = index;
+                       break;
+               case RPMTAG_CONFLICTVERSION:
+                       rpm->conflicts.version = index;
+                       break;
+               case RPMTAG_CONFLICTFLAGS:
+                       rpm->conflicts.flags = index;
                        break;
-               }
 
-               switch (type) {
-               case RPM_STRING_TYPE:
-                       printf("    (%s %s)\n", name, pool + offset);
+               case RPMTAG_DIRINDEXES:
+                       rpm->dirindexes = index;
+                       break;
+               case RPMTAG_BASENAMES:
+                       rpm->basenames = index;
                        break;
-               case RPM_STRING_ARRAY_TYPE:
-                       printf("    (%s", name);
-                       for (j = 0; j < count; j++) {
-                               printf(" %s", pool + offset);
-                               offset += strlen(pool + offset) + 1;
-                       }
-                       printf(")\n");
+               case RPMTAG_DIRNAMES:
+                       rpm->dirnames = index;
                        break;
                }
        }
+
+       return 0;
 }
 
-void
-razor_rpm_dump(const char *filename)
+static int
+razor_rpm_close(struct rpm *rpm)
 {
-       struct stat buf;
-       void *p;
-       int fd, nindex, hsize;
-       struct rpm_header *signature, *header;
-       struct rpm_header_index *index;
+       return munmap(rpm->map, rpm->size);
+}
 
-       if (stat(filename, &buf) < 0) {
-               fprintf(stderr, "no such file %s\n", filename);
-               return;
+int
+razor_importer_add_rpm(struct razor_importer *importer, const char *filename)
+{
+       struct rpm rpm;
+
+       if (razor_rpm_open(&rpm, filename) < 0) {
+               fprintf(stderr, "failed to open rpm %s (%m)\n", filename);
+               return -1;
        }
 
-       fd = open(filename, O_RDONLY);
-       p = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-       close(fd);
+       razor_importer_begin_package(importer,
+                                    rpm.pool + ntohl(rpm.name->offset),
+                                    rpm.pool + ntohl(rpm.version->offset));
 
-       printf("%s: %ldkB\n", filename, buf.st_size / 1024);
-       signature = p + RPM_LEAD_SIZE;
+       import_properties(importer, &rpm.requires,
+                         rpm.pool, RAZOR_PROPERTY_REQUIRES);
+       import_properties(importer, &rpm.provides,
+                         rpm.pool, RAZOR_PROPERTY_PROVIDES);
+       import_properties(importer, &rpm.conflicts,
+                         rpm.pool, RAZOR_PROPERTY_CONFLICTS);
+       import_properties(importer, &rpm.obsoletes,
+                         rpm.pool, RAZOR_PROPERTY_OBSOLETES);
+       import_files(importer, &rpm);
 
-       nindex = ntohl(signature->nindex);
-       hsize = ntohl(signature->hsize);
-       header = (void *) (signature + 1) +
-               ALIGN(nindex * sizeof *index + hsize, 8);
+       razor_importer_finish_package(importer);
 
-       dump_header(signature);
-       dump_header(header);
+       razor_rpm_close(&rpm);
 
-       munmap(p, buf.st_size);
+       return 0;
 }