--- /dev/null
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "misc.h"
+#include "oldheader.h"
+#include "rpmerr.h"
+#include "rpmlib.h"
+
+/* This *can't* read 1.0 headers -- it needs 1.1 (w/ group and icon fields)
+ or better. I'd be surprised if any 1.0 headers are left anywhere anyway.
+ Red Hat 2.0 shipped with 1.1 headers, but some old BETAs used 1.0. */
+
+struct literalHeader {
+ unsigned char m1, m2, m3, m4;
+ unsigned char major, minor;
+
+ unsigned short type, cpu;
+ char labelstr[66];
+ unsigned int specOffset;
+ unsigned int specLength;
+ unsigned int archiveOffset;
+ unsigned int size;
+ unsigned int os;
+ unsigned int groupLength;
+ unsigned int iconLength;
+} ;
+
+/* this leaves the file pointer pointing at the data section */
+
+char * oldhdrReadFromStream(int fd, struct oldrpmHeader * header) {
+ struct literalHeader lit;
+ char * chptr;
+ int bytesRead;
+ char ch;
+ unsigned int specOffset;
+ unsigned int archiveOffset;
+ unsigned int groupLength;
+
+ if (read(fd, &lit, sizeof(lit)) != sizeof(lit)) {
+ return strerror(errno);
+ }
+
+ bytesRead = sizeof(lit);
+
+ if (lit.m1 != 0xed || lit.m2 != 0xab || lit.m3 != 0xee ||
+ lit.m4 != 0xdb) {
+ return "bad magic for RPM package";
+ }
+
+ specOffset = htonl(lit.specOffset);
+ header->specLength = htonl(lit.specLength);
+ archiveOffset = htonl(lit.archiveOffset);
+ header->size = htonl(lit.size);
+ header->os = htonl(lit.os);
+ groupLength = htonl(lit.groupLength);
+ header->iconLength = htonl(lit.iconLength);
+
+ header->spec = malloc(header->specLength);
+ header->name = malloc(strlen(lit.labelstr) + 1);
+ if (!header->spec || !header->name) {
+ header->spec ? free(header->spec) : 0;
+ header->name ? free(header->name) : 0;
+ return "out of memory";
+ }
+
+ strcpy(header->name, lit.labelstr);
+ chptr = header->name + strlen(header->name);
+ while (*chptr != '-') chptr--;
+ *chptr = '\0';
+ header->release = chptr + 1;
+ while (*chptr != '-') chptr--;
+ *chptr = '\0';
+ header->version = chptr + 1;
+
+ if (groupLength) {
+ header->group = malloc(groupLength + 1);
+ if (!header->group) {
+ free(header->spec);
+ free(header->name);
+ return "out of memory";
+ }
+
+ if (read(fd, header->group, groupLength) != groupLength) {
+ oldhdrFree(header);
+ return strerror(errno);
+ }
+ header->group[groupLength] = '\0';
+ bytesRead += groupLength;
+ } else {
+ header->group = NULL;
+ }
+
+ if (header->iconLength) {
+ header->icon = malloc(header->iconLength);
+ if (!header->icon) {
+ free(header->spec);
+ free(header->name);
+ free(header->icon);
+ return "out of memory";
+ }
+ if (read(fd, header->icon, header->iconLength) != header->iconLength) {
+ oldhdrFree(header);
+ return strerror(errno);
+ }
+ bytesRead += header->iconLength;
+ } else {
+ header->icon = NULL;
+ }
+
+ while (bytesRead < specOffset) {
+ if (read(fd, &ch, 1) != 1) {
+ oldhdrFree(header);
+ return strerror(errno);
+ }
+ bytesRead++;
+ }
+
+ if (read(fd, header->spec, header->specLength) != header->specLength) {
+ oldhdrFree(header);
+ return strerror(errno);
+ }
+ bytesRead += header->specLength;
+
+ while (bytesRead < archiveOffset) {
+ if (read(fd, &ch, 1) != 1) {
+ oldhdrFree(header);
+ return strerror(errno);
+ }
+ bytesRead++;
+ }
+
+ return NULL;
+}
+
+char * oldhdrReadFromFile(char * filename, struct oldrpmHeader * header) {
+ char * rc;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) return strerror(errno);
+
+ rc = oldhdrReadFromStream(fd, header);
+ close(fd);
+
+ return rc;
+}
+
+void oldhdrFree(struct oldrpmHeader * header) {
+ free(header->name);
+ free(header->spec);
+ header->group ? free(header->icon) : 0;
+ header->group ? free(header->group) : 0;
+}
+
+void oldhdrSpecFree(struct oldrpmHeaderSpec * spec) {
+ free(spec->copyright);
+ free(spec->description);
+ free(spec->vendor);
+ free(spec->distribution);
+ free(spec->buildHost);
+
+ while (spec->fileCount) {
+ spec->fileCount--;
+ oldrpmfileFree(spec->files + spec->fileCount);
+ }
+
+ free(spec->files);
+}
+
+char * oldhdrParseSpec(struct oldrpmHeader * header, struct oldrpmHeaderSpec * spec) {
+ char ** lines;
+ char ** strptr;
+ char ** files = NULL;
+ int inFilelist = 0, i;
+
+ lines = splitString(header->spec, header->specLength, '\n');
+ if (!lines) {
+ return "out of memory";
+ }
+
+ /* these are optional */
+ spec->distribution = NULL;
+ spec->vendor = NULL;
+ spec->description = NULL;
+ spec->copyright = NULL;
+
+ spec->fileCount = 0;
+ for (strptr = lines; *strptr; strptr++) {
+ if (inFilelist) {
+ if (**strptr)
+ spec->fileCount++;
+ } else {
+ if (!strncmp("Description: ", *strptr, 13))
+ spec->description = strdup((*strptr) + 13);
+ else if (!strncmp("Distribution: ", *strptr, 14))
+ spec->distribution = strdup((*strptr) + 14);
+ else if (!strncmp("Vendor: ", *strptr, 8))
+ spec->vendor = strdup((*strptr) + 8);
+ else if (!strncmp("BuildHost: ", *strptr, 11))
+ spec->buildHost = strdup((*strptr) + 11);
+ else if (!strncmp("BuildTime: ", *strptr, 11))
+ spec->buildTime = atoi((*strptr) + 11);
+ else if (!strncmp("Copyright: ", *strptr, 11))
+ spec->copyright = strdup((*strptr) + 11);
+ else if (!strncmp("%speci", *strptr, 6)) {
+ inFilelist = 1;
+ files = strptr + 1;
+ }
+ }
+ }
+
+ spec->files = malloc(sizeof(struct oldrpmFileInfo) * spec->fileCount);
+ if (!spec->files) {
+ freeSplitString(lines);
+ return "out of memory";
+ }
+
+ for (strptr = files, i = 0; *strptr; strptr++, i++) {
+ if (**strptr)
+ oldrpmfileFromSpecLine(*strptr, spec->files + i);
+ }
+
+ freeSplitString(lines);
+
+ if (!spec->vendor) spec->vendor = strdup("");
+ if (!spec->description) spec->description = strdup("");
+ if (!spec->distribution) spec->distribution = strdup("");
+ if (!spec->copyright) spec->copyright = strdup("");
+
+ return NULL;
+}
+
+static void infoFromFields(char ** fields, struct oldrpmFileInfo * fi);
+
+void oldrpmfileFromInfoLine(char * path, char * state, char * str,
+ struct oldrpmFileInfo * fi) {
+ char ** fields;
+
+ fields = splitString(str, strlen(str), ' ');
+
+ fi->path = strdup(path);
+ if (!strcmp(state, "normal"))
+ fi->state = RPMFILE_STATE_NORMAL;
+ else if (!strcmp(state, "replaced"))
+ fi->state = RPMFILE_STATE_REPLACED;
+ else
+ error(RPMERR_INTERNAL, "bad file state: ", state);
+
+ infoFromFields(fields, fi);
+
+ freeSplitString(fields);
+}
+
+void oldrpmfileFromSpecLine(char * str, struct oldrpmFileInfo * fi) {
+ char ** fields;
+
+ fields = splitString(str, strlen(str), ' ');
+
+ fi->path = strdup(fields[0]);
+ fi->state = RPMFILE_STATE_NORMAL;
+
+ infoFromFields(fields + 1, fi);
+
+ freeSplitString(fields);
+}
+
+void infoFromFields(char ** fields, struct oldrpmFileInfo * fi) {
+ fi->size = strtol(fields[0], NULL, 10);
+ fi->mtime = strtol(fields[1], NULL, 10);
+ strcpy(fi->md5, fields[2]);
+ fi->mode = strtol(fields[3], NULL, 8);
+ fi->uid = strtol(fields[4], NULL, 10);
+ fi->gid = strtol(fields[5], NULL, 10);
+ fi->isconf = fields[6][0] != '0';
+ fi->isdoc = fields[7][0] != '0';
+ fi->rdev = strtol(fields[8], NULL, 16);
+
+ if (S_ISLNK(fi->mode)) {
+ fi->linkto = strdup(fields[9]);
+ } else {
+ fi->linkto = NULL;
+ }
+}
+
+void oldrpmfileFree(struct oldrpmFileInfo * fi) {
+ free(fi->path);
+ fi->linkto ? free(fi->linkto) : 0;
+}
+
+char * oldrpmfileToInfoStr(struct oldrpmFileInfo * fi) {
+ char * buf;
+
+ if (fi->linkto)
+ buf = malloc(strlen(fi->linkto) + 100);
+ else
+ buf = malloc(100);
+
+ sprintf(buf, "%ld %ld %s %o %d %d %s %s %x ", fi->size, fi->mtime,
+ fi->md5, fi->mode, fi->uid, fi->gid,
+ fi->isconf ? "1" : "0", fi->isdoc ? "1" : "0",
+ fi->rdev);
+
+ if (fi->linkto)
+ strcat(buf, fi->linkto);
+ else
+ strcat(buf, "X");
+
+ return buf;
+}