/* * Copyright (c) 2005 Michael Schroeder (mls@suse.de) * * This program is licensed under the BSD license, read LICENSE.BSD * for further information */ #include #include #include #include #include #include #include #include #include #include #include "md5.h" #include "rpmhead.h" #include "cfile.h" #include "deltarpm.h" #include "util.h" 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); } } void writedeltarpm(struct deltarpm *d, unsigned char **indatalist) { int fd, i; MD5_CTX paymd5; unsigned char paymd5res[16]; unsigned char oldpayformat[4]; unsigned int written; struct cfile *bfd; unsigned char sighdr[16 + 16 * 3 + 4 + 16 + 16 + 4]; if (!d->h && d->version < 0x444c5433) { fprintf(stderr, "%s: rpm only deltarpm not supported in V1 or V2 deltarpms\n", d->name); exit(1); } #ifdef DELTARPM_64BIT if ((d->outlen >= 0x100000000ULL || d->inlen >= 0x100000000ULL) && d->version < 0x444c5433) { fprintf(stderr, "%s: cpio sizes >4GB not supported in V1 or V2 deltarpms\n", d->name); exit(1); } #endif if (!strcmp(d->name, "-")) fd = 1; else if ((fd = open(d->name, O_RDWR|O_CREAT|O_TRUNC, 0666)) == -1) { perror(d->name); exit(1); } rpmMD5Init(&paymd5); if (d->h) { if (write(fd, d->rpmlead, 96) != 96) { perror("rpmlead write"); exit(1); } memset(sighdr, 0, sizeof(sighdr)); sighdr[0] = 0x8e; sighdr[1] = 0xad; sighdr[2] = 0xe8; sighdr[3] = 0x01; sighdr[11] = 3; sighdr[15] = 4 + 16 + 16; sighdr[16*1+3] = 0x3e; /* HEADER_SIGNATURES */ sighdr[16*1+7] = 7; sighdr[16*1+11] = 4 + 16; sighdr[16*1+15] = 16; sighdr[16*2+2] = 0x03; /* size */ sighdr[16*2+3] = 0xe8; sighdr[16*2+7] = 4; sighdr[16*2+15] = 1; sighdr[16*3+2] = 0x03; /* md5 */ sighdr[16*3+3] = 0xec; sighdr[16*3+7] = 7; sighdr[16*3+11] = 4; sighdr[16*3+15] = 16; sighdr[16 + 16 * 3 + 4 + 16 + 3] = 0x3e; sighdr[16 + 16 * 3 + 4 + 16 + 7] = 7; sighdr[16 + 16 * 3 + 4 + 16 + 8] = 0xff; sighdr[16 + 16 * 3 + 4 + 16 + 9] = 0xff; sighdr[16 + 16 * 3 + 4 + 16 + 10] = 0xff; sighdr[16 + 16 * 3 + 4 + 16 + 11] = 256 - 3 * 16; sighdr[16 + 16 * 3 + 4 + 16 + 15] = 16; if (write(fd, sighdr, sizeof(sighdr)) != sizeof(sighdr)) { perror("sig hdr write"); exit(1); } if (write(fd, d->h->intro, 16) != 16) { perror("hdr write"); exit(1); } rpmMD5Update(&paymd5, d->h->intro, 16); if (d->payformatoff) { memcpy(oldpayformat, d->h->dp + d->payformatoff, 4); memcpy(d->h->dp + d->payformatoff, "drpm", 4); } if (write(fd, d->h->data, 16 * d->h->cnt + d->h->dcnt) != 16 * d->h->cnt + d->h->dcnt) { perror("hdr write"); exit(1); } rpmMD5Update(&paymd5, d->h->data, 16 * d->h->cnt + d->h->dcnt); if (d->payformatoff) memcpy(d->h->dp + d->payformatoff, oldpayformat, 4); } else { unsigned char *intro; int nevrlen; nevrlen = strlen(d->targetnevr) + 1; intro = xmalloc(4 + 4 + 4 + nevrlen + 4); memcpy(intro, "drpm", 4); intro[4] = d->version >> 24; intro[5] = d->version >> 16; intro[6] = d->version >> 8; intro[7] = d->version; intro[8] = nevrlen >> 24; intro[9] = nevrlen >> 16; intro[10] = nevrlen >> 8; intro[11] = nevrlen; memcpy(intro + 12 , d->targetnevr, nevrlen); intro[12 + nevrlen] = d->addblklen >> 24; intro[13 + nevrlen] = d->addblklen >> 16; intro[14 + nevrlen] = d->addblklen >> 8; intro[15 + nevrlen] = d->addblklen; if (write(fd, intro, 4 + 4 + 4 + nevrlen + 4) != 4 + 4 + 4 + nevrlen + 4) { perror("header write"); exit(1); } xfree(intro); if (d->addblklen) { if (write(fd, d->addblk, d->addblklen) != d->addblklen) { perror("add data write"); exit(1); } } } if ((bfd = cfile_open(CFILE_OPEN_WR, fd, 0, d->deltacomp, CFILE_LEN_UNLIMITED, (cfile_ctxup)rpmMD5Update, &paymd5)) == 0) { fprintf(stderr, "payload open failed\n"); exit(1); } write32(bfd, d->version); write32(bfd, strlen(d->nevr) + 1); if (bfd->write(bfd, d->nevr, strlen(d->nevr) + 1) != strlen(d->nevr) + 1) { fprintf(stderr, "payload write failed\n"); exit(1); } write32(bfd, d->seql); if (bfd->write(bfd, d->seq, d->seql) != d->seql) { fprintf(stderr, "payload write failed\n"); exit(1); } if (bfd->write(bfd, d->targetmd5, 16) != 16) { fprintf(stderr, "payload write failed\n"); exit(1); } if (d->version != 0x444c5431) { write32(bfd, d->targetsize); write32(bfd, d->targetcomp); write32(bfd, 0); if (d->version != 0x444c5432) { write32(bfd, d->compheadlen); write32(bfd, d->offadjn); for (i = 0; i < d->offadjn; i++) write32(bfd, d->offadjs[2 * i]); for (i = 0; i < d->offadjn; i++) { if ((int)d->offadjs[2 * i + 1] < 0) write32(bfd, (unsigned int)(-(int)d->offadjs[2 * i + 1]) | 0x80000000); else write32(bfd, d->offadjs[2 * i + 1]); } } } write32(bfd, d->leadl); if (bfd->write(bfd, d->lead, d->leadl) != d->leadl) { fprintf(stderr, "payload write failed\n"); exit(1); } write32(bfd, d->payformatoff); write32(bfd, d->inn); write32(bfd, d->outn); for (i = 0; i < d->inn; i++) write32(bfd, d->in[2 * i]); for (i = 0; i < d->inn; i++) write32(bfd, d->in[2 * i + 1]); for (i = 0; i < d->outn; i++) { if ((int)d->out[2 * i] < 0) write32(bfd, (unsigned int)(-d->out[2 * i]) | 0x80000000); else write32(bfd, d->out[2 * i]); } for (i = 0; i < d->outn; i++) write32(bfd, d->out[2 * i + 1]); #ifdef DELTARPM_64BIT if (d->version > 0x444c5432) write32(bfd, (unsigned int)(d->outlen >> 32)); #else if (d->version > 0x444c5432) write32(bfd, 0); #endif write32(bfd, (unsigned int)d->outlen); if (d->h) { write32(bfd, d->addblklen); if (d->addblklen) { if (bfd->write(bfd, d->addblk, d->addblklen) != d->addblklen) { fprintf(stderr, "add data write failed\n"); exit(1); } } } else write32(bfd, 0); #ifdef DELTARPM_64BIT if (d->version > 0x444c5432) write32(bfd, (unsigned int)(d->inlen >> 32)); #else if (d->version > 0x444c5432) write32(bfd, 0); #endif write32(bfd, (unsigned int)d->inlen); if (d->inlen) { if (indatalist) { for (i = 0; i < d->inn; i++) if (bfd->write(bfd, indatalist[i], d->in[2 * i + 1]) != d->in[2 * i + 1]) { fprintf(stderr, "data write failed\n"); exit(1); } } else if (bfd->write(bfd, d->indata, d->inlen) != d->inlen) { fprintf(stderr, "data write failed\n"); exit(1); } } if ((written = bfd->close(bfd)) == -1) { fprintf(stderr, "payload write failed\n"); exit(1); } rpmMD5Final(paymd5res, &paymd5); if (d->h) { if (lseek(fd, (off_t)96, SEEK_SET) == (off_t)-1) { fprintf(stderr, "sig seek failed\n"); exit(1); } /* add header size */ written += 16 + d->h->cnt * 16 + d->h->dcnt; sighdr[16 + 16 * 3 + 0] = written >> 24; sighdr[16 + 16 * 3 + 1] = written >> 16; sighdr[16 + 16 * 3 + 2] = written >> 8; sighdr[16 + 16 * 3 + 3] = written; memcpy(&sighdr[16 + 16 * 3 + 4], paymd5res, 16); if (write(fd, sighdr, sizeof(sighdr)) != sizeof(sighdr)) { fprintf(stderr, "sig write failed\n"); exit(1); } } if (strcmp(d->name, "-") != 0 && close(fd) != 0) { fprintf(stderr, "payload write failed\n"); exit(1); } }