#include "config.h" #include "miscfn.h" #include #include #include #include #include #include #include #include #include "misc.h" #include "oldheader.h" #include "rpmlib.h" #include "tread.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 (timedRead(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 (timedRead(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 (timedRead(fd, header->icon, header->iconLength) != header->iconLength) { oldhdrFree(header); return strerror(errno); } bytesRead += header->iconLength; } else { header->icon = NULL; } while (bytesRead < specOffset) { if (timedRead(fd, &ch, 1) != 1) { oldhdrFree(header); return strerror(errno); } bytesRead++; } if (timedRead(fd, header->spec, header->specLength) != header->specLength) { oldhdrFree(header); return strerror(errno); } bytesRead += header->specLength; while (bytesRead < archiveOffset) { if (timedRead(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); if (spec->postun) free(spec->postun); if (spec->postin) free(spec->postin); if (spec->preun) free(spec->preun); if (spec->prein) free(spec->prein); 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; char ** str = NULL; int strlength = 0; int i; enum { FILELIST, PREIN, POSTIN, PREUN, POSTUN, PREAMBLE } state = PREAMBLE; 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->prein = spec->postin = NULL; spec->preun = spec->postun = NULL; spec->fileCount = 0; for (strptr = lines; *strptr; strptr++) { if (!strncmp("%speci", *strptr, 6)) { state = FILELIST; files = strptr + 1; } else if (!strncmp("%postun", *strptr, 7)) { state = POSTUN; str = &spec->postun; } else if (!strncmp("%preun", *strptr, 6)) { state = PREUN; str = &spec->preun; } else if (!strncmp("%post", *strptr, 5)) { state = POSTIN; str = &spec->postin; } else if (!strncmp("%pre", *strptr, 4)) { state = PREIN; str = &spec->prein; } else { switch (state) { case FILELIST: if (**strptr) spec->fileCount++; break; case PREAMBLE: 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("BuildDate: ", *strptr, 11)) spec->buildTime = atoi((*strptr) + 11); else if (!strncmp("Copyright: ", *strptr, 11)) spec->copyright = strdup((*strptr) + 11); break; case PREUN: case PREIN: case POSTIN: case POSTUN: if (!*str) { *str = malloc(strlen(*strptr) + 2); strlength = 0; (*str)[0] = '\0'; } else *str = realloc(*str, strlength + strlen(*strptr) + 2); strcat(*str, *strptr); strcat(*str, "\n"); strlength += strlen(*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 rpmError(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; }