Print this page
PSARC 2007/569 lofi(7D) compression support
6618343 lofi compression support
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/lofiadm/main.c
+++ new/usr/src/cmd/lofiadm/main.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * lofiadm - administer lofi(7d). Very simple, add and remove file<->device
28 28 * associations, and display status. All the ioctls are private between
|
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
29 29 * lofi and lofiadm, and so are very simple - device information is
30 30 * communicated via a minor number.
31 31 */
32 32
33 33 #pragma ident "%Z%%M% %I% %E% SMI"
34 34
35 35 #include <sys/types.h>
36 36 #include <sys/param.h>
37 37 #include <sys/lofi.h>
38 38 #include <sys/stat.h>
39 +#include <netinet/in.h>
39 40 #include <stdio.h>
40 41 #include <fcntl.h>
41 42 #include <locale.h>
42 43 #include <string.h>
43 44 #include <errno.h>
44 45 #include <stdlib.h>
45 46 #include <unistd.h>
46 47 #include <stropts.h>
47 48 #include <libdevinfo.h>
49 +#include <libgen.h>
50 +#include <zlib.h>
48 51 #include "utils.h"
49 52
50 53 static const char USAGE[] =
51 54 "Usage: %s -a file [ device ]\n"
52 55 " %s -d file | device \n"
56 + " %s -C [algorithm] [-s segment_size] file \n"
57 + " %s -U file \n"
53 58 " %s [ device | file ]\n";
54 59
55 60 static const char *pname;
56 61 static int addflag = 0;
57 62 static int deleteflag = 0;
58 63 static int errflag = 0;
64 +static int compressflag = 0;
65 +static int uncompressflag = 0;
59 66
60 -#define FORMAT "%-20s %s\n"
67 +static int gzip_compress(void *src, size_t srclen, void *dst,
68 + size_t *destlen, int level);
61 69
70 +lofi_compress_info_t lofi_compress_table[LOFI_COMPRESS_FUNCTIONS] = {
71 + {NULL, gzip_compress, 6, "gzip"}, /* default */
72 + {NULL, gzip_compress, 6, "gzip-6"},
73 + {NULL, gzip_compress, 9, "gzip-9"}
74 +};
75 +
76 +#define FORMAT "%-20s %-30s %s\n"
77 +#define REGULAR "-"
78 +#define COMPRESS "Compressed"
79 +#define COMPRESS_THRESHOLD 2048
80 +#define COMPRESS_ALGORITHM "gzip"
81 +#define SEGSIZE 131072
82 +
83 +static int gzip_compress(void *src, size_t srclen, void *dst,
84 + size_t *dstlen, int level)
85 +{
86 + if (compress2(dst, (ulong_t *)dstlen, src, srclen, level) != Z_OK)
87 + return (-1);
88 +
89 + return (0);
90 +}
91 +
62 92 /*
63 93 * Print the list of all the mappings. Including a header.
64 94 */
65 95 static void
66 96 print_mappings(int fd)
67 97 {
68 98 struct lofi_ioctl li;
69 99 int minor;
70 100 int maxminor;
71 - char path[MAXPATHLEN + 1];
101 + char path[MAXPATHLEN];
102 + char type[MAXPATHLEN];
72 103
73 104 li.li_minor = 0;
74 105 if (ioctl(fd, LOFI_GET_MAXMINOR, &li) == -1) {
75 106 perror("ioctl");
76 107 exit(E_ERROR);
77 108 }
78 109
79 110 maxminor = li.li_minor;
80 111
81 - (void) printf(FORMAT, "Block Device", "File");
112 + (void) printf(FORMAT, "Block Device", "File", "Options");
82 113 for (minor = 1; minor <= maxminor; minor++) {
83 114 li.li_minor = minor;
84 115 if (ioctl(fd, LOFI_GET_FILENAME, &li) == -1) {
85 116 if (errno == ENXIO)
86 117 continue;
87 118 perror("ioctl");
88 119 break;
89 120 }
90 121 (void) snprintf(path, sizeof (path), "/dev/%s/%d",
91 122 LOFI_BLOCK_NAME, minor);
92 - (void) printf(FORMAT, path, li.li_filename);
123 + if (li.li_algorithm[0] == '\0')
124 + (void) snprintf(type, sizeof (type), "%s", REGULAR);
125 + else
126 + (void) snprintf(type, sizeof (type),
127 + COMPRESS "(%s)", li.li_algorithm);
128 +
129 + (void) printf(FORMAT, path, li.li_filename, type);
93 130 }
94 131 }
95 132
96 133 static void
97 134 usage(void)
98 135 {
99 - (void) fprintf(stderr, gettext(USAGE), pname, pname, pname);
136 + (void) fprintf(stderr, gettext(USAGE), pname, pname,
137 + pname, pname, pname);
100 138 exit(E_USAGE);
101 139 }
102 140
103 141 /*
104 142 * Translate a lofi device name to a minor number. We might be asked
105 143 * to do this when there is no association (such as when the user specifies
106 144 * a particular device), so we can only look at the string.
107 145 */
108 146 static int
109 147 name_to_minor(const char *devicename)
110 148 {
111 149 int minor;
112 150
113 151 if (sscanf(devicename, "/dev/" LOFI_BLOCK_NAME "/%d", &minor) == 1) {
114 152 return (minor);
115 153 }
116 154 if (sscanf(devicename, "/dev/" LOFI_CHAR_NAME "/%d", &minor) == 1) {
117 155 return (minor);
118 156 }
119 157 return (0);
120 158 }
121 159
122 160 /*
123 161 * This might be the first time we've used this minor number. If so,
124 162 * it might also be that the /dev links are in the process of being created
125 163 * by devfsadmd (or that they'll be created "soon"). We cannot return
126 164 * until they're there or the invoker of lofiadm might try to use them
127 165 * and not find them. This can happen if a shell script is running on
|
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
128 166 * an MP.
129 167 */
130 168 static int sleeptime = 2; /* number of seconds to sleep between stat's */
131 169 static int maxsleep = 120; /* maximum number of seconds to sleep */
132 170
133 171 static void
134 172 wait_until_dev_complete(int minor)
135 173 {
136 174 struct stat64 buf;
137 175 int cursleep;
138 - char blkpath[MAXPATHLEN + 1];
139 - char charpath[MAXPATHLEN + 1];
176 + char blkpath[MAXPATHLEN];
177 + char charpath[MAXPATHLEN];
140 178 di_devlink_handle_t hdl;
141 179
142 180
143 181 (void) snprintf(blkpath, sizeof (blkpath), "/dev/%s/%d",
144 182 LOFI_BLOCK_NAME, minor);
145 183 (void) snprintf(charpath, sizeof (charpath), "/dev/%s/%d",
146 184 LOFI_CHAR_NAME, minor);
147 185
148 186 /* Check if links already present */
149 187 if (stat64(blkpath, &buf) == 0 && stat64(charpath, &buf) == 0)
150 188 return;
151 189
152 190 /* First use di_devlink_init() */
153 191 if (hdl = di_devlink_init("lofi", DI_MAKE_LINK)) {
154 192 (void) di_devlink_fini(&hdl);
155 193 goto out;
156 194 }
157 195
158 196 /*
159 197 * Under normal conditions, di_devlink_init(DI_MAKE_LINK) above will
160 198 * only fail if the caller is non-root. In that case, wait for
161 199 * link creation via sysevents.
162 200 */
163 201 cursleep = 0;
164 202 while (cursleep < maxsleep) {
165 203 if ((stat64(blkpath, &buf) == -1) ||
166 204 (stat64(charpath, &buf) == -1)) {
167 205 (void) sleep(sleeptime);
168 206 cursleep += sleeptime;
169 207 continue;
170 208 }
171 209 return;
172 210 }
173 211
174 212 /* one last try */
175 213
176 214 out:
177 215 if (stat64(blkpath, &buf) == -1) {
178 216 die(gettext("%s was not created"), blkpath);
179 217 }
|
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
180 218 if (stat64(charpath, &buf) == -1) {
181 219 die(gettext("%s was not created"), charpath);
182 220 }
183 221 }
184 222
185 223 /*
186 224 * Add a device association. If devicename is NULL, let the driver
187 225 * pick a device.
188 226 */
189 227 static void
190 -add_mapping(int lfd, const char *devicename, const char *filename)
228 +add_mapping(int lfd, const char *devicename, const char *filename,
229 + int *minor_created, int suppress)
191 230 {
192 231 struct lofi_ioctl li;
193 232 int minor;
194 233
195 234 if (devicename == NULL) {
196 235 /* pick one */
197 236 li.li_minor = 0;
198 - (void) strcpy(li.li_filename, filename);
237 + (void) strlcpy(li.li_filename, filename,
238 + sizeof (li.li_filename));
199 239 minor = ioctl(lfd, LOFI_MAP_FILE, &li);
200 240 if (minor == -1) {
201 241 die(gettext("could not map file %s"), filename);
202 242 }
203 243 wait_until_dev_complete(minor);
204 244 /* print one picked */
205 - (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, minor);
245 + if (!suppress)
246 + (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, minor);
247 +
248 + /* fill in the minor if needed */
249 + if (minor_created != NULL) {
250 + *minor_created = minor;
251 + }
206 252 return;
207 253 }
208 254 /* use device we were given */
209 255 minor = name_to_minor(devicename);
210 256 if (minor == 0) {
211 257 die(gettext("malformed device name %s\n"), devicename);
212 258 }
213 259 (void) strcpy(li.li_filename, filename);
214 260 li.li_minor = minor;
215 261 if (ioctl(lfd, LOFI_MAP_FILE_MINOR, &li) == -1) {
216 262 die(gettext("could not map file %s to %s"), filename,
217 263 devicename);
218 264 }
219 265 wait_until_dev_complete(minor);
220 266 }
221 267
222 268 /*
223 269 * Remove an association. Delete by device name if non-NULL, or by
224 270 * filename otherwise.
225 271 */
226 272 static void
227 273 delete_mapping(int lfd, const char *devicename, const char *filename,
228 274 boolean_t force)
229 275 {
230 276 struct lofi_ioctl li;
231 277
232 278 li.li_force = force;
233 279 if (devicename == NULL) {
234 280 /* delete by filename */
235 281 (void) strcpy(li.li_filename, filename);
236 282 li.li_minor = 0;
237 283 if (ioctl(lfd, LOFI_UNMAP_FILE, &li) == -1) {
238 284 die(gettext("could not unmap file %s"), filename);
239 285 }
240 286 return;
241 287 }
242 288 /* delete by device */
243 289
244 290 li.li_minor = name_to_minor(devicename);
245 291 if (li.li_minor == 0) {
246 292 die(gettext("malformed device name %s\n"), devicename);
247 293 }
248 294 if (ioctl(lfd, LOFI_UNMAP_FILE_MINOR, &li) == -1) {
249 295 die(gettext("could not unmap device %s"), devicename);
250 296 }
251 297 }
252 298
253 299 static void
254 300 print_one_mapping(int lfd, const char *devicename, const char *filename)
255 301 {
256 302 struct lofi_ioctl li;
257 303
258 304 if (devicename == NULL) {
259 305 /* given filename, print devicename */
260 306 li.li_minor = 0;
261 307 (void) strcpy(li.li_filename, filename);
262 308 if (ioctl(lfd, LOFI_GET_MINOR, &li) == -1) {
263 309 die(gettext("could not find device for %s"), filename);
264 310 }
265 311 (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, li.li_minor);
266 312 return;
267 313 }
268 314
269 315 /* given devicename, print filename */
|
↓ open down ↓ |
54 lines elided |
↑ open up ↑ |
270 316 li.li_minor = name_to_minor(devicename);
271 317 if (li.li_minor == 0) {
272 318 die(gettext("malformed device name %s\n"), devicename);
273 319 }
274 320 if (ioctl(lfd, LOFI_GET_FILENAME, &li) == -1) {
275 321 die(gettext("could not find filename for %s"), devicename);
276 322 }
277 323 (void) printf("%s\n", li.li_filename);
278 324 }
279 325
326 +/*
327 + * Uncompress a file.
328 + *
329 + * First map the file in to establish a device
330 + * association, then read from it. On-the-fly
331 + * decompression will automatically uncompress
332 + * the file if it's compressed
333 + *
334 + * If the file is mapped and a device association
335 + * has been established, disallow uncompressing
336 + * the file until it is unmapped.
337 + */
338 +static void
339 +lofi_uncompress(int lfd, const char *filename)
340 +{
341 + struct lofi_ioctl li;
342 + char buf[MAXBSIZE];
343 + char devicename[32];
344 + char tmpfilename[MAXPATHLEN];
345 + char *dir, *file;
346 + int minor;
347 + struct stat64 statbuf;
348 + int compfd = -1;
349 + int uncompfd = -1;
350 + ssize_t rbytes;
351 +
352 + /*
353 + * Disallow uncompressing the file if it is
354 + * already mapped.
355 + */
356 + li.li_minor = 0;
357 + (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename));
358 + if (ioctl(lfd, LOFI_GET_MINOR, &li) != -1)
359 + die(gettext("%s must be unmapped before uncompressing"),
360 + filename);
361 +
362 + add_mapping(lfd, NULL, filename, &minor, 1);
363 + (void) snprintf(devicename, sizeof (devicename), "/dev/%s/%d",
364 + LOFI_BLOCK_NAME, minor);
365 +
366 + /* If the file isn't compressed, we just return */
367 + if ((ioctl(lfd, LOFI_CHECK_COMPRESSED, &li) == -1) ||
368 + (li.li_algorithm == '\0')) {
369 + delete_mapping(lfd, devicename, filename, B_TRUE);
370 + return;
371 + }
372 +
373 + if ((compfd = open64(devicename, O_RDONLY | O_NONBLOCK)) == -1) {
374 + die(gettext("open: %s"), filename);
375 + }
376 + if (fstat64(compfd, &statbuf) == -1) {
377 + (void) close(compfd);
378 + die(gettext("fstat: %s"), filename);
379 + }
380 +
381 + /* Zero length files don't need to be uncompressed */
382 + if (statbuf.st_size == 0) {
383 + (void) close(compfd);
384 + return;
385 + }
386 +
387 + /* Create a temp file in the same directory */
388 + dir = strdup(filename);
389 + dir = dirname(dir);
390 + file = strdup(filename);
391 + file = basename(file);
392 + (void) snprintf(tmpfilename, sizeof (tmpfilename),
393 + "%s/.%sXXXXXX", dir, file);
394 +
395 + if ((uncompfd = mkstemp64(tmpfilename)) == -1) {
396 + (void) close(compfd);
397 + free(dir);
398 + free(file);
399 + return;
400 + }
401 +
402 + /*
403 + * Set the mode bits and the owner of this temporary
404 + * file to be that of the original uncompressed file
405 + */
406 + (void) fchmod(uncompfd, statbuf.st_mode);
407 +
408 + if (fchown(uncompfd, statbuf.st_uid, statbuf.st_gid) == -1) {
409 + (void) close(compfd);
410 + (void) close(uncompfd);
411 + free(dir);
412 + free(file);
413 + return;
414 + }
415 +
416 + /* Now read from the device in MAXBSIZE-sized chunks */
417 + for (;;) {
418 + rbytes = read(compfd, buf, sizeof (buf));
419 +
420 + if (rbytes <= 0)
421 + break;
422 +
423 + if (write(uncompfd, buf, rbytes) != rbytes) {
424 + rbytes = -1;
425 + break;
426 + }
427 + }
428 +
429 + (void) close(compfd);
430 + (void) close(uncompfd);
431 + free(dir);
432 + free(file);
433 +
434 + /* Delete the mapping */
435 + delete_mapping(lfd, devicename, filename, B_TRUE);
436 +
437 + /*
438 + * If an error occured while reading or writing, rbytes will
439 + * be negative
440 + */
441 + if (rbytes < 0) {
442 + (void) unlink(tmpfilename);
443 + die(gettext("could not read from %s"), filename);
444 + }
445 +
446 + /* Rename the temp file to the actual file */
447 + if (rename(tmpfilename, filename) == -1)
448 + (void) unlink(tmpfilename);
449 +}
450 +
451 +/*
452 + * Compress a file
453 + */
454 +static void
455 +lofi_compress(int lfd, const char *filename, int compress_index,
456 + uint32_t segsize)
457 +{
458 + struct lofi_ioctl lic;
459 + lofi_compress_info_t *li;
460 + char tmpfilename[MAXPATHLEN];
461 + char comp_filename[MAXPATHLEN];
462 + char *dir = NULL, *file = NULL;
463 + uchar_t *uncompressed_seg = NULL;
464 + uchar_t *compressed_seg = NULL;
465 + uint32_t compressed_segsize;
466 + uint32_t len_compressed, count, index_sz;
467 + uint64_t *index = NULL;
468 + uint64_t offset;
469 + size_t real_segsize;
470 + struct stat64 statbuf;
471 + int compfd = -1, uncompfd = -1;
472 + int tfd = -1;
473 + ssize_t rbytes, wbytes, lastread;
474 + int i, type;
475 +
476 + /*
477 + * Disallow compressing the file if it is
478 + * already mapped
479 + */
480 + lic.li_minor = 0;
481 + (void) strlcpy(lic.li_filename, filename, sizeof (lic.li_filename));
482 + if (ioctl(lfd, LOFI_GET_MINOR, &lic) != -1)
483 + die(gettext("%s must be unmapped before compressing"),
484 + filename);
485 +
486 + li = &lofi_compress_table[compress_index];
487 +
488 + /*
489 + * The size of the buffer to hold compressed data must
490 + * be slightly larger than the compressed segment size.
491 + *
492 + * The compress functions use part of the buffer as
493 + * scratch space to do calculations.
494 + * Ref: http://www.zlib.net/manual.html#compress2
495 + */
496 + compressed_segsize = segsize + (segsize >> 6);
497 + compressed_seg = (uchar_t *)malloc(compressed_segsize + SEGHDR);
498 + uncompressed_seg = (uchar_t *)malloc(segsize);
499 +
500 + if (compressed_seg == NULL || uncompressed_seg == NULL)
501 + die(gettext("No memory"));
502 +
503 + if ((uncompfd = open64(filename, O_RDONLY|O_LARGEFILE, 0)) == -1)
504 + die(gettext("open: %s"), filename);
505 +
506 + if (fstat64(uncompfd, &statbuf) == -1) {
507 + (void) close(uncompfd);
508 + die(gettext("fstat: %s"), filename);
509 + }
510 +
511 + /* Zero length files don't need to be compressed */
512 + if (statbuf.st_size == 0) {
513 + (void) close(uncompfd);
514 + return;
515 + }
516 +
517 + /*
518 + * Create temporary files in the same directory that
519 + * will hold the intermediate data
520 + */
521 + dir = strdup(filename);
522 + dir = dirname(dir);
523 + file = strdup(filename);
524 + file = basename(file);
525 + (void) snprintf(tmpfilename, sizeof (tmpfilename),
526 + "%s/.%sXXXXXX", dir, file);
527 + (void) snprintf(comp_filename, sizeof (comp_filename),
528 + "%s/.%sXXXXXX", dir, file);
529 +
530 + if ((tfd = mkstemp64(tmpfilename)) == -1)
531 + goto cleanup;
532 +
533 + if ((compfd = mkstemp64(comp_filename)) == -1)
534 + goto cleanup;
535 +
536 + /*
537 + * Set the mode bits and owner of the compressed
538 + * file to be that of the original uncompressed file
539 + */
540 + (void) fchmod(compfd, statbuf.st_mode);
541 +
542 + if (fchown(compfd, statbuf.st_uid, statbuf.st_gid) == -1)
543 + goto cleanup;
544 +
545 + /*
546 + * Calculate the number of index entries required.
547 + * index entries are stored as an array. adding
548 + * a '2' here accounts for the fact that the last
549 + * segment may not be a multiple of the segment size
550 + */
551 + index_sz = (statbuf.st_size / segsize) + 2;
552 + index = malloc(sizeof (uint64_t) * index_sz);
553 +
554 + if (index == NULL)
555 + goto cleanup;
556 +
557 + offset = 0;
558 + lastread = segsize;
559 + count = 0;
560 +
561 + /*
562 + * Now read from the uncompressed file in 'segsize'
563 + * sized chunks, compress what was read in and
564 + * write it out to a temporary file
565 + */
566 + for (;;) {
567 + rbytes = read(uncompfd, uncompressed_seg, segsize);
568 +
569 + if (rbytes <= 0)
570 + break;
571 +
572 + if (lastread < segsize)
573 + goto cleanup;
574 +
575 + /*
576 + * Account for the first byte that
577 + * indicates whether a segment is
578 + * compressed or not
579 + */
580 + real_segsize = segsize - 1;
581 + (void) li->l_compress(uncompressed_seg, rbytes,
582 + compressed_seg + SEGHDR, &real_segsize, li->l_level);
583 +
584 + /*
585 + * If the length of the compressed data is more
586 + * than a threshold then there isn't any benefit
587 + * to be had from compressing this segment - leave
588 + * it uncompressed.
589 + *
590 + * NB. In case an error occurs during compression (above)
591 + * the 'real_segsize' isn't changed. The logic below
592 + * ensures that that segment is left uncompressed.
593 + */
594 + len_compressed = real_segsize;
595 + if (real_segsize > segsize - COMPRESS_THRESHOLD) {
596 + (void) memcpy(compressed_seg + SEGHDR, uncompressed_seg,
597 + rbytes);
598 + type = UNCOMPRESSED;
599 + len_compressed = rbytes;
600 + } else {
601 + type = COMPRESSED;
602 + }
603 +
604 + /*
605 + * Set the first byte or the SEGHDR to
606 + * indicate if it's compressed or not
607 + */
608 + *compressed_seg = type;
609 + wbytes = write(tfd, compressed_seg, len_compressed + SEGHDR);
610 + if (wbytes != (len_compressed + SEGHDR)) {
611 + rbytes = -1;
612 + break;
613 + }
614 +
615 + index[count] = offset;
616 + offset += wbytes;
617 + lastread = rbytes;
618 + count++;
619 + }
620 +
621 + (void) close(uncompfd);
622 +
623 + if (rbytes < 0)
624 + goto cleanup;
625 + /*
626 + * This is a sentinel index entry. It does not point to an actual
627 + * compressed segment but helps in computing the size of the
628 + * compressed segment. The size of each compressed segment is
629 + * computed by subtracting the current index value from the next
630 + * one (the compressed blocks are stored sequentially)
631 + */
632 + index[count++] = offset;
633 +
634 + /*
635 + * Now write the compressed data along with the
636 + * header information to this file which will
637 + * later be renamed to the original uncompressed
638 + * file name
639 + *
640 + * The header is as follows -
641 + *
642 + * Signature (name of the compression algorithm)
643 + * Compression segment size (a multiple of 512)
644 + * Number of index entries
645 + * Size of the last block
646 + * The array containing the index entries
647 + *
648 + * the header is always stored in network byte
649 + * order
650 + */
651 + if (write(compfd, li->l_name, strlen(li->l_name))
652 + != strlen(li->l_name))
653 + goto cleanup;
654 +
655 + segsize = htonl(segsize);
656 + if (write(compfd, &segsize, sizeof (segsize)) != sizeof (segsize))
657 + goto cleanup;
658 +
659 + count = htonl(count);
660 + if (write(compfd, &count, sizeof (count)) != sizeof (count))
661 + goto cleanup;
662 +
663 + lastread = htonl(lastread);
664 + if (write(compfd, &lastread, sizeof (lastread)) != sizeof (lastread))
665 + goto cleanup;
666 +
667 + /* Restore the value of 'count' */
668 + count = ntohl(count);
669 + for (i = 0; i < count; i++) {
670 + if (write(compfd, index + i, sizeof (*index)) !=
671 + sizeof (*index))
672 + goto cleanup;
673 + }
674 +
675 + /* Header is written, now write the compressed data */
676 + if (lseek(tfd, 0, SEEK_SET) != 0)
677 + goto cleanup;
678 +
679 + rbytes = wbytes = 0;
680 +
681 + for (;;) {
682 + rbytes = read(tfd, compressed_seg, compressed_segsize + SEGHDR);
683 +
684 + if (rbytes <= 0)
685 + break;
686 +
687 + if (write(compfd, compressed_seg, rbytes) != rbytes)
688 + goto cleanup;
689 + }
690 +
691 + if (fstat64(compfd, &statbuf) == -1)
692 + goto cleanup;
693 +
694 + /*
695 + * Round up the compressed file size to be a multiple of
696 + * DEV_BSIZE. lofi(7D) likes it that way.
697 + */
698 + if ((offset = statbuf.st_size % DEV_BSIZE) > 0) {
699 +
700 + offset = DEV_BSIZE - offset;
701 +
702 + for (i = 0; i < offset; i++)
703 + uncompressed_seg[i] = '\0';
704 + if (write(compfd, uncompressed_seg, offset) != offset)
705 + goto cleanup;
706 + }
707 + (void) close(compfd);
708 + (void) close(tfd);
709 + (void) unlink(tmpfilename);
710 +cleanup:
711 + if (rbytes < 0) {
712 + if (tfd != -1)
713 + (void) unlink(tmpfilename);
714 + if (compfd != -1)
715 + (void) unlink(comp_filename);
716 + die(gettext("error compressing file %s"), filename);
717 + } else {
718 + /* Rename the compressed file to the actual file */
719 + if (rename(comp_filename, filename) == -1) {
720 + (void) unlink(comp_filename);
721 + die(gettext("error compressing file %s"), filename);
722 + }
723 + }
724 + if (compressed_seg != NULL)
725 + free(compressed_seg);
726 + if (uncompressed_seg != NULL)
727 + free(uncompressed_seg);
728 + if (dir != NULL)
729 + free(dir);
730 + if (file != NULL)
731 + free(file);
732 + if (index != NULL)
733 + free(index);
734 + if (compfd != -1)
735 + (void) close(compfd);
736 + if (uncompfd != -1)
737 + (void) close(uncompfd);
738 + if (tfd != -1)
739 + (void) close(tfd);
740 +}
741 +
742 +static int
743 +lofi_compress_select(const char *algname)
744 +{
745 + int i;
746 +
747 + for (i = 0; i < LOFI_COMPRESS_FUNCTIONS; i++) {
748 + if (strcmp(lofi_compress_table[i].l_name, algname) == 0)
749 + return (i);
750 + }
751 + return (-1);
752 +}
753 +
280 754 int
281 755 main(int argc, char *argv[])
282 756 {
283 757 int lfd;
284 758 int c;
285 759 int error;
286 760 struct stat64 buf;
287 761 const char *devicename = NULL;
288 762 const char *filename = NULL;
763 + const char *algname = COMPRESS_ALGORITHM;
289 764 int openflag;
290 765 int minor;
291 766 int fd = -1;
767 + int compress_index;
768 + uint32_t segsize = SEGSIZE;
292 769 static char *lofictl = "/dev/" LOFI_CTL_NAME;
293 770 boolean_t force = B_FALSE;
294 771
295 772 pname = getpname(argv[0]);
296 773
297 774 (void) setlocale(LC_ALL, "");
298 775 (void) textdomain(TEXT_DOMAIN);
299 776
300 - while ((c = getopt(argc, argv, "a:d:f")) != EOF) {
777 + while ((c = getopt(argc, argv, "a:C:d:s:U:f")) != EOF) {
301 778 switch (c) {
302 779 case 'a':
303 780 addflag = 1;
304 781 filename = optarg;
305 782 fd = open64(filename, O_RDONLY);
306 783 if (fd == -1) {
307 784 die(gettext("open: %s"), filename);
308 785 }
309 786 error = fstat64(fd, &buf);
310 787 if (error == -1) {
311 788 die(gettext("fstat: %s"), filename);
312 789 } else if (!S_ISLOFIABLE(buf.st_mode)) {
313 790 die(gettext("%s is not a regular file, "
314 791 "block, or character device\n"),
315 792 filename);
316 793 } else if ((buf.st_size % DEV_BSIZE) != 0) {
317 794 die(gettext("size of %s is not a multiple "
318 795 "of %d\n"),
319 796 filename, DEV_BSIZE);
320 797 }
321 798 (void) close(fd);
322 799 minor = name_to_minor(filename);
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
323 800 if (minor != 0) {
324 801 die(gettext("cannot use " LOFI_DRIVER_NAME
325 802 " on itself\n"), devicename);
326 803 }
327 804 if (((argc - optind) > 0) && (*argv[optind] != '-')) {
328 805 /* optional device */
329 806 devicename = argv[optind];
330 807 optind++;
331 808 }
332 809 break;
810 + case 'C':
811 + compressflag = 1;
812 +
813 + if (((argc - optind) == 1) && (*argv[optind] != '-')) {
814 + algname = optarg;
815 + filename = argv[optind];
816 + optind++;
817 + } else if (((argc - optind) > 0) &&
818 + (*argv[optind] == '-')) {
819 + algname = optarg;
820 + } else {
821 + filename = optarg;
822 + }
823 +
824 + fd = open64(filename, O_RDONLY);
825 + if (fd == -1) {
826 + die(gettext("open: %s"), filename);
827 + }
828 + error = fstat64(fd, &buf);
829 + if (error == -1) {
830 + die(gettext("fstat: %s"), filename);
831 + } else if (!S_ISLOFIABLE(buf.st_mode)) {
832 + die(gettext("%s is not a regular file, "
833 + "block, or character device\n"),
834 + filename);
835 + } else if ((buf.st_size % DEV_BSIZE) != 0) {
836 + die(gettext("size of %s is not a multiple "
837 + "of %d\n"),
838 + filename, DEV_BSIZE);
839 + }
840 + (void) close(fd);
841 +
842 + compress_index = lofi_compress_select(algname);
843 + if (compress_index < 0)
844 + die(gettext("invalid algorithm name: %s"),
845 + algname);
846 + break;
333 847 case 'd':
334 848 deleteflag = 1;
335 849
336 850 minor = name_to_minor(optarg);
337 851 if (minor != 0)
338 852 devicename = optarg;
339 853 else
340 854 filename = optarg;
341 855 break;
342 856 case 'f':
343 857 force = B_TRUE;
344 858 break;
859 + case 's':
860 + segsize = atol(optarg);
861 +
862 + if (segsize % DEV_BSIZE)
863 + die(gettext("segment size %ld is not a "
864 + "multiple of minimum block size %ld"),
865 + segsize, DEV_BSIZE);
866 +
867 + if (((argc - optind) > 0) && (*argv[optind] != '-')) {
868 + filename = argv[optind];
869 + optind++;
870 + }
871 + break;
872 + case 'U':
873 + uncompressflag = 1;
874 + filename = optarg;
875 + fd = open64(filename, O_RDONLY);
876 + if (fd == -1) {
877 + die(gettext("open: %s"), filename);
878 + }
879 + error = fstat64(fd, &buf);
880 + if (error == -1) {
881 + die(gettext("fstat: %s"), filename);
882 + } else if (!S_ISLOFIABLE(buf.st_mode)) {
883 + die(gettext("%s is not a regular file, "
884 + "block, or character device\n"),
885 + filename);
886 + } else if ((buf.st_size % DEV_BSIZE) != 0) {
887 + die(gettext("size of %s is not a multiple "
888 + "of %d\n"), filename, DEV_BSIZE);
889 + }
890 + (void) close(fd);
891 + minor = name_to_minor(filename);
892 + if (minor != 0) {
893 + die(gettext("cannot use " LOFI_DRIVER_NAME
894 + " on itself\n"), devicename);
895 + }
896 + break;
345 897 case '?':
346 898 default:
347 899 errflag = 1;
348 900 break;
349 901 }
350 902 }
351 - if (errflag || (addflag && deleteflag))
903 + if (errflag ||
904 + (addflag && deleteflag) ||
905 + ((compressflag || uncompressflag) && (addflag || deleteflag)))
352 906 usage();
353 907
354 908 switch (argc - optind) {
355 909 case 0: /* no more args */
356 910 break;
357 911 case 1: /* one arg without options means print the association */
358 912 if (addflag || deleteflag)
359 913 usage();
914 + if (compressflag || uncompressflag)
915 + usage();
360 916 minor = name_to_minor(argv[optind]);
361 917 if (minor != 0)
362 918 devicename = argv[optind];
363 919 else
364 920 filename = argv[optind];
365 921 break;
366 922 default:
367 923 usage();
368 924 break;
369 925 }
370 926
371 927 if (filename && !valid_abspath(filename))
372 928 exit(E_ERROR);
|
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
373 929
374 930 /*
375 931 * Here, we know the arguments are correct, the filename is an
376 932 * absolute path, it exists and is a regular file. We don't yet
377 933 * know that the device name is ok or not.
378 934 */
379 935 /*
380 936 * Now to the real work.
381 937 */
382 938 openflag = O_EXCL;
383 - if (addflag || deleteflag)
939 + if (addflag || deleteflag || compressflag || uncompressflag)
384 940 openflag |= O_RDWR;
385 941 else
386 942 openflag |= O_RDONLY;
387 943 lfd = open(lofictl, openflag);
388 944 if (lfd == -1) {
389 945 if ((errno == EPERM) || (errno == EACCES)) {
390 946 die("you do not have permission to perform "
391 947 "that operation.\n");
392 948 } else {
393 949 die("%s", lofictl);
394 950 }
395 951 /*NOTREACHED*/
396 952 }
397 953 if (addflag)
398 - add_mapping(lfd, devicename, filename);
954 + add_mapping(lfd, devicename, filename, NULL, 0);
955 + else if (compressflag)
956 + lofi_compress(lfd, filename, compress_index, segsize);
957 + else if (uncompressflag)
958 + lofi_uncompress(lfd, filename);
399 959 else if (deleteflag)
400 960 delete_mapping(lfd, devicename, filename, force);
401 961 else if (filename || devicename)
402 962 print_one_mapping(lfd, devicename, filename);
403 963 else
404 964 print_mappings(lfd);
405 965 (void) close(lfd);
406 966 return (E_SUCCESS);
407 967 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX