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> 1427d0a1a4SMax Khon #include <sys/disk.h> 157f4caa8cSMaxim Sobolev #include <sys/endian.h> 167f4caa8cSMaxim Sobolev #include <sys/param.h> 177f4caa8cSMaxim Sobolev #include <sys/stat.h> 187f4caa8cSMaxim Sobolev #include <sys/uio.h> 197f4caa8cSMaxim Sobolev #include <netinet/in.h> 207f4caa8cSMaxim Sobolev #include <zlib.h> 217f4caa8cSMaxim Sobolev #include <err.h> 227f4caa8cSMaxim Sobolev #include <fcntl.h> 237f4caa8cSMaxim Sobolev #include <signal.h> 247f4caa8cSMaxim Sobolev #include <stdio.h> 257f4caa8cSMaxim Sobolev #include <stdlib.h> 267f4caa8cSMaxim Sobolev #include <string.h> 277f4caa8cSMaxim Sobolev #include <unistd.h> 287f4caa8cSMaxim Sobolev 297f4caa8cSMaxim Sobolev #define CLSTSIZE 16384 307f4caa8cSMaxim Sobolev #define DEFAULT_SUFX ".uzip" 317f4caa8cSMaxim Sobolev 327f4caa8cSMaxim Sobolev #define CLOOP_MAGIC_LEN 128 337f4caa8cSMaxim Sobolev static char CLOOP_MAGIC_START[] = "#!/bin/sh\n#V2.0 Format\n" 345cf3bf70SMax Khon "m=geom_uzip\n(kldstat -m $m 2>&-||kldload $m)>&-&&" 357f4caa8cSMaxim Sobolev "mount_cd9660 /dev/`mdconfig -af $0`.uzip $1\nexit $?\n"; 367f4caa8cSMaxim Sobolev 377f4caa8cSMaxim Sobolev static char *readblock(int, char *, u_int32_t); 387f4caa8cSMaxim Sobolev static void usage(void); 397f4caa8cSMaxim Sobolev static void *safe_malloc(size_t); 407f4caa8cSMaxim Sobolev static void cleanup(void); 417f4caa8cSMaxim Sobolev 427f4caa8cSMaxim Sobolev static char *cleanfile = NULL; 437f4caa8cSMaxim Sobolev 447f4caa8cSMaxim Sobolev int main(int argc, char **argv) 457f4caa8cSMaxim Sobolev { 467f4caa8cSMaxim Sobolev char *iname, *oname, *obuf, *ibuf; 477f4caa8cSMaxim Sobolev uint64_t *toc; 487f4caa8cSMaxim Sobolev int fdr, fdw, i, opt, verbose, tmp; 497f4caa8cSMaxim Sobolev struct iovec iov[2]; 507f4caa8cSMaxim Sobolev struct stat sb; 517f4caa8cSMaxim Sobolev uLongf destlen; 527f4caa8cSMaxim Sobolev uint64_t offset; 537f4caa8cSMaxim Sobolev struct cloop_header { 547f4caa8cSMaxim Sobolev char magic[CLOOP_MAGIC_LEN]; /* cloop magic */ 557f4caa8cSMaxim Sobolev uint32_t blksz; /* block size */ 567f4caa8cSMaxim Sobolev uint32_t nblocks; /* number of blocks */ 577f4caa8cSMaxim Sobolev } hdr; 587f4caa8cSMaxim Sobolev 597f4caa8cSMaxim Sobolev memset(&hdr, 0, sizeof(hdr)); 607f4caa8cSMaxim Sobolev hdr.blksz = CLSTSIZE; 617f4caa8cSMaxim Sobolev strcpy(hdr.magic, CLOOP_MAGIC_START); 627f4caa8cSMaxim Sobolev oname = NULL; 637f4caa8cSMaxim Sobolev verbose = 0; 647f4caa8cSMaxim Sobolev 657f4caa8cSMaxim Sobolev while((opt = getopt(argc, argv, "o:s:v")) != -1) { 667f4caa8cSMaxim Sobolev switch(opt) { 677f4caa8cSMaxim Sobolev case 'o': 687f4caa8cSMaxim Sobolev oname = optarg; 697f4caa8cSMaxim Sobolev break; 707f4caa8cSMaxim Sobolev 717f4caa8cSMaxim Sobolev case 's': 727f4caa8cSMaxim Sobolev tmp = atoi(optarg); 737f4caa8cSMaxim Sobolev if (tmp <= 0) { 747f4caa8cSMaxim Sobolev errx(1, "invalid cluster size specified: %s", 757f4caa8cSMaxim Sobolev optarg); 767f4caa8cSMaxim Sobolev /* Not reached */ 777f4caa8cSMaxim Sobolev } 787f4caa8cSMaxim Sobolev if (tmp % DEV_BSIZE != 0) { 797f4caa8cSMaxim Sobolev errx(1, "cluster size should be multiple of %d", 807f4caa8cSMaxim Sobolev DEV_BSIZE); 817f4caa8cSMaxim Sobolev /* Not reached */ 827f4caa8cSMaxim Sobolev } 830b99ac63SMaxim Sobolev if (compressBound(tmp) > MAXPHYS) { 840b99ac63SMaxim Sobolev errx(1, "cluster size is too large"); 857f4caa8cSMaxim Sobolev /* Not reached */ 867f4caa8cSMaxim Sobolev } 877f4caa8cSMaxim Sobolev hdr.blksz = tmp; 887f4caa8cSMaxim Sobolev break; 897f4caa8cSMaxim Sobolev 907f4caa8cSMaxim Sobolev case 'v': 917f4caa8cSMaxim Sobolev verbose = 1; 927f4caa8cSMaxim Sobolev break; 937f4caa8cSMaxim Sobolev 947f4caa8cSMaxim Sobolev default: 957f4caa8cSMaxim Sobolev usage(); 967f4caa8cSMaxim Sobolev /* Not reached */ 977f4caa8cSMaxim Sobolev } 987f4caa8cSMaxim Sobolev } 997f4caa8cSMaxim Sobolev argc -= optind; 1007f4caa8cSMaxim Sobolev argv += optind; 1017f4caa8cSMaxim Sobolev 1027f4caa8cSMaxim Sobolev if (argc != 1) { 1037f4caa8cSMaxim Sobolev usage(); 1047f4caa8cSMaxim Sobolev /* Not reached */ 1057f4caa8cSMaxim Sobolev } 1067f4caa8cSMaxim Sobolev 1077f4caa8cSMaxim Sobolev iname = argv[0]; 1087f4caa8cSMaxim Sobolev if (oname == NULL) { 1097f4caa8cSMaxim Sobolev asprintf(&oname, "%s%s", iname, DEFAULT_SUFX); 1107f4caa8cSMaxim Sobolev if (oname == NULL) { 1117f4caa8cSMaxim Sobolev err(1, "can't allocate memory"); 1127f4caa8cSMaxim Sobolev /* Not reached */ 1137f4caa8cSMaxim Sobolev } 1147f4caa8cSMaxim Sobolev } 1157f4caa8cSMaxim Sobolev 1167f4caa8cSMaxim Sobolev obuf = safe_malloc(compressBound(hdr.blksz)); 1177f4caa8cSMaxim Sobolev ibuf = safe_malloc(hdr.blksz); 1187f4caa8cSMaxim Sobolev 1197f4caa8cSMaxim Sobolev signal(SIGHUP, exit); 1207f4caa8cSMaxim Sobolev signal(SIGINT, exit); 1217f4caa8cSMaxim Sobolev signal(SIGTERM, exit); 1227f4caa8cSMaxim Sobolev signal(SIGXCPU, exit); 1237f4caa8cSMaxim Sobolev signal(SIGXFSZ, exit); 1247f4caa8cSMaxim Sobolev atexit(cleanup); 1257f4caa8cSMaxim Sobolev 12627d0a1a4SMax Khon fdr = open(iname, O_RDONLY); 12727d0a1a4SMax Khon if (fdr < 0) { 12827d0a1a4SMax Khon err(1, "open(%s)", iname); 1297f4caa8cSMaxim Sobolev /* Not reached */ 1307f4caa8cSMaxim Sobolev } 13127d0a1a4SMax Khon if (fstat(fdr, &sb) != 0) { 13227d0a1a4SMax Khon err(1, "fstat(%s)", iname); 13327d0a1a4SMax Khon /* Not reached */ 13427d0a1a4SMax Khon } 13527d0a1a4SMax Khon if (S_ISCHR(sb.st_mode)) { 13627d0a1a4SMax Khon off_t ms; 13727d0a1a4SMax Khon 13827d0a1a4SMax Khon if (ioctl(fdr, DIOCGMEDIASIZE, &ms) < 0) { 13927d0a1a4SMax Khon err(1, "ioctl(DIOCGMEDIASIZE)"); 14027d0a1a4SMax Khon /* Not reached */ 14127d0a1a4SMax Khon } 14227d0a1a4SMax Khon sb.st_size = ms; 14327d0a1a4SMax Khon } else if (!S_ISREG(sb.st_mode)) { 14427d0a1a4SMax Khon fprintf(stderr, "%s: not a character device or regular file\n", 14527d0a1a4SMax Khon iname); 14627d0a1a4SMax Khon exit(1); 14727d0a1a4SMax Khon } 1487f4caa8cSMaxim Sobolev hdr.nblocks = sb.st_size / hdr.blksz; 1490b99ac63SMaxim Sobolev if ((sb.st_size % hdr.blksz) != 0) { 1500b99ac63SMaxim Sobolev if (verbose != 0) 1510b99ac63SMaxim Sobolev fprintf(stderr, "file size is not multiple " 1520b99ac63SMaxim Sobolev "of %d, padding data\n", hdr.blksz); 1530b99ac63SMaxim Sobolev hdr.nblocks++; 1540b99ac63SMaxim Sobolev } 1557f4caa8cSMaxim Sobolev toc = safe_malloc((hdr.nblocks + 1) * sizeof(*toc)); 1567f4caa8cSMaxim Sobolev 1577f4caa8cSMaxim Sobolev fdw = open(oname, O_WRONLY | O_TRUNC | O_CREAT, 1585cf3bf70SMax Khon S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 1597f4caa8cSMaxim Sobolev if (fdw < 0) { 160d72d8f53SPawel Jakub Dawidek err(1, "open(%s)", oname); 1617f4caa8cSMaxim Sobolev /* Not reached */ 1627f4caa8cSMaxim Sobolev } 1637f4caa8cSMaxim Sobolev cleanfile = oname; 1647f4caa8cSMaxim Sobolev 1657f4caa8cSMaxim Sobolev /* Prepare header that we will write later when we have index ready. */ 1667f4caa8cSMaxim Sobolev iov[0].iov_base = (char *)&hdr; 1677f4caa8cSMaxim Sobolev iov[0].iov_len = sizeof(hdr); 1687f4caa8cSMaxim Sobolev iov[1].iov_base = (char *)toc; 1697f4caa8cSMaxim Sobolev iov[1].iov_len = (hdr.nblocks + 1) * sizeof(*toc); 1707f4caa8cSMaxim Sobolev offset = iov[0].iov_len + iov[1].iov_len; 1717f4caa8cSMaxim Sobolev 1727f4caa8cSMaxim Sobolev /* Reserve space for header */ 1737f4caa8cSMaxim Sobolev lseek(fdw, offset, SEEK_SET); 1747f4caa8cSMaxim Sobolev 1757f4caa8cSMaxim Sobolev if (verbose != 0) 176ed9302fdSMaxim Sobolev fprintf(stderr, "data size %ju bytes, number of clusters " 1775cf3bf70SMax Khon "%u, index length %zu bytes\n", sb.st_size, 1780b99ac63SMaxim Sobolev hdr.nblocks, iov[1].iov_len); 1797f4caa8cSMaxim Sobolev 1807f4caa8cSMaxim Sobolev for(i = 0; i == 0 || ibuf != NULL; i++) { 1817f4caa8cSMaxim Sobolev ibuf = readblock(fdr, ibuf, hdr.blksz); 1827f4caa8cSMaxim Sobolev if (ibuf != NULL) { 1837f4caa8cSMaxim Sobolev destlen = compressBound(hdr.blksz); 1840b99ac63SMaxim Sobolev if (compress2(obuf, &destlen, ibuf, hdr.blksz, 1850b99ac63SMaxim Sobolev Z_BEST_COMPRESSION) != Z_OK) { 1860b99ac63SMaxim Sobolev errx(1, "can't compress data: compress2() " 1870b99ac63SMaxim Sobolev "failed"); 1887f4caa8cSMaxim Sobolev /* Not reached */ 1897f4caa8cSMaxim Sobolev } 1900b99ac63SMaxim Sobolev if (verbose != 0) 1910b99ac63SMaxim Sobolev fprintf(stderr, "cluster #%d, in %u bytes, " 1920b99ac63SMaxim Sobolev "out %lu bytes\n", i, hdr.blksz, destlen); 1937f4caa8cSMaxim Sobolev } else { 1947f4caa8cSMaxim Sobolev destlen = DEV_BSIZE - (offset % DEV_BSIZE); 1957f4caa8cSMaxim Sobolev memset(obuf, 0, destlen); 1960b99ac63SMaxim Sobolev if (verbose != 0) 1970b99ac63SMaxim Sobolev fprintf(stderr, "padding data with %lu bytes so " 1980b99ac63SMaxim Sobolev "that file size is multiple of %d\n", destlen, 1990b99ac63SMaxim Sobolev DEV_BSIZE); 2007f4caa8cSMaxim Sobolev } 2017f4caa8cSMaxim Sobolev if (write(fdw, obuf, destlen) < 0) { 202d72d8f53SPawel Jakub Dawidek err(1, "write(%s)", oname); 2037f4caa8cSMaxim Sobolev /* Not reached */ 2047f4caa8cSMaxim Sobolev } 2057f4caa8cSMaxim Sobolev toc[i] = htobe64(offset); 2067f4caa8cSMaxim Sobolev offset += destlen; 2077f4caa8cSMaxim Sobolev } 2087f4caa8cSMaxim Sobolev close(fdr); 2097f4caa8cSMaxim Sobolev 2107f4caa8cSMaxim Sobolev if (verbose != 0) 211ed9302fdSMaxim Sobolev fprintf(stderr, "compressed data to %ju bytes, saved %lld " 2120b99ac63SMaxim Sobolev "bytes, %.2f%% decrease.\n", offset, (long long)(sb.st_size - offset), 2130b99ac63SMaxim Sobolev 100.0 * (long long)(sb.st_size - offset) / (float)sb.st_size); 2147f4caa8cSMaxim Sobolev 2157f4caa8cSMaxim Sobolev /* Convert to big endian */ 2167f4caa8cSMaxim Sobolev hdr.blksz = htonl(hdr.blksz); 2177f4caa8cSMaxim Sobolev hdr.nblocks = htonl(hdr.nblocks); 2187f4caa8cSMaxim Sobolev /* Write headers into pre-allocated space */ 2197f4caa8cSMaxim Sobolev lseek(fdw, 0, SEEK_SET); 2207f4caa8cSMaxim Sobolev if (writev(fdw, iov, 2) < 0) { 221d72d8f53SPawel Jakub Dawidek err(1, "writev(%s)", oname); 2227f4caa8cSMaxim Sobolev /* Not reached */ 2237f4caa8cSMaxim Sobolev } 2247f4caa8cSMaxim Sobolev cleanfile = NULL; 2257f4caa8cSMaxim Sobolev close(fdw); 2267f4caa8cSMaxim Sobolev 2277f4caa8cSMaxim Sobolev exit(0); 2287f4caa8cSMaxim Sobolev } 2297f4caa8cSMaxim Sobolev 2307f4caa8cSMaxim Sobolev static char * 2310b99ac63SMaxim Sobolev readblock(int fd, char *ibuf, u_int32_t clstsize) 2320b99ac63SMaxim Sobolev { 2337f4caa8cSMaxim Sobolev int numread; 2347f4caa8cSMaxim Sobolev 2357f4caa8cSMaxim Sobolev bzero(ibuf, clstsize); 2367f4caa8cSMaxim Sobolev numread = read(fd, ibuf, clstsize); 2377f4caa8cSMaxim Sobolev if (numread < 0) { 2387f4caa8cSMaxim Sobolev err(1, "read() failed"); 2397f4caa8cSMaxim Sobolev /* Not reached */ 2407f4caa8cSMaxim Sobolev } 2417f4caa8cSMaxim Sobolev if (numread == 0) { 2427f4caa8cSMaxim Sobolev return NULL; 2437f4caa8cSMaxim Sobolev } 2447f4caa8cSMaxim Sobolev return ibuf; 2457f4caa8cSMaxim Sobolev } 2467f4caa8cSMaxim Sobolev 2477f4caa8cSMaxim Sobolev static void 2480b99ac63SMaxim Sobolev usage(void) 2490b99ac63SMaxim Sobolev { 2507f4caa8cSMaxim Sobolev 2517f4caa8cSMaxim Sobolev fprintf(stderr, "usage: mkuzip [-v] [-o outfile] [-s cluster_size] infile\n"); 2527f4caa8cSMaxim Sobolev exit(1); 2537f4caa8cSMaxim Sobolev } 2547f4caa8cSMaxim Sobolev 2557f4caa8cSMaxim Sobolev static void * 2560b99ac63SMaxim Sobolev safe_malloc(size_t size) 2570b99ac63SMaxim Sobolev { 2587f4caa8cSMaxim Sobolev void *retval; 2597f4caa8cSMaxim Sobolev 2607f4caa8cSMaxim Sobolev retval = malloc(size); 2617f4caa8cSMaxim Sobolev if (retval == NULL) { 2627f4caa8cSMaxim Sobolev err(1, "can't allocate memory"); 2637f4caa8cSMaxim Sobolev /* Not reached */ 2647f4caa8cSMaxim Sobolev } 2657f4caa8cSMaxim Sobolev return retval; 2667f4caa8cSMaxim Sobolev } 2677f4caa8cSMaxim Sobolev 2687f4caa8cSMaxim Sobolev static void 2690b99ac63SMaxim Sobolev cleanup(void) 2700b99ac63SMaxim Sobolev { 2717f4caa8cSMaxim Sobolev 2727f4caa8cSMaxim Sobolev if (cleanfile != NULL) 2737f4caa8cSMaxim Sobolev unlink(cleanfile); 2747f4caa8cSMaxim Sobolev } 275