1 /*
2 Copyright (C) Andrew Tridgell 1998-2003
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 /* rzip compression - main program */
19
20 #include "rzip.h"
21
usage(void)22 static void usage(void)
23 {
24 printf("rzip %d.%d\n", RZIP_MAJOR_VERSION, RZIP_MINOR_VERSION);
25 printf("Copright (C) Andrew Tridgell 1998-2003\n\n");
26 printf("usage: rzip [options] <file...>\n");
27 printf(" Options:\n");
28 printf(" -0 fastest (worst) compression\n");
29 printf(" -6 default compression level\n");
30 printf(" -9 slowest (best) compression\n");
31 printf(" -d decompress\n");
32 printf(" -o filename specify the output file name\n");
33 printf(" -S suffix specify compressed suffix (default '.rz')\n");
34 printf(" -f force overwrite of any existing files\n");
35 printf(" -k keep existing files\n");
36 printf(" -P show compression progress\n");
37 printf(" -L level set compression level\n");
38 printf(" -V show version\n");
39 #if 0
40 /* damn, this will be quite hard to do */
41 printf(" -t test compressed file integrity\n");
42 #endif
43 printf("\nnote that rzip cannot operate on stdin/stdout\n");
44 }
45
46
write_magic(int fd_in,int fd_out)47 static void write_magic(int fd_in, int fd_out)
48 {
49 struct stat st;
50 char magic[24];
51 uint32_t v;
52
53 memset(magic, 0, sizeof(magic));
54 strcpy(magic, "RZIP");
55 magic[4] = RZIP_MAJOR_VERSION;
56 magic[5] = RZIP_MINOR_VERSION;
57
58 if (fstat(fd_in, &st) != 0) {
59 fatal("bad magic file descriptor!?\n");
60 }
61
62 #if HAVE_LARGE_FILES
63 v = htonl(st.st_size & 0xFFFFFFFF);
64 memcpy(&magic[6], &v, 4);
65 v = htonl(st.st_size >> 32);
66 memcpy(&magic[10], &v, 4);
67 #else
68 v = htonl(st.st_size);
69 memcpy(&magic[6], &v, 4);
70 #endif
71
72 if (write(fd_out, magic, sizeof(magic)) != sizeof(magic)) {
73 fatal("Failed to write magic header\n");
74 }
75 }
76
read_magic(int fd_in,int fd_out,off_t * expected_size)77 static void read_magic(int fd_in, int fd_out, off_t *expected_size)
78 {
79 uint32_t v;
80 char magic[24];
81
82 if (read(fd_in, magic, sizeof(magic)) != sizeof(magic)) {
83 fatal("Failed to read magic header\n");
84 }
85
86 *expected_size = 0;
87
88 if (strncmp(magic, "RZIP", 4) != 0) {
89 fatal("Not an rzip file\n");
90 }
91
92 #if HAVE_LARGE_FILES
93 memcpy(&v, &magic[6], 4);
94 *expected_size = ntohl(v);
95 memcpy(&v, &magic[10], 4);
96 *expected_size |= ((off_t)ntohl(v)) << 32;
97 #else
98 memcpy(&v, &magic[6], 4);
99 *expected_size = ntohl(v);
100 #endif
101
102 }
103
104
105 /* preserve ownership and permissions where possible */
preserve_perms(struct rzip_control * control,int fd_in,int fd_out)106 static void preserve_perms(struct rzip_control *control,
107 int fd_in, int fd_out)
108 {
109 struct stat st;
110
111 if (fstat(fd_in, &st) != 0) {
112 fatal("Failed to fstat input file\n");
113 }
114 if (fchmod(fd_out, (st.st_mode & 0777)) != 0) {
115 fatal("Failed to set permissions on %s\n", control->outfile);
116 }
117
118 /* chown fail is not fatal */
119 fchown(fd_out, st.st_uid, st.st_gid);
120 }
121
122
123
124 /*
125 decompress one file from the command line
126 */
decompress_file(struct rzip_control * control)127 static void decompress_file(struct rzip_control *control)
128 {
129 int fd_in, fd_out = -1, fd_hist = -1;
130 off_t expected_size;
131
132 if (control->outname) {
133 control->outfile = strdup(control->outname);
134 } else {
135 if (strlen(control->suffix) >= strlen(control->infile) ||
136 strcmp(control->suffix,
137 control->infile +
138 strlen(control->infile) - strlen(control->suffix)) != 0) {
139 fatal("%s: unknown suffix\n", control->infile);
140 }
141
142 control->outfile = strdup(control->infile);
143 control->outfile[strlen(control->infile) - strlen(control->suffix)] = 0;
144 }
145
146 fd_in = open(control->infile,O_RDONLY);
147 if (fd_in == -1) {
148 fatal("Failed to open %s: %s\n",
149 control->infile,
150 strerror(errno));
151 }
152
153 if ((control->flags & FLAG_TEST_ONLY) == 0) {
154 if (control->flags & FLAG_FORCE_REPLACE) {
155 fd_out = open(control->outfile,O_WRONLY|O_CREAT|O_TRUNC,0666);
156 } else {
157 fd_out = open(control->outfile,O_WRONLY|O_CREAT|O_EXCL,0666);
158 }
159 if (fd_out == -1) {
160 fatal("Failed to create %s: %s\n",
161 control->outfile, strerror(errno));
162 }
163
164 preserve_perms(control, fd_in, fd_out);
165
166 fd_hist = open(control->outfile,O_RDONLY);
167 if (fd_hist == -1) {
168 fatal("Failed to open history file %s\n",
169 control->outfile);
170 }
171 }
172
173
174 read_magic(fd_in, fd_out, &expected_size);
175 runzip_fd(fd_in, fd_out, fd_hist, expected_size);
176
177 if ((control->flags & FLAG_TEST_ONLY) == 0) {
178 if (close(fd_hist) != 0 ||
179 close(fd_out) != 0) {
180 fatal("Failed to close files\n");
181 }
182 }
183
184 close(fd_in);
185
186 if ((control->flags & (FLAG_KEEP_FILES | FLAG_TEST_ONLY)) == 0) {
187 if (unlink(control->infile) != 0) {
188 fatal("Failed to unlink %s: %s\n",
189 control->infile, strerror(errno));
190 }
191 }
192
193 free(control->outfile);
194 }
195
196 /*
197 compress one file from the command line
198 */
compress_file(struct rzip_control * control)199 static void compress_file(struct rzip_control *control)
200 {
201 int fd_in, fd_out;
202
203 if (strlen(control->suffix) <= strlen(control->infile) &&
204 strcmp(control->suffix, control->infile + strlen(control->infile) - strlen(control->suffix)) == 0) {
205 printf("%s: already has %s suffix\n", control->infile, control->suffix);
206 return;
207 }
208
209 if (control->outname) {
210 control->outfile = strdup(control->outname);
211 } else {
212 control->outfile = malloc(strlen(control->infile) +
213 strlen(control->suffix) + 1);
214 if (!control->outfile) {
215 fatal("Failed to allocate outfile name\n");
216 }
217 strcpy(control->outfile, control->infile);
218 strcat(control->outfile, control->suffix);
219 }
220
221 fd_in = open(control->infile,O_RDONLY);
222 if (fd_in == -1) {
223 fatal("Failed to open %s: %s\n", control->infile, strerror(errno));
224 }
225
226 if (control->flags & FLAG_FORCE_REPLACE) {
227 fd_out = open(control->outfile,O_WRONLY|O_CREAT|O_TRUNC,0666);
228 } else {
229 fd_out = open(control->outfile,O_WRONLY|O_CREAT|O_EXCL,0666);
230 }
231 if (fd_out == -1) {
232 fatal("Failed to create %s: %s\n", control->outfile, strerror(errno));
233 }
234
235 preserve_perms(control, fd_in, fd_out);
236
237 write_magic(fd_in, fd_out);
238 rzip_fd(control, fd_in, fd_out);
239
240 if (close(fd_in) != 0 ||
241 close(fd_out) != 0) {
242 fatal("Failed to close files\n");
243 }
244
245 if ((control->flags & FLAG_KEEP_FILES) == 0) {
246 if (unlink(control->infile) != 0) {
247 fatal("Failed to unlink %s: %s\n", control->infile, strerror(errno));
248 }
249 }
250
251 free(control->outfile);
252 }
253
main(int argc,char * argv[])254 int main(int argc, char *argv[])
255 {
256 extern int optind;
257 int c, i;
258 struct rzip_control control;
259
260 memset(&control, 0, sizeof(control));
261
262 control.compression_level = 6;
263 control.flags = 0;
264 control.suffix = ".rz";
265
266 if (strstr(argv[0], "runzip")) {
267 control.flags |= FLAG_DECOMPRESS;
268 }
269
270 while ((c = getopt(argc, argv, "h0123456789dS:tVvkfPo:L:")) != -1) {
271 if (isdigit(c)) {
272 control.compression_level = c - '0';
273 continue;
274 }
275 switch (c) {
276 case 'L':
277 control.compression_level = atoi(optarg);
278 break;
279 case 'd':
280 control.flags |= FLAG_DECOMPRESS;
281 break;
282 case 'S':
283 control.suffix = optarg;
284 break;
285 case 'o':
286 control.outname = optarg;
287 break;
288 case 't':
289 fatal("integrity checking currently not implemented\n");
290 control.flags |= FLAG_TEST_ONLY;
291 break;
292 case 'f':
293 control.flags |= FLAG_FORCE_REPLACE;
294 break;
295 case 'k':
296 control.flags |= FLAG_KEEP_FILES;
297 break;
298 case 'v':
299 control.verbosity++;
300 break;
301 case 'P':
302 control.flags |= FLAG_SHOW_PROGRESS;
303 break;
304 case 'V':
305 printf("rzip version %d.%d\n",
306 RZIP_MAJOR_VERSION, RZIP_MINOR_VERSION);
307 exit(0);
308 break;
309
310 default:
311 case 'h':
312 usage();
313 return -1;
314 }
315 }
316
317 argc -= optind;
318 argv += optind;
319
320 if (control.outname && argc > 1) {
321 fatal("Cannot specify output filename with more than 1 file\n");
322 }
323
324 if (argc < 1) {
325 usage();
326 exit(1);
327 }
328
329 for (i=0;i<argc;i++) {
330 control.infile = argv[i];
331
332 if (control.flags & (FLAG_DECOMPRESS | FLAG_TEST_ONLY)) {
333 decompress_file(&control);
334 } else {
335 compress_file(&control);
336 }
337 }
338
339 return 0;
340 }
341