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