]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/mkuzip/mkuzip.c
Regen.
[FreeBSD/FreeBSD.git] / usr.bin / mkuzip / mkuzip.c
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <sobomax@FreeBSD.ORG> wrote this file. As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.       Maxim Sobolev
7  * ----------------------------------------------------------------------------
8  *
9  * $FreeBSD$
10  *
11  */
12
13 #include <sys/types.h>
14 #include <sys/endian.h>
15 #include <sys/param.h>
16 #include <sys/stat.h>
17 #include <sys/uio.h>
18 #include <netinet/in.h>
19 #include <zlib.h>
20 #include <err.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #define CLSTSIZE        16384
29 #define DEFAULT_SUFX    ".uzip"
30
31 #define CLOOP_MAGIC_LEN 128
32 static char CLOOP_MAGIC_START[] = "#!/bin/sh\n#V2.0 Format\n"
33     "m=geom_uzip\n(kldstat -m $m 2>&-||kldload $m)>&-&&"
34     "mount_cd9660 /dev/`mdconfig -af $0`.uzip $1\nexit $?\n";
35
36 static char *readblock(int, char *, u_int32_t);
37 static void usage(void);
38 static void *safe_malloc(size_t);
39 static void cleanup(void);
40
41 static char *cleanfile = NULL;
42
43 int main(int argc, char **argv)
44 {
45         char *iname, *oname, *obuf, *ibuf;
46         uint64_t *toc;
47         int fdr, fdw, i, opt, verbose, tmp;
48         struct iovec iov[2];
49         struct stat sb;
50         uLongf destlen;
51         uint64_t offset;
52         struct cloop_header {
53                 char magic[CLOOP_MAGIC_LEN];    /* cloop magic */
54                 uint32_t blksz;                 /* block size */
55                 uint32_t nblocks;               /* number of blocks */
56         } hdr;
57
58         memset(&hdr, 0, sizeof(hdr));
59         hdr.blksz = CLSTSIZE;
60         strcpy(hdr.magic, CLOOP_MAGIC_START);
61         oname = NULL;
62         verbose = 0;
63
64         while((opt = getopt(argc, argv, "o:s:v")) != -1) {
65                 switch(opt) {
66                 case 'o':
67                         oname = optarg;
68                         break;
69
70                 case 's':
71                         tmp = atoi(optarg);
72                         if (tmp <= 0) {
73                                 errx(1, "invalid cluster size specified: %s",
74                                     optarg);
75                                 /* Not reached */
76                         }
77                         if (tmp % DEV_BSIZE != 0) {
78                                 errx(1, "cluster size should be multiple of %d",
79                                     DEV_BSIZE);
80                                 /* Not reached */
81                         }
82                         if (compressBound(tmp) > MAXPHYS) {
83                                 errx(1, "cluster size is too large");
84                                     /* Not reached */
85                         }
86                         hdr.blksz = tmp;
87                         break;
88
89                 case 'v':
90                         verbose = 1;
91                         break;
92
93                 default:
94                         usage();
95                         /* Not reached */
96                 }
97         }
98         argc -= optind;
99         argv += optind;
100
101         if (argc != 1) {
102                 usage();
103                 /* Not reached */
104         }
105
106         iname = argv[0];
107         if (oname == NULL) {
108                 asprintf(&oname, "%s%s", iname, DEFAULT_SUFX);
109                 if (oname == NULL) {
110                         err(1, "can't allocate memory");
111                         /* Not reached */
112                 }
113         }
114
115         obuf = safe_malloc(compressBound(hdr.blksz));
116         ibuf = safe_malloc(hdr.blksz);
117
118         signal(SIGHUP, exit);
119         signal(SIGINT, exit);
120         signal(SIGTERM, exit);
121         signal(SIGXCPU, exit);
122         signal(SIGXFSZ, exit);
123         atexit(cleanup);
124
125         if (stat(iname, &sb) != 0) {
126                 err(1, "stat(%s)", iname);
127                 /* Not reached */
128         }
129         hdr.nblocks = sb.st_size / hdr.blksz;
130         if ((sb.st_size % hdr.blksz) != 0) {
131                 if (verbose != 0)
132                         fprintf(stderr, "file size is not multiple "
133                         "of %d, padding data\n", hdr.blksz);
134                 hdr.nblocks++;
135         }
136         toc = safe_malloc((hdr.nblocks + 1) * sizeof(*toc));
137
138         fdr = open(iname, O_RDONLY);
139         if (fdr < 0) {
140                 err(1, "open(%s)", iname);
141                 /* Not reached */
142         }
143         fdw = open(oname, O_WRONLY | O_TRUNC | O_CREAT,
144                    S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
145         if (fdw < 0) {
146                 err(1, "open(%s)", oname);
147                 /* Not reached */
148         }
149         cleanfile = oname;
150
151         /* Prepare header that we will write later when we have index ready. */
152         iov[0].iov_base = (char *)&hdr;
153         iov[0].iov_len = sizeof(hdr);
154         iov[1].iov_base = (char *)toc;
155         iov[1].iov_len = (hdr.nblocks + 1) * sizeof(*toc);
156         offset = iov[0].iov_len + iov[1].iov_len;
157
158         /* Reserve space for header */
159         lseek(fdw, offset, SEEK_SET);
160
161         if (verbose != 0)
162                 fprintf(stderr, "data size %ju bytes, number of clusters "
163                     "%u, index length %zu bytes\n", sb.st_size,
164                     hdr.nblocks, iov[1].iov_len);
165
166         for(i = 0; i == 0 || ibuf != NULL; i++) {
167                 ibuf = readblock(fdr, ibuf, hdr.blksz);
168                 if (ibuf != NULL) {
169                         destlen = compressBound(hdr.blksz);
170                         if (compress2(obuf, &destlen, ibuf, hdr.blksz,
171                             Z_BEST_COMPRESSION) != Z_OK) {
172                                 errx(1, "can't compress data: compress2() "
173                                     "failed");
174                                 /* Not reached */
175                         }
176                         if (verbose != 0)
177                                 fprintf(stderr, "cluster #%d, in %u bytes, "
178                                     "out %lu bytes\n", i, hdr.blksz, destlen);
179                 } else {
180                         destlen = DEV_BSIZE - (offset % DEV_BSIZE);
181                         memset(obuf, 0, destlen);
182                         if (verbose != 0)
183                                 fprintf(stderr, "padding data with %lu bytes so "
184                                     "that file size is multiple of %d\n", destlen,
185                                     DEV_BSIZE);
186                 }
187                 if (write(fdw, obuf, destlen) < 0) {
188                         err(1, "write(%s)", oname);
189                         /* Not reached */
190                 }
191                 toc[i] = htobe64(offset);
192                 offset += destlen;
193         }
194         close(fdr);
195
196         if (verbose != 0)
197                 fprintf(stderr, "compressed data to %ju bytes, saved %lld "
198                     "bytes, %.2f%% decrease.\n", offset, (long long)(sb.st_size - offset),
199                     100.0 * (long long)(sb.st_size - offset) / (float)sb.st_size);
200
201         /* Convert to big endian */
202         hdr.blksz = htonl(hdr.blksz);
203         hdr.nblocks = htonl(hdr.nblocks);
204         /* Write headers into pre-allocated space */
205         lseek(fdw, 0, SEEK_SET);
206         if (writev(fdw, iov, 2) < 0) {
207                 err(1, "writev(%s)", oname);
208                 /* Not reached */
209         }
210         cleanfile = NULL;
211         close(fdw);
212
213         exit(0);
214 }
215
216 static char *
217 readblock(int fd, char *ibuf, u_int32_t clstsize)
218 {
219         int numread;
220
221         bzero(ibuf, clstsize);
222         numread = read(fd, ibuf, clstsize);
223         if (numread < 0) {
224                 err(1, "read() failed");
225                 /* Not reached */
226         }
227         if (numread == 0) {
228                 return NULL;
229         }
230         return ibuf;
231 }
232
233 static void
234 usage(void)
235 {
236
237         fprintf(stderr, "usage: mkuzip [-v] [-o outfile] [-s cluster_size] infile\n");
238         exit(1);
239 }
240
241 static void *
242 safe_malloc(size_t size)
243 {
244         void *retval;
245
246         retval = malloc(size);
247         if (retval == NULL) {
248                 err(1, "can't allocate memory");
249                 /* Not reached */
250         }
251         return retval;
252 }
253
254 static void
255 cleanup(void)
256 {
257
258         if (cleanfile != NULL)
259                 unlink(cleanfile);
260 }