/* * Copyright (c) 2005 Michael Schroeder (mls@suse.de) * * This program is licensed under the BSD license, read LICENSE.BSD * for further information */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include "rpmhead.h" #include "md5.h" #include "util.h" #include "cfile.h" struct rpmpay { char *name; unsigned int x; unsigned int lx; off64_t o; unsigned int l; unsigned char lmd5[16]; unsigned char hmd5[16]; }; static unsigned int get4(unsigned char *p) { return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; } static unsigned int get4n(unsigned char *p) { return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; } static void readblk(FILE *fp, unsigned char *blk, unsigned int num) { if (fseeko64(fp, 0x800 * (off64_t)num, SEEK_SET) != 0) { perror("fseeko"); exit(1); } if (fread(blk, 0x800, 1, fp) != 1) { perror("fread"); exit(1); } } static struct rpmpay *rpmpays; static int rpmpayn; static void addrpm(char *name, off64_t o, unsigned int l, unsigned char *lmd5, unsigned char *hmd5) { char *n; if ((rpmpayn & 31) == 0) { if (rpmpays == 0) rpmpays = malloc(32 * sizeof(*rpmpays)); else rpmpays = realloc(rpmpays, (rpmpayn + 32) * sizeof(*rpmpays)); if (!rpmpays) { fprintf(stderr, "out of mem\n"); exit(1); } } n = name ? strdup(name) : 0; if (name && !n) { fprintf(stderr, "out of mem\n"); exit(1); } rpmpays[rpmpayn].name = n; rpmpays[rpmpayn].o = o; rpmpays[rpmpayn].l = l; rpmpays[rpmpayn].x = 0; rpmpays[rpmpayn].lx = 0; if (lmd5) memcpy(rpmpays[rpmpayn].lmd5, lmd5, 16); else memset(rpmpays[rpmpayn].lmd5, 0, 16); if (hmd5) memcpy(rpmpays[rpmpayn].hmd5, hmd5, 16); else memset(rpmpays[rpmpayn].hmd5, 0, 16); rpmpayn++; } static int sortrpmcmp(const void *av, const void *bv) { const struct rpmpay *a = av; const struct rpmpay *b = bv; if (a->o < b->o) return -1; if (a->o > b->o) return 1; return strcmp(a->name, b->name); } static void sortrpm() { if (!rpmpayn) return; qsort(rpmpays, rpmpayn, sizeof(*rpmpays), sortrpmcmp); } void readrpm(char *name, FILE *fp, unsigned int filepos, unsigned int filelen) { static unsigned int rpmbalen; static unsigned char *rpmb; int rpmblen; int len, hcnt, hdcnt, hoffset; struct rpmhead *h, *sigh; char *rpmn, *rpma; unsigned char lmd5[16], *hmd5; char nbuf[256 * 3]; char *suf; MD5_CTX ctx; unsigned int filepos2 = filepos; len = strlen(name); suf = ""; if (len > 10 && !strcmp(name + len - 10, ".delta.rpm")) suf = ".delta"; else if (len > 10 && !strcmp(name + len - 10, ".patch.rpm")) suf = ".patch"; if (!rpmb) { rpmbalen += 0x800 * 4; rpmb = xrealloc(rpmb, rpmbalen); } readblk(fp, rpmb, filepos++); rpmblen = 0x800; if (get4(rpmb) != 0xdbeeabed) return; /* not really a rpm */ if (get4(rpmb + 0x60) != 0x01e8ad8e) { fprintf(stderr, "bad rpm (bad sigheader): %s\n", name); exit(1); } hcnt = get4n(rpmb + 0x68); hdcnt = get4n(rpmb + 0x6c); if ((hdcnt & 7) != 0) hdcnt += 8 - (hdcnt & 7); len = 0x60 + 16 + hcnt * 16 + hdcnt + 16; if (len > filelen) { fprintf(stderr, "bad rpm (EOF): %s\n", name); exit(1); } while (rpmblen < len) { if (rpmblen + 0x800 > rpmbalen) { rpmbalen += 0x800 * 4; rpmb = xrealloc(rpmb, rpmbalen); } readblk(fp, rpmb + rpmblen, filepos++); rpmblen += 0x800; } sigh = readhead_buf(rpmb + 0x60, len - 16, 1); if (!sigh) { fprintf(stderr, "bad rpm (bad sigh): %s\n", name); exit(1); } hoffset = len - 16; if (get4(rpmb + hoffset) != 0x01e8ad8e) { fprintf(stderr, "bad rpm (bad header): %s\n", name); exit(1); } hcnt = get4n(rpmb + hoffset + 8); hdcnt = get4n(rpmb + hoffset + 12); len += hcnt * 16 + hdcnt; if (len > filelen) { fprintf(stderr, "bad rpm (EOF): %s\n", name); exit(1); } while (rpmblen < len) { if (rpmblen + 0x800 > rpmbalen) { rpmbalen += 0x800 * 4; rpmb = xrealloc(rpmb, rpmbalen); } readblk(fp, rpmb + rpmblen, filepos++); rpmblen += 0x800; } h = readhead_buf(rpmb + hoffset, 16 + hcnt * 16 + hdcnt, 0); if (!h) { fprintf(stderr, "bad rpm (bad h): %s\n", name); exit(1); } /* ok, all header are read in, extract information */ rpmn = headstring(h, TAG_NAME); if (!rpmn) { fprintf(stderr, "bad rpm (header contains no name): %s\n", name); exit(1); } rpma = headstring(h, TAG_ARCH); if (!rpma) { fprintf(stderr, "bad rpm (header contains no arch): %s\n", name); exit(1); } if (strlen(rpmn) > 256 || strchr(rpmn, ' ') || strchr(rpmn, '/') || strchr(rpmn, '\n')) rpmn = "unknown"; if (!headstring(h, TAG_SOURCERPM)) { if (headtagtype(h, TAG_NOSOURCE) || headtagtype(h, TAG_NOPATCH)) rpma = "nosrc"; else rpma = "src"; } if (strlen(rpma) > 256 || strchr(rpma, ' ') || strchr(rpma, '/') || strchr(rpma, '\n')) rpma = "unknown"; hmd5 = headbin(sigh, SIGTAG_MD5, 16); if (!hmd5) { fprintf(stderr, "bad rpm (signature contains no md5 entry): %s\n", name); exit(1); } sprintf(nbuf, "%s.%s%s", rpmn, rpma, suf); rpmMD5Init(&ctx); rpmMD5Update(&ctx, rpmb, hoffset); rpmMD5Final(lmd5, &ctx); addrpm(nbuf, 0x800 * (off64_t)filepos2, filelen, lmd5, hmd5); h = xfree(h); sigh = xfree(sigh); } int rpmoffs(FILE *fp, char *isoname, struct rpmpay **retp) { unsigned char blk[0x800]; unsigned char blk2[0x800]; unsigned char name[256]; int namel; unsigned int filepos, filelen; unsigned char *pt, *ep; int i, j, l, nl, el, nml, nmf; unsigned int path_table_size; unsigned int path_table_pos; unsigned int dirpos, dirlen; int sp_bytes_skip = 0; unsigned int ce_blk; unsigned int ce_off; unsigned int ce_len; readblk(fp, blk, 16); if (memcmp(blk, "\001CD001", 6)) { fprintf(stderr, "primary volume descriptor missing\n"); exit(1); } path_table_size = get4(blk + 132); path_table_pos = get4(blk + 140); pt = malloc(path_table_size); if (!pt) { fprintf(stderr, "out of mem\n"); exit(1); } readblk(fp, blk, path_table_pos); if (fseeko64(fp, 0x800 * (off64_t)path_table_pos, SEEK_SET) != 0) { perror("fseeko64"); exit(1); } if (fread(pt, path_table_size, 1, fp) != 1) { perror("fread"); exit(1); } for (i = 0; i < path_table_size; ) { l = pt[i]; if (l == 0) { fprintf(stderr, "empty dir in path table\n"); exit(1); } dirpos = get4(pt + i + 2); i += 8 + l + (l & 1); readblk(fp, blk, dirpos); dirlen = get4(blk + 10); if (dirlen & 0x7ff) { fprintf(stderr, "bad directory len\n"); exit(1); } for(j = 0; dirlen; ) { if (j == 0x800 || (l = blk[j]) == 0) { readblk(fp, blk, ++dirpos); j = 0; dirlen -= 0x800; continue; } if (j + l > 0x800) { fprintf(stderr, "bad dir entry\n"); exit(1); } if ((blk[j + 25] & 2) != 0) /* directory? */ { j += l; continue; } if ((blk[j + 25] & 4) != 0) /* associated file? */ { fprintf(stderr, "associated file\n"); exit(1); } if (blk[j + 26] != 0 || blk[j + 27] != 0) { fprintf(stderr, "interleaved file\n"); exit(1); } filepos = get4(blk + j + 2); filelen = get4(blk + j + 10); nl = blk[j + 32]; if (nl == 0 || j + nl + 33 > 0x800) { fprintf(stderr, "bad dir entry\n"); exit(1); } if ((nl & 1) == 0) nl++; ep = blk + j + 33 + nl; el = l - nl - 33; if (el >= 7 && ep[0] == 'S' && ep[1] == 'P') sp_bytes_skip = ep[6]; else { ep += sp_bytes_skip; el -= sp_bytes_skip; } ce_len = 0; ce_blk = 0; ce_off = 0; namel = 0; nmf = 0; for (;;) { if (el <= 2) { if (!ce_len) break; readblk(fp, blk2, ce_blk); ep = blk2 + ce_off; el = ce_len; ce_len = 0; } if (ep[0] == 'C' && ep[1] == 'E') { ce_blk = get4(ep + 4); ce_off = get4(ep + 12); ce_len = get4(ep + 20); } else if (ep[0] == 'N' && ep[1] == 'M') { nml = ep[2] - 5; if ((nmf & 1) == 0) namel = 0; nmf = ep[4]; if (namel + nml + 2 >= sizeof(name)) { fprintf(stderr, "name overflow\n"); exit(1); } strncpy((char *)name + namel, (char *)ep + 5, nml); namel += nml; name[namel] = 0; } el -= ep[2]; ep += ep[2]; } j += l; if (namel < 5) continue; if (filelen < 0x70 || (strcmp((char *)name + namel - 4, ".rpm") && strcmp((char *)name + namel - 4, ".spm"))) continue; readrpm((char *)name, fp, filepos, filelen); #if 0 readblk(fp, blk2, filepos); filepos2 = filepos; if (get4(blk2) != 0xdbeeabed) continue; if (get4(blk2 + 0x60) != 0x01e8ad8e) { fprintf(stderr, "bad rpm (bad sigheader): %s\n", name); exit(1); } hcnt = get4n(blk2 + 0x68); hdcnt = get4n(blk2 + 0x6c); if ((hdcnt & 7) != 0) hdcnt += 8 - (hdcnt & 7); if (0x70 + hcnt * 16 + hdcnt + 0x70 >= filelen) { fprintf(stderr, "bad rpm (no header): %s\n", name); exit(1); } hstart = 0x70 + hcnt * 16 + hdcnt; if (hstart >= 0x800) { filepos2 += hstart / 0x800; readblk(fp, blk2, filepos2); hstart &= 0x7ff; } if (get4(blk2 + hstart) != 0x01e8ad8e) { fprintf(stderr, "bad rpm (bad header): %s\n", name); exit(1); } hstart += 8; if (hstart >= 0x800) { filepos2++; readblk(fp, blk2, filepos2); hstart &= 0x7ff; } hcnt = get4n(blk2 + hstart); hdcnt = get4n(blk2 + hstart + 4); hstart += 0x8 + hcnt * 16 + hdcnt; if (hstart >= 0x800) { filepos2 += hstart / 0x800; hstart &= 0x7ff; } if (hstart + (filepos2 - filepos) * 0x800 > filelen) { fprintf(stderr, "bad rpm (no payload): %s\n", name); exit(1); } paystart = 0x800 * (off64_t)filepos2 + hstart; paylen = filelen - (hstart + (filepos2 - filepos) * 0x800); namel -= 4; name[namel] = 0; l = namel; if (l > 6 && !strncmp((char *)name + l - 6, ".patch", 6)) l -= 6; if (l > 6 && !strncmp((char *)name + l - 6, ".delta", 6)) l -= 6; l--; while (l > 0 && name[l] != '.') l--; if (l) { int l2 = l; l--; while (l > 0 && name[l] != '-') l--; if (l) { l--; while (l > 0 && name[l] != '-') l--; if (l) { memmove(name + l, name + l2, namel - l2 + 1); namel -= l2 - l; } } } addrpm((char *)name, paystart, paylen); #endif } } sortrpm(); addrpm(0, 0, 0, 0, 0); i = rpmpayn - 1; *retp = rpmpays; rpmpayn = 0; rpmpays = 0; return i; } static void write32(struct cfile *cf, unsigned int d) { unsigned char dd[4]; dd[0] = d >> 24; dd[1] = d >> 16; dd[2] = d >> 8; dd[3] = d; if (cf->write(cf, dd, 4) != 4) { perror("write32"); exit(1); } } static void write64(struct cfile *cf, off64_t d) { unsigned char dd[8]; dd[0] = d >> 56; dd[1] = d >> 48; dd[2] = d >> 40; dd[3] = d >> 32; dd[4] = d >> 24; dd[5] = d >> 16; dd[6] = d >> 8; dd[7] = d; if (cf->write(cf, dd, 8) != 8) { perror("write64"); exit(1); } } static unsigned int read32(struct cfile *bfp) { unsigned char d[4]; if (bfp->read(bfp, d, 4) != 4) { perror("read32 error"); exit(1); } return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; } static off64_t read64(struct cfile *bfp) { unsigned char d[8]; if (bfp->read(bfp, d, 8) != 8) { perror("read64 error"); exit(1); } return (off64_t)d[0] << 56 | (off64_t)d[1] << 48 | (off64_t)d[2] << 40 | (off64_t)d[3] << 32 | (off64_t)d[4] << 24 | (off64_t)d[5] << 16 | (off64_t)d[6] << 8 | (off64_t)d[7]; } void make(char *iso, char *fiso) { int i, j; FILE *fp, *ofp; struct rpmpay *pays = 0; int payn = 0; struct cfile *cfp; char buf[8192]; unsigned int l, l2; off64_t o, lo; if (!strcmp(iso, "-")) fp = stdin; else if ((fp = fopen64(iso, "r")) == 0) { perror(iso); exit(1); } payn = rpmoffs(fp, iso, &pays); for (i = j = 0; i < payn; i++) { if (i && pays[i - 1].o == pays[i].o) continue; if (i != j) pays[j] = pays[i]; j++; } payn = j; if (!strcmp(fiso, "-")) ofp = stdout; else if ((ofp = fopen64(fiso, "w")) == 0) { perror(fiso); exit(1); } fputc('F', ofp); fputc('I', ofp); fputc('S', ofp); fputc('O', ofp); fputc(0, ofp); fputc(0, ofp); fputc(0, ofp); fputc(1, ofp); cfp = cfile_open(CFILE_OPEN_WR, CFILE_IO_FILE, ofp, CFILE_COMP_GZ, CFILE_LEN_UNLIMITED, 0, 0); if (!cfp) { fprintf(stderr, "could not open compression stream\n"); exit(1); } write32(cfp, payn); for (i = 0; i < payn; i++) { write64(cfp, pays[i].o); write32(cfp, pays[i].l); j = strlen(pays[i].name) + 1; write32(cfp, j); if (cfp->write(cfp, pays[i].name, j) != j) { fprintf(stderr, "write error\n"); exit(1); } if (cfp->write(cfp, pays[i].lmd5, 16) != 16) { fprintf(stderr, "write error\n"); exit(1); } if (cfp->write(cfp, pays[i].hmd5, 16) != 16) { fprintf(stderr, "write error\n"); exit(1); } } o = 0; if (fseeko64(fp, o, SEEK_SET)) { fprintf(stderr, "%s: seek error\n", iso); exit(1); } for (i = 0; i < payn; i++) { if (o < pays[i].o) { lo = pays[i].o - o; while (lo > 0) { l2 = lo > sizeof(buf) ? sizeof(buf) : lo; if (fread(buf, l2, 1, fp) != 1) { fprintf(stderr, "%s: read error\n", iso); exit(1); } if (cfp->write(cfp, buf, l2) != l2) { fprintf(stderr, "write error\n"); exit(1); } lo -= l2; } o = pays[i].o; } o += pays[i].l; if (fseeko64(fp, o, SEEK_SET)) { fprintf(stderr, "%s: seek error\n", iso); exit(1); } } /* now to EOF */ while ((l = fread(buf, 1, sizeof(buf), fp)) > 0) { if (cfp->write(cfp, buf, l) != l) { fprintf(stderr, "write error\n"); exit(1); } } if (ferror(fp)) { fprintf(stderr, "%s: read error\n", iso); exit(1); } if (fp != stdin) fclose(fp); if (cfp->close(cfp) == -1) { fprintf(stderr, "close error\n"); exit(1); } if (fflush(ofp) || (ofp != stdout && fclose(ofp) != 0)) { fprintf(stderr, "write error\n"); exit(1); } } static int readfiso(FILE *fp, char *fiso, struct cfile **cfpp, struct rpmpay **paysp) { char magic[8]; unsigned int version; struct cfile *cfp; int i, payn, nl; struct rpmpay *pays; off64_t o; if (fread(magic, 8, 1, fp) != 1) { fprintf(stderr, "%s: not a fragiso file\n", fiso); exit(1); } if (magic[0] != 'F' || magic[1] != 'I' || magic[2] != 'S' || magic[3] != 'O') { fprintf(stderr, "%s: not a fragiso file\n", fiso); exit(1); } version = magic[4] << 24 | magic[5] << 16 | magic[6] << 8 || magic[7]; if (version != 1) { fprintf(stderr, "%s: unknown fragiso version: %d\n", fiso, version); exit(1); } cfp = cfile_open(CFILE_OPEN_RD, CFILE_IO_FILE, fp, CFILE_COMP_XX, CFILE_LEN_UNLIMITED, 0, 0); if (!cfp) { fprintf(stderr, "could not open compression stream\n"); exit(1); } payn = read32(cfp); pays = xmalloc2(payn, sizeof(*pays)); o = 0; for (i = 0; i < payn; i++) { pays[i].o = read64(cfp); pays[i].l = read32(cfp); if (pays[i].o <= o || pays[i].l < 0x70) { fprintf(stderr, "%s: bad fragiso\n", fiso); exit(1); } o = pays[i].o; nl = read32(cfp); pays[i].name = xmalloc(nl + 1); if (cfp->read(cfp, pays[i].name, nl) != nl) { fprintf(stderr, "read error\n"); exit(1); } pays[i].name[nl] = 0; if (cfp->read(cfp, pays[i].lmd5, 16) != 16) { fprintf(stderr, "read error\n"); exit(1); } if (cfp->read(cfp, pays[i].hmd5, 16) != 16) { fprintf(stderr, "read error\n"); exit(1); } } *cfpp = cfp; *paysp = pays; return payn; } static char * checknamearch(char *na) { int i, c, n; n = 0; for (i = 0; ; i++) { c = ((unsigned char *)na)[i]; if (c <= 32 || c == '/') break; if (c == '.') { if (i == 0 || !na[i + 1]) break; n++; } } if (c || !n) return "unknown.unknown"; return na; } static void list(struct rpmpay *pays, int payn) { int i, j; for (i = 0; i < payn; i++) { printf("%010llx:%08x ", (unsigned long long)pays[i].o, pays[i].l); for (j = 0; j < 16; j++) { putchar("0123456789abcdef"[pays[i].lmd5[j] >> 4]); putchar("0123456789abcdef"[pays[i].lmd5[j] & 15]); } for (j = 0; j < 16; j++) { putchar("0123456789abcdef"[pays[i].hmd5[j] >> 4]); putchar("0123456789abcdef"[pays[i].hmd5[j] & 15]); } printf(" %s\n", checknamearch(pays[i].name)); } } void listfiso(char *fiso) { FILE *fp; struct cfile *cf; int payn; struct rpmpay *pays; if (!strcmp(fiso, "-")) fp = stdin; else if ((fp = fopen64(fiso, "r")) == 0) { perror(fiso); exit(1); } payn = readfiso(fp, fiso, &cf, &pays); cf->close(cf); if (fp != stdin) fclose(fp); list(pays, payn); } void listiso(char *iso) { FILE *fp; int payn, i, j; struct rpmpay *pays; if (!strcmp(iso, "-")) fp = stdin; else if ((fp = fopen64(iso, "r")) == 0) { perror(iso); exit(1); } payn = rpmoffs(fp, iso, &pays); if (fp != stdin) fclose(fp); for (i = j = 0; i < payn; i++) { if (i && pays[i - 1].o == pays[i].o) continue; if (i != j) pays[j] = pays[i]; j++; } payn = j; list(pays, payn); } void assemble(char *fiso, char *dir, char *iso) { FILE *fp, *rfp, *ofp; struct cfile *cf; int i, payn; struct rpmpay *pays; char *dbuf; int dl; off64_t o, lo; unsigned char buf[8192]; int l2; unsigned int l, cl = 0, cl2; MD5_CTX ctx; int start; unsigned char lmd5[16]; dl = strlen(dir) + 1; dbuf = xmalloc(dl + 10 + 1 + 8 + 1); strcpy(dbuf, dir); dbuf[dl - 1] = '/'; if (!strcmp(fiso, "-")) fp = stdin; else if ((fp = fopen64(fiso, "r")) == 0) { perror(fiso); exit(1); } payn = readfiso(fp, fiso, &cf, &pays); if (!strcmp(iso, "-")) ofp = stdout; else if ((ofp = fopen64(iso, "w")) == 0) { perror(iso); exit(1); } o = 0; for (i = 0; i < payn; i++) { if (o < pays[i].o) { lo = pays[i].o - o; while (lo > 0) { l2 = lo > sizeof(buf) ? sizeof(buf) : lo; if (cf->read(cf, buf, l2) != l2) { fprintf(stderr, "%s: read error\n", fiso); exit(1); } if (fwrite(buf, l2, 1, ofp) != 1) { fprintf(stderr, "%s: write error\n", iso); exit(1); } lo -= l2; } } o = pays[i].o; sprintf(dbuf + dl, "%010llx:%08x", (unsigned long long)pays[i].o, pays[i].l); if ((rfp = fopen64(dbuf, "r")) == 0) { perror(dbuf); exit(1); } l = pays[i].l; rpmMD5Init(&ctx); start = 1; while (l > 0) { l2 = l > sizeof(buf) ? sizeof(buf) : l; if (fread(buf, l2, 1, rfp) != 1) { fprintf(stderr, "%s: read error\n", dbuf); exit(1); } if (start) { if (get4n(buf) != 0xedabeedb || get4n(buf + 0x60) != 0x8eade801) { fprintf(stderr, "%s: not a rpm\n", dbuf); exit(1); } cl = 0x70 + get4n(buf + 0x68) * 16 + get4n(buf + 0x6c); if ((cl & 7) != 0) cl += 8 - (cl & 7); if (cl > pays[i].l) { fprintf(stderr, "%s: bad rpm\n", dbuf); exit(1); } start = 0; } if (cl) { cl2 = cl > l2 ? l2 : cl; rpmMD5Update(&ctx, buf, cl2); cl -= cl2; } if (fwrite(buf, l2, 1, ofp) != 1) { fprintf(stderr, "%s: write error\n", iso); exit(1); } l -= l2; } fclose(rfp); rpmMD5Final(lmd5, &ctx); if (memcmp(lmd5, pays[i].lmd5, 16)) { fprintf(stderr, "%s: rpm does not match\n", dbuf); exit(1); } o += pays[i].l; } while ((l2 = cf->read(cf, buf, sizeof(buf))) > 0) { if (fwrite(buf, l2, 1, ofp) != 1) { fprintf(stderr, "%s: write error\n", iso); exit(1); } } if (l2) { fprintf(stderr, "%s: read error\n", fiso); exit(1); } if (fflush(ofp) || (ofp != stdout && fclose(ofp) != 0)) { fprintf(stderr, "%s: write error\n", iso); exit(1); } } void fill(char *fiso, char *iso, int mopt) { FILE *fp, *ofp; struct cfile *cf; int i, payn; struct rpmpay *pays; off64_t o, lo; unsigned char buf[8192]; unsigned int cl, dl, cl2; MD5_CTX ctx, mctx; unsigned char lmd5[16]; int mfd; int l2; if (!strcmp(fiso, "-")) fp = stdin; else if ((fp = fopen64(fiso, "r")) == 0) { perror(fiso); exit(1); } payn = readfiso(fp, fiso, &cf, &pays); mfd = 1; if (!strcmp(iso, "-")) { ofp = stdout; mfd = 2; } else if ((ofp = fopen64(iso, "r+")) == 0) { perror(iso); exit(1); } rpmMD5Init(&mctx); o = 0; for (i = 0; i < payn; i++) { if (o < pays[i].o) { fseeko64(ofp, o, SEEK_SET); lo = pays[i].o - o; while (lo > 0) { l2 = lo > sizeof(buf) ? sizeof(buf) : lo; if (cf->read(cf, buf, l2) != l2) { fprintf(stderr, "%s: read error\n", fiso); exit(1); } if (fwrite(buf, l2, 1, ofp) != 1) { fprintf(stderr, "%s: write error\n", iso); exit(1); } if (mopt) rpmMD5Update(&mctx, buf, l2); lo -= l2; } } o = pays[i].o; /* verify that right rpm is at pos o */ fseeko64(ofp, o, SEEK_SET); if (fread(buf, 0x70, 1, ofp) != 1) { fprintf(stderr, "%s: read error\n", iso); exit(1); } if (mopt) rpmMD5Update(&mctx, buf, 0x70); if (get4n(buf) != 0xedabeedb || get4n(buf + 0x60) != 0x8eade801) { fprintf(stderr, "%llx: not a rpm\n", (unsigned long long)o); exit(1); } cl = 0x70 + get4n(buf + 0x68) * 16 + get4n(buf + 0x6c); if ((cl & 7) != 0) cl += 8 - (cl & 7); if (cl > pays[i].l) { fprintf(stderr, "%llx: bad rpm\n", (unsigned long long)o); exit(1); } dl = pays[i].l - cl; rpmMD5Init(&ctx); rpmMD5Update(&ctx, buf, 0x70); cl -= 0x70; while (cl) { cl2 = cl > sizeof(buf) ? sizeof(buf) : cl; if (fread(buf, cl2, 1, ofp) != 1) { fprintf(stderr, "%s: read error\n", iso); exit(1); } rpmMD5Update(&ctx, buf, cl2); if (mopt) rpmMD5Update(&mctx, buf, cl2); cl -= cl2; } rpmMD5Final(lmd5, &ctx); if (memcmp(lmd5, pays[i].lmd5, 16)) { fprintf(stderr, "%llx: rpm lead+signature does not match\n", (unsigned long long)o); exit(1); } rpmMD5Init(&ctx); while (dl) { cl2 = dl > sizeof(buf) ? sizeof(buf) : dl; if (fread(buf, cl2, 1, ofp) != 1) { fprintf(stderr, "%s: read error\n", iso); exit(1); } rpmMD5Update(&ctx, buf, cl2); if (mopt) rpmMD5Update(&mctx, buf, cl2); dl -= cl2; } rpmMD5Final(lmd5, &ctx); if (memcmp(lmd5, pays[i].hmd5, 16)) { fprintf(stderr, "%llx: rpm header+payload does not match\n", (unsigned long long)o); exit(1); } o += pays[i].l; } fseeko64(ofp, o, SEEK_SET); while ((l2 = cf->read(cf, buf, sizeof(buf))) > 0) { if (fwrite(buf, l2, 1, ofp) != 1) { fprintf(stderr, "%s: write error\n", iso); exit(1); } if (mopt) rpmMD5Update(&mctx, buf, l2); o += l2; } if (l2) { fprintf(stderr, "%s: read error\n", fiso); exit(1); } if (fflush(ofp)) { fprintf(stderr, "%s: write error\n", iso); exit(1); } if (ftruncate64(fileno(ofp), o)) { fprintf(stderr, "%s: truncate error\n", iso); exit(1); } if (ofp != stdout && fclose(ofp) != 0) { fprintf(stderr, "%s: write error\n", iso); exit(1); } if (mopt) { rpmMD5Final(lmd5, &mctx); for (i = 0; i < 16; i++) { buf[2 * i + 0] = "0123456789abcdef"[lmd5[i] >> 4]; buf[2 * i + 1] = "0123456789abcdef"[lmd5[i] & 15]; } buf[32] = '\n'; write(mfd, buf, 33); } } void extract(char *iso, char *offlen, char *rpm) { off64_t o; unsigned int l, l2; FILE *fp, *ofp; int i; char buf[8192]; if (strlen(offlen) != 10 + 1 + 8 || offlen[10] != ':') { fprintf(stderr, "bad off:len %s\n", offlen); exit(1); } o = 0; for (i = 0; i < 10; i++) { o <<= 4; if (offlen[i] >= '0' && offlen[i] <= '9') o |= offlen[i] - '0'; else if (offlen[i] >= 'a' && offlen[i] <= 'f') o |= offlen[i] - ('a' - 10); else if (offlen[i] >= 'A' && offlen[i] <= 'F') o |= offlen[i] - ('A' - 10); else { fprintf(stderr, "bad off:len %s\n", offlen); exit(1); } } l = 0; for (i = 0; i < 8; i++) { l <<= 4; if (offlen[11 + i] >= '0' && offlen[11 + i] <= '9') l |= offlen[11 + i] - '0'; else if (offlen[11 + i] >= 'a' && offlen[11 + i] <= 'f') l |= offlen[11 + i] - ('a' - 10); else if (offlen[11 + i] >= 'A' && offlen[11 + i] <= 'F') l |= offlen[11 + i] - ('A' - 10); else { fprintf(stderr, "bad off:len %s\n", offlen); exit(1); } } if (!strcmp(iso, "-")) fp = stdin; else if ((fp = fopen64(iso, "r")) == 0) { perror(iso); exit(1); } if (fseeko64(fp, o, SEEK_SET) != 0) { perror("fseek"); exit(1); } if (!strcmp(rpm, "-")) ofp = stdout; else if ((ofp = fopen64(rpm, "w")) == 0) { perror(rpm); exit(1); } while (l > 0) { l2 = l > sizeof(buf) ? sizeof(buf) : l; if (fread(buf, l2, 1, fp) != 1) { fprintf(stderr, "%s: read error\n", iso); exit(1); } if (fwrite(buf, l2, 1, ofp) != 1) { fprintf(stderr, "%s: write error\n", rpm); exit(1); } l -= l2; } if (fflush(ofp) || (ofp != stdout && fclose(ofp) != 0)) { fprintf(stderr, "write error\n"); exit(1); } } int main(int argc, char **argv) { if (argc == 4 && !strcmp(argv[1], "make")) make(argv[2], argv[3]); else if (argc == 3 && !strcmp(argv[1], "list")) listfiso(argv[2]); else if (argc == 3 && !strcmp(argv[1], "listiso")) listiso(argv[2]); else if (argc == 5 && !strcmp(argv[1], "assemble")) assemble(argv[2], argv[3], argv[4]); else if (argc == 5 && !strcmp(argv[1], "fill") && !strcmp(argv[2], "-m")) fill(argv[3], argv[4], 1); else if (argc == 4 && !strcmp(argv[1], "fill")) fill(argv[2], argv[3], 0); else if (argc == 5 && !strcmp(argv[1], "extract")) extract(argv[2], argv[3], argv[4]); else { fprintf(stderr, "usage: fragiso make \n"); fprintf(stderr, " fragiso list \n"); fprintf(stderr, " fragiso listiso \n"); fprintf(stderr, " fragiso assemble \n"); fprintf(stderr, " fragiso fill [-m] \n"); fprintf(stderr, " fragiso extract \n"); exit(1); } exit(0); }