2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* $Id: mkzftree.c,v 1.18 2006/07/04 04:57:42 hpa Exp $ */
14 /* ----------------------------------------------------------------------- *
16 * Copyright 2001 H. Peter Anvin - All Rights Reserved
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
21 * USA; either version 2 of the License, or (at your option) any later
22 * version; incorporated herein by reference.
24 * ----------------------------------------------------------------------- */
29 * - Generate block-compression of files for use with
30 * the "ZF" extension to the iso9660/RockRidge filesystem.
32 * The file compression technique used is the "deflate"
33 * algorithm used by the zlib library; each block must have a
34 * valid (12-byte) zlib header. In addition, the file itself
35 * has the following structure:
37 * Byte offset iso9660 type Contents
38 * 0 (8 bytes) Magic number (37 E4 53 96 C9 DB D6 07)
39 * 8 7.3.1 Uncompressed file size
40 * 12 7.1.1 header_size >> 2 (currently 4)
41 * 13 7.1.1 log2(block_size)
42 * 14 (2 bytes) Reserved, must be zero
44 * The header may get expanded in the future, at which point the
45 * header size field will be used to increase the space for the
48 * All implementations are required to support a block_size of 32K
51 * Note that bytes 12 and 13 and the uncompressed length are also
52 * present in the ZF record; THE TWO MUST BOTH BE CONSISTENT AND
55 * Given the uncompressed size, block_size, and header_size:
57 * Nblocks := ceil(size/block_size)
59 * After the header follow (nblock+1) 32-bit pointers, recorded as
60 * iso9660 7.3.1 (littleendian); each indicate the byte offset (from
61 * the start of the file) to one block and the first byte beyond the
62 * end of the previous block; the first pointer thus point to the
63 * start of the data area and the last pointer to the first byte
66 * block_no := floor(byte_offset/block_size)
68 * block_start := read_pointer_731( (header_size+block_no)*4 )
69 * block_end := read_pointer_731( (header_size+block_no+1)*4 )
71 * The block data is compressed according to "zlib".
74 #include "mkzftree.h" /* Must be included first! */
83 #include <sys/types.h>
92 /* Command line options */
93 struct cmdline_options opt = {
94 0, /* Force compression */
95 9, /* Compression level */
96 0, /* Parallelism (0 = strictly serial) */
97 0, /* One filesystem only */
98 0, /* One directory only */
99 1, /* Create stub directories */
100 0, /* Root may be a file */
101 0, /* Be paranoid about metadata */
102 default_verbosity, /* Default verbosity */
103 block_compress_file /* Default transformation function */
110 #define OPTSTRING "fz:up:xXC:lLFvqV:hw"
111 #ifdef HAVE_GETOPT_LONG
112 const struct option long_options[] = {
113 { "force", 0, 0, 'f' },
114 { "level", 1, 0, 'z' },
115 { "uncompress", 0, 0, 'u' },
116 { "parallelism", 1, 0, 'p' },
117 { "one-filesystem", 0, 0, 'x' },
118 { "strict-one-filesystem", 0, 0, 'X' },
119 { "crib-tree", 1, 0, 'C' },
120 { "local", 0, 0, 'l' },
121 { "strict-local", 0, 0, 'L' },
122 { "file", 0, 0, 'F' },
123 { "verbose", 0, 0, 'v' },
124 { "quiet", 0, 0, 'q' },
125 { "verbosity", 1, 0, 'V' },
126 { "help", 0, 0, 'h' },
127 { "version", 0, 0, 'w' },
132 #define getopt_long(C,V,O,L,I) getopt(C,V,O)
136 static void usage(enum verbosity level, int err)
139 "zisofs-tools " ZISOFS_TOOLS_VERSION "\n"
140 "Usage: %s [options] intree outtree\n"
141 LO(" --force ")" -f Always compress, even if result is larger\n"
142 LO(" --level # ")" -z # Set compression level (1-9)\n"
143 LO(" --uncompress ")" -u Uncompress an already compressed tree\n"
144 LO(" --parallelism # ")" -p # Process up to # files in parallel\n"
145 LO(" --one-filesystem ")" -x Do not cross filesystem boundaries\n"
146 LO(" --strict-one-filesystem")" -X Same as -x, but don't create stubs dirs\n"
147 LO(" --crib-tree ")" -C Steal \"crib\" files from an old tree\n"
148 LO(" --local ")" -l Do not recurse into subdirectoires\n"
149 LO(" --strict-local ")" -L Same as -l, but don't create stubs dirs\n"
150 LO(" --file ")" -F Operate possibly on a single file\n"
151 LO(" --sloppy ")" -s Don't abort if metadata cannot be set\n"
152 LO(" --verbose ")" -v Increase message verbosity\n"
153 LO(" --verbosity # ")" -V # Set message verbosity to # (default = %d)\n"
154 LO(" --quiet ")" -q No messages, not even errors (-V 0)\n"
155 LO(" --help ")" -h Display this message\n"
156 LO(" --version ")" -w Display the program version\n"
157 ,program, (int)default_verbosity);
161 static int opt_atoi(const char *str)
166 out = strtol(str, &endptr, 10);
168 usage(vl_error, EX_USAGE);
174 int main(int argc, char *argv[])
176 const char *in, *out, *crib = NULL;
182 while ( (optch = getopt_long(argc, argv, OPTSTRING, long_options, NULL))
186 opt.force = 1; /* Always compress */
189 opt.level = opt_atoi(optarg);
190 if ( opt.level < 1 || opt.level > 9 ) {
191 message(vl_error, "%s: invalid compression level: %d\n",
200 opt.verbosity = opt_atoi(optarg);
203 opt.verbosity = vl_quiet;
206 opt.munger = block_uncompress_file;
212 opt.parallel = opt_atoi(optarg);
215 opt.onefs = 1; opt.do_mkdir = 1;
218 opt.onedir = 1; opt.do_mkdir = 1;
221 opt.onefs = 1; opt.do_mkdir = 0;
224 opt.onedir = 1; opt.do_mkdir = 0;
236 message(vl_quiet, "zisofs-tools " ZISOFS_TOOLS_VERSION "\n");
239 usage(vl_error, EX_USAGE);
244 if ( (argc-optind) != 2 )
245 usage(vl_error, EX_USAGE);
247 in = argv[optind]; /* Input tree */
248 out = argv[optind+1]; /* Output tree */
252 if ( opt.file_root ) {
253 if ( lstat(in, &st) ) {
254 message(vl_error, "%s: %s: %s\n", program, in, strerror(errno));
258 err = munge_entry(in, out, crib, NULL);
260 /* Special case: we use stat() for the root, not lstat() */
261 if ( stat(in, &st) ) {
262 message(vl_error, "%s: %s: %s\n", program, in, strerror(errno));
265 if ( !S_ISDIR(st.st_mode) ) {
266 message(vl_error, "%s: %s: Not a directory\n", program, in);
270 err = munge_tree(in, out, crib);
273 wait_for_all_workers();
278 if ( !opt.file_root ) {
279 if ( chown(out, st.st_uid, st.st_gid) && !opt.sloppy ) {
280 message(vl_error, "%s: %s: %s", program, out, strerror(errno));
283 if ( chmod(out, st.st_mode) && !opt.sloppy && !err ) {
284 message(vl_error, "%s: %s: %s", program, out, strerror(errno));
287 if ( copytime(out, &st) && !opt.sloppy && !err ) {
288 message(vl_error, "%s: %s: %s", program, out, strerror(errno));