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