1 /* lzop.c --
2
3 This file is part of the lzop file compressor.
4
5 Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
6 All Rights Reserved.
7
8 lzop and the LZO library are free software; you can redistribute them
9 and/or modify them under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of
11 the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING.
20 If not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
25 http://www.oberhumer.com/opensource/lzop/
26 */
27
28
29 #include "conf.h"
30 #include "version.h"
31
32
33 /*************************************************************************
34 // options
35 **************************************************************************/
36
37 int opt_cmd = CMD_NONE;
38 int opt_method = 0;
39 int opt_level = 0;
40 int opt_filter = 0;
41
42 int opt_checksum = -1;
43 int opt_console = CON_INIT;
44 lzo_bool opt_crc32 = 0;
45 lzo_bool opt_decompress_safe = 1;
46 lzo_bool opt_file = 0;
47 int opt_force = 0;
48 lzo_bool opt_ignorewarn = 0;
49 lzo_bool opt_keep = 0;
50 int opt_num_threads = 1; /* NOT YET IMPLEMENTED */
51 #ifdef MAINT
52 int opt_noheader = 0;
53 #endif
54 lzo_bool opt_nowarn = 0;
55 const char *opt_ls_flags = "";
56 int opt_name = -1;
57 const char *opt_output_name = NULL;
58 const char *opt_output_path = NULL;
59 lzo_bool opt_optimize = 0;
60 lzo_bool opt_path = 0;
61 lzo_bool opt_restore_mode = 1;
62 lzo_bool opt_restore_time = 1;
63 lzo_bool opt_shortname = 0;
64 int opt_stdin = 0;
65 lzo_bool opt_stdout = 0;
66 char opt_suffix[1+SUFFIX_MAX+1] = { 0 };
67 lzo_bool opt_unlink = 0;
68 int opt_verbose = 1;
69
70 static int done_output_name = 0;
71 static int done_output_path = 0;
72 static int done_suffix = 0;
73
74 /* invocation options */
75 enum {
76 PGM_LZOP,
77 PGM_UNLZOP,
78 PGM_OCAT
79 };
80
81 int opt_pgm = PGM_LZOP;
82
83
84 const char *argv0 = "";
85 const char *progname = "";
86 MODE_T u_mask = 0700;
87 time_t current_time;
88
89 FILE *con_term = NULL;
90
91
92 static int num_files = -1;
93 static int exit_code = EXIT_OK;
94
95 static file_t fi;
96 static file_t fo;
97
98 static unsigned long total_d_files = 0;
99 static unsigned long total_c_files = 0;
100 static lzop_ulong_t total_d_len = 0;
101 static lzop_ulong_t total_c_len = 0;
102
103 /* some statistics */
104 static lzop_ulong_t total_bytes_written = 0;
105 static lzop_ulong_t total_bytes_read = 0;
106
107
108 /*************************************************************************
109 // exit handlers
110 **************************************************************************/
111
do_exit(void)112 static void do_exit(void)
113 {
114 static lzo_bool in_exit = 0;
115
116 if (in_exit)
117 exit(exit_code);
118 in_exit = 1;
119
120 fflush(con_term);
121 fflush(stderr);
122 exit(exit_code);
123 }
124
125
126 #define EXIT_FATAL 3
127
set_eec(int ec,int * eec)128 static lzo_bool set_eec(int ec, int *eec)
129 {
130 if (ec == EXIT_FATAL)
131 {
132 *eec = EXIT_ERROR;
133 return 1;
134 }
135 else if (ec < 0 || ec == EXIT_ERROR)
136 {
137 *eec = EXIT_ERROR;
138 }
139 else if (ec == EXIT_WARN)
140 {
141 if (!opt_ignorewarn)
142 if (*eec == EXIT_OK)
143 *eec = ec;
144 }
145 else if (ec == EXIT_OK)
146 {
147 /* do nothing */
148 }
149 else
150 {
151 assert(0);
152 }
153 return 0;
154 }
155
set_ec(int ec)156 static lzo_bool set_ec(int ec)
157 {
158 return set_eec(ec,&exit_code);
159 }
160
161
e_exit(int ec)162 void e_exit(int ec)
163 {
164 (void) set_ec(ec);
165 do_exit();
166 }
167
168
e_usage(void)169 void e_usage(void)
170 {
171 usage();
172 e_exit(EXIT_USAGE);
173 }
174
175
e_memory(void)176 void e_memory(void)
177 {
178 head();
179 fflush(con_term);
180 fprintf(stderr,"%s: out of memory\n", argv0);
181 e_exit(EXIT_MEMORY);
182 }
183
184
e_method(int m)185 void e_method(int m)
186 {
187 fflush(con_term);
188 #if (UINT_MAX < LZO_0xffffffffL)
189 /* 16-bit DOS/Windows */
190 fprintf(stderr,"%s: 16-bit versions are not officially supported\n", argv0);
191 #endif
192 fprintf(stderr,"%s: illegal method option -- %c\n", argv0, m & 255);
193 e_usage();
194 }
195
196
197 #if defined(OPTIONS_VAR)
e_envopt(const char * n)198 void e_envopt(const char *n)
199 {
200 fflush(con_term);
201 if (n)
202 fprintf(stderr,"%s: invalid string '%s' in environment variable '%s'\n",
203 argv0, n, OPTIONS_VAR);
204 else
205 fprintf(stderr,"%s: illegal option in environment variable '%s'\n",
206 argv0, OPTIONS_VAR);
207 e_exit(EXIT_USAGE);
208 }
209 #endif
210
211
212 #if defined(__cplusplus)
213 extern "C" {
214 #endif
e_sighandler(acc_signo_t signo)215 static void __acc_cdecl_sighandler e_sighandler(acc_signo_t signo)
216 {
217 UNUSED(signo);
218 e_exit(EXIT_FATAL);
219 }
220 #if defined(__cplusplus)
221 }
222 #endif
223
224
225 /*************************************************************************
226 // error handlers
227 **************************************************************************/
228
do_error(file_t * ft,const char * n,const char * msg,int ec,int err)229 static void do_error(file_t *ft, const char *n, const char *msg, int ec, int err)
230 {
231 const char *fn;
232 const char *errmsg;
233
234 fflush(con_term);
235 if (!(ec == EXIT_WARN && (opt_nowarn || opt_ignorewarn || opt_verbose == 0)))
236 {
237 fn = ft && ft->name[0] ? ft->name : UNKNOWN_NAME;
238 fprintf(stderr, "%s%s: %s: ", n, progname, fn);
239 if (ec == EXIT_WARN)
240 fprintf(stderr, "warning: ");
241 if (err != 0)
242 {
243 errmsg = strerror(err);
244 if (msg && msg[0])
245 fprintf(stderr, "%s: %s\n", msg, errmsg);
246 else
247 fprintf(stderr, "%s\n", errmsg);
248 }
249 else
250 fprintf(stderr, "%s\n", msg);
251 fflush(stderr);
252 }
253 if (set_ec(ec))
254 do_exit();
255 }
256
257
258 static const char *err_nl = "";
set_err_nl(lzo_bool x)259 void set_err_nl(lzo_bool x)
260 {
261 err_nl = x ? "\n" : "";
262 }
263
264
fatal(file_t * ft,const char * msg)265 void fatal(file_t *ft, const char *msg)
266 {
267 do_error(ft,err_nl,msg,EXIT_FATAL,0);
268 }
269
error(file_t * ft,const char * msg)270 void error(file_t *ft, const char *msg)
271 {
272 do_error(ft,err_nl,msg,EXIT_ERROR,0);
273 }
274
warn(file_t * ft,const char * msg)275 void warn(file_t *ft, const char *msg)
276 {
277 do_error(ft,err_nl,msg,EXIT_WARN,0);
278 }
279
info(file_t * ft,const char * msg)280 void info(file_t *ft, const char *msg)
281 {
282 do_error(ft,err_nl,msg,EXIT_OK,0);
283 }
284
p_fatal(file_t * ft,const char * msg)285 void p_fatal(file_t *ft, const char *msg)
286 {
287 do_error(ft,err_nl,msg,EXIT_FATAL,errno);
288 }
289
p_error(file_t * ft,const char * msg)290 void p_error(file_t *ft, const char *msg)
291 {
292 do_error(ft,err_nl,msg,EXIT_ERROR,errno);
293 }
294
p_warn(file_t * ft,const char * msg)295 void p_warn(file_t *ft, const char *msg)
296 {
297 do_error(ft,err_nl,msg,EXIT_WARN,errno);
298 }
299
300
read_error(file_t * ft)301 void read_error(file_t *ft)
302 {
303 const char *fn = ft && ft->name[0] ? ft->name : UNKNOWN_NAME;
304 const char *errmsg = "unexpected end of file";
305 if (errno != 0)
306 errmsg = strerror(errno);
307 fflush(con_term);
308 fprintf(stderr, "%s%s: %s: %s\n", err_nl, progname, errmsg, fn);
309 e_exit(EXIT_FATAL);
310 }
311
312
write_error(file_t * ft)313 void write_error(file_t *ft)
314 {
315 const char *fn = ft && ft->name[0] ? ft->name : UNKNOWN_NAME;
316 const char *errmsg = "write error";
317 if (errno != 0)
318 errmsg = strerror(errno);
319 fflush(con_term);
320 fprintf(stderr, "%s%s: %s: %s\n", err_nl, progname, errmsg, fn);
321 e_exit(EXIT_FATAL);
322 }
323
324
325 /*************************************************************************
326 // file_t
327 **************************************************************************/
328
f_reset(file_t * ft)329 void f_reset(file_t *ft)
330 {
331 ft->opt_name = opt_name;
332 ft->part = 0;
333 ft->bytes_read = 0;
334 ft->bytes_written = 0;
335 ft->warn_multipart = 0;
336 ft->warn_unknown_suffix = 0;
337 }
338
339
f_init(void)340 void f_init(void)
341 {
342 memset(&fi,0,sizeof(file_t));
343 memset(&fo,0,sizeof(file_t));
344 fi.fd = -1;
345 fo.fd = -1;
346 #if defined(USE_FOPEN)
347 fi.file = NULL;
348 fo.file = NULL;
349 #endif
350 f_reset(&fi);
351 f_reset(&fo);
352 }
353
354
f_open(file_t * ft,lzo_bool r)355 int f_open(file_t *ft, lzo_bool r)
356 {
357 assert(ft->name[0]);
358 ft->fd = -1;
359 #if defined(O_BINARY)
360 ft->open_flags |= O_BINARY;
361 #endif
362 #if (ACC_OS_WIN32 || ACC_OS_WIN64) && defined(_O_SEQUENTIAL)
363 ft->open_flags |= _O_SEQUENTIAL;
364 #endif
365 #if defined(USE_FOPEN)
366 ft->file = NULL;
367 if (r)
368 ft->file = fopen(ft->name,"rb");
369 else if (ft->open_flags & O_EXCL)
370 {
371 if (file_exists(ft->name))
372 errno = EEXIST;
373 else
374 ft->file = fopen(ft->name,"wb");
375 }
376 else
377 ft->file = fopen(ft->name,"wb");
378 if (ft->file != NULL)
379 {
380 ft->fd = fileno(ft->file);
381 assert(ft->fd >= 0);
382 }
383 #else
384 if (r)
385 ft->fd = open(ft->name, ft->open_flags, 0);
386 else
387 {
388 #if defined(O_EXCL_BROKEN)
389 if ((ft->open_flags & O_EXCL) && file_exists(ft->name))
390 errno = EEXIST;
391 else
392 #endif
393 ft->fd = open(ft->name, ft->open_flags, ft->st.st_mode);
394 }
395 #endif
396 if (ft->fd >= 0 && (ft->fd == STDIN_FILENO || ft->fd == STDOUT_FILENO || ft->fd == STDERR_FILENO))
397 {
398 fatal(ft,"sanity check failed: f_open()");
399 ft->fd = -1;
400 }
401 return ft->fd;
402 }
403
404
f_close(file_t * ft)405 int f_close(file_t *ft)
406 {
407 int r;
408
409 if (ft->fd < 0)
410 return 0;
411 if (ft->fd == STDIN_FILENO || ft->fd == STDOUT_FILENO || ft->fd == STDERR_FILENO)
412 return 0;
413 #if defined(USE_FOPEN)
414 assert(ft->file != NULL);
415 r = fclose(ft->file);
416 ft->file = NULL;
417 #else
418 r = close(ft->fd);
419 #endif
420 ft->fd = -1;
421 return r;
422 }
423
424
425 /*************************************************************************
426 // read and write
427 // handles partial pipe writes and interrupted system calls
428 **************************************************************************/
429
read_buf(file_t * ft,lzo_voidp buffer,lzo_int cnt)430 lzo_int read_buf(file_t *ft, lzo_voidp buffer, lzo_int cnt)
431 {
432 lzo_int n;
433 long l;
434
435 assert(cnt >= 0 && cnt < LONG_MAX);
436 l = acc_safe_hread(ft->fd, buffer, (long) cnt);
437 n = (lzo_int) l;
438 assert(n >= 0); assert(n == l);
439
440 ft->bytes_read += n;
441 total_bytes_read += n;
442 return n;
443 }
444
445
write_buf(file_t * ft,const lzo_voidp buffer,lzo_int cnt)446 void write_buf(file_t *ft, const lzo_voidp buffer, lzo_int cnt)
447 {
448 lzo_int n;
449 long l;
450
451 assert(cnt >= 0 && cnt < LONG_MAX);
452 if (ft->fd < 0)
453 return;
454 l = acc_safe_hwrite(ft->fd, buffer, (long) cnt);
455 n = (lzo_int) l;
456 assert(n >= 0); assert(n == l);
457
458 ft->bytes_written += n;
459 total_bytes_written += n;
460 if (n != cnt)
461 write_error(ft);
462 }
463
464
465 /*************************************************************************
466 // misc IO
467 **************************************************************************/
468
get_be16(const unsigned char * b)469 static unsigned get_be16(const unsigned char *b)
470 {
471 unsigned v;
472
473 v = (unsigned) b[1] << 0;
474 v |= (unsigned) b[0] << 8;
475 return v;
476 }
477
set_be16(unsigned char * b,unsigned v)478 static void set_be16(unsigned char *b, unsigned v)
479 {
480 b[1] = (unsigned char) (v >> 0);
481 b[0] = (unsigned char) (v >> 8);
482 }
483
484
get_be32(const unsigned char * b)485 static lzo_uint32 get_be32(const unsigned char *b)
486 {
487 lzo_uint32 v;
488
489 v = (lzo_uint32) b[3] << 0;
490 v |= (lzo_uint32) b[2] << 8;
491 v |= (lzo_uint32) b[1] << 16;
492 v |= (lzo_uint32) b[0] << 24;
493 return v;
494 }
495
set_be32(unsigned char * b,lzo_uint32 v)496 static void set_be32(unsigned char *b, lzo_uint32 v)
497 {
498 b[3] = (unsigned char) (v >> 0);
499 b[2] = (unsigned char) (v >> 8);
500 b[1] = (unsigned char) (v >> 16);
501 b[0] = (unsigned char) (v >> 24);
502 }
503
504
505 #if 0 /* NOT USED */
506 static void write8(file_t *ft, int v)
507 {
508 unsigned char b = (unsigned char) v;
509 write_buf(ft,&b,1);
510 }
511 #endif
512
513
read32(file_t * ft,lzo_uint32 * v)514 void read32(file_t *ft, lzo_uint32 *v)
515 {
516 unsigned char b[4];
517 if (read_buf(ft,b,4) != 4)
518 read_error(ft);
519 *v = get_be32(b);
520 }
521
write32(file_t * ft,lzo_uint32 v)522 void write32(file_t *ft, lzo_uint32 v)
523 {
524 unsigned char b[4];
525 set_be32(b,v);
526 write_buf(ft,b,4);
527 }
528
529
f_read8(file_t * ft,unsigned char * b)530 static int f_read8(file_t *ft, unsigned char *b)
531 {
532 unsigned char bb;
533 if (read_buf(ft,&bb,1) != 1)
534 read_error(ft);
535 ft->f_adler32 = lzo_adler32(ft->f_adler32,&bb,1);
536 ft->f_crc32 = lzo_crc32(ft->f_crc32,&bb,1);
537 if (b)
538 *b = bb;
539 return bb;
540 }
541
f_write8(file_t * ft,int v)542 static void f_write8(file_t *ft, int v)
543 {
544 unsigned char b = (unsigned char) v;
545 write_buf(ft,&b,1);
546 ft->f_adler32 = lzo_adler32(ft->f_adler32,&b,1);
547 ft->f_crc32 = lzo_crc32(ft->f_crc32,&b,1);
548 }
549
550
f_read16(file_t * ft,unsigned * v)551 static void f_read16(file_t *ft, unsigned *v)
552 {
553 unsigned char b[2];
554 if (read_buf(ft,b,2) != 2)
555 read_error(ft);
556 ft->f_adler32 = lzo_adler32(ft->f_adler32,b,2);
557 ft->f_crc32 = lzo_crc32(ft->f_crc32,b,2);
558 *v = get_be16(b);
559 }
560
f_write16(file_t * ft,unsigned v)561 static void f_write16(file_t *ft, unsigned v)
562 {
563 unsigned char b[2];
564 set_be16(b,v);
565 write_buf(ft,b,2);
566 ft->f_adler32 = lzo_adler32(ft->f_adler32,b,2);
567 ft->f_crc32 = lzo_crc32(ft->f_crc32,b,2);
568 }
569
570
f_read32(file_t * ft,lzo_uint32 * v)571 static void f_read32(file_t *ft, lzo_uint32 *v)
572 {
573 unsigned char b[4];
574 if (read_buf(ft,b,4) != 4)
575 read_error(ft);
576 ft->f_adler32 = lzo_adler32(ft->f_adler32,b,4);
577 ft->f_crc32 = lzo_crc32(ft->f_crc32,b,4);
578 *v = get_be32(b);
579 }
580
f_write32(file_t * ft,lzo_uint32 v)581 static void f_write32(file_t *ft, lzo_uint32 v)
582 {
583 unsigned char b[4];
584 set_be32(b,v);
585 write_buf(ft,b,4);
586 ft->f_adler32 = lzo_adler32(ft->f_adler32,b,4);
587 ft->f_crc32 = lzo_crc32(ft->f_crc32,b,4);
588 }
589
590
f_write(file_t * ft,const lzo_voidp buf,lzo_int cnt)591 static void f_write(file_t *ft, const lzo_voidp buf, lzo_int cnt)
592 {
593 if (cnt > 0)
594 {
595 write_buf(ft,buf,cnt);
596 ft->f_adler32 = lzo_adler32(ft->f_adler32,(const lzo_bytep)buf,cnt);
597 ft->f_crc32 = lzo_crc32(ft->f_crc32,(const lzo_bytep)buf,cnt);
598 }
599 }
600
f_read(file_t * ft,lzo_voidp buf,lzo_int cnt)601 static lzo_int f_read(file_t *ft, lzo_voidp buf, lzo_int cnt)
602 {
603 cnt = read_buf(ft,buf,cnt);
604 if (cnt > 0)
605 {
606 ft->f_adler32 = lzo_adler32(ft->f_adler32,(const lzo_bytep)buf,cnt);
607 ft->f_crc32 = lzo_crc32(ft->f_crc32,(const lzo_bytep)buf,cnt);
608 }
609 return cnt;
610 }
611
612
613 /***********************************************************************
614 // lzop file signature
615 ************************************************************************/
616
617 /*
618 * The first nine bytes of a lzop file always contain the following values:
619 *
620 * 0 1 2 3 4 5 6 7 8
621 * --- --- --- --- --- --- --- --- ---
622 * (hex) 89 4c 5a 4f 00 0d 0a 1a 0a
623 * (decimal) 137 76 90 79 0 13 10 26 10
624 * (C notation - ASCII) \211 L Z O \0 \r \n \032 \n
625 */
626
627 static const unsigned char lzop_magic[9] =
628 { 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a };
629
630 static const char * const header_error[] = {
631 "[0]",
632 "not a " PACKAGE " file", /* 1 */
633 "header corrupted (checksum error)", /* 2 */
634 "header corrupted", /* 3 */
635 "header corrupted (DOS -> UNIX conversion ?)", /* 4 */
636 "header corrupted (DOS -> Mac conversion ?)", /* 5 */
637 "header corrupted (UNIX -> Mac conversion ?)", /* 6 */
638 "header corrupted (Mac -> UNIX conversion ?)", /* 7 */
639 "header corrupted (UNIX -> DOS conversion ?)", /* 8 */
640 "header corrupted (end of line conversion ?)", /* 9 */
641 "header corrupted (DOS EOF conversion ?)", /* 10 */
642 "header corrupted (transmitted through a 7-bit channel ?)", /* 11 */
643 "header corrupted (transmitted in text mode ?)", /* 12 */
644 "unknown header flags -- get a newer version of " PACKAGE, /* 13 */
645 "unknown compression method -- get a newer version of " PACKAGE, /* 14 */
646 "unknown compression level -- get a newer version of " PACKAGE, /* 15 */
647 "you need a newer version of " PACKAGE, /* 16 */
648 "compression method not supported -- recompile " PACKAGE, /* 17 */
649 "decompression method not supported -- recompile " PACKAGE, /* 18 */
650 NULL
651 };
652
653
check_magic(const unsigned char * magic)654 static int check_magic(const unsigned char *magic)
655 {
656 const unsigned char *m;
657
658 if (memcmp(magic,lzop_magic,sizeof(lzop_magic)) == 0)
659 return 0;
660
661 /* We have a bad magic signature. Try to figure what possibly
662 * could have gone wrong. */
663
664 /* look at bytes 1-3: "LZO" in hex and local text format */
665 if (memcmp(&magic[1],&lzop_magic[1],3) != 0 &&
666 memcmp(&magic[1],"LZO",3) != 0)
667 return 1;
668
669 /* look at byte 4 */
670 if (magic[4] != lzop_magic[4])
671 return 1;
672
673 /* look at bytes 5-8 */
674 m = &magic[5];
675 if (memcmp(m,"\012\012\032",3) == 0)
676 return 7;
677 if (memcmp(m,"\012\012",2) == 0)
678 return 4;
679 if (memcmp(m,"\012\032",2) == 0)
680 return 4;
681 if (memcmp(m,"\015\012\012",3) == 0)
682 return 10;
683 if (memcmp(m,"\015\012\032\012",4) == 0)
684 return 9;
685 if (memcmp(m,"\015\012\032\015",4) == 0)
686 return 8;
687 if (memcmp(m,"\015\015\012\032",4) == 0)
688 return 8;
689 if (memcmp(m,"\015\015\032",3) == 0)
690 return 6;
691 if (memcmp(m,"\015\032",2) == 0)
692 return 5;
693 if (memcmp(m,&lzop_magic[5],4) != 0)
694 return 12;
695
696 /* look at byte 0 */
697 if (magic[0] == (unsigned char) (lzop_magic[0] & 0x7f))
698 return 11;
699 if (magic[0] != lzop_magic[0])
700 return 12;
701
702 return 3;
703 }
704
705
706 /*************************************************************************
707 // lzop file header
708 **************************************************************************/
709
init_compress_header(header_t * h,const file_t * fip,const file_t * fop)710 void init_compress_header(header_t *h, const file_t *fip, const file_t *fop)
711 {
712 assert(opt_method > 0);
713 assert(opt_level > 0);
714 assert(fip->st.st_mode == 0 || S_ISREG(fip->st.st_mode));
715
716 memset(h,0,sizeof(header_t));
717
718 h->version = LZOP_VERSION & 0xffff;
719 h->version_needed_to_extract = opt_filter ? 0x0950: 0x0940;
720 h->lib_version = lzo_version() & 0xffff;
721 h->method = (unsigned char) opt_method;
722 h->level = (unsigned char) opt_level;
723 h->filter = opt_filter;
724
725 h->flags = 0;
726 h->flags |= F_OS & F_OS_MASK;
727 h->flags |= F_CS & F_CS_MASK;
728 if (opt_filter)
729 h->flags |= F_H_FILTER;
730 if (fip->fd == STDIN_FILENO)
731 h->flags |= F_STDIN;
732 if (fop->fd == STDOUT_FILENO)
733 h->flags |= F_STDOUT;
734 if (!opt_file && num_files > 1)
735 h->flags |= F_MULTIPART;
736 #ifdef OPT_NAME_DEFAULT
737 h->flags |= F_NAME_DEFAULT;
738 #endif
739 #ifdef DOSISH
740 h->flags |= F_DOSISH;
741 #endif
742 if (opt_crc32)
743 {
744 h->flags |= F_H_CRC32;
745 if (h->version_needed_to_extract < 0x1001)
746 h->version_needed_to_extract = 0x1001;
747 }
748
749 h->mode = fix_mode_for_header(fip->st.st_mode);
750
751 if (fip->st.st_mtime > 0)
752 {
753 h->mtime_low = (lzo_uint32) (fip->st.st_mtime);
754 h->mtime_high = (lzo_uint32) ((fip->st.st_mtime >> 16) >> 16);
755 }
756
757 if (fip->name[0] && fip->fd != STDIN_FILENO)
758 {
759 int r = 0;
760 if (opt_path)
761 {
762 char newname[255+1];
763 r = fn_cleanpath(fip->name, newname, sizeof(newname), 0);
764 if (r > 0 && newname[0] && strlen(newname) <= 255)
765 {
766 strcpy(h->name, newname);
767 h->flags |= F_H_PATH;
768 if (h->version_needed_to_extract < 0x1001)
769 h->version_needed_to_extract = 0x1001;
770 }
771 else
772 r = 0;
773 }
774 if (r == 0)
775 {
776 const char *n = fn_basename(fip->name);
777 if (n[0] && strlen(n) <= 255)
778 strcpy(h->name, n);
779 }
780 }
781 }
782
783
write_header(file_t * ft,const header_t * h)784 void write_header(file_t *ft, const header_t *h)
785 {
786 size_t l;
787
788 #ifdef MAINT
789 /* undocumented option '--no-header'. just for testing. */
790 if (opt_noheader > 0)
791 {
792 switch (opt_noheader)
793 {
794 case 1:
795 write32(ft,h->flags);
796 break;
797 case 2:
798 write32(ft,h->flags);
799 write8(ft,h->method);
800 write8(ft,h->level);
801 break;
802 default:
803 /* write no header at all */
804 break;
805 }
806 return;
807 }
808 #endif
809
810 write_buf(ft,lzop_magic,sizeof(lzop_magic));
811
812 ft->f_adler32 = ADLER32_INIT_VALUE;
813 ft->f_crc32 = CRC32_INIT_VALUE;
814
815 f_write16(ft,h->version);
816 f_write16(ft,h->lib_version);
817 f_write16(ft,h->version_needed_to_extract);
818 f_write8(ft,h->method);
819 f_write8(ft,h->level);
820 f_write32(ft,h->flags);
821 if (h->flags & F_H_FILTER)
822 f_write32(ft,h->filter);
823 f_write32(ft,h->mode);
824 f_write32(ft,h->mtime_low);
825 f_write32(ft,h->mtime_high);
826
827 l = strlen(h->name);
828 assert(l <= 255);
829 f_write8(ft,(int)l);
830 if (l > 0)
831 f_write(ft,h->name,(int)l);
832
833 if (h->flags & F_H_CRC32)
834 f_write32(ft,ft->f_crc32);
835 else
836 f_write32(ft,ft->f_adler32);
837 }
838
839
read_header(file_t * ft,header_t * h)840 static int read_header(file_t *ft, header_t *h)
841 {
842 int r;
843 int l;
844 lzo_uint32 checksum;
845
846 memset(h,0,sizeof(header_t));
847 h->version_needed_to_extract = 0x0900; /* first public lzop version */
848 h->level = 0;
849 h->method_name = "unknown";
850
851 ft->f_adler32 = ADLER32_INIT_VALUE;
852 ft->f_crc32 = CRC32_INIT_VALUE;
853
854 f_read16(ft,&h->version);
855 if (h->version < 0x0900)
856 return 3;
857 f_read16(ft,&h->lib_version);
858 if (h->version >= 0x0940)
859 {
860 f_read16(ft,&h->version_needed_to_extract);
861 if (h->version_needed_to_extract > LZOP_VERSION)
862 return 16;
863 if (h->version_needed_to_extract < 0x0900)
864 return 3;
865 }
866 f_read8(ft,&h->method);
867 if (h->version >= 0x0940)
868 f_read8(ft,&h->level);
869 f_read32(ft,&h->flags);
870 if (h->flags & F_H_FILTER)
871 f_read32(ft,&h->filter);
872 f_read32(ft,&h->mode);
873 #if 1
874 if (h->flags & F_STDIN) /* do not use mode from stdin compression */
875 h->mode = 0;
876 #endif
877 f_read32(ft,&h->mtime_low);
878 if (h->version >= 0x0940)
879 f_read32(ft,&h->mtime_high);
880 if (h->version < 0x0120) {
881 if (h->mtime_low == 0xffffffffUL)
882 h->mtime_low = 0;
883 h->mtime_high = 0;
884 }
885
886 l = f_read8(ft,NULL);
887 if (l > 0) {
888 char name[255+1];
889 if (f_read(ft,name,l) != l)
890 read_error(ft);
891 name[l] = 0;
892 if (fn_cleanpath(name, h->name, 255+1, 1|2) < 0)
893 h->name[0] = 0;
894 }
895
896 checksum = (h->flags & F_H_CRC32) ? ft->f_crc32 : ft->f_adler32;
897 f_read32(ft,&h->header_checksum);
898 if (h->header_checksum != checksum)
899 return 2;
900
901 if (h->method <= 0)
902 return 14;
903 r = x_get_method(h);
904 if (r != 0)
905 return r;
906
907 /* check reserved flags */
908 if (h->flags & F_RESERVED)
909 return (opt_force >= 2) ? -13 : 13;
910
911 /* skip extra field [not used yet] */
912 if (h->flags & F_H_EXTRA_FIELD)
913 {
914 lzo_uint32 k;
915
916 /* note: the checksum also covers the length */
917 ft->f_adler32 = ADLER32_INIT_VALUE;
918 ft->f_crc32 = CRC32_INIT_VALUE;
919 f_read32(ft,&h->extra_field_len);
920 for (k = 0; k < h->extra_field_len; k++)
921 (void) f_read8(ft,NULL);
922 checksum = (h->flags & F_H_CRC32) ? ft->f_crc32 : ft->f_adler32;
923 f_read32(ft,&h->extra_field_checksum);
924 if (h->extra_field_checksum != checksum)
925 return 3;
926 if (opt_verbose >= 2)
927 info(ft,"ignoring extra field");
928 }
929
930 return 0;
931 }
932
933
934 /* return 0 for valid magic, -1 for EOF, or positive value for error */
p_magic(file_t * ft)935 static int p_magic(file_t *ft)
936 {
937 int r;
938 lzo_int l;
939 unsigned char magic[sizeof(lzop_magic)];
940
941 l = read_buf(ft,magic,sizeof(magic));
942 if (ft->part > 0 && l <= 0)
943 return -1;
944 if (l == (lzo_int) sizeof(magic))
945 r = check_magic(magic);
946 else
947 r = 1;
948 assert(r >= 0);
949 if (ft->part > 0 && r == 1)
950 {
951 #if 1
952 /* gzip: check for trailing zero bytes */
953 unsigned char b;
954 while (--l >= 0)
955 if (magic[(int)l] != '\0')
956 goto garbage;
957 while (read_buf(ft,&b,1) == 1)
958 if (b != '\0')
959 goto garbage;
960 if (opt_verbose >= 2)
961 warn(ft,"ignoring trailing zero bytes in " PACKAGE " file");
962 return -1;
963 garbage:
964 #endif
965 warn(ft,"ignoring trailing garbage in " PACKAGE " file");
966 return -1;
967 }
968 if (r != 0)
969 {
970 assert(r > 0 && r <= 18);
971 error(ft,header_error[r]);
972 }
973 return r;
974 }
975
976
p_header(file_t * ft,header_t * h)977 static lzo_bool p_header(file_t *ft, header_t *h)
978 {
979 int r;
980
981 r = read_header(ft,h);
982 if (r == 0)
983 return 1;
984 if (r < 0)
985 {
986 r = -r;
987 assert(r > 0 && r <= 18);
988 error(ft,header_error[r]);
989 return 1;
990 }
991 else
992 {
993 assert(r > 0 && r <= 18);
994 error(ft,header_error[r]);
995 return 0;
996 }
997 }
998
999
1000 /*************************************************************************
1001 // test
1002 **************************************************************************/
1003
do_test(const header_t * h,lzop_ulong_t d_len,lzop_ulong_t c_len)1004 void do_test(const header_t *h, lzop_ulong_t d_len, lzop_ulong_t c_len)
1005 {
1006 total_d_files++;
1007 total_c_len += c_len;
1008 total_d_len += d_len;
1009 UNUSED(h);
1010 }
1011
1012
do_test_total(void)1013 void do_test_total(void)
1014 {
1015 FILE *f;
1016
1017 if ((total_c_files < 2 && total_d_files < 2) || opt_verbose < 2)
1018 return;
1019
1020 f = stderr;
1021 fprintf(f,"%lu file%s successfully tested", total_c_files,
1022 total_c_files == 1 ? " was" : "s were");
1023 if (total_c_files != total_d_files)
1024 fprintf(f," [containing %lu files]", total_d_files);
1025 fprintf(f,"\n");
1026 fflush(f);
1027 }
1028
1029
1030 /*************************************************************************
1031 // list a file
1032 **************************************************************************/
1033
get_ratio(lzop_ulong_t d_len,lzop_ulong_t c_len)1034 static unsigned long get_ratio(lzop_ulong_t d_len, lzop_ulong_t c_len)
1035 {
1036 unsigned long n1 = 1000L * 1000L;
1037 unsigned long n2 = 1;
1038 const lzop_ulong_t umax = ~((lzop_ulong_t)0);
1039
1040 if (d_len <= 0)
1041 return c_len <= 0 ? 0ul : n1;
1042 while (n1 > 1 && c_len > (umax / n1))
1043 {
1044 n1 /= 10;
1045 n2 *= 10;
1046 }
1047 return (unsigned long) ((c_len * n1) / (d_len / n2));
1048 }
1049
1050
pr_size(FILE * f,lzop_ulong_t a,lzop_ulong_t b,int flags)1051 static void pr_size(FILE *f, lzop_ulong_t a, lzop_ulong_t b, int flags)
1052 {
1053 unsigned long ratio, r1, r2, al, bl;
1054
1055 ratio = (flags & 1) ? get_ratio(a, b) : get_ratio(b, a);
1056 ratio += 500; /* for rounding */
1057 r1 = ratio / 10000;
1058 r2 = (ratio % 10000) / 1000;
1059
1060 #if (SIZEOF_LONG >= 8) || !defined(acc_int64l_t)
1061 al = (unsigned long) a;
1062 bl = (unsigned long) b;
1063 fprintf(f,"%9lu %9lu %3lu.%01lu%%", al, bl, r1, r2);
1064 #else
1065 al = (unsigned long) (a % 1000000000ul);
1066 bl = (unsigned long) (b % 1000000000ul);
1067 if (a == al && b == bl)
1068 {
1069 fprintf(f,"%9lu %9lu %3lu.%01lu%%", al, bl, r1, r2);
1070 }
1071 else if (a == al)
1072 {
1073 unsigned long bh = (unsigned long) (b / 1000000000ul);
1074 fprintf(f,"%9lu %lu%09lu %3lu.%01lu%%", al, bh, bl, r1, r2);
1075 }
1076 else if (b == bl)
1077 {
1078 unsigned long ah = (unsigned long) (a / 1000000000ul);
1079 fprintf(f,"%lu%09lu %9lu %3lu.%01lu%%", ah, al, bl, r1, r2);
1080 }
1081 else
1082 {
1083 unsigned long ah = (unsigned long) (a / 1000000000ul);
1084 unsigned long bh = (unsigned long) (b / 1000000000ul);
1085 fprintf(f,"%lu%09lu %lu%09lu %3lu.%01lu%%", ah, al, bh, bl, r1, r2);
1086 }
1087 #endif
1088 }
1089
1090
modestr(lzo_uint32 mode)1091 static char *modestr(lzo_uint32 mode)
1092 {
1093 static char s[10+1];
1094
1095 mode_string(fix_mode_for_ls(mode),s);
1096 s[0] = '-';
1097 s[10] = 0;
1098 return s;
1099 }
1100
1101
do_list(const header_t * h,lzop_ulong_t d_len,lzop_ulong_t c_len)1102 void do_list(const header_t *h, lzop_ulong_t d_len, lzop_ulong_t c_len)
1103 {
1104 FILE *f;
1105 char s[40];
1106 time_t t;
1107
1108 f = stdout;
1109 s[0] = 0;
1110 t = get_mtime(h);
1111
1112 if (total_d_files == 0 && opt_verbose > 0)
1113 {
1114 if (opt_verbose >= 3)
1115 ((void)0);
1116 else if (opt_verbose >= 2)
1117 {
1118 fprintf(f,"Method Length Packed Ratio ");
1119 fprintf(f," Date Time Name\n");
1120 fprintf(f,"------ ------ ------ ----- ");
1121 fprintf(f," ---- ---- ----\n");
1122 }
1123 else
1124 {
1125 fprintf(f,"%-11s ", "method");
1126 fprintf(f,"compressed uncompr. ratio");
1127 fprintf(f," uncompressed_name\n");
1128 }
1129 fflush(f);
1130 }
1131
1132 if (opt_verbose >= 3)
1133 {
1134 fprintf(f,"%-10s", modestr(h->mode));
1135 if (t)
1136 time2str(s,sizeof(s),&t);
1137 fprintf(f," %-19s",s);
1138 fprintf(f," %-20s",fi.name);
1139 if (fo.name[0])
1140 fprintf(f," %s", fo.name);
1141 }
1142 else if (opt_verbose >= 2)
1143 {
1144 fprintf(f,"%-11s ", h->method_name);
1145 pr_size(f, d_len, c_len, 1);
1146 if (t)
1147 time2str(s,sizeof(s),&t);
1148 s[16] = 0; /* cut off seconds */
1149 fprintf(f," %-16s",s);
1150 if (fo.name[0])
1151 fprintf(f," %s", fo.name);
1152 }
1153 else
1154 {
1155 fprintf(f,"%-11s ", h->method_name);
1156 pr_size(f, c_len, d_len, 0);
1157 if (fo.name[0])
1158 fprintf(f," %s", fo.name);
1159 }
1160
1161 fprintf(f,"\n");
1162 fflush(f);
1163
1164 total_d_files++;
1165 total_c_len += c_len;
1166 total_d_len += d_len;
1167 }
1168
1169
do_list_total(void)1170 void do_list_total(void)
1171 {
1172 FILE *f;
1173
1174 if (total_d_files < 2 || opt_verbose == 0)
1175 return;
1176 if (opt_verbose >= 3)
1177 return;
1178
1179 f = stdout;
1180 if (opt_verbose >= 2)
1181 {
1182 fprintf(f," ------- ------- ----- ");
1183 fprintf(f," ----\n");
1184 fprintf(f,"%-11s ", "");
1185 pr_size(f, total_d_len, total_c_len, 1);
1186 fprintf(f," %-16s", "");
1187 fprintf(f," %lu files\n", total_d_files);
1188 }
1189 else
1190 {
1191 fprintf(f,"%-11s ", "");
1192 pr_size(f, total_c_len, total_d_len, 0);
1193 fprintf(f," (totals -- %lu files)\n", total_d_files);
1194 }
1195 fflush(f);
1196 }
1197
1198
1199 /*************************************************************************
1200 // list a file similar to 'ls -ln'
1201 **************************************************************************/
1202
do_ls(const header_t * h,lzop_ulong_t d_len,lzop_ulong_t c_len)1203 void do_ls(const header_t *h, lzop_ulong_t d_len, lzop_ulong_t c_len)
1204 {
1205 FILE *f;
1206 char s[40];
1207 time_t t;
1208 const char *name = fo.name[0] ? fo.name : UNKNOWN_NAME;
1209
1210 f = stdout;
1211 t = get_mtime(h);
1212 if (t == 0)
1213 time(&t);
1214 fprintf(f,"%-10s 1", modestr(h->mode));
1215 if (opt_stdin)
1216 fprintf(f," %-8s", "user");
1217 else
1218 fprintf(f," %-8ld", (long) fi.st.st_uid);
1219 if (!strchr(opt_ls_flags,'G'))
1220 {
1221 if (opt_stdin)
1222 fprintf(f," %-8s", "group");
1223 else
1224 fprintf(f," %-8ld", (long) fi.st.st_gid);
1225 }
1226
1227 #if (SIZEOF_LONG >= 8) || !defined(acc_int64l_t)
1228 fprintf(f," %8lu", (unsigned long) d_len);
1229 #else
1230 {
1231 unsigned long d0, d1, d2;
1232 d0 = (unsigned long) (d_len % 100000000ul);
1233 if (d0 == d_len)
1234 fprintf(f," %8lu", d0);
1235 else
1236 {
1237 d1 = (unsigned long) ((d_len / 100000000ul) % 100000000ul);
1238 d2 = (unsigned long) ((d_len / 100000000ul) / 100000000ul);
1239 if (d2 != 0)
1240 fprintf(f,"%lu%08lu%08lu", d2, d1, d0);
1241 else
1242 fprintf(f,"%lu%08lu", d1, d0);
1243 }
1244 }
1245 #endif
1246 time2ls(s, sizeof(s), &t);
1247 fprintf(f," %-12s",s);
1248 if (strchr(opt_ls_flags,'Q'))
1249 fprintf(f," \"%s\"", name);
1250 else
1251 fprintf(f," %s", name);
1252 if (strchr(opt_ls_flags,'F'))
1253 if (h->mode & 0111)
1254 fprintf(f,"*");
1255 fprintf(f,"\n");
1256 fflush(f);
1257
1258 UNUSED(c_len);
1259 }
1260
1261
1262 /*************************************************************************
1263 // header info
1264 **************************************************************************/
1265
print_version(FILE * f,unsigned v)1266 static void print_version(FILE *f, unsigned v)
1267 {
1268 fprintf(f,"%1x.%03x", (v >> 12) & 0xf, v & 0xfff);
1269 }
1270
1271
print_os(FILE * f,lzo_uint32 flags)1272 static void print_os(FILE *f, lzo_uint32 flags)
1273 {
1274 flags = (flags & F_OS_MASK) >> F_OS_SHIFT;
1275 fprintf(f,"%2ld", (long) flags);
1276 }
1277
1278
do_info(const header_t * h,lzop_ulong_t d_len,lzop_ulong_t c_len)1279 void do_info(const header_t *h, lzop_ulong_t d_len, lzop_ulong_t c_len)
1280 {
1281 int v = opt_verbose;
1282 FILE *f;
1283
1284 f = stdout;
1285 opt_verbose = 2;
1286 ++total_d_files; /* do not print the list-header */
1287 do_list(h,d_len,c_len);
1288 --total_d_files;
1289 opt_verbose = v;
1290
1291 fprintf(f," ");
1292 print_version(f,h->version);
1293 fprintf(f," ");
1294 print_version(f,h->lib_version);
1295 fprintf(f," ");
1296 print_version(f,h->version_needed_to_extract);
1297 fprintf(f," Fl: 0x%08lx", (long) h->flags);
1298 fprintf(f," Mo: 0%011lo", (long) h->mode);
1299 fprintf(f," Me: %d/%d", h->method, h->level);
1300 fprintf(f," OS: ");
1301 print_os(f,h->flags);
1302 if (h->filter)
1303 fprintf(f," Fi: %3ld", (long) h->filter);
1304 fprintf(f,"\n");
1305 }
1306
1307
1308 /*************************************************************************
1309 // determine name of output file
1310 **************************************************************************/
1311
can_restore_name(file_t * ft,const header_t * h)1312 static lzo_bool can_restore_name(file_t *ft, const header_t *h)
1313 {
1314 if (h->name[0] == 0 || ft->opt_name == 0)
1315 return 0;
1316 else if (ft->opt_name > 0)
1317 return 1;
1318 #ifdef OPT_NAME_DEFAULT
1319 #if 1
1320 else
1321 return 1;
1322 #else
1323 /* restore the name by default only when created on such a system */
1324 else if ((h->flags & F_NAME_DEFAULT))
1325 return 1;
1326 else
1327 return 0;
1328 #endif
1329 #else
1330 /* do not restore the name by default */
1331 else
1332 return 0;
1333 #endif /* OPT_NAME_DEFAULT */
1334 }
1335
1336
oname_error(void)1337 static lzo_bool oname_error(void)
1338 {
1339 if (opt_force >= 2 || opt_cmd == CMD_TEST)
1340 {
1341 warn(&fi,"can't determine name of output file -- using default");
1342 return 1;
1343 }
1344 if (opt_name != 1)
1345 error(&fi,"can't determine name of output file (try option '-N')");
1346 else
1347 error(&fi,"can't determine name of output file (use option '-o')");
1348 strcpy(fo.name,UNKNOWN_NAME);
1349 return 0;
1350 }
1351
1352
p_set_oname(const header_t * h)1353 static lzo_bool p_set_oname(const header_t *h)
1354 {
1355 char *base;
1356 char *ext;
1357 int suff;
1358 size_t l;
1359 const char *err_name;
1360 const char *s;
1361 size_t sl;
1362
1363 fo.name[0] = 0;
1364 if (opt_output_name)
1365 {
1366 /* name given on command line; perform no additional checks */
1367 strcpy(fo.name,opt_output_name);
1368 return 1;
1369 }
1370
1371 assert(!opt_stdout);
1372 assert(opt_file);
1373
1374 #if defined(NRVP)
1375 err_name = (opt_cmd == CMD_COMPRESS) ? "nrvp.nrv" : "nrvp.raw";
1376 s = opt_suffix[0] ? opt_suffix : ".nrv";
1377 #else
1378 err_name = (opt_cmd == CMD_COMPRESS) ? "lzop.lzo" : "lzop.raw";
1379 s = opt_suffix[0] ? opt_suffix : ".lzo";
1380 #endif
1381
1382 sl = strlen(s);
1383
1384 if (opt_output_path)
1385 {
1386 strcpy(fo.name,opt_output_path);
1387 fn_addslash(fo.name,1);
1388 if (!opt_stdin)
1389 strcat(fo.name,fn_basename(fi.name));
1390 }
1391 else if (!opt_stdin)
1392 strcpy(fo.name,fi.name);
1393 l = strlen(fo.name);
1394 if (l >= PATH_MAX)
1395 {
1396 error(&fo,"name too long (use option '-o')");
1397 return 0;
1398 }
1399 base = fo.name + fn_baseindex(fo.name);
1400 suff = fn_has_suffix(base);
1401 ext = strchr(base,'.');
1402
1403 if (opt_cmd == CMD_COMPRESS)
1404 {
1405 assert(!opt_stdin);
1406 assert(base[0]);
1407 #if defined(DOSISH)
1408 if (suff == SUFF_TAR)
1409 {
1410 #if defined(NRVP)
1411 strcpy(ext, opt_suffix[0] ? opt_suffix : ".tnv");
1412 #else
1413 strcpy(ext, opt_suffix[0] ? opt_suffix : ".tzo");
1414 #endif
1415 }
1416 else
1417 #endif
1418 if (opt_shortname && ext)
1419 strcpy(ext,s);
1420 else
1421 strcat(fo.name,s);
1422 }
1423 else
1424 {
1425 lzo_bool u = 0;
1426
1427 if (can_restore_name(&fi,h))
1428 {
1429 if (opt_path)
1430 strcpy(base,h->name);
1431 else
1432 strcpy(base,fn_basename(h->name));
1433 }
1434 else if (opt_stdin)
1435 {
1436 if (!oname_error())
1437 return 0;
1438 strcpy(base,err_name);
1439 }
1440 else if (suff == SUFF_LZO)
1441 fo.name[l-4] = 0;
1442 else if (suff == SUFF_LZOP)
1443 fo.name[l-5] = 0;
1444 else if (suff == SUFF_NRV)
1445 fo.name[l-4] = 0;
1446 else if (suff == SUFF_TZO)
1447 strcpy(&fo.name[l-4],".tar");
1448 else if (suff == SUFF_USER)
1449 fo.name[l-sl] = 0;
1450 else
1451 {
1452 u = 1;
1453 if (opt_shortname && ext)
1454 strcpy(ext,".raw");
1455 else
1456 strcat(fo.name,".raw");
1457 }
1458
1459 if (u && opt_cmd == CMD_DECOMPRESS && !opt_stdin)
1460 {
1461 #if 1
1462 if (!(opt_force >= 2))
1463 {
1464 if (fi.warn_unknown_suffix == 0)
1465 error(&fi,"unknown suffix -- ignored");
1466 fi.warn_unknown_suffix = 1;
1467 return 0;
1468 }
1469 #else
1470 /* gzip: '--force' doesn't override these checks */
1471 if (fi.warn_unknown_suffix == 0)
1472 error(&fi,"unknown suffix -- ignored");
1473 fi.warn_unknown_suffix = 1;
1474 return 0;
1475 #endif
1476 }
1477
1478 }
1479
1480 if (strlen(fo.name) >= PATH_MAX)
1481 {
1482 error(&fo,"name too long (use option '-o')");
1483 return 0;
1484 }
1485 #if defined(DOSISH)
1486 s = maybe_rename_file(fo.name);
1487 if (s == NULL)
1488 {
1489 if (!oname_error())
1490 return 0;
1491 strcpy(base,err_name);
1492 }
1493 else if (s != fo.name)
1494 {
1495 if (strcmp(s,fo.name) != 0)
1496 {
1497 warn(&fo,"renaming output file to match OS conventions");
1498 strcpy(fo.name,s);
1499 }
1500 }
1501 #endif
1502
1503 UNUSED(ext);
1504 return 1;
1505 }
1506
1507
1508 /*************************************************************************
1509 // stdin/stdout
1510 **************************************************************************/
1511
check_stdin(file_t * ft)1512 static lzo_bool check_stdin(file_t *ft)
1513 {
1514 if (!opt_force && acc_isatty(STDIN_FILENO))
1515 {
1516 strcpy(ft->name,STDIN_NAME);
1517 if (opt_cmd == CMD_COMPRESS)
1518 fatal(ft,"uncompressed data not read from a terminal");
1519 else
1520 fatal(ft,"compressed data not read from a terminal");
1521 return 0;
1522 }
1523 return 1;
1524 }
1525
1526
check_stdout(file_t * ft)1527 static lzo_bool check_stdout(file_t *ft)
1528 {
1529 if (!(opt_cmd == CMD_COMPRESS || opt_cmd == CMD_DECOMPRESS))
1530 return 1;
1531 if (!opt_force && acc_isatty(STDOUT_FILENO))
1532 {
1533 strcpy(ft->name,STDOUT_NAME);
1534 if (opt_cmd == CMD_COMPRESS)
1535 fatal(ft,"compressed data not written to a terminal");
1536 else
1537 fatal(ft,"uncompressed data not written to a terminal");
1538 return 0;
1539 }
1540 return 1;
1541 }
1542
1543
open_stdin(file_t * ft)1544 static lzo_bool open_stdin(file_t *ft)
1545 {
1546 #if !defined(NO_SETMODE)
1547 static lzo_bool setmode_done = 0;
1548 #endif
1549
1550 assert(ft->fd == -1);
1551 f_reset(ft);
1552
1553 strcpy(ft->name,STDIN_NAME);
1554 ft->fd = STDIN_FILENO;
1555
1556 #if !defined(NO_SETMODE)
1557 if (!setmode_done)
1558 {
1559 if (acc_set_binmode(ft->fd, 1) == -1)
1560 {
1561 p_fatal(ft,"acc_set_binmode(stdin) failed");
1562 return 0;
1563 }
1564 }
1565 setmode_done = 1;
1566 #endif
1567
1568 ft->st.st_mtime = time(NULL);
1569 #if 1 && defined(HAVE_FSTAT)
1570 {
1571 struct stat st;
1572 if (fstat(ft->fd, &st) == 0 && S_ISREG(st.st_mode))
1573 ft->st = st;
1574 }
1575 #endif
1576 ft->st.st_atime = fix_time(ft->st.st_atime);
1577 ft->st.st_mtime = fix_time(ft->st.st_mtime);
1578 return 1;
1579 }
1580
1581
open_stdout(file_t * ft)1582 static lzo_bool open_stdout(file_t *ft)
1583 {
1584 #if !defined(NO_SETMODE)
1585 static lzo_bool setmode_done = 0;
1586 #endif
1587
1588 assert(ft->fd == -1);
1589 f_reset(ft);
1590
1591 strcpy(ft->name,STDOUT_NAME);
1592 if (!(opt_cmd == CMD_COMPRESS || opt_cmd == CMD_DECOMPRESS))
1593 {
1594 ft->fd = -2; /* special file-handle for dummy output */
1595 return 1;
1596 }
1597 ft->fd = STDOUT_FILENO;
1598
1599 #if !defined(NO_SETMODE)
1600 if (!setmode_done)
1601 {
1602 if (acc_set_binmode(ft->fd, 1) == -1)
1603 {
1604 p_fatal(ft,"acc_set_binmode(stdout) failed");
1605 return 0;
1606 }
1607 }
1608 setmode_done = 1;
1609 #endif
1610
1611 return 1;
1612 }
1613
1614
1615 /*************************************************************************
1616 // open input file
1617 **************************************************************************/
1618
p_open_fi(const char * name)1619 lzo_bool p_open_fi(const char *name)
1620 {
1621 int r, saved_errno;
1622 #if defined(HAVE_LSTAT) && defined(S_ISLNK)
1623 int r2;
1624 #endif
1625
1626 if (fi.fd != -1)
1627 return 1;
1628
1629 f_reset(&fi);
1630
1631 /* prepare file name */
1632 assert(name != NULL);
1633 if (strlen(name) >= PATH_MAX)
1634 {
1635 if (strlen(name) >= sizeof(fi.name))
1636 strcpy(fi.name,UNKNOWN_NAME);
1637 else
1638 strcpy(fi.name,name);
1639 error(&fi,"name too long");
1640 return 0;
1641 }
1642 strcpy(fi.name,name);
1643 fn_strlwr(fi.name);
1644 if (opt_cmd == CMD_COMPRESS)
1645 {
1646 int suff = fn_has_suffix(fi.name);
1647 #if 1
1648 if (opt_stdout || opt_output_name)
1649 suff = SUFF_NONE; /* do not warn */
1650 #endif
1651 #if 1
1652 if (opt_force >= 2)
1653 suff = SUFF_NONE; /* do not warn */
1654 #else
1655 /* gzip: '--force' doesn't override these checks */
1656 #endif
1657 if (suff == SUFF_LZO)
1658 {
1659 warn(&fi,"already has .lzo suffix -- unchanged");
1660 return 0;
1661 }
1662 else if (suff == SUFF_LZOP)
1663 {
1664 warn(&fi,"already has .lzop suffix -- unchanged");
1665 return 0;
1666 }
1667 else if (suff == SUFF_NRV)
1668 {
1669 warn(&fi,"already has .nrv suffix -- unchanged");
1670 return 0;
1671 }
1672 else if (suff == SUFF_TZO)
1673 {
1674 warn(&fi,"already has .tzo suffix -- unchanged");
1675 return 0;
1676 }
1677 else if (suff == SUFF_USER)
1678 {
1679 warn(&fi,"already has user suffix -- unchanged");
1680 return 0;
1681 }
1682 }
1683
1684 /* open file */
1685 errno = 0;
1686 r = stat(fi.name, &fi.st);
1687 saved_errno = errno;
1688 if (r != 0)
1689 memset(&fi.st, 0, sizeof(fi.st));
1690 #if defined(HAVE_LSTAT) && defined(S_ISLNK)
1691 r2 = lstat(fi.name, &fi.lst);
1692 if (r2 != 0)
1693 memset(&fi.lst, 0, sizeof(fi.lst));
1694 if (r2 == 0 && S_ISLNK(fi.lst.st_mode))
1695 {
1696 if (r != 0)
1697 {
1698 errno = saved_errno;
1699 #if 0
1700 p_error(&fi,"can't open input file -- dangling symlink");
1701 #else
1702 do_error(&fi,err_nl,"can't open input file: Dangling symlink",EXIT_ERROR,0);
1703 #endif
1704 return 0;
1705 }
1706 }
1707 #endif
1708 if (r == 0 && !S_ISREG(fi.st.st_mode))
1709 {
1710 warn(&fi,"not a regular file -- skipped");
1711 return 0;
1712 }
1713 fi.open_flags = O_RDONLY;
1714 f_open(&fi,1);
1715 #if 0 && defined(__DJGPP__)
1716 /* try again without LFN */
1717 if (fi.fd < 0 && errno == ENOENT && _USE_LFN)
1718 {
1719 if (!(_crt0_startup_flags & _CRT0_FLAG_NO_LFN))
1720 {
1721 int k = _crt0_startup_flags;
1722 _crt0_startup_flags |= _CRT0_FLAG_NO_LFN;
1723 r = stat(fi.name, &fi.st);
1724 saved_errno = errno;
1725 _crt0_startup_flags = k;
1726 if (r == 0 && !S_ISREG(fi.st.st_mode))
1727 {
1728 warn(&fi,"not a regular file -- skipped");
1729 return 0;
1730 }
1731 f_open(&fi,1);
1732 }
1733 }
1734 #endif
1735 if (fi.fd < 0)
1736 {
1737 p_error(&fi,"can't open input file");
1738 return 0;
1739 }
1740 if (r != 0)
1741 {
1742 errno = saved_errno;
1743 p_error(&fi,"can't stat input file");
1744 (void) f_close(&fi);
1745 return 0;
1746 }
1747
1748 fi.st.st_atime = fix_time(fi.st.st_atime);
1749 fi.st.st_mtime = fix_time(fi.st.st_mtime);
1750 return 1;
1751 }
1752
1753
1754 /*************************************************************************
1755 // open output file
1756 **************************************************************************/
1757
p_open_fo(const header_t * h)1758 lzo_bool p_open_fo(const header_t *h)
1759 {
1760 if (fo.fd != -1)
1761 return 1;
1762
1763 f_reset(&fo);
1764
1765 if (!p_set_oname(h))
1766 return 0;
1767 fn_strlwr(fo.name);
1768
1769 if (!(opt_cmd == CMD_COMPRESS || opt_cmd == CMD_DECOMPRESS))
1770 {
1771 fo.fd = opt_output_name ? -2 : -1;
1772 return 1;
1773 }
1774
1775 if (fn_is_same_file(fi.name,fo.name))
1776 {
1777 if (opt_cmd == CMD_COMPRESS)
1778 error(&fi,"can't compress to same file");
1779 else
1780 error(&fi,"can't decompress to same file");
1781 return 0;
1782 }
1783 fo.open_flags = O_CREAT | O_WRONLY;
1784 if (opt_force)
1785 fo.open_flags |= O_TRUNC;
1786 else
1787 fo.open_flags |= O_EXCL;
1788 #if defined(__MINT__)
1789 fo.open_flags |= O_TRUNC | O_DENYRW;
1790 #endif
1791 fo.st.st_mode = fix_mode_for_open(fi.st.st_mode);
1792 if (opt_cmd == CMD_DECOMPRESS && opt_path && (h->flags & F_H_PATH))
1793 {
1794 /* create missing directories */
1795 char *name;
1796 int n = 0;
1797 name = fo.name;
1798 while (name[n])
1799 {
1800 while (name[n] && name[n] != '/')
1801 n++;
1802 if (name[n] == '/')
1803 {
1804 name[n] = 0;
1805 (void) acc_mkdir(name, 0777);
1806 name[n] = DIR_SEP[0];
1807 n++;
1808 }
1809 }
1810 }
1811 f_open(&fo,0);
1812 if (fo.fd < 0)
1813 {
1814 if ((fo.open_flags & O_EXCL) && errno == EEXIST)
1815 error(&fo,"already exists; not overwritten");
1816 else
1817 p_error(&fo,"can't open output file");
1818 return 0;
1819 }
1820
1821 return 1;
1822 }
1823
1824
1825 /*************************************************************************
1826 // close files
1827 **************************************************************************/
1828
p_close(int i,int o)1829 static lzo_bool p_close(int i, int o)
1830 {
1831 int r = 1;
1832
1833 if (i && f_close(&fi) != 0)
1834 {
1835 p_error(&fi,"can't close input file");
1836 r = 0;
1837 }
1838 if (o && f_close(&fo) != 0)
1839 {
1840 p_error(&fo,"can't close output file");
1841 r = 0;
1842 }
1843 return r;
1844 }
1845
1846
1847 /*************************************************************************
1848 // compress
1849 **************************************************************************/
1850
copy_perms(void)1851 static void copy_perms(void)
1852 {
1853 #if defined(HAVE_UTIME)
1854 /* copy the time stamp */
1855 struct utimbuf u;
1856 u.actime = fi.st.st_atime;
1857 u.modtime = fi.st.st_mtime;
1858 if (utime(fo.name,&u) != 0)
1859 p_warn(&fo,"can't copy file time");
1860 #endif
1861 #if defined(HAVE_CHMOD)
1862 /* copy the protection mode */
1863 fo.st.st_mode = fi.st.st_mode;
1864 if (chmod(fo.name, fo.st.st_mode) != 0)
1865 p_warn(&fo,"can't copy file mode");
1866 #endif
1867 #if defined(HAVE_CHOWN)
1868 /* copy the ownership */
1869 if (chown(fo.name, fi.st.st_uid, fi.st.st_gid) != 0) {
1870 /* ignore */
1871 }
1872 #endif
1873 }
1874
1875
do_compress(const char * name,lzo_bool handle_perms)1876 static lzo_bool do_compress(const char *name, lzo_bool handle_perms)
1877 {
1878 lzo_bool ok = 1;
1879 header_t header;
1880
1881 if (!p_open_fi(name))
1882 return 0;
1883 if (!p_open_fo(NULL))
1884 {
1885 if (opt_output_name || opt_stdout)
1886 e_exit(EXIT_ERROR);
1887 return 0;
1888 }
1889
1890 ok = x_compress(&fi,&fo,&header);
1891 if (!ok)
1892 return 0;
1893
1894 if (handle_perms)
1895 {
1896 if (!p_close(1,1))
1897 return 0;
1898 copy_perms();
1899 }
1900
1901 return ok;
1902 }
1903
1904
1905 /*************************************************************************
1906 // decompress
1907 **************************************************************************/
1908
restore_perms(const header_t * h)1909 static void restore_perms(const header_t *h)
1910 {
1911 #if defined(HAVE_UTIME)
1912 /* restore or copy the time stamp */
1913 struct utimbuf u;
1914 if (opt_restore_time && (h->mtime_low || h->mtime_high))
1915 {
1916 u.actime = u.modtime = get_mtime(h);
1917 if (u.actime)
1918 if (utime(fo.name,&u) != 0)
1919 p_warn(&fo,"can't restore file time");
1920 }
1921 else if (fi.st.st_atime && fi.st.st_mtime)
1922 {
1923 u.actime = fi.st.st_atime;
1924 u.modtime = fi.st.st_mtime;
1925 if (utime(fo.name,&u) != 0)
1926 p_warn(&fo,"can't copy file time");
1927 }
1928 #endif
1929 #if defined(HAVE_CHMOD)
1930 /* restore or copy the protection mode */
1931 if (opt_restore_mode && h->mode)
1932 {
1933 fo.st.st_mode = fix_mode_for_chmod(h->mode);
1934 if (chmod(fo.name, fo.st.st_mode) != 0)
1935 p_warn(&fo,"can't restore file mode");
1936 }
1937 else if (fi.st.st_mode > 0)
1938 {
1939 fo.st.st_mode = fi.st.st_mode;
1940 if (chmod(fo.name, fo.st.st_mode) != 0)
1941 p_warn(&fo,"can't copy file mode");
1942 }
1943 #endif
1944 #if defined(HAVE_CHOWN)
1945 /* copy the ownership */
1946 if (!opt_stdin)
1947 if (chown(fo.name, fi.st.st_uid, fi.st.st_gid) != 0) {
1948 /* ignore */
1949 }
1950 #endif
1951 UNUSED(h);
1952 }
1953
1954
warn_multipart(file_t * ft,const header_t * h)1955 static lzo_bool warn_multipart(file_t *ft, const header_t *h)
1956 {
1957 if (!((ft->part > 0) || (h->flags & F_MULTIPART)))
1958 return 1;
1959
1960 if (opt_stdin && opt_stdout && opt_cmd == CMD_TEST && can_restore_name(ft,h))
1961 return 1;
1962 if (opt_stdout || opt_output_name)
1963 {
1964 if (!ft->warn_multipart)
1965 warn(&fi,"this is a multipart archive (try option '-N')");
1966 ft->warn_multipart = 1;
1967 }
1968 else if (opt_file && !can_restore_name(ft,h))
1969 {
1970 ft->opt_name = 1;
1971 if (opt_cmd == CMD_TEST)
1972 {
1973 if (!ft->warn_multipart)
1974 warn(&fi,"this is a multipart archive (try option '-N')");
1975 ft->warn_multipart = 1;
1976 }
1977 else if (can_restore_name(ft,h))
1978 {
1979 if (!ft->warn_multipart)
1980 warn(&fi,"multipart archive -- restoring file names");
1981 ft->warn_multipart = 1;
1982 }
1983 else
1984 {
1985 error(&fi,"multipart archive, but no filename stored (use option '-o')");
1986 return 0;
1987 }
1988 }
1989 return 1;
1990 }
1991
1992
do_decompress(const char * name,lzo_bool handle_perms)1993 static lzo_bool do_decompress(const char *name, lzo_bool handle_perms)
1994 {
1995 lzo_bool ok = 1;
1996 lzo_bool unlink_ok = 1;
1997 lzo_bool skip = 0;
1998 header_t header;
1999 int r;
2000
2001 if (!p_open_fi(name))
2002 return 0;
2003
2004 for ( ; ok; fi.part++)
2005 {
2006 r = p_magic(&fi);
2007 if (r > 0)
2008 return 0;
2009 if (fi.part == 0)
2010 total_c_files++;
2011 if (fi.part > 0 && (opt_file || (r < 0 && handle_perms)))
2012 {
2013 if (!p_close(0,1))
2014 return 0;
2015 if (!skip && handle_perms && (opt_file || (r < 0 && fi.part == 1)))
2016 restore_perms(&header);
2017 }
2018 if (r < 0)
2019 {
2020 assert(fi.part > 0);
2021 break;
2022 }
2023
2024 if (!p_header(&fi,&header))
2025 {
2026 /* use '--info -f -f' to try to list a corrupted header */
2027 if (opt_cmd == CMD_INFO && opt_force >= 2)
2028 {
2029 (void) x_get_method(&header);
2030 do_info(&header,0,0);
2031 }
2032 return 0;
2033 }
2034
2035 #if 0
2036 /* debug */
2037 do_info(&header,0,0);
2038 #endif
2039
2040 if (!warn_multipart(&fi,&header))
2041 return 0;
2042
2043 skip = 0;
2044 ok = p_open_fo(&header);
2045 if (!ok)
2046 {
2047 unlink_ok = 0;
2048 if (opt_output_name || opt_stdout)
2049 e_exit(EXIT_ERROR);
2050 if (opt_cmd != CMD_TEST)
2051 skip = 1;
2052 }
2053
2054 ok = x_decompress(&fi,&fo,&header,skip);
2055 }
2056
2057 return ok && unlink_ok;
2058 }
2059
2060
2061 /*************************************************************************
2062 // process files
2063 **************************************************************************/
2064
do_one_file(const char * name,lzo_bool handle_perms)2065 static lzo_bool do_one_file(const char *name, lzo_bool handle_perms)
2066 {
2067 lzo_bool ok;
2068
2069 if (opt_cmd == CMD_COMPRESS)
2070 ok = do_compress(name,handle_perms);
2071 else
2072 ok = do_decompress(name,handle_perms);
2073
2074 if (!p_close(1,0))
2075 ok = 0;
2076 if (opt_file && !p_close(0,1))
2077 ok = 0;
2078
2079 if (ok && opt_unlink)
2080 {
2081 #if defined(HAVE_CHMOD)
2082 (void) chmod(fi.name, 0777);
2083 #endif
2084 if (unlink(fi.name) != 0)
2085 p_warn(&fi,"can't unlink file");
2086 }
2087
2088 if (fi.fd == -1)
2089 fi.name[0] = 0;
2090 if (fo.fd == -1)
2091 fo.name[0] = 0;
2092
2093 return ok;
2094 }
2095
2096
do_files(int i,int argc,char * argv[])2097 static void do_files(int i, int argc, char *argv[])
2098 {
2099 lzo_bool handle_perms;
2100
2101 if (opt_cmd == CMD_COMPRESS)
2102 handle_perms = !opt_stdin;
2103 else if (opt_cmd == CMD_DECOMPRESS)
2104 handle_perms = 1;
2105 else
2106 handle_perms = 0;
2107
2108 if (opt_stdin)
2109 {
2110 assert(opt_stdout || opt_output_name || opt_output_path);
2111 assert(i == argc);
2112 assert(num_files == 0);
2113 if (!check_stdin(&fi) || !open_stdin(&fi))
2114 return;
2115 }
2116 if (opt_stdout)
2117 {
2118 assert(!opt_output_name);
2119 if (!check_stdout(&fo) || !open_stdout(&fo))
2120 return;
2121 handle_perms = 0;
2122 }
2123 if (opt_output_name)
2124 {
2125 assert(!opt_stdout);
2126 handle_perms &= (num_files == 1);
2127 }
2128
2129 if (opt_stdin)
2130 do_one_file(NULL,handle_perms);
2131 else
2132 {
2133 for ( ; i < argc; i++)
2134 do_one_file(argv[i],handle_perms);
2135 }
2136
2137 (void) p_close(1,1);
2138
2139 if (opt_cmd == CMD_LIST)
2140 do_list_total();
2141 if (opt_cmd == CMD_TEST)
2142 do_test_total();
2143 }
2144
2145
2146 /*************************************************************************
2147 // check options
2148 **************************************************************************/
2149
check_not_both(lzo_bool e1,lzo_bool e2,int c1,int c2)2150 static void check_not_both(lzo_bool e1, lzo_bool e2, int c1, int c2)
2151 {
2152 if (e1 && e2)
2153 {
2154 fprintf(stderr,"%s: ",argv0);
2155 fprintf(stderr,"cannot use both '-%c' and '-%c'\n", c1, c2);
2156 e_usage();
2157 }
2158 }
2159
2160
check_options(int i,int argc)2161 void check_options(int i, int argc)
2162 {
2163 assert(i <= argc);
2164
2165 if (opt_keep)
2166 opt_unlink = 0;
2167 if (!(opt_cmd == CMD_COMPRESS || opt_cmd == CMD_DECOMPRESS))
2168 opt_unlink = 0;
2169
2170 if (opt_stdin == OPT_STDIN_GUESSED && i != argc)
2171 opt_stdin = 0;
2172 if (opt_stdin)
2173 {
2174 opt_unlink = 0;
2175 #if 0
2176 /* gzip: always use stdout */
2177 opt_stdout = 1;
2178 #else
2179 if (!opt_output_name && !opt_output_path)
2180 opt_stdout = 1;
2181 #endif
2182 }
2183 if (opt_stdout)
2184 {
2185 check_not_both(1, opt_output_name != NULL, 'c', 'o');
2186 check_not_both(1, opt_output_path != NULL, 'c', 'p');
2187 check_not_both(1, opt_suffix[0] != 0, 'c', 'S');
2188 opt_output_name = NULL;
2189 opt_output_path = NULL;
2190 opt_suffix[0] = 0;
2191 if (opt_unlink && !opt_force)
2192 {
2193 fprintf(stderr,"%s: both '-c' and '-U' given (use '-f' to force)\n",argv0);
2194 e_usage();
2195 }
2196 }
2197 if (opt_output_name)
2198 {
2199 check_not_both(1, opt_output_path != NULL, 'o', 'p');
2200 check_not_both(1, opt_suffix[0] != 0, 'o', 'S');
2201 opt_output_path = NULL;
2202 opt_suffix[0] = 0;
2203 }
2204
2205 /* check number of remaining args */
2206 if (opt_stdin)
2207 {
2208 if (opt_cmd == CMD_COMPRESS && opt_output_path)
2209 {
2210 fprintf(stderr,"%s: cannot use '-p' when compressing stdin\n",argv0);
2211 e_usage();
2212 }
2213
2214 /* No more args allowed */
2215 if (i != argc)
2216 {
2217 fprintf(stderr,"%s: no filename allowed when reading from stdin\n",argv0);
2218 e_usage();
2219 }
2220 }
2221 else
2222 {
2223 if (i == argc)
2224 {
2225 fprintf(stderr,"%s: nothing to do !\n",argv0);
2226 e_usage();
2227 }
2228
2229 if (opt_stdout || opt_output_name)
2230 {
2231 #if 1
2232 /* Allow multiple files */
2233 if (i + 1 != argc)
2234 {
2235 opt_name = 1;
2236 }
2237 #else
2238 /* Exactly one input file */
2239 if (i + 1 != argc)
2240 {
2241 fprintf(stderr,"%s: only one file allowed\n",argv0);
2242 e_usage();
2243 }
2244 #endif
2245 }
2246 }
2247
2248 opt_file = !opt_stdout && !opt_output_name;
2249 }
2250
2251
2252 /*************************************************************************
2253 // misc
2254 **************************************************************************/
2255
e_help(void)2256 void e_help(void)
2257 {
2258 if (opt_pgm == PGM_LZOP)
2259 help();
2260 else if (opt_pgm == PGM_UNLZOP)
2261 help();
2262 else if (opt_pgm == PGM_OCAT)
2263 {
2264 if (opt_stdin)
2265 check_stdin(&fi);
2266 if (opt_stdout)
2267 check_stdout(&fo);
2268 usage();
2269 }
2270 else
2271 help();
2272 e_exit(EXIT_USAGE);
2273 }
2274
2275
set_term(FILE * f)2276 void set_term(FILE *f)
2277 {
2278 if (f)
2279 con_term = f;
2280 else
2281 con_term = acc_isatty(STDOUT_FILENO) ? stdout : stderr;
2282 }
2283
2284
set_cmd(int cmd)2285 void set_cmd(int cmd)
2286 {
2287 if (cmd == CMD_COMPRESS && (opt_pgm == PGM_UNLZOP || opt_pgm == PGM_OCAT))
2288 return;
2289 #if 0
2290 if (opt_cmd != CMD_NONE && cmd != opt_cmd)
2291 {
2292 fprintf(stderr,"%s: multiple commands given\n",argv0);
2293 e_usage();
2294 }
2295 opt_cmd = cmd;
2296 #else
2297 /* gzip: commands have a certain priority */
2298 if (cmd > opt_cmd)
2299 opt_cmd = cmd;
2300 #endif
2301 }
2302
2303
set_method(int m,int l)2304 lzo_bool set_method(int m, int l)
2305 {
2306 if (x_set_method(m,l) != 0)
2307 return 0;
2308 set_cmd(CMD_COMPRESS);
2309 return 1;
2310 }
2311
2312
set_output_name(const char * n,lzo_bool allow_m)2313 void set_output_name(const char *n, lzo_bool allow_m)
2314 {
2315 #if 1
2316 if (done_output_name > 0)
2317 {
2318 fprintf(stderr,"%s: option '-o' more than once given\n",argv0);
2319 e_usage();
2320 }
2321 #endif
2322 if (!n || !n[0] || (!allow_m && n[0] == '-'))
2323 {
2324 fprintf(stderr,"%s: missing output name\n",argv0);
2325 e_usage();
2326 }
2327 if (strlen(n) >= PATH_MAX)
2328 {
2329 fprintf(stderr,"%s: output name too long\n",argv0);
2330 e_usage();
2331 }
2332 opt_output_name = n;
2333 done_output_name++;
2334 }
2335
2336
set_output_path(const char * n,lzo_bool allow_m)2337 void set_output_path(const char *n, lzo_bool allow_m)
2338 {
2339 int r;
2340 struct stat st;
2341 file_t f;
2342
2343 #if 1
2344 if (done_output_path > 0)
2345 {
2346 fprintf(stderr,"%s: option '-p' more than once given\n",argv0);
2347 e_usage();
2348 }
2349 #endif
2350 if (!n || (!allow_m && n[0] == '-'))
2351 {
2352 fprintf(stderr,"%s: missing path\n",argv0);
2353 e_usage();
2354 }
2355 if (strlen(n) >= PATH_MAX)
2356 {
2357 fprintf(stderr,"%s: path too long\n",argv0);
2358 e_usage();
2359 }
2360 if (n[0])
2361 {
2362 r = stat(n, &st);
2363 if (r != 0)
2364 {
2365 strcpy(f.name,n);
2366 p_fatal(&f,"invalid path");
2367 }
2368 #if defined(S_ISDIR)
2369 if (!S_ISDIR(st.st_mode))
2370 {
2371 strcpy(f.name,n);
2372 fatal(&f,"invalid path - must be a directory");
2373 }
2374 #endif
2375 }
2376 #if defined(HAVE_ACCESS) && defined(W_OK)
2377 {
2378 const char *p = n[0] ? n : ".";
2379 if (access(p,W_OK) != 0)
2380 {
2381 strcpy(f.name,p);
2382 p_fatal(&f,"can't write to path");
2383 }
2384 }
2385 #endif
2386 opt_output_path = n;
2387 done_output_path++;
2388 }
2389
2390
set_suffix(const char * n)2391 lzo_bool set_suffix(const char *n)
2392 {
2393 size_t l;
2394 const char *p;
2395 static const char * const invalid_suffixes[] =
2396 { "ace", "arc", "arj", "bz", "bz2", "gz", "lha", "lzh",
2397 #if !defined(NRVP)
2398 "nrv", "tnv",
2399 #endif
2400 "rar", "raw", "sz", "tar", "taz", "tbz", "tgz", "tsz",
2401 "upx", "Z", "zip", "zoo", NULL };
2402 const char * const *is = invalid_suffixes;
2403
2404 #if 1
2405 if (done_suffix > 0)
2406 {
2407 fprintf(stderr,"%s: option '-S' more than once given\n",argv0);
2408 e_usage();
2409 return 0;
2410 }
2411 #endif
2412 while (n && *n == '.')
2413 n++;
2414
2415 if (!n || *n == 0 || *n == '-')
2416 return 0;
2417 #if 1 || defined(DOSISH)
2418 if (strchr(n,'.'))
2419 return 0;
2420 #endif
2421 for (p = n; *p; p++)
2422 if (strchr("+*?=/\\ \t\n\r\a", *p))
2423 return 0;
2424 for ( ; *is; is++)
2425 if (strcasecmp(n,*is) == 0)
2426 return 0;
2427
2428 l = strlen(n);
2429 if (l + 1 > SUFFIX_MAX || (opt_shortname && l > 3))
2430 {
2431 fprintf(stderr,"%s: suffix '%s' is too long\n",argv0,n);
2432 e_usage();
2433 return 0;
2434 }
2435
2436 opt_suffix[0] = '.';
2437 strcpy(opt_suffix + 1, n);
2438 done_suffix++;
2439 return 1;
2440 }
2441
2442
2443 /*************************************************************************
2444 // get options
2445 **************************************************************************/
2446
2447 static
prepare_shortopts(char * buf,const char * n,const struct acc_getopt_longopt_t * longopts)2448 char* prepare_shortopts(char *buf, const char *n,
2449 const struct acc_getopt_longopt_t *longopts)
2450 {
2451 char *o = buf;
2452
2453 for ( ; n && *n; n++)
2454 if (*n != ' ')
2455 *o++ = *n;
2456 *o = 0;
2457 for ( ; longopts && longopts->name; longopts++)
2458 {
2459 int v = longopts->val;
2460 if (v > 0 && v < 256 && strchr(buf,v) == NULL)
2461 {
2462 *o++ = (char) v;
2463 if (longopts->has_arg >= 1)
2464 *o++ = ':';
2465 if (longopts->has_arg >= 2)
2466 *o++ = ':';
2467 *o = 0;
2468 }
2469 }
2470 return buf;
2471 }
2472
2473
do_option(acc_getopt_p g,int optc)2474 static int do_option(acc_getopt_p g, int optc)
2475 {
2476 #define mfx_optarg g->optarg
2477 int i = 0;
2478 int m = -1;
2479
2480 switch (optc)
2481 {
2482 case 'c':
2483 opt_stdout = 1;
2484 break;
2485 case 'C':
2486 opt_checksum = (opt_checksum >= 1) ? opt_checksum + 1 : 1;
2487 opt_decompress_safe = 1;
2488 break;
2489 case 'd':
2490 set_cmd(CMD_DECOMPRESS);
2491 break;
2492 case 'f':
2493 opt_force++;
2494 break;
2495 case 'F':
2496 opt_checksum = 0;
2497 opt_decompress_safe = 0;
2498 break;
2499 case 'h':
2500 case 'H':
2501 case '?':
2502 set_cmd(CMD_HELP);
2503 break;
2504 case 'h'+256:
2505 /* according to GNU standards */
2506 set_term(stdout);
2507 opt_console = CON_NONE;
2508 help();
2509 e_exit(EXIT_OK);
2510 break;
2511 case 'i':
2512 case 'i'+256:
2513 set_cmd(CMD_INFO);
2514 break;
2515 case 'I':
2516 set_cmd(CMD_SYSINFO);
2517 break;
2518 case 'k':
2519 opt_keep = 1;
2520 break;
2521 case 'l':
2522 set_cmd(CMD_LIST);
2523 break;
2524 case 'L':
2525 set_cmd(CMD_LICENSE);
2526 break;
2527 case 'n':
2528 opt_name = 0;
2529 opt_path = 0;
2530 break;
2531 case 'N':
2532 opt_name = 1;
2533 break;
2534 case 'o':
2535 set_output_name(mfx_optarg,1);
2536 break;
2537 case 'p':
2538 case 'p'+256:
2539 if (mfx_optarg && mfx_optarg[0])
2540 set_output_path(mfx_optarg,0);
2541 else if (optc == 'p')
2542 set_output_path("",0);
2543 else
2544 set_output_path(NULL,0);
2545 break;
2546 case 'P':
2547 opt_path = 1;
2548 opt_name = 1;
2549 break;
2550 case 'q':
2551 opt_verbose = 0;
2552 break;
2553 case 'S':
2554 if (!set_suffix(mfx_optarg))
2555 {
2556 fprintf(stderr,"%s: invalid suffix '%s'\n",argv0,mfx_optarg);
2557 e_usage();
2558 }
2559 break;
2560 case 't':
2561 set_cmd(CMD_TEST);
2562 break;
2563 case 'T':
2564 if (!(mfx_optarg && isdigit(mfx_optarg[0])))
2565 {
2566 fprintf(stderr,"%s: invalid '--threads=' args: '%s'\n",argv0,mfx_optarg);
2567 e_usage();
2568 }
2569 opt_num_threads = atoi(mfx_optarg);
2570 if (opt_num_threads < 1 || opt_num_threads > MAX_NUM_THREADS)
2571 {
2572 fprintf(stderr,"%s: invalid number of threads: %d\n",argv0,opt_num_threads);
2573 e_usage();
2574 }
2575 #if !defined(WITH_THREADS)
2576 opt_num_threads = 1;
2577 #endif
2578 break;
2579 case 'U':
2580 opt_unlink = 1;
2581 break;
2582 case 'v':
2583 opt_verbose = (opt_verbose < 2) ? 2 : opt_verbose + 1;
2584 break;
2585 case 'V':
2586 set_cmd(CMD_VERSION);
2587 break;
2588 case 'V'+256:
2589 /* according to GNU standards */
2590 set_term(stdout);
2591 opt_console = CON_NONE;
2592 fprintf(stdout,"lzop %s\n",LZOP_VERSION_STRING);
2593 fprintf(stdout,"LZO library %s\n",lzo_version_string());
2594 fprintf(stdout,"Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer\n");
2595 e_exit(EXIT_OK);
2596 break;
2597 case 'x':
2598 set_cmd(CMD_DECOMPRESS);
2599 opt_name = 1;
2600 opt_path = 1;
2601 opt_restore_mode = 1;
2602 opt_restore_time = 1;
2603 if (!opt_output_name && !opt_output_path)
2604 {
2605 set_output_path("",0);
2606 --done_output_path;
2607 }
2608 opt_unlink = 0;
2609 break;
2610 case 'Z'+256:
2611 set_cmd(CMD_LS);
2612 if (mfx_optarg && mfx_optarg[0])
2613 {
2614 opt_ls_flags = mfx_optarg;
2615 for (i = 0; opt_ls_flags[i]; i++)
2616 if (!strchr("FGQ",opt_ls_flags[i]))
2617 {
2618 fprintf(stderr,"%s: invalid '--ls' flags: '%s'\n",argv0,mfx_optarg);
2619 e_usage();
2620 }
2621 }
2622 break;
2623 #ifdef MAINT
2624 case 520:
2625 opt_noheader++;
2626 break;
2627 #endif
2628 case 522:
2629 opt_stdin = 0;
2630 break;
2631 case 523:
2632 opt_restore_mode = 0;
2633 break;
2634 case 524:
2635 opt_restore_time = 0;
2636 break;
2637 case 525:
2638 opt_nowarn = 1;
2639 break;
2640 case 526:
2641 opt_ignorewarn = 1;
2642 break;
2643 case 527:
2644 opt_crc32 = 1;
2645 break;
2646
2647 case 512:
2648 opt_console = CON_NONE;
2649 break;
2650 case 513:
2651 opt_console = CON_ANSI_MONO;
2652 break;
2653 case 514:
2654 opt_console = CON_ANSI_COLOR;
2655 break;
2656 case 515:
2657 set_cmd(CMD_INTRO);
2658 break;
2659
2660
2661 case '1':
2662 case '2':
2663 case '3':
2664 case '4':
2665 case '5':
2666 case '6':
2667 case '7':
2668 case '8':
2669 case '9':
2670 if (!set_method(0,optc - '0'))
2671 e_method(optc);
2672 break;
2673
2674 #if defined(WITH_NRV)
2675 case 811:
2676 if (m < 0) m = M_NRV1A;
2677 /* fallthrough */
2678 case 812:
2679 if (m < 0) m = M_NRV1B;
2680 /* fallthrough */
2681 case 813:
2682 if (m < 0) m = M_NRV2A;
2683 /* fallthrough */
2684 case 814:
2685 if (m < 0) m = M_NRV2B;
2686 i = 1;
2687 if (mfx_optarg && isdigit(mfx_optarg[0]) && !mfx_optarg[1])
2688 i = mfx_optarg[0] - '0';
2689 if (!set_method(m,i))
2690 e_usage();
2691 break;
2692 #endif
2693 #if defined(WITH_ZLIB)
2694 case 801:
2695 i = 6;
2696 if (mfx_optarg && mfx_optarg[0] && !mfx_optarg[1])
2697 i = mfx_optarg[0] - '0';
2698 if (!set_method(M_ZLIB,i))
2699 e_usage();
2700 break;
2701 #endif
2702
2703 case 521:
2704 if (!(mfx_optarg && isdigit(mfx_optarg[0])))
2705 {
2706 fprintf(stderr,"%s: invalid '--filter=' args: '%s'\n",argv0,mfx_optarg);
2707 e_usage();
2708 }
2709 if (strcmp(mfx_optarg,"0") == 0)
2710 {
2711 opt_filter = 0;
2712 break;
2713 }
2714 opt_filter = atoi(mfx_optarg);
2715 if (opt_filter < 1 || opt_filter > 16)
2716 {
2717 fprintf(stderr,"%s: invalid filter: %d\n",argv0,opt_filter);
2718 e_usage();
2719 }
2720 break;
2721
2722 case '\0':
2723 return -1;
2724 case ':':
2725 return -2;
2726 default:
2727 fprintf(stderr,"%s: internal error in getopt (%d)\n",argv0,optc);
2728 return -3;
2729 }
2730
2731 UNUSED(i);
2732 UNUSED(m);
2733 return 0;
2734 #undef mfx_optarg
2735 }
2736
2737
handle_opterr(acc_getopt_p g,const char * f,void * v)2738 static void handle_opterr(acc_getopt_p g, const char *f, void *v)
2739 {
2740 struct A { va_list ap; };
2741 struct A *a = (struct A *) v;
2742 fprintf( stderr, "%s: ", g->progname);
2743 if (a)
2744 vfprintf(stderr, f, a->ap);
2745 else
2746 fprintf( stderr, "UNKNOWN GETOPT ERROR");
2747 fprintf( stderr, "\n");
2748 }
2749
2750
get_options(int argc,char ** argv)2751 static int get_options(int argc, char **argv)
2752 {
2753
2754 static const struct acc_getopt_longopt_t longopts[] =
2755 {
2756 {"best", 0, 0, '9'}, /* compress better */
2757 {"decompress", 0, 0, 'd'}, /* decompress */
2758 {"fast", 0, 0, '1'}, /* compress faster */
2759 {"help", 0, 0, 'h'+256}, /* give help */
2760 {"info", 0, 0, 'i'+256},
2761 {"license", 0, 0, 'L'}, /* display software license */
2762 {"list", 0, 0, 'l'}, /* list .lzo file contents */
2763 {"ls", 2, 0, 'Z'+256}, /* list .lzo file contents */
2764 {"sysinfo", 0, 0, 'I'},
2765 {"test", 0, 0, 't'}, /* test compressed file integrity */
2766 {"uncompress", 0, 0, 'd'}, /* decompress */
2767 {"version", 0, 0, 'V'+256}, /* display version number */
2768 #if defined(WITH_NRV)
2769 {"nrv1a", 0x22, 0, 811},
2770 {"nrv2a", 0x22, 0, 813},
2771 {"nrv2b", 0x22, 0, 814},
2772 #endif
2773 #if defined(WITH_ZLIB)
2774 {"zlib", 0x22, 0, 801},
2775 #endif
2776
2777 {"checksum", 0, 0, 'C'},
2778 {"crc32", 0x10, 0, 527}, /* use a crc32 checksum instead of adler32 */
2779 {"delete", 0, 0, 'U'},
2780 {"extract", 0, 0, 'x'},
2781 {"filter", 1, 0, 521},
2782 {"force", 0, 0, 'f'}, /* force overwrite of output file */
2783 {"ignore-warn",0, 0, 526}, /* ignore any warnings */
2784 {"keep", 0, 0, 'k'},
2785 {"name", 0, 0, 'N'}, /* restore original name */
2786 {"no-checksum",0, 0, 'F'},
2787 #ifdef MAINT
2788 {"no-header", 0, 0, 520},
2789 #endif
2790 {"no-mode", 0, 0, 523}, /* don't restore original mode */
2791 {"no-name", 0, 0, 'n'}, /* don't restore original name */
2792 {"no-stdin", 0, 0, 522},
2793 {"no-time", 0, 0, 524}, /* don't restore original time */
2794 {"no-warn", 0, 0, 525}, /* do not display any warnings */
2795 {"output", 1, 0, 'o'},
2796 {"path", 1, 0, 'p'+256},
2797 {"quiet", 0, 0, 'q'}, /* quiet mode */
2798 {"silent", 0, 0, 'q'}, /* quiet mode */
2799 {"stdout", 0, 0, 'c'}, /* write output on standard output */
2800 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .lzo */
2801 {"threads", 0x21, 0, 'T'}, /* number of threads */
2802 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
2803 {"unlink", 0, 0, 'U'},
2804 {"verbose", 0, 0, 'v'}, /* verbose mode */
2805
2806 {"no-color", 0, 0, 512},
2807 {"mono", 0, 0, 513},
2808 {"color", 0, 0, 514},
2809 {"intro", 0, 0, 515},
2810
2811 { 0, 0, 0, 0 }
2812 };
2813
2814 acc_getopt_t mfx_getopt;
2815 int optc;
2816 int i;
2817 char shortopts[128];
2818
2819 prepare_shortopts(shortopts, "123456789hH?PVp::", longopts),
2820 acc_getopt_init(&mfx_getopt, 1, argc, argv);
2821 mfx_getopt.progname = argv0;
2822 mfx_getopt.opterr = handle_opterr;
2823 while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, NULL)) >= 0)
2824 {
2825 if (do_option(&mfx_getopt, optc) != 0)
2826 e_usage();
2827 }
2828
2829 /* accept "-" as synonym for stdin */
2830 for (i = mfx_getopt.optind; i < argc; i++)
2831 if (strcmp(argv[i], "-") == 0)
2832 opt_stdin = OPT_STDIN_REQUESTED;
2833 for (i = mfx_getopt.optind; i < argc; i++)
2834 if (strcmp(argv[i], "-") != 0)
2835 break;
2836 return i;
2837 }
2838
2839
2840 #if defined(OPTIONS_VAR)
get_envoptions(int argc,char ** argv)2841 static void get_envoptions(int argc, char **argv)
2842 {
2843
2844 /* only some options are allowed in the environment variable */
2845
2846 static const struct acc_getopt_longopt_t longopts[] =
2847 {
2848 {"best", 0, 0, '9'}, /* compress better */
2849 {"checksum", 0, 0, 'C'},
2850 {"crc32", 0x10, 0, 527}, /* use a crc32 checksum instead of adler32 */
2851 {"delete", 0, 0, 'U'},
2852 {"fast", 0, 0, '1'}, /* compress faster */
2853 {"ignore-warn",0, 0, 526}, /* ignore any warnings */
2854 {"keep", 0, 0, 'k'},
2855 {"name", 0, 0, 'N'}, /* restore original name */
2856 {"no-checksum",0, 0, 'F'},
2857 {"no-mode", 0, 0, 523}, /* don't restore original mode */
2858 {"no-name", 0, 0, 'n'}, /* don't restore original name */
2859 {"no-time", 0, 0, 524}, /* don't restore original time */
2860 {"no-stdin", 0, 0, 522},
2861 {"no-warn", 0, 0, 525}, /* do not display any warnings */
2862 {"quiet", 0, 0, 'q'}, /* quiet mode */
2863 {"silent", 0, 0, 'q'}, /* quiet mode */
2864 {"threads", 0x21, 0, 'T'}, /* number of threads */
2865 {"unlink", 0, 0, 'U'},
2866 {"verbose", 0, 0, 'v'}, /* verbose mode */
2867
2868 {"no-color", 0, 0, 512},
2869 {"mono", 0, 0, 513},
2870 {"color", 0, 0, 514},
2871
2872 { 0, 0, 0, 0 }
2873 };
2874
2875 char *env, *p;
2876 int i, optc;
2877 int nargc;
2878 char **nargv = NULL;
2879 static const char sep[] = " \t";
2880 acc_getopt_t mfx_getopt;
2881 char shortopts[128];
2882
2883 env = (char *) getenv(OPTIONS_VAR);
2884 if (env == NULL || !env[0])
2885 return;
2886 p = (char *) malloc(strlen(env)+1);
2887 if (p == NULL)
2888 return;
2889 strcpy(p,env);
2890 env = p;
2891
2892 nargc = 1;
2893 for (;;)
2894 {
2895 while (*p && strchr(sep,*p))
2896 p++;
2897 if (*p == '\0')
2898 break;
2899 nargc++;
2900 while (*p && !strchr(sep,*p))
2901 p++;
2902 if (*p == '\0')
2903 break;
2904 p++;
2905 }
2906
2907 if (nargc > 1)
2908 nargv = (char **) calloc(nargc+1,sizeof(char *));
2909 if (nargv == NULL)
2910 {
2911 free(env);
2912 return;
2913 }
2914
2915 nargv[0] = argv[0];
2916 p = env;
2917 nargc = 1;
2918 for (;;)
2919 {
2920 while (*p && strchr(sep,*p))
2921 p++;
2922 if (*p == '\0')
2923 break;
2924 nargv[nargc++] = p;
2925 while (*p && !strchr(sep,*p))
2926 p++;
2927 if (*p == '\0')
2928 break;
2929 *p++ = '\0';
2930 }
2931 nargv[nargc] = NULL;
2932
2933 #if 0
2934 /* debug */
2935 fprintf(stderr,"%3d\n",nargc);
2936 for (i = 0; i <= nargc; i++)
2937 fprintf(stderr,"%3d '%s'\n",i,nargv[i]);
2938 #endif
2939
2940 for (i = 1; i < nargc; i++)
2941 if (nargv[i][0] != '-' || !nargv[i][1] || strcmp(nargv[i],"--") == 0)
2942 e_envopt(nargv[i]);
2943
2944 prepare_shortopts(shortopts, "123456789P", longopts);
2945 acc_getopt_init(&mfx_getopt, 1, nargc, nargv);
2946 mfx_getopt.progname = argv0;
2947 mfx_getopt.opterr = handle_opterr;
2948 while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, NULL)) >= 0)
2949 {
2950 if (do_option(&mfx_getopt, optc) != 0)
2951 e_envopt(NULL);
2952 }
2953
2954 if (mfx_getopt.optind < nargc)
2955 e_envopt(nargv[mfx_getopt.optind]);
2956
2957 free(nargv);
2958 free(env);
2959 UNUSED(argc);
2960
2961 if (opt_checksum)
2962 opt_checksum = -1; /* reset to default */
2963 }
2964 #endif /* defined(OPTIONS_VAR) */
2965
2966
2967 #define ACC_WANT_ACC_CHK_CH 1
2968 #undef ACCCHK_ASSERT
2969 #include "miniacc.h"
2970 #undef ACCCHK_ASSERT
2971
sanity_check(void)2972 static void sanity_check(void)
2973 {
2974 #if (ACC_CC_MSC && ((_MSC_VER) < 700))
2975 #else
2976 #define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT(expr)
2977 #include "miniacc.h"
2978 #endif
2979 #undef ACCCHK_ASSERT
2980 #undef ACC_WANT_ACC_CHK_CH
2981 }
2982
2983
2984 /*************************************************************************
2985 // main entry point
2986 **************************************************************************/
2987
main(int argc,char * argv[])2988 int __acc_cdecl_main main(int argc, char *argv[])
2989 {
2990 int i;
2991 lzo_bool foreground = 0;
2992 static char default_argv0[] = "lzop";
2993 int cmdline_cmd = CMD_NONE;
2994
2995 #if (ACC_OS_WIN32 || ACC_OS_WIN64) && (ACC_CC_MSC) && defined(_WRITE_ABORT_MSG) && defined(_CALL_REPORTFAULT)
2996 _set_abort_behavior(_WRITE_ABORT_MSG, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
2997 #endif
2998 acc_wildargv(&argc, &argv);
2999
3000 sanity_check();
3001
3002 #if defined(__DJGPP__)
3003 opt_shortname = !_USE_LFN;
3004 #elif (ACC_OS_DOS16 || ACC_OS_WIN16 || ACC_OS_DOS32)
3005 opt_shortname = 1;
3006 #endif
3007
3008 current_time = fix_time(time(NULL));
3009
3010 if (!argv[0] || !argv[0][0])
3011 argv[0] = default_argv0;
3012 argv0 = argv[0];
3013 progname = fn_basename(argv0);
3014 #if defined(DOSISH)
3015 if (strcasecmp(progname,"lzop.exe") == 0)
3016 progname = default_argv0;
3017 else if (strcasecmp(progname,"lzop.ttp") == 0)
3018 progname = default_argv0;
3019 #endif
3020
3021 /* For compatibility with gzip, use program name as an option. */
3022 if (strncasecmp(progname, "un", 2) == 0) /* unlzop */
3023 opt_pgm = PGM_UNLZOP;
3024 #if 0
3025 if (progname[0] && strcasecmp(progname+1, "cat") == 0) /* ocat */
3026 opt_pgm = PGM_OCAT;
3027 #endif
3028
3029 set_term(stderr);
3030 opt_stdin = acc_isatty(STDIN_FILENO) ? 0 : OPT_STDIN_GUESSED;
3031
3032 UNUSED(foreground);
3033 #ifdef SIGINT
3034 foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
3035 if (foreground)
3036 (void) signal(SIGINT, e_sighandler);
3037 #endif
3038 #ifdef SIGBREAK
3039 if (foreground)
3040 (void) signal(SIGBREAK, e_sighandler);
3041 #endif
3042 #ifdef SIGTERM
3043 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
3044 (void) signal(SIGTERM, e_sighandler);
3045 #endif
3046 #ifdef SIGHUP
3047 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
3048 (void) signal(SIGHUP, e_sighandler);
3049 #endif
3050
3051 #if defined(HAVE_UMASK)
3052 u_mask = (MODE_T) umask(0700);
3053 (void) umask(u_mask);
3054 #endif
3055 u_mask &= 0777;
3056
3057 #if defined(WITH_LZO)
3058 if (lzo_init() != LZO_E_OK)
3059 {
3060 head();
3061 fprintf(stderr,"lzo_init() failed - check your LZO installation !\n");
3062 if (LZO_VERSION != lzo_version())
3063 fprintf(stderr,"library version conflict (%x, %x) - check your LZO installation !\n", LZO_VERSION, lzo_version());
3064 e_exit(EXIT_LZO_INIT);
3065 }
3066 #if 0
3067 if (lzo_version() < LZO_VERSION)
3068 {
3069 head();
3070 fprintf(stderr,"library version conflict (%x, %x) - check your LZO installation !\n", LZO_VERSION, lzo_version());
3071 e_exit(EXIT_LZO_INIT);
3072 }
3073 #endif
3074 #endif
3075 #if defined(WITH_NRV)
3076 if (nrv_init() != NRV_E_OK)
3077 {
3078 e_exit(EXIT_LZO_INIT);
3079 }
3080 #endif
3081
3082 ACC_COMPILE_TIME_ASSERT(sizeof(lzo_uint32) >= 4)
3083 #if defined(SIZEOF_SIZE_T)
3084 ACC_COMPILE_TIME_ASSERT(sizeof(size_t) == SIZEOF_SIZE_T)
3085 #endif
3086 ACC_COMPILE_TIME_ASSERT(sizeof(fi.name) >= 2*(PATH_MAX))
3087 assert(STDIN_FILENO >= 0);
3088 assert(STDOUT_FILENO >= 0);
3089 assert(STDERR_FILENO >= 0);
3090
3091 f_init();
3092 #if defined(OPTIONS_VAR)
3093 get_envoptions(argc,argv);
3094 #endif
3095 assert(cmdline_cmd == CMD_NONE);
3096 i = get_options(argc,argv);
3097 assert(i <= argc);
3098
3099 set_term(NULL);
3100 cmdline_cmd = opt_cmd;
3101 switch (opt_cmd)
3102 {
3103 case CMD_NONE:
3104 /* For compatibility with gzip, use program name as an option. */
3105 if (opt_pgm == PGM_UNLZOP)
3106 {
3107 set_cmd(CMD_DECOMPRESS);
3108 break;
3109 }
3110 #if 0
3111 if (opt_pgm == PGM_OCAT)
3112 {
3113 set_cmd(CMD_DECOMPRESS);
3114 if (i == argc)
3115 opt_stdin = OPT_STDIN_REQUESTED;
3116 if (!opt_output_name)
3117 opt_stdout = 1;
3118 break;
3119 }
3120 #endif
3121 /* default - compress */
3122 if (!set_method(0,3))
3123 e_method('3');
3124 break;
3125 case CMD_COMPRESS:
3126 break;
3127 case CMD_DECOMPRESS:
3128 break;
3129 case CMD_TEST:
3130 opt_checksum = 1;
3131 opt_decompress_safe = 1;
3132 break;
3133 case CMD_LIST:
3134 break;
3135 case CMD_LS:
3136 break;
3137 case CMD_INFO:
3138 break;
3139 case CMD_SYSINFO:
3140 sysinfo();
3141 e_exit(EXIT_OK);
3142 break;
3143 case CMD_LICENSE:
3144 license();
3145 e_exit(EXIT_OK);
3146 break;
3147 case CMD_HELP:
3148 help();
3149 e_exit(EXIT_OK);
3150 break;
3151 case CMD_INTRO:
3152 opt_console = CON_SCREEN;
3153 (void) ((con_intro(con_term) || (help(), 0)));
3154 e_exit(EXIT_OK);
3155 break;
3156 case CMD_VERSION:
3157 version();
3158 e_exit(EXIT_OK);
3159 break;
3160 default:
3161 /* ??? */
3162 break;
3163 }
3164
3165 if (opt_cmd != CMD_COMPRESS)
3166 {
3167 opt_method = 0;
3168 opt_level = 0;
3169 opt_filter = 0;
3170 }
3171
3172 if (!opt_stdin && !opt_stdout && opt_verbose > 0)
3173 {
3174 if (argc == 1)
3175 {
3176 /* no arguments */
3177 (void) (opt_pgm == PGM_LZOP && con_intro(con_term));
3178 e_help();
3179 }
3180 #if 0
3181 else if (cmdline_cmd == CMD_NONE && i == argc)
3182 {
3183 /* no command and no file */
3184 e_help();
3185 }
3186 #endif
3187 }
3188
3189 set_term(stderr);
3190 check_options(i,argc);
3191 num_files = argc - i;
3192
3193 if (!x_enter(NULL))
3194 e_memory();
3195
3196 do_files(i,argc,argv);
3197
3198 x_leave(NULL);
3199 do_exit();
3200 return exit_code;
3201 }
3202
3203
3204 /* vim:set ts=4 sw=4 et: */
3205