rpm.c
author Kristian H?gsberg <krh@redhat.com>
Thu Nov 08 17:14:19 2007 -0500 (2007-11-08)
changeset 75 93278d8ec39c
parent 74 f23a93d41f32
child 77 3d14834c56ea
permissions -rw-r--r--
Extend rpm dumper into an rpm importer.
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <sys/stat.h>
     4 #include <sys/mman.h>
     5 #include <fcntl.h>
     6 #include <unistd.h>
     7 #include <arpa/inet.h>
     8 #include <rpm/rpmlib.h>
     9 
    10 #include "razor.h"
    11 
    12 #define	RPM_LEAD_SIZE 96
    13 
    14 struct rpm_lead {
    15 	unsigned char magic[4];
    16 	unsigned char major;
    17 	unsigned char minor;
    18 	short type;
    19 	short archnum;
    20 	char name[66];
    21 	short osnum;
    22 	short signature_type;
    23 	char reserved[16];
    24 };
    25 
    26 struct rpm_header {
    27 	unsigned char magic[4];
    28 	unsigned char reserved[4];
    29 	int nindex;
    30 	int hsize;
    31 };
    32 
    33 struct rpm_header_index {
    34 	int tag;
    35 	int type;
    36 	int offset;
    37 	int count;
    38 };
    39 
    40 struct properties {
    41 	struct rpm_header_index *name;
    42 	struct rpm_header_index *version;
    43 	struct rpm_header_index *flags;
    44 };
    45 
    46 struct rpm {
    47 	struct rpm_header *signature;
    48 	struct rpm_header *header;
    49 
    50 	struct rpm_header_index *name;
    51 	struct rpm_header_index *version;
    52 	struct rpm_header_index *release;
    53 
    54 	struct rpm_header_index *dirnames;
    55 	struct rpm_header_index *dirindexes;
    56 	struct rpm_header_index *basenames;
    57 
    58 	struct properties provides;
    59 	struct properties requires;
    60 	struct properties obsoletes;
    61 	struct properties conflicts;
    62 
    63 	const char *pool;
    64 	void *map;
    65 	size_t size;
    66 };
    67 
    68 #define ALIGN(value, base) (((value) + (base - 1)) & ~((base) - 1))
    69 
    70 static void
    71 import_properties(struct razor_importer *importer,
    72 		  struct properties *properties,
    73 		  const char *pool, unsigned long type)
    74 {
    75 	const char *name, *version;
    76 	int i, count;
    77 
    78 	/* assert: count is the same for all arrays */
    79 
    80 	if (properties->name == NULL)
    81 		return;
    82 
    83 	count = ntohl(properties->name->count);
    84 	name = pool + ntohl(properties->name->offset);
    85 	version = pool + ntohl(properties->version->offset);
    86 	for (i = 0; i < count; i++) {
    87 		razor_importer_add_property(importer, name, version, type);
    88 		name += strlen(name) + 1;
    89 		version += strlen(version) + 1;
    90 	}
    91 }
    92 
    93 static void
    94 import_files(struct razor_importer *importer, struct rpm *rpm)
    95 {
    96 	const char *name, **dir;
    97 	unsigned long *index;
    98 	int i, count;
    99 	char buffer[256];
   100 
   101 	/* assert: count is the same for all arrays */
   102 
   103 	if (rpm->dirnames == NULL)
   104 		return;
   105 
   106 	count = ntohl(rpm->dirnames->count);
   107 	dir = calloc(count, sizeof *dir);
   108 	name = rpm->pool + ntohl(rpm->dirnames->offset);
   109 	for (i = 0; i < count; i++) {
   110 		dir[i] = name;
   111 		name += strlen(name) + 1;
   112 	}
   113 
   114 	count = ntohl(rpm->basenames->count);
   115 	index = (unsigned long *) (rpm->pool + ntohl(rpm->dirindexes->offset));
   116 	name = rpm->pool + ntohl(rpm->basenames->offset);
   117 	for (i = 0; i < count; i++) {
   118 		snprintf(buffer, sizeof buffer,
   119 			 "%s%s", dir[ntohl(*index)], name);
   120 		razor_importer_add_file(importer, buffer);
   121 		name += strlen(name) + 1;
   122 		index++;
   123 	}
   124 }
   125 
   126 static int
   127 razor_rpm_open(struct rpm *rpm, const char *filename)
   128 {
   129 	struct rpm_header_index *base, *index;
   130 	struct stat buf;
   131 	int fd, nindex, hsize, i;
   132 
   133 	memset(rpm, 0, sizeof *rpm);
   134 	if (stat(filename, &buf) < 0) {
   135 		fprintf(stderr, "no such file %s (%m)\n", filename);
   136 		return -1;
   137 	}
   138 
   139 	fd = open(filename, O_RDONLY);
   140 	if (fd < 0) {
   141 		fprintf(stderr, "couldn't open %s\n", filename);
   142 		return -1;
   143 	}
   144 	rpm->size = buf.st_size;
   145 	rpm->map = mmap(NULL, rpm->size, PROT_READ, MAP_PRIVATE, fd, 0);
   146 	if (rpm->map == MAP_FAILED) {
   147 		fprintf(stderr, "couldn't mmap %s\n", filename);
   148 		return -1;
   149 	}
   150 	close(fd);
   151 
   152 	rpm->signature = rpm->map + RPM_LEAD_SIZE;
   153 	nindex = ntohl(rpm->signature->nindex);
   154 	hsize = ntohl(rpm->signature->hsize);
   155 	rpm->header = (void *) (rpm->signature + 1) +
   156 		ALIGN(nindex * sizeof *index + hsize, 8);
   157 
   158 	nindex = ntohl(rpm->header->nindex);
   159 	base = (struct rpm_header_index *) (rpm->header + 1);
   160 	rpm->pool = (void *) base + nindex * sizeof *index;
   161 
   162 	for (i = 0; i < nindex; i++) {
   163 		index = base + i;
   164 		switch (ntohl(index->tag)) {
   165 		case RPMTAG_NAME:
   166 			rpm->name = index;
   167 			break;
   168 		case RPMTAG_VERSION:
   169 			rpm->version = index;
   170 			break;
   171 		case RPMTAG_RELEASE:
   172 			rpm->release = index;
   173 			break;
   174 
   175 		case RPMTAG_REQUIRENAME:
   176 			rpm->requires.name = index;
   177 			break;
   178 		case RPMTAG_REQUIREVERSION:
   179 			rpm->requires.version = index;
   180 			break;
   181 		case RPMTAG_REQUIREFLAGS:
   182 			rpm->requires.flags = index;
   183 			break;
   184 
   185 		case RPMTAG_PROVIDENAME:
   186 			rpm->provides.name = index;
   187 			break;
   188 		case RPMTAG_PROVIDEVERSION:
   189 			rpm->provides.version = index;
   190 			break;
   191 		case RPMTAG_PROVIDEFLAGS:
   192 			rpm->provides.flags = index;
   193 			break;
   194 
   195 		case RPMTAG_OBSOLETENAME:
   196 			rpm->obsoletes.name = index;
   197 			break;
   198 		case RPMTAG_OBSOLETEVERSION:
   199 			rpm->obsoletes.version = index;
   200 			break;
   201 		case RPMTAG_OBSOLETEFLAGS:
   202 			rpm->obsoletes.flags = index;
   203 			break;
   204 
   205 		case RPMTAG_CONFLICTNAME:
   206 			rpm->conflicts.name = index;
   207 			break;
   208 		case RPMTAG_CONFLICTVERSION:
   209 			rpm->conflicts.version = index;
   210 			break;
   211 		case RPMTAG_CONFLICTFLAGS:
   212 			rpm->conflicts.flags = index;
   213 			break;
   214 
   215 		case RPMTAG_DIRINDEXES:
   216 			rpm->dirindexes = index;
   217 			break;
   218 		case RPMTAG_BASENAMES:
   219 			rpm->basenames = index;
   220 			break;
   221 		case RPMTAG_DIRNAMES:
   222 			rpm->dirnames = index;
   223 			break;
   224 		}
   225 	}
   226 
   227 	return 0;
   228 }
   229 
   230 static int
   231 razor_rpm_close(struct rpm *rpm)
   232 {
   233 	return munmap(rpm->map, rpm->size);
   234 }
   235 
   236 int
   237 razor_importer_add_rpm(struct razor_importer *importer, const char *filename)
   238 {
   239 	struct rpm rpm;
   240 
   241 	if (razor_rpm_open(&rpm, filename) < 0) {
   242 		fprintf(stderr, "failed to open rpm %s (%m)\n", filename);
   243 		return -1;
   244 	}
   245 
   246 	razor_importer_begin_package(importer,
   247 				     rpm.pool + ntohl(rpm.name->offset),
   248 				     rpm.pool + ntohl(rpm.version->offset));
   249 
   250 	import_properties(importer, &rpm.requires,
   251 			  rpm.pool, RAZOR_PROPERTY_REQUIRES);
   252 	import_properties(importer, &rpm.provides,
   253 			  rpm.pool, RAZOR_PROPERTY_PROVIDES);
   254 	import_properties(importer, &rpm.conflicts,
   255 			  rpm.pool, RAZOR_PROPERTY_CONFLICTS);
   256 	import_properties(importer, &rpm.obsoletes,
   257 			  rpm.pool, RAZOR_PROPERTY_OBSOLETES);
   258 	import_files(importer, &rpm);
   259 
   260 	razor_importer_finish_package(importer);
   261 
   262 	razor_rpm_close(&rpm);
   263 
   264 	return 0;
   265 }