From owner-p4-projects@FreeBSD.ORG Fri Mar 8 23:46:48 2013 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 18895FE; Fri, 8 Mar 2013 23:46:48 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id C7FBEFC for ; Fri, 8 Mar 2013 23:46:47 +0000 (UTC) (envelope-from brooks@freebsd.org) Received: from skunkworks.freebsd.org (skunkworks.freebsd.org [IPv6:2001:1900:2254:2068::682:0]) by mx1.freebsd.org (Postfix) with ESMTP id 9D3D7FCF for ; Fri, 8 Mar 2013 23:46:47 +0000 (UTC) Received: from skunkworks.freebsd.org ([127.0.1.74]) by skunkworks.freebsd.org (8.14.6/8.14.6) with ESMTP id r28NklBS057004 for ; Fri, 8 Mar 2013 23:46:47 GMT (envelope-from brooks@freebsd.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.6/8.14.6/Submit) id r28NklFm057001 for perforce@freebsd.org; Fri, 8 Mar 2013 23:46:47 GMT (envelope-from brooks@freebsd.org) Date: Fri, 8 Mar 2013 23:46:47 GMT Message-Id: <201303082346.r28NklFm057001@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to brooks@freebsd.org using -f From: Brooks Davis Subject: PERFORCE change 222732 for review To: Perforce Change Reviews Precedence: bulk X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.14 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 08 Mar 2013 23:46:48 -0000 http://p4web.freebsd.org/@@222732?ac=10 Change 222732 by brooks@brooks_zenith on 2013/03/08 23:46:06 Refactor to remove globals from the extract and verify code. Add some default output on success. Affected files ... .. //depot/projects/ctsrd/beribsd/src/ctsrd/writefile/writefile.c#2 edit Differences ... ==== //depot/projects/ctsrd/beribsd/src/ctsrd/writefile/writefile.c#2 (text+ko) ==== @@ -46,23 +46,35 @@ enum eav_error { EAV_SUCCESS = 0, - EAV_MEM, - EAV_MD5, - EAV_COMP_UNKNOWN, - EAV_COMP_UNSUPPORTED, - EAV_COMP_BZ + EAV_ERR_MEM, + EAV_ERR_DIGEST, + EAV_ERR_DIGEST_UNKNOWN, + EAV_ERR_COMP, + EAV_ERR_COMP_UNKNOWN, + EAV_ERR_COMP_UNSUPPORTED +}; + +enum eav_digest { + EAV_DIGEST_NONE = 0, + EAV_DIGEST_MD5 +}; + +enum eav_compression { + EAV_COMP_NONE = 0, + EAV_COMP_BZIP2, + EAV_COMP_GZIP, + EAV_COMP_XZ, + + EAV_COMP_UNKNOWN }; static void usage(int) __dead2; -int verify; -char *md5sum; - static void usage(int error) { fprintf(stderr, -"writefile [-hTvz] [-b ] [-i ] [-l length] [-m md5]\n" +"writefile [-hqTvz] [-b ] [-i ] [-l length] [-m md5]\n" " [-o ] \n"); exit(error); } @@ -87,6 +99,41 @@ return(len); } +static enum eav_compression +eav_taste(const unsigned char *buf, off_t len) +{ + + /* + * BZIP header from wikipedia: + * .magic:16 = 'BZ' signature/magic number + * .version:8 = 'h' for Bzip2 + * ('H'uffman coding), + * '0' for Bzip1 (deprecated) + * .hundred_k_blocksize:8 = '1'..'9' + * block-size 100 kB-900 kB + * .compressed_magic:48 = + * 0x314159265359 (BCD (pi)) + */ + if( len > 10 && buf[0] == 'B' && buf[1] == 'Z' && + buf[4] == 0x31 && buf[5] == 0x41 && buf[6] == 0x59 && + buf[7] == 0x26 && buf[8] == 0x53 && buf[9] == 0x59) { + if (buf[2] == 'h') + return (EAV_COMP_BZIP2); + else + /* Could be bzip 1, but that is unsupported */ + return (EAV_COMP_UNKNOWN); + } else if (len > 2 && buf[0] == 0x1f && buf[1] == 0x8b) { + /* gzip per RFC1952 */ + return (EAV_COMP_GZIP); + } else if (len > 6 && buf[0] == 0xfd && buf[1] == '7' && + buf[2] == 'z' && buf[3] == 'X' && + buf[4] == 'Z' && buf[5] == 0x00) { + /* XZ per Wikipedia */ + return (EAV_COMP_XZ); + } else + return (EAV_COMP_UNKNOWN); +} + static const char * eav_strerror(enum eav_error error) { @@ -94,16 +141,18 @@ switch (error) { case EAV_SUCCESS: return "Success"; - case EAV_MEM: + case EAV_ERR_MEM: return "malloc error"; - case EAV_MD5: - return "MD5 checksum mismatch"; - case EAV_COMP_UNKNOWN: + case EAV_ERR_DIGEST: + return "checksum mismatch"; + case EAV_ERR_DIGEST_UNKNOWN: + return "unknown digest"; + case EAV_ERR_COMP: + return "decompression error"; + case EAV_ERR_COMP_UNKNOWN: return "Unknown compression type"; - case EAV_COMP_UNSUPPORTED: + case EAV_ERR_COMP_UNSUPPORTED: return "Unsupported compression type"; - case EAV_COMP_BZ: - return "bzip2 error"; default: return "Unknown error"; } @@ -111,7 +160,9 @@ static enum eav_error extract_and_verify(unsigned char *ibuf, size_t ilen, - unsigned char **obufp, size_t *olenp, size_t blocksize, int decompress) + unsigned char **obufp, size_t *olenp, size_t blocksize, + enum eav_compression ctype, + enum eav_digest dtype, const unsigned char *digest) { int ret; char *obuf = NULL; @@ -120,44 +171,37 @@ MD5_CTX md5ctx; char i_md5sum[33]; - if (decompress || md5sum != NULL) { - if (md5sum != NULL) + switch (ctype) { + case EAV_COMP_NONE: + case EAV_COMP_BZIP2: + break; + case EAV_COMP_GZIP: + case EAV_COMP_XZ: + return (EAV_ERR_COMP_UNSUPPORTED); + default: + return (EAV_ERR_COMP_UNKNOWN); + } + + switch (dtype) { + case EAV_DIGEST_NONE: + case EAV_DIGEST_MD5: + break; + default: + return (EAV_ERR_DIGEST_UNKNOWN); + } + + if (dtype || ctype) { + if (dtype == EAV_DIGEST_MD5) MD5Init(&md5ctx); - if (decompress) { - /* - * BZIP header from wikipedia: - * .magic:16 = 'BZ' signature/magic number - * .version:8 = 'h' for Bzip2 - * ('H'uffman coding), - * '0' for Bzip1 (deprecated) - * .hundred_k_blocksize:8 = '1'..'9' - * block-size 100 kB-900 kB - * .compressed_magic:48 = - * 0x314159265359 (BCD (pi)) - */ - if(ibuf[0] == 'B' && ibuf[1] == 'Z' && - ibuf[4] == 0x31 && ibuf[5] == 0x41 && - ibuf[6] == 0x59 && ibuf[7] == 0x26 && - ibuf[8] == 0x53 && ibuf[9] == 0x59) { - if (ibuf[2] != 'h') - return (EAV_COMP_UNSUPPORTED); - } else if (ibuf[0] == 0x1f && ibuf[1] == 0x8b) { - /* gzip per RFC1952 */ - return (EAV_COMP_UNSUPPORTED); - } else if (ibuf[0] == 0xfd && ibuf[1] == '7' && - ibuf[2] == 'z' && ibuf[3] == 'X' && - ibuf[4] == 'Z' && ibuf[5] == 0x00) { - /* XZ per Wikipedia */ - return (EAV_COMP_UNSUPPORTED); - } else - return (EAV_COMP_UNKNOWN); - + if (ctype) { + /* XXX: assume bzip2 for now */ olen = 1024 * 1024; if ((obuf = malloc(olen)) == NULL) - return (EAV_MEM); + return (EAV_ERR_MEM); - /* XXX: assume bzip2 for now */ + total_in = 0; + prev_total_in = 0; bzs.bzalloc = NULL; bzs.bzfree = NULL; @@ -166,17 +210,15 @@ bzs.avail_in = MIN(ilen, 1024 * 1024); bzs.next_out = obuf; bzs.avail_out = olen; - total_in = 0; - prev_total_in = 0; if (BZ2_bzDecompressInit(&bzs, 0, 0) != BZ_OK) - return (EAV_COMP_BZ); + return (EAV_ERR_COMP); while ((ret = BZ2_bzDecompress(&bzs)) != BZ_STREAM_END) { if (ret != BZ_OK) { free(obuf); BZ2_bzDecompressEnd(&bzs); - return (EAV_COMP_BZ); + return (EAV_ERR_COMP); } total_in = ((size_t)bzs.total_in_hi32 << 32) + @@ -184,8 +226,9 @@ total_out = ((size_t)bzs.total_out_hi32 << 32) + bzs.total_out_lo32; - MD5Update(&md5ctx, ibuf + prev_total_in, - total_in - prev_total_in); + if (dtype == EAV_DIGEST_MD5) + MD5Update(&md5ctx, ibuf + prev_total_in, + total_in - prev_total_in); prev_total_in = total_in; if (bzs.avail_in == 0) @@ -197,12 +240,10 @@ if ((obuf = reallocf(obuf, olen)) == NULL) { BZ2_bzDecompressEnd(&bzs); - return (EAV_COMP_BZ); + return (EAV_ERR_COMP); } - bzs.next_out = - obuf + total_out; - bzs.avail_out = - olen - total_out; + bzs.next_out = obuf + total_out; + bzs.avail_out = olen - total_out; } } BZ2_bzDecompressEnd(&bzs); @@ -212,9 +253,9 @@ bzs.total_out_lo32; /* Push the last read block in the MD5 machine */ - MD5Update(&md5ctx, ibuf + prev_total_in, - total_in - prev_total_in); - prev_total_in = total_in; + if (dtype == EAV_DIGEST_MD5) + MD5Update(&md5ctx, ibuf + prev_total_in, + total_in - prev_total_in); /* Round up to blocksize and zero pad */ olen = roundup2(total_out, blocksize); @@ -222,17 +263,21 @@ memset(obuf + total_out, '\0', olen - total_out); /* XXX: realloc to shorten allocation? */ - } else if (md5sum != NULL) - MD5Update(&md5ctx, ibuf, ilen); + } else if (dtype) { + if (dtype == EAV_DIGEST_MD5) + MD5Update(&md5ctx, ibuf, ilen); + } - if (md5sum != NULL) { - MD5End(&md5ctx, i_md5sum); - if (strcmp(md5sum, i_md5sum) != 0) - return (EAV_MD5); + if (dtype) { + if (dtype == EAV_DIGEST_MD5) { + MD5End(&md5ctx, i_md5sum); + if (strcmp(digest, i_md5sum) != 0) + return (EAV_ERR_DIGEST); + } } } - if (!decompress) { + if (ctype == EAV_COMP_NONE) { *obufp = ibuf; *olenp = ilen; } else { @@ -263,14 +308,17 @@ int main(int argc, char *argv[]) { - char ch, *cp; + char ch, *cp, *digest = NULL; unsigned char *ibuf, *obuf = NULL, *vbuf; size_t blocksize = 0; off_t iseek = 0, oseek = 0, olen = -1, wlen = -1; - int decompress = 0, ifd, notruncate = 0, ofd, ret; + int decompress = 0, ifd, notruncate = 0, ofd, quiet = 0, ret, + verify_write = 0; + enum eav_compression ctype; + enum eav_digest dtype = EAV_DIGEST_NONE; struct stat isb, osb; - while ((ch = getopt(argc, argv, "b:hi:l:m:o:Tvz")) != -1) { + while ((ch = getopt(argc, argv, "b:hi:l:m:o:qTvz")) != -1) { switch (ch) { case 'b': if ((blocksize = parse_offset(optarg)) < 1) @@ -287,10 +335,15 @@ warnx("Invalid length %s", optarg); break; case 'm': - md5sum = optarg; - if (strlen(optarg) != 32) + if (dtype != EAV_DIGEST_NONE) { + warnx("Too many digest options"); + usage(1j); + } + dtype = EAV_DIGEST_MD5; + digest = optarg; + if (strlen(digest) != 32) warnx("invalid md5 checksum"); - for (cp = md5sum; *cp != '\0'; cp++) { + for (cp = digest; *cp != '\0'; cp++) { if (!isxdigit(*cp)) warnx("invalid md5 checksum"); *cp = tolower(*cp); @@ -300,11 +353,14 @@ if ((oseek = parse_offset(optarg)) < 1) warnx("Invalid output seek %s", optarg); break; + case 'q': + quiet = 1; + break; case 'T': notruncate = 1; break; case 'v': - verify = 1; + verify_write = 1; break; case 'z': decompress = 1; @@ -335,11 +391,23 @@ blocksize = 1; } + if (decompress) + ctype = eav_taste(ibuf, isb.st_size); + else + ctype = EAV_COMP_NONE; + if ((ret = extract_and_verify(ibuf, isb.st_size, &obuf, &olen, - blocksize, decompress)) != EAV_SUCCESS) + blocksize, ctype, dtype, digest)) != EAV_SUCCESS) errx(1, "failed to extract and verify %s: %s", argv[0], eav_strerror(ret)); + if (!quiet) { + if (dtype) + printf("verified %jd input bytes\n", isb.st_size); + if (ctype && ctype != EAV_COMP_UNKNOWN) + printf("extracted %jd bytes\n", olen); + } + if (wlen == -1) wlen = olen - iseek; else if (wlen > olen - iseek) { @@ -366,8 +434,11 @@ /* Explict close to force final writes to flash etc. */ close(ofd); + if (!quiet) + printf("wrote %jd bytes\n", wlen); + /* XXX: won't work if you can't map olen + oseek even with small olen */ - if (verify) { + if (verify_write) { if ((ofd = open(argv[1], O_RDONLY)) == -1) err(1, "open(%s)", argv[1]); if ((vbuf = mmap(NULL, wlen + oseek, PROT_READ, MAP_PRIVATE, @@ -375,6 +446,8 @@ err(1, "mmap(%s)", argv[1]); if (memcmp(obuf + iseek, vbuf + oseek, wlen) != 0) err(1, "output file does not match input!"); + if (!quiet) + printf("verified %jd written bytes\n", wlen); } if (obuf != ibuf)