17f4caa8cSMaxim Sobolev /* 27f4caa8cSMaxim Sobolev * ---------------------------------------------------------------------------- 37f4caa8cSMaxim Sobolev * "THE BEER-WARE LICENSE" (Revision 42): 47f4caa8cSMaxim Sobolev * <sobomax@FreeBSD.ORG> wrote this file. As long as you retain this notice you 57f4caa8cSMaxim Sobolev * can do whatever you want with this stuff. If we meet some day, and you think 67f4caa8cSMaxim Sobolev * this stuff is worth it, you can buy me a beer in return. Maxim Sobolev 77f4caa8cSMaxim Sobolev * ---------------------------------------------------------------------------- 87f4caa8cSMaxim Sobolev * 97f4caa8cSMaxim Sobolev * $FreeBSD$ 107f4caa8cSMaxim Sobolev * 117f4caa8cSMaxim Sobolev */ 127f4caa8cSMaxim Sobolev 137f4caa8cSMaxim Sobolev #include <sys/types.h> 147f4caa8cSMaxim Sobolev #include <sys/endian.h> 157f4caa8cSMaxim Sobolev #include <sys/param.h> 167f4caa8cSMaxim Sobolev #include <sys/stat.h> 177f4caa8cSMaxim Sobolev #include <sys/uio.h> 187f4caa8cSMaxim Sobolev #include <netinet/in.h> 197f4caa8cSMaxim Sobolev #include <zlib.h> 207f4caa8cSMaxim Sobolev #include <err.h> 217f4caa8cSMaxim Sobolev #include <fcntl.h> 227f4caa8cSMaxim Sobolev #include <signal.h> 237f4caa8cSMaxim Sobolev #include <stdio.h> 247f4caa8cSMaxim Sobolev #include <stdlib.h> 257f4caa8cSMaxim Sobolev #include <string.h> 267f4caa8cSMaxim Sobolev #include <unistd.h> 277f4caa8cSMaxim Sobolev 287f4caa8cSMaxim Sobolev #define CLSTSIZE 16384 297f4caa8cSMaxim Sobolev #define DEFAULT_SUFX ".uzip" 307f4caa8cSMaxim Sobolev 317f4caa8cSMaxim Sobolev #define CLOOP_MAGIC_LEN 128 327f4caa8cSMaxim Sobolev static char CLOOP_MAGIC_START[] = "#!/bin/sh\n#V2.0 Format\n" 337f4caa8cSMaxim Sobolev "m=geom_uzip\n(kldstat -n $m 2>&-||kldload $m)>&-&&" 347f4caa8cSMaxim Sobolev "mount_cd9660 /dev/`mdconfig -af $0`.uzip $1\nexit $?\n"; 357f4caa8cSMaxim Sobolev 367f4caa8cSMaxim Sobolev static char *readblock(int, char *, u_int32_t); 377f4caa8cSMaxim Sobolev static void usage(void); 387f4caa8cSMaxim Sobolev static void *safe_malloc(size_t); 397f4caa8cSMaxim Sobolev static void cleanup(void); 407f4caa8cSMaxim Sobolev 417f4caa8cSMaxim Sobolev static char *cleanfile = NULL; 427f4caa8cSMaxim Sobolev 437f4caa8cSMaxim Sobolev int main(int argc, char **argv) 447f4caa8cSMaxim Sobolev { 457f4caa8cSMaxim Sobolev char *iname, *oname, *obuf, *ibuf; 467f4caa8cSMaxim Sobolev uint64_t *toc; 477f4caa8cSMaxim Sobolev int fdr, fdw, i, opt, verbose, tmp; 487f4caa8cSMaxim Sobolev struct iovec iov[2]; 497f4caa8cSMaxim Sobolev struct stat sb; 507f4caa8cSMaxim Sobolev uLongf destlen; 517f4caa8cSMaxim Sobolev uint64_t offset; 527f4caa8cSMaxim Sobolev struct cloop_header { 537f4caa8cSMaxim Sobolev char magic[CLOOP_MAGIC_LEN]; /* cloop magic */ 547f4caa8cSMaxim Sobolev uint32_t blksz; /* block size */ 557f4caa8cSMaxim Sobolev uint32_t nblocks; /* number of blocks */ 567f4caa8cSMaxim Sobolev } hdr; 577f4caa8cSMaxim Sobolev 587f4caa8cSMaxim Sobolev memset(&hdr, 0, sizeof(hdr)); 597f4caa8cSMaxim Sobolev hdr.blksz = CLSTSIZE; 607f4caa8cSMaxim Sobolev strcpy(hdr.magic, CLOOP_MAGIC_START); 617f4caa8cSMaxim Sobolev oname = NULL; 627f4caa8cSMaxim Sobolev verbose = 0; 637f4caa8cSMaxim Sobolev 647f4caa8cSMaxim Sobolev while((opt = getopt(argc, argv, "o:s:v")) != -1) { 657f4caa8cSMaxim Sobolev switch(opt) { 667f4caa8cSMaxim Sobolev case 'o': 677f4caa8cSMaxim Sobolev oname = optarg; 687f4caa8cSMaxim Sobolev break; 697f4caa8cSMaxim Sobolev 707f4caa8cSMaxim Sobolev case 's': 717f4caa8cSMaxim Sobolev tmp = atoi(optarg); 727f4caa8cSMaxim Sobolev if (tmp <= 0) { 737f4caa8cSMaxim Sobolev errx(1, "invalid cluster size specified: %s", 747f4caa8cSMaxim Sobolev optarg); 757f4caa8cSMaxim Sobolev /* Not reached */ 767f4caa8cSMaxim Sobolev } 777f4caa8cSMaxim Sobolev if (tmp % DEV_BSIZE != 0) { 787f4caa8cSMaxim Sobolev errx(1, "cluster size should be multiple of %d", 797f4caa8cSMaxim Sobolev DEV_BSIZE); 807f4caa8cSMaxim Sobolev /* Not reached */ 817f4caa8cSMaxim Sobolev } 820b99ac63SMaxim Sobolev if (compressBound(tmp) > MAXPHYS) { 830b99ac63SMaxim Sobolev errx(1, "cluster size is too large"); 847f4caa8cSMaxim Sobolev /* Not reached */ 857f4caa8cSMaxim Sobolev } 867f4caa8cSMaxim Sobolev hdr.blksz = tmp; 877f4caa8cSMaxim Sobolev break; 887f4caa8cSMaxim Sobolev 897f4caa8cSMaxim Sobolev case 'v': 907f4caa8cSMaxim Sobolev verbose = 1; 917f4caa8cSMaxim Sobolev break; 927f4caa8cSMaxim Sobolev 937f4caa8cSMaxim Sobolev default: 947f4caa8cSMaxim Sobolev usage(); 957f4caa8cSMaxim Sobolev /* Not reached */ 967f4caa8cSMaxim Sobolev } 977f4caa8cSMaxim Sobolev } 987f4caa8cSMaxim Sobolev argc -= optind; 997f4caa8cSMaxim Sobolev argv += optind; 1007f4caa8cSMaxim Sobolev 1017f4caa8cSMaxim Sobolev if (argc != 1) { 1027f4caa8cSMaxim Sobolev usage(); 1037f4caa8cSMaxim Sobolev /* Not reached */ 1047f4caa8cSMaxim Sobolev } 1057f4caa8cSMaxim Sobolev 1067f4caa8cSMaxim Sobolev iname = argv[0]; 1077f4caa8cSMaxim Sobolev if (oname == NULL) { 1087f4caa8cSMaxim Sobolev asprintf(&oname, "%s%s", iname, DEFAULT_SUFX); 1097f4caa8cSMaxim Sobolev if (oname == NULL) { 1107f4caa8cSMaxim Sobolev err(1, "can't allocate memory"); 1117f4caa8cSMaxim Sobolev /* Not reached */ 1127f4caa8cSMaxim Sobolev } 1137f4caa8cSMaxim Sobolev } 1147f4caa8cSMaxim Sobolev 1157f4caa8cSMaxim Sobolev obuf = safe_malloc(compressBound(hdr.blksz)); 1167f4caa8cSMaxim Sobolev ibuf = safe_malloc(hdr.blksz); 1177f4caa8cSMaxim Sobolev 1187f4caa8cSMaxim Sobolev signal(SIGHUP, exit); 1197f4caa8cSMaxim Sobolev signal(SIGINT, exit); 1207f4caa8cSMaxim Sobolev signal(SIGTERM, exit); 1217f4caa8cSMaxim Sobolev signal(SIGXCPU, exit); 1227f4caa8cSMaxim Sobolev signal(SIGXFSZ, exit); 1237f4caa8cSMaxim Sobolev atexit(cleanup); 1247f4caa8cSMaxim Sobolev 1257f4caa8cSMaxim Sobolev if (stat(iname, &sb) != 0) { 1267f4caa8cSMaxim Sobolev err(1, "%s", iname); 1277f4caa8cSMaxim Sobolev /* Not reached */ 1287f4caa8cSMaxim Sobolev } 1297f4caa8cSMaxim Sobolev hdr.nblocks = sb.st_size / hdr.blksz; 1300b99ac63SMaxim Sobolev if ((sb.st_size % hdr.blksz) != 0) { 1310b99ac63SMaxim Sobolev if (verbose != 0) 1320b99ac63SMaxim Sobolev fprintf(stderr, "file size is not multiple " 1330b99ac63SMaxim Sobolev "of %d, padding data\n", hdr.blksz); 1340b99ac63SMaxim Sobolev hdr.nblocks++; 1350b99ac63SMaxim Sobolev } 1367f4caa8cSMaxim Sobolev toc = safe_malloc((hdr.nblocks + 1) * sizeof(*toc)); 1377f4caa8cSMaxim Sobolev 1387f4caa8cSMaxim Sobolev fdr = open(iname, O_RDONLY); 1397f4caa8cSMaxim Sobolev if (fdr < 0) { 1407f4caa8cSMaxim Sobolev err(1, "%s", iname); 1417f4caa8cSMaxim Sobolev /* Not reached */ 1427f4caa8cSMaxim Sobolev } 1437f4caa8cSMaxim Sobolev fdw = open(oname, O_WRONLY | O_TRUNC | O_CREAT, 1447f4caa8cSMaxim Sobolev S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 1457f4caa8cSMaxim Sobolev if (fdw < 0) { 1467f4caa8cSMaxim Sobolev err(1, "%s", oname); 1477f4caa8cSMaxim Sobolev /* Not reached */ 1487f4caa8cSMaxim Sobolev } 1497f4caa8cSMaxim Sobolev cleanfile = oname; 1507f4caa8cSMaxim Sobolev 1517f4caa8cSMaxim Sobolev /* Prepare header that we will write later when we have index ready. */ 1527f4caa8cSMaxim Sobolev iov[0].iov_base = (char *)&hdr; 1537f4caa8cSMaxim Sobolev iov[0].iov_len = sizeof(hdr); 1547f4caa8cSMaxim Sobolev iov[1].iov_base = (char *)toc; 1557f4caa8cSMaxim Sobolev iov[1].iov_len = (hdr.nblocks + 1) * sizeof(*toc); 1567f4caa8cSMaxim Sobolev offset = iov[0].iov_len + iov[1].iov_len; 1577f4caa8cSMaxim Sobolev 1587f4caa8cSMaxim Sobolev /* Reserve space for header */ 1597f4caa8cSMaxim Sobolev lseek(fdw, offset, SEEK_SET); 1607f4caa8cSMaxim Sobolev 1617f4caa8cSMaxim Sobolev if (verbose != 0) 162ed9302fdSMaxim Sobolev fprintf(stderr, "data size %ju bytes, number of clusters " 163ed9302fdSMaxim Sobolev "%u, index lengh %zu bytes\n", sb.st_size, 1640b99ac63SMaxim Sobolev hdr.nblocks, iov[1].iov_len); 1657f4caa8cSMaxim Sobolev 1667f4caa8cSMaxim Sobolev for(i = 0; i == 0 || ibuf != NULL; i++) { 1677f4caa8cSMaxim Sobolev ibuf = readblock(fdr, ibuf, hdr.blksz); 1687f4caa8cSMaxim Sobolev if (ibuf != NULL) { 1697f4caa8cSMaxim Sobolev destlen = compressBound(hdr.blksz); 1700b99ac63SMaxim Sobolev if (compress2(obuf, &destlen, ibuf, hdr.blksz, 1710b99ac63SMaxim Sobolev Z_BEST_COMPRESSION) != Z_OK) { 1720b99ac63SMaxim Sobolev errx(1, "can't compress data: compress2() " 1730b99ac63SMaxim Sobolev "failed"); 1747f4caa8cSMaxim Sobolev /* Not reached */ 1757f4caa8cSMaxim Sobolev } 1760b99ac63SMaxim Sobolev if (verbose != 0) 1770b99ac63SMaxim Sobolev fprintf(stderr, "cluster #%d, in %u bytes, " 1780b99ac63SMaxim Sobolev "out %lu bytes\n", i, hdr.blksz, destlen); 1797f4caa8cSMaxim Sobolev } else { 1807f4caa8cSMaxim Sobolev destlen = DEV_BSIZE - (offset % DEV_BSIZE); 1817f4caa8cSMaxim Sobolev memset(obuf, 0, destlen); 1820b99ac63SMaxim Sobolev if (verbose != 0) 1830b99ac63SMaxim Sobolev fprintf(stderr, "padding data with %lu bytes so " 1840b99ac63SMaxim Sobolev "that file size is multiple of %d\n", destlen, 1850b99ac63SMaxim Sobolev DEV_BSIZE); 1867f4caa8cSMaxim Sobolev } 1877f4caa8cSMaxim Sobolev if (write(fdw, obuf, destlen) < 0) { 1887f4caa8cSMaxim Sobolev err(1, "%s", oname); 1897f4caa8cSMaxim Sobolev /* Not reached */ 1907f4caa8cSMaxim Sobolev } 1917f4caa8cSMaxim Sobolev toc[i] = htobe64(offset); 1927f4caa8cSMaxim Sobolev offset += destlen; 1937f4caa8cSMaxim Sobolev } 1947f4caa8cSMaxim Sobolev close(fdr); 1957f4caa8cSMaxim Sobolev 1967f4caa8cSMaxim Sobolev if (verbose != 0) 197ed9302fdSMaxim Sobolev fprintf(stderr, "compressed data to %ju bytes, saved %lld " 1980b99ac63SMaxim Sobolev "bytes, %.2f%% decrease.\n", offset, (long long)(sb.st_size - offset), 1990b99ac63SMaxim Sobolev 100.0 * (long long)(sb.st_size - offset) / (float)sb.st_size); 2007f4caa8cSMaxim Sobolev 2017f4caa8cSMaxim Sobolev /* Convert to big endian */ 2027f4caa8cSMaxim Sobolev hdr.blksz = htonl(hdr.blksz); 2037f4caa8cSMaxim Sobolev hdr.nblocks = htonl(hdr.nblocks); 2047f4caa8cSMaxim Sobolev /* Write headers into pre-allocated space */ 2057f4caa8cSMaxim Sobolev lseek(fdw, 0, SEEK_SET); 2067f4caa8cSMaxim Sobolev if (writev(fdw, iov, 2) < 0) { 2077f4caa8cSMaxim Sobolev err(1, "%s", oname); 2087f4caa8cSMaxim Sobolev /* Not reached */ 2097f4caa8cSMaxim Sobolev } 2107f4caa8cSMaxim Sobolev cleanfile = NULL; 2117f4caa8cSMaxim Sobolev close(fdw); 2127f4caa8cSMaxim Sobolev 2137f4caa8cSMaxim Sobolev exit(0); 2147f4caa8cSMaxim Sobolev } 2157f4caa8cSMaxim Sobolev 2167f4caa8cSMaxim Sobolev static char * 2170b99ac63SMaxim Sobolev readblock(int fd, char *ibuf, u_int32_t clstsize) 2180b99ac63SMaxim Sobolev { 2197f4caa8cSMaxim Sobolev int numread; 2207f4caa8cSMaxim Sobolev 2217f4caa8cSMaxim Sobolev bzero(ibuf, clstsize); 2227f4caa8cSMaxim Sobolev numread = read(fd, ibuf, clstsize); 2237f4caa8cSMaxim Sobolev if (numread < 0) { 2247f4caa8cSMaxim Sobolev err(1, "read() failed"); 2257f4caa8cSMaxim Sobolev /* Not reached */ 2267f4caa8cSMaxim Sobolev } 2277f4caa8cSMaxim Sobolev if (numread == 0) { 2287f4caa8cSMaxim Sobolev return NULL; 2297f4caa8cSMaxim Sobolev } 2307f4caa8cSMaxim Sobolev return ibuf; 2317f4caa8cSMaxim Sobolev } 2327f4caa8cSMaxim Sobolev 2337f4caa8cSMaxim Sobolev static void 2340b99ac63SMaxim Sobolev usage(void) 2350b99ac63SMaxim Sobolev { 2367f4caa8cSMaxim Sobolev 2377f4caa8cSMaxim Sobolev fprintf(stderr, "usage: mkuzip [-v] [-o outfile] [-s cluster_size] infile\n"); 2387f4caa8cSMaxim Sobolev exit(1); 2397f4caa8cSMaxim Sobolev } 2407f4caa8cSMaxim Sobolev 2417f4caa8cSMaxim Sobolev static void * 2420b99ac63SMaxim Sobolev safe_malloc(size_t size) 2430b99ac63SMaxim Sobolev { 2447f4caa8cSMaxim Sobolev void *retval; 2457f4caa8cSMaxim Sobolev 2467f4caa8cSMaxim Sobolev retval = malloc(size); 2477f4caa8cSMaxim Sobolev if (retval == NULL) { 2487f4caa8cSMaxim Sobolev err(1, "can't allocate memory"); 2497f4caa8cSMaxim Sobolev /* Not reached */ 2507f4caa8cSMaxim Sobolev } 2517f4caa8cSMaxim Sobolev return retval; 2527f4caa8cSMaxim Sobolev } 2537f4caa8cSMaxim Sobolev 2547f4caa8cSMaxim Sobolev static void 2550b99ac63SMaxim Sobolev cleanup(void) 2560b99ac63SMaxim Sobolev { 2577f4caa8cSMaxim Sobolev 2587f4caa8cSMaxim Sobolev if (cleanfile != NULL) 2597f4caa8cSMaxim Sobolev unlink(cleanfile); 2607f4caa8cSMaxim Sobolev } 261