1135045Ssobomax/* 2135045Ssobomax * ---------------------------------------------------------------------------- 3135045Ssobomax * "THE BEER-WARE LICENSE" (Revision 42): 4135045Ssobomax * <sobomax@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5135045Ssobomax * can do whatever you want with this stuff. If we meet some day, and you think 6135045Ssobomax * this stuff is worth it, you can buy me a beer in return. Maxim Sobolev 7135045Ssobomax * ---------------------------------------------------------------------------- 8135045Ssobomax * 9135045Ssobomax * $FreeBSD: releng/10.3/usr.bin/mkuzip/mkuzip.c 221832 2011-05-13 09:55:48Z ru $ 10135045Ssobomax * 11135045Ssobomax */ 12135045Ssobomax 13135045Ssobomax#include <sys/types.h> 14167272Sfjoe#include <sys/disk.h> 15135045Ssobomax#include <sys/endian.h> 16135045Ssobomax#include <sys/param.h> 17135045Ssobomax#include <sys/stat.h> 18135045Ssobomax#include <sys/uio.h> 19135045Ssobomax#include <netinet/in.h> 20135045Ssobomax#include <zlib.h> 21135045Ssobomax#include <err.h> 22135045Ssobomax#include <fcntl.h> 23135045Ssobomax#include <signal.h> 24135045Ssobomax#include <stdio.h> 25135045Ssobomax#include <stdlib.h> 26135045Ssobomax#include <string.h> 27135045Ssobomax#include <unistd.h> 28135045Ssobomax 29135045Ssobomax#define CLSTSIZE 16384 30135045Ssobomax#define DEFAULT_SUFX ".uzip" 31135045Ssobomax 32135045Ssobomax#define CLOOP_MAGIC_LEN 128 33135045Ssobomaxstatic char CLOOP_MAGIC_START[] = "#!/bin/sh\n#V2.0 Format\n" 34221832Sru "(kldstat -qm g_uzip||kldload geom_uzip)>&-&&" 35135045Ssobomax "mount_cd9660 /dev/`mdconfig -af $0`.uzip $1\nexit $?\n"; 36135045Ssobomax 37135045Ssobomaxstatic char *readblock(int, char *, u_int32_t); 38135045Ssobomaxstatic void usage(void); 39135045Ssobomaxstatic void *safe_malloc(size_t); 40135045Ssobomaxstatic void cleanup(void); 41135045Ssobomax 42135045Ssobomaxstatic char *cleanfile = NULL; 43135045Ssobomax 44135045Ssobomaxint main(int argc, char **argv) 45135045Ssobomax{ 46135045Ssobomax char *iname, *oname, *obuf, *ibuf; 47135045Ssobomax uint64_t *toc; 48135045Ssobomax int fdr, fdw, i, opt, verbose, tmp; 49135045Ssobomax struct iovec iov[2]; 50135045Ssobomax struct stat sb; 51135045Ssobomax uLongf destlen; 52135045Ssobomax uint64_t offset; 53135045Ssobomax struct cloop_header { 54135045Ssobomax char magic[CLOOP_MAGIC_LEN]; /* cloop magic */ 55135045Ssobomax uint32_t blksz; /* block size */ 56135045Ssobomax uint32_t nblocks; /* number of blocks */ 57135045Ssobomax } hdr; 58135045Ssobomax 59135045Ssobomax memset(&hdr, 0, sizeof(hdr)); 60135045Ssobomax hdr.blksz = CLSTSIZE; 61135045Ssobomax strcpy(hdr.magic, CLOOP_MAGIC_START); 62135045Ssobomax oname = NULL; 63135045Ssobomax verbose = 0; 64135045Ssobomax 65135045Ssobomax while((opt = getopt(argc, argv, "o:s:v")) != -1) { 66135045Ssobomax switch(opt) { 67135045Ssobomax case 'o': 68135045Ssobomax oname = optarg; 69135045Ssobomax break; 70135045Ssobomax 71135045Ssobomax case 's': 72135045Ssobomax tmp = atoi(optarg); 73135045Ssobomax if (tmp <= 0) { 74135045Ssobomax errx(1, "invalid cluster size specified: %s", 75135045Ssobomax optarg); 76135045Ssobomax /* Not reached */ 77135045Ssobomax } 78135045Ssobomax if (tmp % DEV_BSIZE != 0) { 79135045Ssobomax errx(1, "cluster size should be multiple of %d", 80135045Ssobomax DEV_BSIZE); 81135045Ssobomax /* Not reached */ 82135045Ssobomax } 83135058Ssobomax if (compressBound(tmp) > MAXPHYS) { 84135058Ssobomax errx(1, "cluster size is too large"); 85135045Ssobomax /* Not reached */ 86135045Ssobomax } 87135045Ssobomax hdr.blksz = tmp; 88135045Ssobomax break; 89135045Ssobomax 90135045Ssobomax case 'v': 91135045Ssobomax verbose = 1; 92135045Ssobomax break; 93135045Ssobomax 94135045Ssobomax default: 95135045Ssobomax usage(); 96135045Ssobomax /* Not reached */ 97135045Ssobomax } 98135045Ssobomax } 99135045Ssobomax argc -= optind; 100135045Ssobomax argv += optind; 101135045Ssobomax 102135045Ssobomax if (argc != 1) { 103135045Ssobomax usage(); 104135045Ssobomax /* Not reached */ 105135045Ssobomax } 106135045Ssobomax 107135045Ssobomax iname = argv[0]; 108135045Ssobomax if (oname == NULL) { 109135045Ssobomax asprintf(&oname, "%s%s", iname, DEFAULT_SUFX); 110135045Ssobomax if (oname == NULL) { 111135045Ssobomax err(1, "can't allocate memory"); 112135045Ssobomax /* Not reached */ 113135045Ssobomax } 114135045Ssobomax } 115135045Ssobomax 116135045Ssobomax obuf = safe_malloc(compressBound(hdr.blksz)); 117135045Ssobomax ibuf = safe_malloc(hdr.blksz); 118135045Ssobomax 119135045Ssobomax signal(SIGHUP, exit); 120135045Ssobomax signal(SIGINT, exit); 121135045Ssobomax signal(SIGTERM, exit); 122135045Ssobomax signal(SIGXCPU, exit); 123135045Ssobomax signal(SIGXFSZ, exit); 124135045Ssobomax atexit(cleanup); 125135045Ssobomax 126167272Sfjoe fdr = open(iname, O_RDONLY); 127167272Sfjoe if (fdr < 0) { 128167272Sfjoe err(1, "open(%s)", iname); 129135045Ssobomax /* Not reached */ 130135045Ssobomax } 131167272Sfjoe if (fstat(fdr, &sb) != 0) { 132167272Sfjoe err(1, "fstat(%s)", iname); 133167272Sfjoe /* Not reached */ 134167272Sfjoe } 135167272Sfjoe if (S_ISCHR(sb.st_mode)) { 136167272Sfjoe off_t ms; 137167272Sfjoe 138167272Sfjoe if (ioctl(fdr, DIOCGMEDIASIZE, &ms) < 0) { 139167272Sfjoe err(1, "ioctl(DIOCGMEDIASIZE)"); 140167272Sfjoe /* Not reached */ 141167272Sfjoe } 142167272Sfjoe sb.st_size = ms; 143167272Sfjoe } else if (!S_ISREG(sb.st_mode)) { 144167272Sfjoe fprintf(stderr, "%s: not a character device or regular file\n", 145167272Sfjoe iname); 146167272Sfjoe exit(1); 147167272Sfjoe } 148135058Ssobomax hdr.nblocks = sb.st_size / hdr.blksz; 149135045Ssobomax if ((sb.st_size % hdr.blksz) != 0) { 150135058Ssobomax if (verbose != 0) 151135058Ssobomax fprintf(stderr, "file size is not multiple " 152135058Ssobomax "of %d, padding data\n", hdr.blksz); 153135058Ssobomax hdr.nblocks++; 154135045Ssobomax } 155135045Ssobomax toc = safe_malloc((hdr.nblocks + 1) * sizeof(*toc)); 156135045Ssobomax 157135045Ssobomax fdw = open(oname, O_WRONLY | O_TRUNC | O_CREAT, 158146107Sfjoe S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 159135045Ssobomax if (fdw < 0) { 160155074Spjd err(1, "open(%s)", oname); 161135045Ssobomax /* Not reached */ 162135045Ssobomax } 163135045Ssobomax cleanfile = oname; 164135045Ssobomax 165135045Ssobomax /* Prepare header that we will write later when we have index ready. */ 166135045Ssobomax iov[0].iov_base = (char *)&hdr; 167135045Ssobomax iov[0].iov_len = sizeof(hdr); 168135045Ssobomax iov[1].iov_base = (char *)toc; 169135045Ssobomax iov[1].iov_len = (hdr.nblocks + 1) * sizeof(*toc); 170135045Ssobomax offset = iov[0].iov_len + iov[1].iov_len; 171135045Ssobomax 172135045Ssobomax /* Reserve space for header */ 173135045Ssobomax lseek(fdw, offset, SEEK_SET); 174135045Ssobomax 175135045Ssobomax if (verbose != 0) 176145808Ssobomax fprintf(stderr, "data size %ju bytes, number of clusters " 177146107Sfjoe "%u, index length %zu bytes\n", sb.st_size, 178135058Ssobomax hdr.nblocks, iov[1].iov_len); 179135045Ssobomax 180135045Ssobomax for(i = 0; i == 0 || ibuf != NULL; i++) { 181135045Ssobomax ibuf = readblock(fdr, ibuf, hdr.blksz); 182135045Ssobomax if (ibuf != NULL) { 183135045Ssobomax destlen = compressBound(hdr.blksz); 184135058Ssobomax if (compress2(obuf, &destlen, ibuf, hdr.blksz, 185135058Ssobomax Z_BEST_COMPRESSION) != Z_OK) { 186135058Ssobomax errx(1, "can't compress data: compress2() " 187135058Ssobomax "failed"); 188135045Ssobomax /* Not reached */ 189135045Ssobomax } 190135058Ssobomax if (verbose != 0) 191135058Ssobomax fprintf(stderr, "cluster #%d, in %u bytes, " 192135058Ssobomax "out %lu bytes\n", i, hdr.blksz, destlen); 193135045Ssobomax } else { 194135045Ssobomax destlen = DEV_BSIZE - (offset % DEV_BSIZE); 195135045Ssobomax memset(obuf, 0, destlen); 196135058Ssobomax if (verbose != 0) 197135058Ssobomax fprintf(stderr, "padding data with %lu bytes so " 198135058Ssobomax "that file size is multiple of %d\n", destlen, 199135058Ssobomax DEV_BSIZE); 200135045Ssobomax } 201135045Ssobomax if (write(fdw, obuf, destlen) < 0) { 202155074Spjd err(1, "write(%s)", oname); 203135045Ssobomax /* Not reached */ 204135045Ssobomax } 205135045Ssobomax toc[i] = htobe64(offset); 206135045Ssobomax offset += destlen; 207135045Ssobomax } 208135045Ssobomax close(fdr); 209135045Ssobomax 210135045Ssobomax if (verbose != 0) 211145808Ssobomax fprintf(stderr, "compressed data to %ju bytes, saved %lld " 212135058Ssobomax "bytes, %.2f%% decrease.\n", offset, (long long)(sb.st_size - offset), 213135058Ssobomax 100.0 * (long long)(sb.st_size - offset) / (float)sb.st_size); 214135045Ssobomax 215135045Ssobomax /* Convert to big endian */ 216135045Ssobomax hdr.blksz = htonl(hdr.blksz); 217135045Ssobomax hdr.nblocks = htonl(hdr.nblocks); 218135045Ssobomax /* Write headers into pre-allocated space */ 219135045Ssobomax lseek(fdw, 0, SEEK_SET); 220135045Ssobomax if (writev(fdw, iov, 2) < 0) { 221155074Spjd err(1, "writev(%s)", oname); 222135045Ssobomax /* Not reached */ 223135045Ssobomax } 224135045Ssobomax cleanfile = NULL; 225135045Ssobomax close(fdw); 226135045Ssobomax 227135045Ssobomax exit(0); 228135045Ssobomax} 229135045Ssobomax 230135045Ssobomaxstatic char * 231135058Ssobomaxreadblock(int fd, char *ibuf, u_int32_t clstsize) 232135058Ssobomax{ 233135045Ssobomax int numread; 234135045Ssobomax 235135045Ssobomax bzero(ibuf, clstsize); 236135045Ssobomax numread = read(fd, ibuf, clstsize); 237135045Ssobomax if (numread < 0) { 238135045Ssobomax err(1, "read() failed"); 239135045Ssobomax /* Not reached */ 240135045Ssobomax } 241135045Ssobomax if (numread == 0) { 242135045Ssobomax return NULL; 243135045Ssobomax } 244135045Ssobomax return ibuf; 245135045Ssobomax} 246135045Ssobomax 247135045Ssobomaxstatic void 248135058Ssobomaxusage(void) 249135058Ssobomax{ 250135045Ssobomax 251135045Ssobomax fprintf(stderr, "usage: mkuzip [-v] [-o outfile] [-s cluster_size] infile\n"); 252135045Ssobomax exit(1); 253135045Ssobomax} 254135045Ssobomax 255135045Ssobomaxstatic void * 256135058Ssobomaxsafe_malloc(size_t size) 257135058Ssobomax{ 258135045Ssobomax void *retval; 259135045Ssobomax 260135045Ssobomax retval = malloc(size); 261135045Ssobomax if (retval == NULL) { 262135045Ssobomax err(1, "can't allocate memory"); 263135045Ssobomax /* Not reached */ 264135045Ssobomax } 265135045Ssobomax return retval; 266135045Ssobomax} 267135045Ssobomax 268135045Ssobomaxstatic void 269135058Ssobomaxcleanup(void) 270135058Ssobomax{ 271135045Ssobomax 272135045Ssobomax if (cleanfile != NULL) 273135045Ssobomax unlink(cleanfile); 274135045Ssobomax} 275