mkuzip.c revision 145808
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: head/usr.bin/mkuzip/mkuzip.c 145808 2005-05-02 17:38:49Z sobomax $ 10135045Ssobomax * 11135045Ssobomax */ 12135045Ssobomax 13135045Ssobomax#include <sys/types.h> 14135045Ssobomax#include <sys/endian.h> 15135045Ssobomax#include <sys/param.h> 16135045Ssobomax#include <sys/stat.h> 17135045Ssobomax#include <sys/uio.h> 18135045Ssobomax#include <netinet/in.h> 19135045Ssobomax#include <zlib.h> 20135045Ssobomax#include <err.h> 21135045Ssobomax#include <fcntl.h> 22135045Ssobomax#include <signal.h> 23135045Ssobomax#include <stdio.h> 24135045Ssobomax#include <stdlib.h> 25135045Ssobomax#include <string.h> 26135045Ssobomax#include <unistd.h> 27135045Ssobomax 28135045Ssobomax#define CLSTSIZE 16384 29135045Ssobomax#define DEFAULT_SUFX ".uzip" 30135045Ssobomax 31135045Ssobomax#define CLOOP_MAGIC_LEN 128 32135045Ssobomaxstatic char CLOOP_MAGIC_START[] = "#!/bin/sh\n#V2.0 Format\n" 33135045Ssobomax "m=geom_uzip\n(kldstat -n $m 2>&-||kldload $m)>&-&&" 34135045Ssobomax "mount_cd9660 /dev/`mdconfig -af $0`.uzip $1\nexit $?\n"; 35135045Ssobomax 36135045Ssobomaxstatic char *readblock(int, char *, u_int32_t); 37135045Ssobomaxstatic void usage(void); 38135045Ssobomaxstatic void *safe_malloc(size_t); 39135045Ssobomaxstatic void cleanup(void); 40135045Ssobomax 41135045Ssobomaxstatic char *cleanfile = NULL; 42135045Ssobomax 43135045Ssobomaxint main(int argc, char **argv) 44135045Ssobomax{ 45135045Ssobomax char *iname, *oname, *obuf, *ibuf; 46135045Ssobomax uint64_t *toc; 47135045Ssobomax int fdr, fdw, i, opt, verbose, tmp; 48135045Ssobomax struct iovec iov[2]; 49135045Ssobomax struct stat sb; 50135045Ssobomax uLongf destlen; 51135045Ssobomax uint64_t offset; 52135045Ssobomax struct cloop_header { 53135045Ssobomax char magic[CLOOP_MAGIC_LEN]; /* cloop magic */ 54135045Ssobomax uint32_t blksz; /* block size */ 55135045Ssobomax uint32_t nblocks; /* number of blocks */ 56135045Ssobomax } hdr; 57135045Ssobomax 58135045Ssobomax memset(&hdr, 0, sizeof(hdr)); 59135045Ssobomax hdr.blksz = CLSTSIZE; 60135045Ssobomax strcpy(hdr.magic, CLOOP_MAGIC_START); 61135045Ssobomax oname = NULL; 62135045Ssobomax verbose = 0; 63135045Ssobomax 64135045Ssobomax while((opt = getopt(argc, argv, "o:s:v")) != -1) { 65135045Ssobomax switch(opt) { 66135045Ssobomax case 'o': 67135045Ssobomax oname = optarg; 68135045Ssobomax break; 69135045Ssobomax 70135045Ssobomax case 's': 71135045Ssobomax tmp = atoi(optarg); 72135045Ssobomax if (tmp <= 0) { 73135045Ssobomax errx(1, "invalid cluster size specified: %s", 74135045Ssobomax optarg); 75135045Ssobomax /* Not reached */ 76135045Ssobomax } 77135045Ssobomax if (tmp % DEV_BSIZE != 0) { 78135045Ssobomax errx(1, "cluster size should be multiple of %d", 79135045Ssobomax DEV_BSIZE); 80135045Ssobomax /* Not reached */ 81135045Ssobomax } 82135058Ssobomax if (compressBound(tmp) > MAXPHYS) { 83135058Ssobomax errx(1, "cluster size is too large"); 84135045Ssobomax /* Not reached */ 85135045Ssobomax } 86135045Ssobomax hdr.blksz = tmp; 87135045Ssobomax break; 88135045Ssobomax 89135045Ssobomax case 'v': 90135045Ssobomax verbose = 1; 91135045Ssobomax break; 92135045Ssobomax 93135045Ssobomax default: 94135045Ssobomax usage(); 95135045Ssobomax /* Not reached */ 96135045Ssobomax } 97135045Ssobomax } 98135045Ssobomax argc -= optind; 99135045Ssobomax argv += optind; 100135045Ssobomax 101135045Ssobomax if (argc != 1) { 102135045Ssobomax usage(); 103135045Ssobomax /* Not reached */ 104135045Ssobomax } 105135045Ssobomax 106135045Ssobomax iname = argv[0]; 107135045Ssobomax if (oname == NULL) { 108135045Ssobomax asprintf(&oname, "%s%s", iname, DEFAULT_SUFX); 109135045Ssobomax if (oname == NULL) { 110135045Ssobomax err(1, "can't allocate memory"); 111135045Ssobomax /* Not reached */ 112135045Ssobomax } 113135045Ssobomax } 114135045Ssobomax 115135045Ssobomax obuf = safe_malloc(compressBound(hdr.blksz)); 116135045Ssobomax ibuf = safe_malloc(hdr.blksz); 117135045Ssobomax 118135045Ssobomax signal(SIGHUP, exit); 119135045Ssobomax signal(SIGINT, exit); 120135045Ssobomax signal(SIGTERM, exit); 121135045Ssobomax signal(SIGXCPU, exit); 122135045Ssobomax signal(SIGXFSZ, exit); 123135045Ssobomax atexit(cleanup); 124135045Ssobomax 125135045Ssobomax if (stat(iname, &sb) != 0) { 126135045Ssobomax err(1, "%s", iname); 127135045Ssobomax /* Not reached */ 128135045Ssobomax } 129135058Ssobomax hdr.nblocks = sb.st_size / hdr.blksz; 130135045Ssobomax if ((sb.st_size % hdr.blksz) != 0) { 131135058Ssobomax if (verbose != 0) 132135058Ssobomax fprintf(stderr, "file size is not multiple " 133135058Ssobomax "of %d, padding data\n", hdr.blksz); 134135058Ssobomax hdr.nblocks++; 135135045Ssobomax } 136135045Ssobomax toc = safe_malloc((hdr.nblocks + 1) * sizeof(*toc)); 137135045Ssobomax 138135045Ssobomax fdr = open(iname, O_RDONLY); 139135045Ssobomax if (fdr < 0) { 140135045Ssobomax err(1, "%s", iname); 141135045Ssobomax /* Not reached */ 142135045Ssobomax } 143135045Ssobomax fdw = open(oname, O_WRONLY | O_TRUNC | O_CREAT, 144135045Ssobomax S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 145135045Ssobomax if (fdw < 0) { 146135045Ssobomax err(1, "%s", oname); 147135045Ssobomax /* Not reached */ 148135045Ssobomax } 149135045Ssobomax cleanfile = oname; 150135045Ssobomax 151135045Ssobomax /* Prepare header that we will write later when we have index ready. */ 152135045Ssobomax iov[0].iov_base = (char *)&hdr; 153135045Ssobomax iov[0].iov_len = sizeof(hdr); 154135045Ssobomax iov[1].iov_base = (char *)toc; 155135045Ssobomax iov[1].iov_len = (hdr.nblocks + 1) * sizeof(*toc); 156135045Ssobomax offset = iov[0].iov_len + iov[1].iov_len; 157135045Ssobomax 158135045Ssobomax /* Reserve space for header */ 159135045Ssobomax lseek(fdw, offset, SEEK_SET); 160135045Ssobomax 161135045Ssobomax if (verbose != 0) 162145808Ssobomax fprintf(stderr, "data size %ju bytes, number of clusters " 163145808Ssobomax "%u, index lengh %zu bytes\n", sb.st_size, 164135058Ssobomax hdr.nblocks, iov[1].iov_len); 165135045Ssobomax 166135045Ssobomax for(i = 0; i == 0 || ibuf != NULL; i++) { 167135045Ssobomax ibuf = readblock(fdr, ibuf, hdr.blksz); 168135045Ssobomax if (ibuf != NULL) { 169135045Ssobomax destlen = compressBound(hdr.blksz); 170135058Ssobomax if (compress2(obuf, &destlen, ibuf, hdr.blksz, 171135058Ssobomax Z_BEST_COMPRESSION) != Z_OK) { 172135058Ssobomax errx(1, "can't compress data: compress2() " 173135058Ssobomax "failed"); 174135045Ssobomax /* Not reached */ 175135045Ssobomax } 176135058Ssobomax if (verbose != 0) 177135058Ssobomax fprintf(stderr, "cluster #%d, in %u bytes, " 178135058Ssobomax "out %lu bytes\n", i, hdr.blksz, destlen); 179135045Ssobomax } else { 180135045Ssobomax destlen = DEV_BSIZE - (offset % DEV_BSIZE); 181135045Ssobomax memset(obuf, 0, destlen); 182135058Ssobomax if (verbose != 0) 183135058Ssobomax fprintf(stderr, "padding data with %lu bytes so " 184135058Ssobomax "that file size is multiple of %d\n", destlen, 185135058Ssobomax DEV_BSIZE); 186135045Ssobomax } 187135045Ssobomax if (write(fdw, obuf, destlen) < 0) { 188135045Ssobomax err(1, "%s", oname); 189135045Ssobomax /* Not reached */ 190135045Ssobomax } 191135045Ssobomax toc[i] = htobe64(offset); 192135045Ssobomax offset += destlen; 193135045Ssobomax } 194135045Ssobomax close(fdr); 195135045Ssobomax 196135045Ssobomax if (verbose != 0) 197145808Ssobomax fprintf(stderr, "compressed data to %ju bytes, saved %lld " 198135058Ssobomax "bytes, %.2f%% decrease.\n", offset, (long long)(sb.st_size - offset), 199135058Ssobomax 100.0 * (long long)(sb.st_size - offset) / (float)sb.st_size); 200135045Ssobomax 201135045Ssobomax /* Convert to big endian */ 202135045Ssobomax hdr.blksz = htonl(hdr.blksz); 203135045Ssobomax hdr.nblocks = htonl(hdr.nblocks); 204135045Ssobomax /* Write headers into pre-allocated space */ 205135045Ssobomax lseek(fdw, 0, SEEK_SET); 206135045Ssobomax if (writev(fdw, iov, 2) < 0) { 207135045Ssobomax err(1, "%s", oname); 208135045Ssobomax /* Not reached */ 209135045Ssobomax } 210135045Ssobomax cleanfile = NULL; 211135045Ssobomax close(fdw); 212135045Ssobomax 213135045Ssobomax exit(0); 214135045Ssobomax} 215135045Ssobomax 216135045Ssobomaxstatic char * 217135058Ssobomaxreadblock(int fd, char *ibuf, u_int32_t clstsize) 218135058Ssobomax{ 219135045Ssobomax int numread; 220135045Ssobomax 221135045Ssobomax bzero(ibuf, clstsize); 222135045Ssobomax numread = read(fd, ibuf, clstsize); 223135045Ssobomax if (numread < 0) { 224135045Ssobomax err(1, "read() failed"); 225135045Ssobomax /* Not reached */ 226135045Ssobomax } 227135045Ssobomax if (numread == 0) { 228135045Ssobomax return NULL; 229135045Ssobomax } 230135045Ssobomax return ibuf; 231135045Ssobomax} 232135045Ssobomax 233135045Ssobomaxstatic void 234135058Ssobomaxusage(void) 235135058Ssobomax{ 236135045Ssobomax 237135045Ssobomax fprintf(stderr, "usage: mkuzip [-v] [-o outfile] [-s cluster_size] infile\n"); 238135045Ssobomax exit(1); 239135045Ssobomax} 240135045Ssobomax 241135045Ssobomaxstatic void * 242135058Ssobomaxsafe_malloc(size_t size) 243135058Ssobomax{ 244135045Ssobomax void *retval; 245135045Ssobomax 246135045Ssobomax retval = malloc(size); 247135045Ssobomax if (retval == NULL) { 248135045Ssobomax err(1, "can't allocate memory"); 249135045Ssobomax /* Not reached */ 250135045Ssobomax } 251135045Ssobomax return retval; 252135045Ssobomax} 253135045Ssobomax 254135045Ssobomaxstatic void 255135058Ssobomaxcleanup(void) 256135058Ssobomax{ 257135045Ssobomax 258135045Ssobomax if (cleanfile != NULL) 259135045Ssobomax unlink(cleanfile); 260135045Ssobomax} 261