17f4caa8cSMaxim Sobolev /* 28f8cb840SMaxim Sobolev * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@FreeBSD.org> 38f8cb840SMaxim Sobolev * All rights reserved. 47f4caa8cSMaxim Sobolev * 58f8cb840SMaxim Sobolev * Redistribution and use in source and binary forms, with or without 68f8cb840SMaxim Sobolev * modification, are permitted provided that the following conditions 78f8cb840SMaxim Sobolev * are met: 88f8cb840SMaxim Sobolev * 1. Redistributions of source code must retain the above copyright 98f8cb840SMaxim Sobolev * notice, this list of conditions and the following disclaimer. 108f8cb840SMaxim Sobolev * 2. Redistributions in binary form must reproduce the above copyright 118f8cb840SMaxim Sobolev * notice, this list of conditions and the following disclaimer in the 128f8cb840SMaxim Sobolev * documentation and/or other materials provided with the distribution. 138f8cb840SMaxim Sobolev * 148f8cb840SMaxim Sobolev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158f8cb840SMaxim Sobolev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168f8cb840SMaxim Sobolev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178f8cb840SMaxim Sobolev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188f8cb840SMaxim Sobolev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198f8cb840SMaxim Sobolev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208f8cb840SMaxim Sobolev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218f8cb840SMaxim Sobolev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228f8cb840SMaxim Sobolev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238f8cb840SMaxim Sobolev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248f8cb840SMaxim Sobolev * SUCH DAMAGE. 257f4caa8cSMaxim Sobolev */ 267f4caa8cSMaxim Sobolev 278f8cb840SMaxim Sobolev #include <sys/cdefs.h> 288f8cb840SMaxim Sobolev __FBSDID("$FreeBSD$"); 298f8cb840SMaxim Sobolev 307f4caa8cSMaxim Sobolev #include <sys/types.h> 3127d0a1a4SMax Khon #include <sys/disk.h> 327f4caa8cSMaxim Sobolev #include <sys/endian.h> 337f4caa8cSMaxim Sobolev #include <sys/param.h> 34*4fc55e3eSMaxim Sobolev #include <sys/sysctl.h> 357f4caa8cSMaxim Sobolev #include <sys/stat.h> 367f4caa8cSMaxim Sobolev #include <sys/uio.h> 377f4caa8cSMaxim Sobolev #include <netinet/in.h> 38*4fc55e3eSMaxim Sobolev #include <assert.h> 398f8cb840SMaxim Sobolev #include <ctype.h> 407f4caa8cSMaxim Sobolev #include <err.h> 417f4caa8cSMaxim Sobolev #include <fcntl.h> 42*4fc55e3eSMaxim Sobolev #include <pthread.h> 437f4caa8cSMaxim Sobolev #include <signal.h> 44*4fc55e3eSMaxim Sobolev #include <stdint.h> 457f4caa8cSMaxim Sobolev #include <stdio.h> 467f4caa8cSMaxim Sobolev #include <stdlib.h> 477f4caa8cSMaxim Sobolev #include <string.h> 487f4caa8cSMaxim Sobolev #include <unistd.h> 497f4caa8cSMaxim Sobolev 508f8cb840SMaxim Sobolev #include "mkuzip.h" 518f8cb840SMaxim Sobolev #include "mkuz_cloop.h" 528f8cb840SMaxim Sobolev #include "mkuz_blockcache.h" 538f8cb840SMaxim Sobolev #include "mkuz_zlib.h" 548f8cb840SMaxim Sobolev #include "mkuz_lzma.h" 55*4fc55e3eSMaxim Sobolev #include "mkuz_blk.h" 56*4fc55e3eSMaxim Sobolev #include "mkuz_cfg.h" 57*4fc55e3eSMaxim Sobolev #include "mkuz_conveyor.h" 58*4fc55e3eSMaxim Sobolev #include "mkuz_format.h" 59*4fc55e3eSMaxim Sobolev #include "mkuz_fqueue.h" 60*4fc55e3eSMaxim Sobolev #include "mkuz_time.h" 618f8cb840SMaxim Sobolev 628f8cb840SMaxim Sobolev #define DEFAULT_CLSTSIZE 16384 638f8cb840SMaxim Sobolev 648f8cb840SMaxim Sobolev static struct mkuz_format uzip_fmt = { 658f8cb840SMaxim Sobolev .magic = CLOOP_MAGIC_ZLIB, 668f8cb840SMaxim Sobolev .default_sufx = DEFAULT_SUFX_ZLIB, 678f8cb840SMaxim Sobolev .f_init = &mkuz_zlib_init, 688f8cb840SMaxim Sobolev .f_compress = &mkuz_zlib_compress 698f8cb840SMaxim Sobolev }; 708f8cb840SMaxim Sobolev 718f8cb840SMaxim Sobolev static struct mkuz_format ulzma_fmt = { 728f8cb840SMaxim Sobolev .magic = CLOOP_MAGIC_LZMA, 738f8cb840SMaxim Sobolev .default_sufx = DEFAULT_SUFX_LZMA, 748f8cb840SMaxim Sobolev .f_init = &mkuz_lzma_init, 758f8cb840SMaxim Sobolev .f_compress = &mkuz_lzma_compress 768f8cb840SMaxim Sobolev }; 777f4caa8cSMaxim Sobolev 78*4fc55e3eSMaxim Sobolev static struct mkuz_blk *readblock(int, u_int32_t); 797f4caa8cSMaxim Sobolev static void usage(void); 807f4caa8cSMaxim Sobolev static void cleanup(void); 81*4fc55e3eSMaxim Sobolev int mkuz_memvcmp(const void *, unsigned char, size_t); 827f4caa8cSMaxim Sobolev 837f4caa8cSMaxim Sobolev static char *cleanfile = NULL; 847f4caa8cSMaxim Sobolev 85*4fc55e3eSMaxim Sobolev static int 86*4fc55e3eSMaxim Sobolev cmp_blkno(const struct mkuz_blk *bp, void *p) 87*4fc55e3eSMaxim Sobolev { 88*4fc55e3eSMaxim Sobolev uint32_t *ap; 89*4fc55e3eSMaxim Sobolev 90*4fc55e3eSMaxim Sobolev ap = (uint32_t *)p; 91*4fc55e3eSMaxim Sobolev 92*4fc55e3eSMaxim Sobolev return (bp->info.blkno == *ap); 93*4fc55e3eSMaxim Sobolev } 94*4fc55e3eSMaxim Sobolev 957f4caa8cSMaxim Sobolev int main(int argc, char **argv) 967f4caa8cSMaxim Sobolev { 97*4fc55e3eSMaxim Sobolev struct mkuz_cfg cfs; 98*4fc55e3eSMaxim Sobolev char *iname, *oname; 997f4caa8cSMaxim Sobolev uint64_t *toc; 100*4fc55e3eSMaxim Sobolev int i, io, opt, tmp; 10162ee4b69SMaxim Sobolev struct { 10262ee4b69SMaxim Sobolev int en; 10362ee4b69SMaxim Sobolev FILE *f; 10462ee4b69SMaxim Sobolev } summary; 1057f4caa8cSMaxim Sobolev struct iovec iov[2]; 1067f4caa8cSMaxim Sobolev struct stat sb; 1078f8cb840SMaxim Sobolev uint64_t offset, last_offset; 1088f8cb840SMaxim Sobolev struct cloop_header hdr; 109*4fc55e3eSMaxim Sobolev struct mkuz_conveyor *cvp; 110*4fc55e3eSMaxim Sobolev void *c_ctx; 111*4fc55e3eSMaxim Sobolev struct mkuz_blk_info *chit; 112*4fc55e3eSMaxim Sobolev size_t ncpusz, ncpu; 113*4fc55e3eSMaxim Sobolev double st, et; 114*4fc55e3eSMaxim Sobolev 115*4fc55e3eSMaxim Sobolev st = getdtime(); 116*4fc55e3eSMaxim Sobolev 117*4fc55e3eSMaxim Sobolev ncpusz = sizeof(size_t); 118*4fc55e3eSMaxim Sobolev if (sysctlbyname("hw.ncpu", &ncpu, &ncpusz, NULL, 0) < 0) { 119*4fc55e3eSMaxim Sobolev ncpu = 1; 120*4fc55e3eSMaxim Sobolev } else if (ncpu > MAX_WORKERS_AUTO) { 121*4fc55e3eSMaxim Sobolev ncpu = MAX_WORKERS_AUTO; 122*4fc55e3eSMaxim Sobolev } 1237f4caa8cSMaxim Sobolev 1247f4caa8cSMaxim Sobolev memset(&hdr, 0, sizeof(hdr)); 125*4fc55e3eSMaxim Sobolev cfs.blksz = DEFAULT_CLSTSIZE; 1267f4caa8cSMaxim Sobolev oname = NULL; 127*4fc55e3eSMaxim Sobolev cfs.verbose = 0; 128*4fc55e3eSMaxim Sobolev cfs.no_zcomp = 0; 129*4fc55e3eSMaxim Sobolev cfs.en_dedup = 0; 13062ee4b69SMaxim Sobolev summary.en = 0; 13162ee4b69SMaxim Sobolev summary.f = stderr; 132*4fc55e3eSMaxim Sobolev cfs.handler = &uzip_fmt; 133*4fc55e3eSMaxim Sobolev cfs.nworkers = ncpu; 134*4fc55e3eSMaxim Sobolev struct mkuz_blk *iblk, *oblk; 1357f4caa8cSMaxim Sobolev 136*4fc55e3eSMaxim Sobolev while((opt = getopt(argc, argv, "o:s:vZdLSj:")) != -1) { 1377f4caa8cSMaxim Sobolev switch(opt) { 1387f4caa8cSMaxim Sobolev case 'o': 1397f4caa8cSMaxim Sobolev oname = optarg; 1407f4caa8cSMaxim Sobolev break; 1417f4caa8cSMaxim Sobolev 1427f4caa8cSMaxim Sobolev case 's': 1437f4caa8cSMaxim Sobolev tmp = atoi(optarg); 1447f4caa8cSMaxim Sobolev if (tmp <= 0) { 1457f4caa8cSMaxim Sobolev errx(1, "invalid cluster size specified: %s", 1467f4caa8cSMaxim Sobolev optarg); 1477f4caa8cSMaxim Sobolev /* Not reached */ 1487f4caa8cSMaxim Sobolev } 149*4fc55e3eSMaxim Sobolev cfs.blksz = tmp; 1507f4caa8cSMaxim Sobolev break; 1517f4caa8cSMaxim Sobolev 1527f4caa8cSMaxim Sobolev case 'v': 153*4fc55e3eSMaxim Sobolev cfs.verbose = 1; 1547f4caa8cSMaxim Sobolev break; 1557f4caa8cSMaxim Sobolev 1568f8cb840SMaxim Sobolev case 'Z': 157*4fc55e3eSMaxim Sobolev cfs.no_zcomp = 1; 1588f8cb840SMaxim Sobolev break; 1598f8cb840SMaxim Sobolev 1608f8cb840SMaxim Sobolev case 'd': 161*4fc55e3eSMaxim Sobolev cfs.en_dedup = 1; 1628f8cb840SMaxim Sobolev break; 1638f8cb840SMaxim Sobolev 1648f8cb840SMaxim Sobolev case 'L': 165*4fc55e3eSMaxim Sobolev cfs.handler = &ulzma_fmt; 1668f8cb840SMaxim Sobolev break; 1678f8cb840SMaxim Sobolev 168d83e0778SMaxim Sobolev case 'S': 16962ee4b69SMaxim Sobolev summary.en = 1; 17062ee4b69SMaxim Sobolev summary.f = stdout; 171d83e0778SMaxim Sobolev break; 172d83e0778SMaxim Sobolev 173*4fc55e3eSMaxim Sobolev case 'j': 174*4fc55e3eSMaxim Sobolev tmp = atoi(optarg); 175*4fc55e3eSMaxim Sobolev if (tmp <= 0) { 176*4fc55e3eSMaxim Sobolev errx(1, "invalid number of compression threads" 177*4fc55e3eSMaxim Sobolev " specified: %s", optarg); 178*4fc55e3eSMaxim Sobolev /* Not reached */ 179*4fc55e3eSMaxim Sobolev } 180*4fc55e3eSMaxim Sobolev cfs.nworkers = tmp; 181*4fc55e3eSMaxim Sobolev break; 182*4fc55e3eSMaxim Sobolev 1837f4caa8cSMaxim Sobolev default: 1847f4caa8cSMaxim Sobolev usage(); 1857f4caa8cSMaxim Sobolev /* Not reached */ 1867f4caa8cSMaxim Sobolev } 1877f4caa8cSMaxim Sobolev } 1887f4caa8cSMaxim Sobolev argc -= optind; 1897f4caa8cSMaxim Sobolev argv += optind; 1907f4caa8cSMaxim Sobolev 1917f4caa8cSMaxim Sobolev if (argc != 1) { 1927f4caa8cSMaxim Sobolev usage(); 1937f4caa8cSMaxim Sobolev /* Not reached */ 1947f4caa8cSMaxim Sobolev } 1957f4caa8cSMaxim Sobolev 196*4fc55e3eSMaxim Sobolev strcpy(hdr.magic, cfs.handler->magic); 1978f8cb840SMaxim Sobolev 198*4fc55e3eSMaxim Sobolev if (cfs.en_dedup != 0) { 1998f8cb840SMaxim Sobolev hdr.magic[CLOOP_OFS_VERSN] = CLOOP_MAJVER_3; 2008f8cb840SMaxim Sobolev hdr.magic[CLOOP_OFS_COMPR] = 2018f8cb840SMaxim Sobolev tolower(hdr.magic[CLOOP_OFS_COMPR]); 2028f8cb840SMaxim Sobolev } 2038f8cb840SMaxim Sobolev 204*4fc55e3eSMaxim Sobolev c_ctx = cfs.handler->f_init(cfs.blksz); 2058f8cb840SMaxim Sobolev 2067f4caa8cSMaxim Sobolev iname = argv[0]; 2077f4caa8cSMaxim Sobolev if (oname == NULL) { 208*4fc55e3eSMaxim Sobolev asprintf(&oname, "%s%s", iname, cfs.handler->default_sufx); 2097f4caa8cSMaxim Sobolev if (oname == NULL) { 2107f4caa8cSMaxim Sobolev err(1, "can't allocate memory"); 2117f4caa8cSMaxim Sobolev /* Not reached */ 2127f4caa8cSMaxim Sobolev } 2137f4caa8cSMaxim Sobolev } 2147f4caa8cSMaxim Sobolev 2157f4caa8cSMaxim Sobolev signal(SIGHUP, exit); 2167f4caa8cSMaxim Sobolev signal(SIGINT, exit); 2177f4caa8cSMaxim Sobolev signal(SIGTERM, exit); 2187f4caa8cSMaxim Sobolev signal(SIGXCPU, exit); 2197f4caa8cSMaxim Sobolev signal(SIGXFSZ, exit); 2207f4caa8cSMaxim Sobolev atexit(cleanup); 2217f4caa8cSMaxim Sobolev 222*4fc55e3eSMaxim Sobolev cfs.fdr = open(iname, O_RDONLY); 223*4fc55e3eSMaxim Sobolev if (cfs.fdr < 0) { 22427d0a1a4SMax Khon err(1, "open(%s)", iname); 2257f4caa8cSMaxim Sobolev /* Not reached */ 2267f4caa8cSMaxim Sobolev } 227*4fc55e3eSMaxim Sobolev if (fstat(cfs.fdr, &sb) != 0) { 22827d0a1a4SMax Khon err(1, "fstat(%s)", iname); 22927d0a1a4SMax Khon /* Not reached */ 23027d0a1a4SMax Khon } 23127d0a1a4SMax Khon if (S_ISCHR(sb.st_mode)) { 23227d0a1a4SMax Khon off_t ms; 23327d0a1a4SMax Khon 234*4fc55e3eSMaxim Sobolev if (ioctl(cfs.fdr, DIOCGMEDIASIZE, &ms) < 0) { 23527d0a1a4SMax Khon err(1, "ioctl(DIOCGMEDIASIZE)"); 23627d0a1a4SMax Khon /* Not reached */ 23727d0a1a4SMax Khon } 23827d0a1a4SMax Khon sb.st_size = ms; 23927d0a1a4SMax Khon } else if (!S_ISREG(sb.st_mode)) { 24027d0a1a4SMax Khon fprintf(stderr, "%s: not a character device or regular file\n", 24127d0a1a4SMax Khon iname); 24227d0a1a4SMax Khon exit(1); 24327d0a1a4SMax Khon } 244*4fc55e3eSMaxim Sobolev hdr.nblocks = sb.st_size / cfs.blksz; 245*4fc55e3eSMaxim Sobolev if ((sb.st_size % cfs.blksz) != 0) { 246*4fc55e3eSMaxim Sobolev if (cfs.verbose != 0) 2470b99ac63SMaxim Sobolev fprintf(stderr, "file size is not multiple " 248*4fc55e3eSMaxim Sobolev "of %d, padding data\n", cfs.blksz); 2490b99ac63SMaxim Sobolev hdr.nblocks++; 2500b99ac63SMaxim Sobolev } 2518f8cb840SMaxim Sobolev toc = mkuz_safe_malloc((hdr.nblocks + 1) * sizeof(*toc)); 2527f4caa8cSMaxim Sobolev 253*4fc55e3eSMaxim Sobolev cfs.fdw = open(oname, (cfs.en_dedup ? O_RDWR : O_WRONLY) | O_TRUNC | O_CREAT, 2545cf3bf70SMax Khon S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 255*4fc55e3eSMaxim Sobolev if (cfs.fdw < 0) { 256d72d8f53SPawel Jakub Dawidek err(1, "open(%s)", oname); 2577f4caa8cSMaxim Sobolev /* Not reached */ 2587f4caa8cSMaxim Sobolev } 2597f4caa8cSMaxim Sobolev cleanfile = oname; 2607f4caa8cSMaxim Sobolev 2617f4caa8cSMaxim Sobolev /* Prepare header that we will write later when we have index ready. */ 2627f4caa8cSMaxim Sobolev iov[0].iov_base = (char *)&hdr; 2637f4caa8cSMaxim Sobolev iov[0].iov_len = sizeof(hdr); 2647f4caa8cSMaxim Sobolev iov[1].iov_base = (char *)toc; 2657f4caa8cSMaxim Sobolev iov[1].iov_len = (hdr.nblocks + 1) * sizeof(*toc); 2667f4caa8cSMaxim Sobolev offset = iov[0].iov_len + iov[1].iov_len; 2677f4caa8cSMaxim Sobolev 2687f4caa8cSMaxim Sobolev /* Reserve space for header */ 269*4fc55e3eSMaxim Sobolev lseek(cfs.fdw, offset, SEEK_SET); 2707f4caa8cSMaxim Sobolev 271*4fc55e3eSMaxim Sobolev if (cfs.verbose != 0) { 272ed9302fdSMaxim Sobolev fprintf(stderr, "data size %ju bytes, number of clusters " 2735cf3bf70SMax Khon "%u, index length %zu bytes\n", sb.st_size, 2740b99ac63SMaxim Sobolev hdr.nblocks, iov[1].iov_len); 275*4fc55e3eSMaxim Sobolev } 276*4fc55e3eSMaxim Sobolev 277*4fc55e3eSMaxim Sobolev cvp = mkuz_conveyor_ctor(&cfs); 2787f4caa8cSMaxim Sobolev 2798f8cb840SMaxim Sobolev last_offset = 0; 280*4fc55e3eSMaxim Sobolev iblk = oblk = NULL; 281*4fc55e3eSMaxim Sobolev for(i = io = 0; iblk != MKUZ_BLK_EOF; i++) { 282*4fc55e3eSMaxim Sobolev iblk = readblock(cfs.fdr, cfs.blksz); 283*4fc55e3eSMaxim Sobolev mkuz_fqueue_enq(cvp->wrk_queue, iblk); 284*4fc55e3eSMaxim Sobolev if (iblk != MKUZ_BLK_EOF && 285*4fc55e3eSMaxim Sobolev (i < (cfs.nworkers * ITEMS_PER_WORKER))) { 286*4fc55e3eSMaxim Sobolev continue; 2877f4caa8cSMaxim Sobolev } 288*4fc55e3eSMaxim Sobolev drain: 289*4fc55e3eSMaxim Sobolev oblk = mkuz_fqueue_deq_when(cvp->results, cmp_blkno, &io); 290*4fc55e3eSMaxim Sobolev assert(oblk->info.blkno == (unsigned)io); 291*4fc55e3eSMaxim Sobolev oblk->info.offset = offset; 292*4fc55e3eSMaxim Sobolev chit = NULL; 293*4fc55e3eSMaxim Sobolev if (cfs.en_dedup != 0 && oblk->info.len > 0) { 294*4fc55e3eSMaxim Sobolev chit = mkuz_blkcache_regblock(cfs.fdw, oblk); 2958f8cb840SMaxim Sobolev /* 2968f8cb840SMaxim Sobolev * There should be at least one non-empty block 2978f8cb840SMaxim Sobolev * between us and the backref'ed offset, otherwise 2988f8cb840SMaxim Sobolev * we won't be able to parse that sequence correctly 2998f8cb840SMaxim Sobolev * as it would be indistinguishible from another 3008f8cb840SMaxim Sobolev * empty block. 3018f8cb840SMaxim Sobolev */ 3028f8cb840SMaxim Sobolev if (chit != NULL && chit->offset == last_offset) { 3038f8cb840SMaxim Sobolev chit = NULL; 3048f8cb840SMaxim Sobolev } 3058f8cb840SMaxim Sobolev } 3068f8cb840SMaxim Sobolev if (chit != NULL) { 307*4fc55e3eSMaxim Sobolev toc[io] = htobe64(chit->offset); 308*4fc55e3eSMaxim Sobolev oblk->info.len = 0; 3098f8cb840SMaxim Sobolev } else { 310*4fc55e3eSMaxim Sobolev if (oblk->info.len > 0 && write(cfs.fdw, oblk->data, 311*4fc55e3eSMaxim Sobolev oblk->info.len) < 0) { 312d72d8f53SPawel Jakub Dawidek err(1, "write(%s)", oname); 3137f4caa8cSMaxim Sobolev /* Not reached */ 3147f4caa8cSMaxim Sobolev } 315*4fc55e3eSMaxim Sobolev toc[io] = htobe64(offset); 3168f8cb840SMaxim Sobolev last_offset = offset; 317*4fc55e3eSMaxim Sobolev offset += oblk->info.len; 3187f4caa8cSMaxim Sobolev } 319*4fc55e3eSMaxim Sobolev if (cfs.verbose != 0) { 3208f8cb840SMaxim Sobolev fprintf(stderr, "cluster #%d, in %u bytes, " 321*4fc55e3eSMaxim Sobolev "out len=%lu offset=%lu", io, cfs.blksz, 322*4fc55e3eSMaxim Sobolev (u_long)oblk->info.len, (u_long)be64toh(toc[io])); 3238f8cb840SMaxim Sobolev if (chit != NULL) { 3248f8cb840SMaxim Sobolev fprintf(stderr, " (backref'ed to #%d)", 3258f8cb840SMaxim Sobolev chit->blkno); 3268f8cb840SMaxim Sobolev } 3278f8cb840SMaxim Sobolev fprintf(stderr, "\n"); 328*4fc55e3eSMaxim Sobolev } 329*4fc55e3eSMaxim Sobolev free(oblk); 330*4fc55e3eSMaxim Sobolev io += 1; 331*4fc55e3eSMaxim Sobolev if (iblk == MKUZ_BLK_EOF) { 332*4fc55e3eSMaxim Sobolev if (io < i) 333*4fc55e3eSMaxim Sobolev goto drain; 334*4fc55e3eSMaxim Sobolev /* Last block, see if we need to add some padding */ 335*4fc55e3eSMaxim Sobolev if ((offset % DEV_BSIZE) == 0) 336*4fc55e3eSMaxim Sobolev continue; 337*4fc55e3eSMaxim Sobolev oblk = mkuz_blk_ctor(DEV_BSIZE - (offset % DEV_BSIZE)); 338*4fc55e3eSMaxim Sobolev oblk->info.blkno = io; 339*4fc55e3eSMaxim Sobolev oblk->info.len = oblk->alen; 340*4fc55e3eSMaxim Sobolev if (cfs.verbose != 0) { 341*4fc55e3eSMaxim Sobolev fprintf(stderr, "padding data with %lu bytes " 342*4fc55e3eSMaxim Sobolev "so that file size is multiple of %d\n", 343*4fc55e3eSMaxim Sobolev (u_long)oblk->alen, DEV_BSIZE); 344*4fc55e3eSMaxim Sobolev } 345*4fc55e3eSMaxim Sobolev mkuz_fqueue_enq(cvp->results, oblk); 346*4fc55e3eSMaxim Sobolev goto drain; 3478f8cb840SMaxim Sobolev } 3488f8cb840SMaxim Sobolev } 3497f4caa8cSMaxim Sobolev 350*4fc55e3eSMaxim Sobolev close(cfs.fdr); 351*4fc55e3eSMaxim Sobolev 352*4fc55e3eSMaxim Sobolev if (cfs.verbose != 0 || summary.en != 0) { 353*4fc55e3eSMaxim Sobolev et = getdtime(); 35462ee4b69SMaxim Sobolev fprintf(summary.f, "compressed data to %ju bytes, saved %lld " 355*4fc55e3eSMaxim Sobolev "bytes, %.2f%% decrease, %.2f bytes/sec.\n", offset, 3568f8cb840SMaxim Sobolev (long long)(sb.st_size - offset), 3578f8cb840SMaxim Sobolev 100.0 * (long long)(sb.st_size - offset) / 358*4fc55e3eSMaxim Sobolev (float)sb.st_size, (float)sb.st_size / (et - st)); 359*4fc55e3eSMaxim Sobolev } 3607f4caa8cSMaxim Sobolev 3617f4caa8cSMaxim Sobolev /* Convert to big endian */ 362*4fc55e3eSMaxim Sobolev hdr.blksz = htonl(cfs.blksz); 3637f4caa8cSMaxim Sobolev hdr.nblocks = htonl(hdr.nblocks); 3647f4caa8cSMaxim Sobolev /* Write headers into pre-allocated space */ 365*4fc55e3eSMaxim Sobolev lseek(cfs.fdw, 0, SEEK_SET); 366*4fc55e3eSMaxim Sobolev if (writev(cfs.fdw, iov, 2) < 0) { 367d72d8f53SPawel Jakub Dawidek err(1, "writev(%s)", oname); 3687f4caa8cSMaxim Sobolev /* Not reached */ 3697f4caa8cSMaxim Sobolev } 3707f4caa8cSMaxim Sobolev cleanfile = NULL; 371*4fc55e3eSMaxim Sobolev close(cfs.fdw); 3727f4caa8cSMaxim Sobolev 3737f4caa8cSMaxim Sobolev exit(0); 3747f4caa8cSMaxim Sobolev } 3757f4caa8cSMaxim Sobolev 376*4fc55e3eSMaxim Sobolev static struct mkuz_blk * 377*4fc55e3eSMaxim Sobolev readblock(int fd, u_int32_t clstsize) 3780b99ac63SMaxim Sobolev { 3797f4caa8cSMaxim Sobolev int numread; 380*4fc55e3eSMaxim Sobolev struct mkuz_blk *rval; 381*4fc55e3eSMaxim Sobolev static int blockcnt; 382*4fc55e3eSMaxim Sobolev off_t cpos; 3837f4caa8cSMaxim Sobolev 384*4fc55e3eSMaxim Sobolev rval = mkuz_blk_ctor(clstsize); 385*4fc55e3eSMaxim Sobolev 386*4fc55e3eSMaxim Sobolev rval->info.blkno = blockcnt; 387*4fc55e3eSMaxim Sobolev blockcnt += 1; 388*4fc55e3eSMaxim Sobolev cpos = lseek(fd, 0, SEEK_CUR); 389*4fc55e3eSMaxim Sobolev if (cpos < 0) { 390*4fc55e3eSMaxim Sobolev err(1, "readblock: lseek() failed"); 391*4fc55e3eSMaxim Sobolev /* Not reached */ 392*4fc55e3eSMaxim Sobolev } 393*4fc55e3eSMaxim Sobolev rval->info.offset = cpos; 394*4fc55e3eSMaxim Sobolev 395*4fc55e3eSMaxim Sobolev numread = read(fd, rval->data, clstsize); 3967f4caa8cSMaxim Sobolev if (numread < 0) { 397*4fc55e3eSMaxim Sobolev err(1, "readblock: read() failed"); 3987f4caa8cSMaxim Sobolev /* Not reached */ 3997f4caa8cSMaxim Sobolev } 4007f4caa8cSMaxim Sobolev if (numread == 0) { 401*4fc55e3eSMaxim Sobolev free(rval); 402*4fc55e3eSMaxim Sobolev return MKUZ_BLK_EOF; 4037f4caa8cSMaxim Sobolev } 404*4fc55e3eSMaxim Sobolev rval->info.len = numread; 405*4fc55e3eSMaxim Sobolev return rval; 4067f4caa8cSMaxim Sobolev } 4077f4caa8cSMaxim Sobolev 4087f4caa8cSMaxim Sobolev static void 4090b99ac63SMaxim Sobolev usage(void) 4100b99ac63SMaxim Sobolev { 4117f4caa8cSMaxim Sobolev 412d83e0778SMaxim Sobolev fprintf(stderr, "usage: mkuzip [-vZdLS] [-o outfile] [-s cluster_size] " 413*4fc55e3eSMaxim Sobolev "[-j ncompr] infile\n"); 4147f4caa8cSMaxim Sobolev exit(1); 4157f4caa8cSMaxim Sobolev } 4167f4caa8cSMaxim Sobolev 4178f8cb840SMaxim Sobolev void * 4188f8cb840SMaxim Sobolev mkuz_safe_malloc(size_t size) 4190b99ac63SMaxim Sobolev { 4207f4caa8cSMaxim Sobolev void *retval; 4217f4caa8cSMaxim Sobolev 4227f4caa8cSMaxim Sobolev retval = malloc(size); 4237f4caa8cSMaxim Sobolev if (retval == NULL) { 4247f4caa8cSMaxim Sobolev err(1, "can't allocate memory"); 4257f4caa8cSMaxim Sobolev /* Not reached */ 4267f4caa8cSMaxim Sobolev } 4277f4caa8cSMaxim Sobolev return retval; 4287f4caa8cSMaxim Sobolev } 4297f4caa8cSMaxim Sobolev 430*4fc55e3eSMaxim Sobolev void * 431*4fc55e3eSMaxim Sobolev mkuz_safe_zmalloc(size_t size) 432*4fc55e3eSMaxim Sobolev { 433*4fc55e3eSMaxim Sobolev void *retval; 434*4fc55e3eSMaxim Sobolev 435*4fc55e3eSMaxim Sobolev retval = mkuz_safe_malloc(size); 436*4fc55e3eSMaxim Sobolev bzero(retval, size); 437*4fc55e3eSMaxim Sobolev return retval; 438*4fc55e3eSMaxim Sobolev } 439*4fc55e3eSMaxim Sobolev 4407f4caa8cSMaxim Sobolev static void 4410b99ac63SMaxim Sobolev cleanup(void) 4420b99ac63SMaxim Sobolev { 4437f4caa8cSMaxim Sobolev 4447f4caa8cSMaxim Sobolev if (cleanfile != NULL) 4457f4caa8cSMaxim Sobolev unlink(cleanfile); 4467f4caa8cSMaxim Sobolev } 4478f8cb840SMaxim Sobolev 448*4fc55e3eSMaxim Sobolev int 449*4fc55e3eSMaxim Sobolev mkuz_memvcmp(const void *memory, unsigned char val, size_t size) 4508f8cb840SMaxim Sobolev { 4518f8cb840SMaxim Sobolev const u_char *mm; 4528f8cb840SMaxim Sobolev 4538f8cb840SMaxim Sobolev mm = (const u_char *)memory; 4548f8cb840SMaxim Sobolev return (*mm == val) && memcmp(mm, mm + 1, size - 1) == 0; 4558f8cb840SMaxim Sobolev } 456