/* lzop.c -- This file is part of the lzop file compressor. Copyright (C) 1996-2010 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. lzop and the LZO library are free software; you can redistribute them and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Markus F.X.J. Oberhumer <markus@oberhumer.com> http://www.oberhumer.com/opensource/lzop/ */ #include "conf.h" #include "version.h" /************************************************************************* // options **************************************************************************/ int opt_cmd = CMD_NONE; int opt_method = 0; int opt_level = 0; int opt_filter = 0; int opt_checksum = -1; int opt_console = CON_INIT; lzo_bool opt_crc32 = 0; lzo_bool opt_decompress_safe = 1; lzo_bool opt_file = 0; int opt_force = 0; lzo_bool opt_ignorewarn = 0; lzo_bool opt_keep = 0; int opt_num_threads = 1; /* NOT YET IMPLEMENTED */ #ifdef MAINT int opt_noheader = 0; #endif lzo_bool opt_nowarn = 0; const char *opt_ls_flags = ""; int opt_name = -1; const char *opt_output_name = NULL; const char *opt_output_path = NULL; lzo_bool opt_optimize = 0; lzo_bool opt_path = 0; lzo_bool opt_restore_mode = 1; lzo_bool opt_restore_time = 1; lzo_bool opt_shortname = 0; int opt_stdin = 0; lzo_bool opt_stdout = 0; char opt_suffix[1+SUFFIX_MAX+1] = { 0 }; lzo_bool opt_unlink = 0; int opt_verbose = 1; static int done_output_name = 0; static int done_output_path = 0; static int done_suffix = 0; /* invocation options */ enum { PGM_LZOP, PGM_UNLZOP, PGM_OCAT }; int opt_pgm = PGM_LZOP; const char *argv0 = ""; const char *progname = ""; MODE_T u_mask = 0700; time_t current_time; FILE *con_term = NULL; static int num_files = -1; static int exit_code = EXIT_OK; static file_t fi; static file_t fo; static unsigned long total_d_files = 0; static unsigned long total_c_files = 0; static lzop_ulong_t total_d_len = 0; static lzop_ulong_t total_c_len = 0; /* some statistics */ static lzop_ulong_t total_bytes_written = 0; static lzop_ulong_t total_bytes_read = 0; /************************************************************************* // exit handlers **************************************************************************/ static void do_exit(void) { static lzo_bool in_exit = 0; if (in_exit) exit(exit_code); in_exit = 1; fflush(con_term); fflush(stderr); exit(exit_code); } #define EXIT_FATAL 3 static lzo_bool set_eec(int ec, int *eec) { if (ec == EXIT_FATAL) { *eec = EXIT_ERROR; return 1; } else if (ec < 0 || ec == EXIT_ERROR) { *eec = EXIT_ERROR; } else if (ec == EXIT_WARN) { if (!opt_ignorewarn) if (*eec == EXIT_OK) *eec = ec; } else if (ec == EXIT_OK) { /* do nothing */ } else { assert(0); } return 0; } static lzo_bool set_ec(int ec) { return set_eec(ec,&exit_code); } void e_exit(int ec) { (void) set_ec(ec); do_exit(); } void e_usage(void) { usage(); e_exit(EXIT_USAGE); } void e_memory(void) { head(); fflush(con_term); fprintf(stderr,"%s: out of memory\n", argv0); e_exit(EXIT_MEMORY); } void e_method(int m) { fflush(con_term); #if (UINT_MAX < LZO_0xffffffffL) /* 16-bit DOS/Windows */ fprintf(stderr,"%s: 16-bit versions are not officially supported\n", argv0); #endif fprintf(stderr,"%s: illegal method option -- %c\n", argv0, m & 255); e_usage(); } #if defined(OPTIONS_VAR) void e_envopt(const char *n) { fflush(con_term); if (n) fprintf(stderr,"%s: invalid string '%s' in environment variable '%s'\n", argv0, n, OPTIONS_VAR); else fprintf(stderr,"%s: illegal option in environment variable '%s'\n", argv0, OPTIONS_VAR); e_exit(EXIT_USAGE); } #endif RETSIGTYPE __acc_cdecl_sighandler e_sighandler(acc_signo_t signo) { UNUSED(signo); e_exit(EXIT_FATAL); } /************************************************************************* // error handlers **************************************************************************/ static void do_error(file_t *ft, const char *n, const char *msg, int ec, int err) { const char *fn; const char *errmsg; fflush(con_term); if (!(ec == EXIT_WARN && (opt_nowarn || opt_ignorewarn || opt_verbose == 0))) { fn = ft && ft->name[0] ? ft->name : UNKNOWN_NAME; fprintf(stderr, "%s%s: %s: ", n, progname, fn); if (ec == EXIT_WARN) fprintf(stderr, "warning: "); if (err != 0) { errmsg = strerror(err); if (msg && msg[0]) fprintf(stderr, "%s: %s\n", msg, errmsg); else fprintf(stderr, "%s\n", errmsg); } else fprintf(stderr, "%s\n", msg); fflush(stderr); } if (set_ec(ec)) do_exit(); } static const char *err_nl = ""; void set_err_nl(lzo_bool x) { err_nl = x ? "\n" : ""; } void fatal(file_t *ft, const char *msg) { do_error(ft,err_nl,msg,EXIT_FATAL,0); } void error(file_t *ft, const char *msg) { do_error(ft,err_nl,msg,EXIT_ERROR,0); } void warn(file_t *ft, const char *msg) { do_error(ft,err_nl,msg,EXIT_WARN,0); } void info(file_t *ft, const char *msg) { do_error(ft,err_nl,msg,EXIT_OK,0); } void p_fatal(file_t *ft, const char *msg) { do_error(ft,err_nl,msg,EXIT_FATAL,errno); } void p_error(file_t *ft, const char *msg) { do_error(ft,err_nl,msg,EXIT_ERROR,errno); } void p_warn(file_t *ft, const char *msg) { do_error(ft,err_nl,msg,EXIT_WARN,errno); } void read_error(file_t *ft) { const char *fn = ft && ft->name[0] ? ft->name : UNKNOWN_NAME; const char *errmsg = "unexpected end of file"; if (errno != 0) errmsg = strerror(errno); fflush(con_term); fprintf(stderr, "%s%s: %s: %s\n", err_nl, progname, errmsg, fn); e_exit(EXIT_FATAL); } void write_error(file_t *ft) { const char *fn = ft && ft->name[0] ? ft->name : UNKNOWN_NAME; const char *errmsg = "write error"; if (errno != 0) errmsg = strerror(errno); fflush(con_term); fprintf(stderr, "%s%s: %s: %s\n", err_nl, progname, errmsg, fn); e_exit(EXIT_FATAL); } /************************************************************************* // file_t **************************************************************************/ void f_reset(file_t *ft) { ft->opt_name = opt_name; ft->part = 0; ft->bytes_read = 0; ft->bytes_written = 0; ft->warn_multipart = 0; ft->warn_unknown_suffix = 0; } void f_init(void) { memset(&fi,0,sizeof(file_t)); memset(&fo,0,sizeof(file_t)); fi.fd = -1; fo.fd = -1; #if defined(USE_FOPEN) fi.file = NULL; fo.file = NULL; #endif f_reset(&fi); f_reset(&fo); } int f_open(file_t *ft, lzo_bool r) { assert(ft->name[0]); ft->fd = -1; #if defined(O_BINARY) ft->open_flags |= O_BINARY; #endif #if (ACC_OS_WIN32 || ACC_OS_WIN64) && defined(_O_SEQUENTIAL) ft->open_flags |= _O_SEQUENTIAL; #endif #if defined(USE_FOPEN) ft->file = NULL; if (r) ft->file = fopen(ft->name,"rb"); else if (ft->open_flags & O_EXCL) { if (file_exists(ft->name)) errno = EEXIST; else ft->file = fopen(ft->name,"wb"); } else ft->file = fopen(ft->name,"wb"); if (ft->file != NULL) { ft->fd = fileno(ft->file); assert(ft->fd >= 0); } #else if (r) ft->fd = open(ft->name, ft->open_flags, 0); else { #if defined(O_EXCL_BROKEN) if ((ft->open_flags & O_EXCL) && file_exists(ft->name)) errno = EEXIST; else #endif ft->fd = open(ft->name, ft->open_flags, ft->st.st_mode); } #endif if (ft->fd >= 0 && (ft->fd == STDIN_FILENO || ft->fd == STDOUT_FILENO || ft->fd == STDERR_FILENO)) { fatal(ft,"sanity check failed: f_open()"); ft->fd = -1; } return ft->fd; } int f_close(file_t *ft) { int r; if (ft->fd < 0) return 0; if (ft->fd == STDIN_FILENO || ft->fd == STDOUT_FILENO || ft->fd == STDERR_FILENO) return 0; #if defined(USE_FOPEN) assert(ft->file != NULL); r = fclose(ft->file); ft->file = NULL; #else r = close(ft->fd); #endif ft->fd = -1; return r; } /************************************************************************* // read and write // handles partial pipe writes and interrupted system calls **************************************************************************/ lzo_int read_buf(file_t *ft, lzo_voidp buffer, lzo_int cnt) { lzo_int n; long l; assert(cnt >= 0 && cnt < LONG_MAX); l = acc_safe_hread(ft->fd, buffer, (long) cnt); n = (lzo_int) l; assert(n >= 0); assert(n == l); ft->bytes_read += n; total_bytes_read += n; return n; } void write_buf(file_t *ft, const lzo_voidp buffer, lzo_int cnt) { lzo_int n; long l; assert(cnt >= 0 && cnt < LONG_MAX); if (ft->fd < 0) return; l = acc_safe_hwrite(ft->fd, buffer, (long) cnt); n = (lzo_int) l; assert(n >= 0); assert(n == l); ft->bytes_written += n; total_bytes_written += n; if (n != cnt) write_error(ft); } /************************************************************************* // misc IO **************************************************************************/ static unsigned get_be16(const unsigned char *b) { unsigned v; v = (unsigned) b[1] << 0; v |= (unsigned) b[0] << 8; return v; } static void set_be16(unsigned char *b, unsigned v) { b[1] = (unsigned char) (v >> 0); b[0] = (unsigned char) (v >> 8); } static lzo_uint32 get_be32(const unsigned char *b) { lzo_uint32 v; v = (lzo_uint32) b[3] << 0; v |= (lzo_uint32) b[2] << 8; v |= (lzo_uint32) b[1] << 16; v |= (lzo_uint32) b[0] << 24; return v; } static void set_be32(unsigned char *b, lzo_uint32 v) { b[3] = (unsigned char) (v >> 0); b[2] = (unsigned char) (v >> 8); b[1] = (unsigned char) (v >> 16); b[0] = (unsigned char) (v >> 24); } #if 0 /* NOT USED */ static void write8(file_t *ft, int v) { unsigned char b = (unsigned char) v; write_buf(ft,&b,1); } #endif void read32(file_t *ft, lzo_uint32 *v) { unsigned char b[4]; if (read_buf(ft,b,4) != 4) read_error(ft); *v = get_be32(b); } void write32(file_t *ft, lzo_uint32 v) { unsigned char b[4]; set_be32(b,v); write_buf(ft,b,4); } static int f_read8(file_t *ft, unsigned char *b) { unsigned char bb; if (read_buf(ft,&bb,1) != 1) read_error(ft); ft->f_adler32 = lzo_adler32(ft->f_adler32,&bb,1); ft->f_crc32 = lzo_crc32(ft->f_crc32,&bb,1); if (b) *b = bb; return bb; } static void f_write8(file_t *ft, int v) { unsigned char b = (unsigned char) v; write_buf(ft,&b,1); ft->f_adler32 = lzo_adler32(ft->f_adler32,&b,1); ft->f_crc32 = lzo_crc32(ft->f_crc32,&b,1); } static void f_read16(file_t *ft, unsigned *v) { unsigned char b[2]; if (read_buf(ft,b,2) != 2) read_error(ft); ft->f_adler32 = lzo_adler32(ft->f_adler32,b,2); ft->f_crc32 = lzo_crc32(ft->f_crc32,b,2); *v = get_be16(b); } static void f_write16(file_t *ft, unsigned v) { unsigned char b[2]; set_be16(b,v); write_buf(ft,b,2); ft->f_adler32 = lzo_adler32(ft->f_adler32,b,2); ft->f_crc32 = lzo_crc32(ft->f_crc32,b,2); } static void f_read32(file_t *ft, lzo_uint32 *v) { unsigned char b[4]; if (read_buf(ft,b,4) != 4) read_error(ft); ft->f_adler32 = lzo_adler32(ft->f_adler32,b,4); ft->f_crc32 = lzo_crc32(ft->f_crc32,b,4); *v = get_be32(b); } static void f_write32(file_t *ft, lzo_uint32 v) { unsigned char b[4]; set_be32(b,v); write_buf(ft,b,4); ft->f_adler32 = lzo_adler32(ft->f_adler32,b,4); ft->f_crc32 = lzo_crc32(ft->f_crc32,b,4); } static void f_write(file_t *ft, const lzo_voidp buf, lzo_int cnt) { if (cnt > 0) { write_buf(ft,buf,cnt); ft->f_adler32 = lzo_adler32(ft->f_adler32,(const lzo_bytep)buf,cnt); ft->f_crc32 = lzo_crc32(ft->f_crc32,(const lzo_bytep)buf,cnt); } } static lzo_int f_read(file_t *ft, lzo_voidp buf, lzo_int cnt) { cnt = read_buf(ft,buf,cnt); if (cnt > 0) { ft->f_adler32 = lzo_adler32(ft->f_adler32,(const lzo_bytep)buf,cnt); ft->f_crc32 = lzo_crc32(ft->f_crc32,(const lzo_bytep)buf,cnt); } return cnt; } /*********************************************************************** // lzop file signature ************************************************************************/ /* * The first nine bytes of a lzop file always contain the following values: * * 0 1 2 3 4 5 6 7 8 * --- --- --- --- --- --- --- --- --- * (hex) 89 4c 5a 4f 00 0d 0a 1a 0a * (decimal) 137 76 90 79 0 13 10 26 10 * (C notation - ASCII) \211 L Z O \0 \r \n \032 \n */ static const unsigned char lzop_magic[9] = { 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a }; static const char * const header_error[] = { "[0]", "not a " PACKAGE " file", /* 1 */ "header corrupted (checksum error)", /* 2 */ "header corrupted", /* 3 */ "header corrupted (DOS -> UNIX conversion ?)", /* 4 */ "header corrupted (DOS -> Mac conversion ?)", /* 5 */ "header corrupted (UNIX -> Mac conversion ?)", /* 6 */ "header corrupted (Mac -> UNIX conversion ?)", /* 7 */ "header corrupted (UNIX -> DOS conversion ?)", /* 8 */ "header corrupted (end of line conversion ?)", /* 9 */ "header corrupted (DOS EOF conversion ?)", /* 10 */ "header corrupted (transmitted through a 7-bit channel ?)", /* 11 */ "header corrupted (transmitted in text mode ?)", /* 12 */ "unknown header flags -- get a newer version of " PACKAGE, /* 13 */ "unknown compression method -- get a newer version of " PACKAGE, /* 14 */ "unknown compression level -- get a newer version of " PACKAGE, /* 15 */ "you need a newer version of " PACKAGE, /* 16 */ "compression method not supported -- recompile " PACKAGE, /* 17 */ "decompression method not supported -- recompile " PACKAGE, /* 18 */ NULL }; static int check_magic(const unsigned char *magic) { const unsigned char *m; if (memcmp(magic,lzop_magic,sizeof(lzop_magic)) == 0) return 0; /* We have a bad magic signature. Try to figure what possibly * could have gone wrong. */ /* look at bytes 1-3: "LZO" in hex and local text format */ if (memcmp(&magic[1],&lzop_magic[1],3) != 0 && memcmp(&magic[1],"LZO",3) != 0) return 1; /* look at byte 4 */ if (magic[4] != lzop_magic[4]) return 1; /* look at bytes 5-8 */ m = &magic[5]; if (memcmp(m,"\012\012\032",3) == 0) return 7; if (memcmp(m,"\012\012",2) == 0) return 4; if (memcmp(m,"\012\032",2) == 0) return 4; if (memcmp(m,"\015\012\012",3) == 0) return 10; if (memcmp(m,"\015\012\032\012",4) == 0) return 9; if (memcmp(m,"\015\012\032\015",4) == 0) return 8; if (memcmp(m,"\015\015\012\032",4) == 0) return 8; if (memcmp(m,"\015\015\032",3) == 0) return 6; if (memcmp(m,"\015\032",2) == 0) return 5; if (memcmp(m,&lzop_magic[5],4) != 0) return 12; /* look at byte 0 */ if (magic[0] == (unsigned char) (lzop_magic[0] & 0x7f)) return 11; if (magic[0] != lzop_magic[0]) return 12; return 3; } /************************************************************************* // lzop file header **************************************************************************/ void init_compress_header(header_t *h, const file_t *fip, const file_t *fop) { assert(opt_method > 0); assert(opt_level > 0); assert(fip->st.st_mode == 0 || S_ISREG(fip->st.st_mode)); memset(h,0,sizeof(header_t)); h->version = LZOP_VERSION & 0xffff; h->version_needed_to_extract = opt_filter ? 0x0950: 0x0940; h->lib_version = lzo_version() & 0xffff; h->method = (unsigned char) opt_method; h->level = (unsigned char) opt_level; h->filter = opt_filter; h->flags = 0; h->flags |= F_OS & F_OS_MASK; h->flags |= F_CS & F_CS_MASK; if (opt_filter) h->flags |= F_H_FILTER; if (fip->fd == STDIN_FILENO) h->flags |= F_STDIN; if (fop->fd == STDOUT_FILENO) h->flags |= F_STDOUT; if (!opt_file && num_files > 1) h->flags |= F_MULTIPART; #ifdef OPT_NAME_DEFAULT h->flags |= F_NAME_DEFAULT; #endif #ifdef DOSISH h->flags |= F_DOSISH; #endif if (opt_crc32) { h->flags |= F_H_CRC32; if (h->version_needed_to_extract < 0x1001) h->version_needed_to_extract = 0x1001; } h->mode = fix_mode_for_header(fip->st.st_mode); if (fip->st.st_mtime) { h->mtime_low = (lzo_uint32) (fip->st.st_mtime); h->mtime_high = (lzo_uint32) (fip->st.st_mtime >> 16 >> 16); if ((lzo_int32) h->mtime_high < 0) h->mtime_high = 0; } if (fip->name[0] && fip->fd != STDIN_FILENO) { int r = 0; if (opt_path) { char newname[255+1]; r = fn_cleanpath(fip->name, newname, sizeof(newname), 0); if (r > 0 && newname[0] && strlen(newname) <= 255) { strcpy(h->name, newname); h->flags |= F_H_PATH; if (h->version_needed_to_extract < 0x1001) h->version_needed_to_extract = 0x1001; } else r = 0; } if (r == 0) { const char *n = fn_basename(fip->name); if (n[0] && strlen(n) <= 255) strcpy(h->name, n); } } } void write_header(file_t *ft, const header_t *h) { size_t l; #ifdef MAINT /* undocumented option '--no-header'. just for testing. */ if (opt_noheader > 0) { switch (opt_noheader) { case 1: write32(ft,h->flags); break; case 2: write32(ft,h->flags); write8(ft,h->method); write8(ft,h->level); break; default: /* write no header at all */ break; } return; } #endif write_buf(ft,lzop_magic,sizeof(lzop_magic)); ft->f_adler32 = ADLER32_INIT_VALUE; ft->f_crc32 = CRC32_INIT_VALUE; f_write16(ft,h->version); f_write16(ft,h->lib_version); f_write16(ft,h->version_needed_to_extract); f_write8(ft,h->method); f_write8(ft,h->level); f_write32(ft,h->flags); if (h->flags & F_H_FILTER) f_write32(ft,h->filter); f_write32(ft,h->mode); f_write32(ft,h->mtime_low); f_write32(ft,h->mtime_high); l = strlen(h->name); assert(l <= 255); f_write8(ft,(int)l); if (l > 0) f_write(ft,h->name,(int)l); if (h->flags & F_H_CRC32) f_write32(ft,ft->f_crc32); else f_write32(ft,ft->f_adler32); } static int read_header(file_t *ft, header_t *h) { int r; int l; lzo_uint32 checksum; memset(h,0,sizeof(header_t)); h->version_needed_to_extract = 0x0900; /* first public lzop version */ h->level = 0; h->method_name = "unknown"; ft->f_adler32 = ADLER32_INIT_VALUE; ft->f_crc32 = CRC32_INIT_VALUE; f_read16(ft,&h->version); if (h->version < 0x0900) return 3; f_read16(ft,&h->lib_version); if (h->version >= 0x0940) { f_read16(ft,&h->version_needed_to_extract); if (h->version_needed_to_extract > LZOP_VERSION) return 16; if (h->version_needed_to_extract < 0x0900) return 3; } f_read8(ft,&h->method); if (h->version >= 0x0940) f_read8(ft,&h->level); f_read32(ft,&h->flags); if (h->flags & F_H_FILTER) f_read32(ft,&h->filter); f_read32(ft,&h->mode); #if 1 if (h->flags & F_STDIN) /* do not use mode from stdin compression */ h->mode = 0; #endif f_read32(ft,&h->mtime_low); if (h->version >= 0x0940) f_read32(ft,&h->mtime_high); if (h->version < 0x0120) { if (h->mtime_low == 0xffffffffUL) h->mtime_low = 0; h->mtime_high = 0; } l = f_read8(ft,NULL); if (l > 0) { char name[255+1]; if (f_read(ft,name,l) != l) read_error(ft); name[l] = 0; if (fn_cleanpath(name, h->name, 255+1, 1|2) < 0) h->name[0] = 0; } checksum = (h->flags & F_H_CRC32) ? ft->f_crc32 : ft->f_adler32; f_read32(ft,&h->header_checksum); if (h->header_checksum != checksum) return 2; if (h->method <= 0) return 14; r = x_get_method(h); if (r != 0) return r; /* check reserved flags */ if (h->flags & F_RESERVED) return (opt_force >= 2) ? -13 : 13; /* skip extra field [not used yet] */ if (h->flags & F_H_EXTRA_FIELD) { lzo_uint32 k; /* note: the checksum also covers the length */ ft->f_adler32 = ADLER32_INIT_VALUE; ft->f_crc32 = CRC32_INIT_VALUE; f_read32(ft,&h->extra_field_len); for (k = 0; k < h->extra_field_len; k++) (void) f_read8(ft,NULL); checksum = (h->flags & F_H_CRC32) ? ft->f_crc32 : ft->f_adler32; f_read32(ft,&h->extra_field_checksum); if (h->extra_field_checksum != checksum) return 3; if (opt_verbose >= 2) info(ft,"ignoring extra field"); } return 0; } /* return 0 for valid magic, -1 for EOF, or positive value for error */ static int p_magic(file_t *ft) { int r; lzo_int l; unsigned char magic[sizeof(lzop_magic)]; l = read_buf(ft,magic,sizeof(magic)); if (ft->part > 0 && l <= 0) return -1; if (l == (lzo_int) sizeof(magic)) r = check_magic(magic); else r = 1; assert(r >= 0); if (ft->part > 0 && r == 1) { #if 1 /* gzip: check for trailing zero bytes */ unsigned char b; while (--l >= 0) if (magic[(int)l] != '\0') goto garbage; while (read_buf(ft,&b,1) == 1) if (b != '\0') goto garbage; if (opt_verbose >= 2) warn(ft,"ignoring trailing zero bytes in " PACKAGE " file"); return -1; garbage: #endif warn(ft,"ignoring trailing garbage in " PACKAGE " file"); return -1; } if (r != 0) { assert(r > 0 && r <= 18); error(ft,header_error[r]); } return r; } static lzo_bool p_header(file_t *ft, header_t *h) { int r; r = read_header(ft,h); if (r == 0) return 1; if (r < 0) { r = -r; assert(r > 0 && r <= 18); error(ft,header_error[r]); return 1; } else { assert(r > 0 && r <= 18); error(ft,header_error[r]); return 0; } } /************************************************************************* // test **************************************************************************/ void do_test(const header_t *h, lzop_ulong_t d_len, lzop_ulong_t c_len) { total_d_files++; total_c_len += c_len; total_d_len += d_len; UNUSED(h); } void do_test_total(void) { FILE *f; if ((total_c_files < 2 && total_d_files < 2) || opt_verbose < 2) return; f = stderr; fprintf(f,"%lu file%s successfully tested", total_c_files, total_c_files == 1 ? " was" : "s were"); if (total_c_files != total_d_files) fprintf(f," [containing %lu files]", total_d_files); fprintf(f,"\n"); fflush(f); } /************************************************************************* // list a file **************************************************************************/ static unsigned long get_ratio(lzop_ulong_t d_len, lzop_ulong_t c_len) { unsigned long n1 = 1000L * 1000L; unsigned long n2 = 1; const lzop_ulong_t umax = ~((lzop_ulong_t)0); if (d_len <= 0) return c_len <= 0 ? 0ul : n1; while (n1 > 1 && c_len > (umax / n1)) { n1 /= 10; n2 *= 10; } return (unsigned long) ((c_len * n1) / (d_len / n2)); } static void pr_size(FILE *f, lzop_ulong_t a, lzop_ulong_t b, int flags) { unsigned long ratio, r1, r2, al, bl; ratio = (flags & 1) ? get_ratio(a, b) : get_ratio(b, a); ratio += 500; /* for rounding */ r1 = ratio / 10000; r2 = (ratio % 10000) / 1000; #if (SIZEOF_LONG >= 8) || !defined(acc_int64l_t) al = (unsigned long) a; bl = (unsigned long) b; fprintf(f,"%9lu %9lu %3lu.%01lu%%", al, bl, r1, r2); #else al = (unsigned long) (a % 1000000000ul); bl = (unsigned long) (b % 1000000000ul); if (a == al && b == bl) { fprintf(f,"%9lu %9lu %3lu.%01lu%%", al, bl, r1, r2); } else if (a == al) { unsigned long bh = (unsigned long) (b / 1000000000ul); fprintf(f,"%9lu %lu%09lu %3lu.%01lu%%", al, bh, bl, r1, r2); } else if (b == bl) { unsigned long ah = (unsigned long) (a / 1000000000ul); fprintf(f,"%lu%09lu %9lu %3lu.%01lu%%", ah, al, bl, r1, r2); } else { unsigned long ah = (unsigned long) (a / 1000000000ul); unsigned long bh = (unsigned long) (b / 1000000000ul); fprintf(f,"%lu%09lu %lu%09lu %3lu.%01lu%%", ah, al, bh, bl, r1, r2); } #endif } static char *modestr(lzo_uint32 mode) { static char s[10+1]; mode_string(fix_mode_for_ls(mode),s); s[0] = '-'; s[10] = 0; return s; } void do_list(const header_t *h, lzop_ulong_t d_len, lzop_ulong_t c_len) { FILE *f; char s[40]; time_t t; f = stdout; s[0] = 0; t = get_mtime(h); if (total_d_files == 0 && opt_verbose > 0) { if (opt_verbose >= 3) ((void)0); else if (opt_verbose >= 2) { fprintf(f,"Method Length Packed Ratio "); fprintf(f," Date Time Name\n"); fprintf(f,"------ ------ ------ ----- "); fprintf(f," ---- ---- ----\n"); } else { fprintf(f,"%-11s ", "method"); fprintf(f,"compressed uncompr. ratio"); fprintf(f," uncompressed_name\n"); } fflush(f); } if (opt_verbose >= 3) { fprintf(f,"%-10s", modestr(h->mode)); if (t) time2str(s,sizeof(s),&t); fprintf(f," %-19s",s); fprintf(f," %-20s",fi.name); if (fo.name[0]) fprintf(f," %s", fo.name); } else if (opt_verbose >= 2) { fprintf(f,"%-11s ", h->method_name); pr_size(f, d_len, c_len, 1); if (t) time2str(s,sizeof(s),&t); s[16] = 0; /* cut off seconds */ fprintf(f," %-16s",s); if (fo.name[0]) fprintf(f," %s", fo.name); } else { fprintf(f,"%-11s ", h->method_name); pr_size(f, c_len, d_len, 0); if (fo.name[0]) fprintf(f," %s", fo.name); } fprintf(f,"\n"); fflush(f); total_d_files++; total_c_len += c_len; total_d_len += d_len; } void do_list_total(void) { FILE *f; if (total_d_files < 2 || opt_verbose == 0) return; if (opt_verbose >= 3) return; f = stdout; if (opt_verbose >= 2) { fprintf(f," ------- ------- ----- "); fprintf(f," ----\n"); fprintf(f,"%-11s ", ""); pr_size(f, total_d_len, total_c_len, 1); fprintf(f," %-16s", ""); fprintf(f," %lu files\n", total_d_files); } else { fprintf(f,"%-11s ", ""); pr_size(f, total_c_len, total_d_len, 0); fprintf(f," (totals -- %lu files)\n", total_d_files); } fflush(f); } /************************************************************************* // list a file similar to 'ls -ln' **************************************************************************/ void do_ls(const header_t *h, lzop_ulong_t d_len, lzop_ulong_t c_len) { FILE *f; char s[40]; time_t t; const char *name = fo.name[0] ? fo.name : UNKNOWN_NAME; f = stdout; t = get_mtime(h); if (t == 0) time(&t); fprintf(f,"%-10s 1", modestr(h->mode)); if (opt_stdin) fprintf(f," %-8s", "user"); else fprintf(f," %-8ld", (long) fi.st.st_uid); if (!strchr(opt_ls_flags,'G')) { if (opt_stdin) fprintf(f," %-8s", "group"); else fprintf(f," %-8ld", (long) fi.st.st_gid); } #if (SIZEOF_LONG >= 8) || !defined(acc_int64l_t) fprintf(f," %8lu", (unsigned long) d_len); #else { unsigned long d0, d1, d2; d0 = (unsigned long) (d_len % 100000000ul); if (d0 == d_len) fprintf(f," %8lu", d0); else { d1 = (unsigned long) ((d_len / 100000000ul) % 100000000ul); d2 = (unsigned long) ((d_len / 100000000ul) / 100000000ul); if (d2 != 0) fprintf(f,"%lu%08lu%08lu", d2, d1, d0); else fprintf(f,"%lu%08lu", d1, d0); } } #endif time2ls(s, sizeof(s), &t); fprintf(f," %-12s",s); if (strchr(opt_ls_flags,'Q')) fprintf(f," \"%s\"", name); else fprintf(f," %s", name); if (strchr(opt_ls_flags,'F')) if (h->mode & 0111) fprintf(f,"*"); fprintf(f,"\n"); fflush(f); UNUSED(c_len); } /************************************************************************* // header info **************************************************************************/ static void print_version(FILE *f, unsigned v) { fprintf(f,"%1x.%03x", (v >> 12) & 0xf, v & 0xfff); } static void print_os(FILE *f, lzo_uint32 flags) { flags = (flags & F_OS_MASK) >> F_OS_SHIFT; fprintf(f,"%2ld", (long) flags); } void do_info(const header_t *h, lzop_ulong_t d_len, lzop_ulong_t c_len) { int v = opt_verbose; FILE *f; f = stdout; opt_verbose = 2; ++total_d_files; /* do not print the list-header */ do_list(h,d_len,c_len); --total_d_files; opt_verbose = v; fprintf(f," "); print_version(f,h->version); fprintf(f," "); print_version(f,h->lib_version); fprintf(f," "); print_version(f,h->version_needed_to_extract); fprintf(f," Fl: 0x%08lx", (long) h->flags); fprintf(f," Mo: 0%011lo", (long) h->mode); fprintf(f," Me: %d/%d", h->method, h->level); fprintf(f," OS: "); print_os(f,h->flags); if (h->filter) fprintf(f," Fi: %3ld", (long) h->filter); fprintf(f,"\n"); } /************************************************************************* // determine name of output file **************************************************************************/ static lzo_bool can_restore_name(file_t *ft, const header_t *h) { if (h->name[0] == 0 || ft->opt_name == 0) return 0; else if (ft->opt_name > 0) return 1; #ifdef OPT_NAME_DEFAULT #if 1 else return 1; #else /* restore the name by default only when created on such a system */ else if ((h->flags & F_NAME_DEFAULT)) return 1; else return 0; #endif #else /* do not restore the name by default */ else return 0; #endif /* OPT_NAME_DEFAULT */ } static lzo_bool oname_error(void) { if (opt_force >= 2 || opt_cmd == CMD_TEST) { warn(&fi,"can't determine name of output file -- using default"); return 1; } if (opt_name != 1) error(&fi,"can't determine name of output file (try option '-N')"); else error(&fi,"can't determine name of output file (use option '-o')"); strcpy(fo.name,UNKNOWN_NAME); return 0; } static lzo_bool p_set_oname(const header_t *h) { char *base; char *ext; int suff; size_t l; const char *err_name; const char *s; size_t sl; fo.name[0] = 0; if (opt_output_name) { /* name given on command line; perform no additional checks */ strcpy(fo.name,opt_output_name); return 1; } assert(!opt_stdout); assert(opt_file); #if defined(NRVP) err_name = (opt_cmd == CMD_COMPRESS) ? "nrvp.nrv" : "nrvp.raw"; s = opt_suffix[0] ? opt_suffix : ".nrv"; #else err_name = (opt_cmd == CMD_COMPRESS) ? "lzop.lzo" : "lzop.raw"; s = opt_suffix[0] ? opt_suffix : ".lzo"; #endif sl = strlen(s); if (opt_output_path) { strcpy(fo.name,opt_output_path); fn_addslash(fo.name,1); if (!opt_stdin) strcat(fo.name,fn_basename(fi.name)); } else if (!opt_stdin) strcpy(fo.name,fi.name); l = strlen(fo.name); if (l >= PATH_MAX) { error(&fo,"name too long (use option '-o')"); return 0; } base = fo.name + fn_baseindex(fo.name); suff = fn_has_suffix(base); ext = strchr(base,'.'); if (opt_cmd == CMD_COMPRESS) { assert(!opt_stdin); assert(base[0]); #if defined(DOSISH) if (suff == SUFF_TAR) { #if defined(NRVP) strcpy(ext, opt_suffix[0] ? opt_suffix : ".tnv"); #else strcpy(ext, opt_suffix[0] ? opt_suffix : ".tzo"); #endif } else #endif if (opt_shortname && ext) strcpy(ext,s); else strcat(fo.name,s); } else { lzo_bool u = 0; if (can_restore_name(&fi,h)) { if (opt_path) strcpy(base,h->name); else strcpy(base,fn_basename(h->name)); } else if (opt_stdin) { if (!oname_error()) return 0; strcpy(base,err_name); } else if (suff == SUFF_LZO) fo.name[l-4] = 0; else if (suff == SUFF_LZOP) fo.name[l-5] = 0; else if (suff == SUFF_NRV) fo.name[l-4] = 0; else if (suff == SUFF_TZO) strcpy(&fo.name[l-4],".tar"); else if (suff == SUFF_USER) fo.name[l-sl] = 0; else { u = 1; if (opt_shortname && ext) strcpy(ext,".raw"); else strcat(fo.name,".raw"); } if (u && opt_cmd == CMD_DECOMPRESS && !opt_stdin) { #if 1 if (!(opt_force >= 2)) { if (fi.warn_unknown_suffix == 0) error(&fi,"unknown suffix -- ignored"); fi.warn_unknown_suffix = 1; return 0; } #else /* gzip: '--force' doesn't override these checks */ if (fi.warn_unknown_suffix == 0) error(&fi,"unknown suffix -- ignored"); fi.warn_unknown_suffix = 1; return 0; #endif } } if (strlen(fo.name) >= PATH_MAX) { error(&fo,"name too long (use option '-o')"); return 0; } #if defined(DOSISH) s = maybe_rename_file(fo.name); if (s == NULL) { if (!oname_error()) return 0; strcpy(base,err_name); } else if (s != fo.name) { if (strcmp(s,fo.name) != 0) { warn(&fo,"renaming output file to match OS conventions"); strcpy(fo.name,s); } } #endif UNUSED(ext); return 1; } /************************************************************************* // stdin/stdout **************************************************************************/ static lzo_bool check_stdin(file_t *ft) { if (!opt_force && acc_isatty(STDIN_FILENO)) { strcpy(ft->name,STDIN_NAME); if (opt_cmd == CMD_COMPRESS) fatal(ft,"uncompressed data not read from a terminal"); else fatal(ft,"compressed data not read from a terminal"); return 0; } return 1; } static lzo_bool check_stdout(file_t *ft) { if (!(opt_cmd == CMD_COMPRESS || opt_cmd == CMD_DECOMPRESS)) return 1; if (!opt_force && acc_isatty(STDOUT_FILENO)) { strcpy(ft->name,STDOUT_NAME); if (opt_cmd == CMD_COMPRESS) fatal(ft,"compressed data not written to a terminal"); else fatal(ft,"uncompressed data not written to a terminal"); return 0; } return 1; } static lzo_bool open_stdin(file_t *ft) { static lzo_bool setmode_done = 0; assert(ft->fd == -1); f_reset(ft); strcpy(ft->name,STDIN_NAME); ft->fd = STDIN_FILENO; #if !defined(NO_SETMODE) if (!setmode_done) { if (acc_set_binmode(ft->fd, 1) == -1) { p_fatal(ft,"acc_set_binmode(stdin) failed"); return 0; } } #endif setmode_done = 1; ft->st.st_mtime = time(NULL); #if 1 && defined(HAVE_FSTAT) { struct stat st; if (fstat(ft->fd, &st) == 0 && S_ISREG(st.st_mode)) ft->st = st; } #endif ft->st.st_atime = fix_time(ft->st.st_atime); ft->st.st_mtime = fix_time(ft->st.st_mtime); return 1; } static lzo_bool open_stdout(file_t *ft) { static lzo_bool setmode_done = 0; assert(ft->fd == -1); f_reset(ft); strcpy(ft->name,STDOUT_NAME); if (!(opt_cmd == CMD_COMPRESS || opt_cmd == CMD_DECOMPRESS)) { ft->fd = -2; /* special file-handle for dummy output */ return 1; } ft->fd = STDOUT_FILENO; #if !defined(NO_SETMODE) if (!setmode_done) { if (acc_set_binmode(ft->fd, 1) == -1) { p_fatal(ft,"acc_set_binmode(stdout) failed"); return 0; } } #endif setmode_done = 1; return 1; } /************************************************************************* // open input file **************************************************************************/ lzo_bool p_open_fi(const char *name) { int r, saved_errno; #if defined(HAVE_LSTAT) && defined(S_ISLNK) int r2; #endif if (fi.fd != -1) return 1; f_reset(&fi); /* prepare file name */ assert(name != NULL); if (strlen(name) >= PATH_MAX) { if (strlen(name) >= sizeof(fi.name)) strcpy(fi.name,UNKNOWN_NAME); else strcpy(fi.name,name); error(&fi,"name too long"); return 0; } strcpy(fi.name,name); fn_strlwr(fi.name); if (opt_cmd == CMD_COMPRESS) { int suff = fn_has_suffix(fi.name); #if 1 if (opt_stdout || opt_output_name) suff = SUFF_NONE; /* do not warn */ #endif #if 1 if (opt_force >= 2) suff = SUFF_NONE; /* do not warn */ #else /* gzip: '--force' doesn't override these checks */ #endif if (suff == SUFF_LZO) { warn(&fi,"already has .lzo suffix -- unchanged"); return 0; } else if (suff == SUFF_LZOP) { warn(&fi,"already has .lzop suffix -- unchanged"); return 0; } else if (suff == SUFF_NRV) { warn(&fi,"already has .nrv suffix -- unchanged"); return 0; } else if (suff == SUFF_TZO) { warn(&fi,"already has .tzo suffix -- unchanged"); return 0; } else if (suff == SUFF_USER) { warn(&fi,"already has user suffix -- unchanged"); return 0; } } /* open file */ errno = 0; r = stat(fi.name, &fi.st); saved_errno = errno; if (r != 0) memset(&fi.st, 0, sizeof(fi.st)); #if defined(HAVE_LSTAT) && defined(S_ISLNK) r2 = lstat(fi.name, &fi.lst); if (r2 != 0) memset(&fi.lst, 0, sizeof(fi.lst)); if (r2 == 0 && S_ISLNK(fi.lst.st_mode)) { if (r != 0) { errno = saved_errno; #if 0 p_error(&fi,"can't open input file -- dangling symlink"); #else do_error(&fi,err_nl,"can't open input file: Dangling symlink",EXIT_ERROR,0); #endif return 0; } } #endif if (r == 0 && !S_ISREG(fi.st.st_mode)) { warn(&fi,"not a regular file -- skipped"); return 0; } fi.open_flags = O_RDONLY; f_open(&fi,1); #if 0 && defined(__DJGPP__) /* try again without LFN */ if (fi.fd < 0 && errno == ENOENT && _USE_LFN) { if (!(_crt0_startup_flags & _CRT0_FLAG_NO_LFN)) { int k = _crt0_startup_flags; _crt0_startup_flags |= _CRT0_FLAG_NO_LFN; r = stat(fi.name, &fi.st); saved_errno = errno; _crt0_startup_flags = k; if (r == 0 && !S_ISREG(fi.st.st_mode)) { warn(&fi,"not a regular file -- skipped"); return 0; } f_open(&fi,1); } } #endif if (fi.fd < 0) { p_error(&fi,"can't open input file"); return 0; } if (r != 0) { errno = saved_errno; p_error(&fi,"can't stat input file"); (void) f_close(&fi); return 0; } fi.st.st_atime = fix_time(fi.st.st_atime); fi.st.st_mtime = fix_time(fi.st.st_mtime); return 1; } /************************************************************************* // open output file **************************************************************************/ lzo_bool p_open_fo(const header_t *h) { if (fo.fd != -1) return 1; f_reset(&fo); if (!p_set_oname(h)) return 0; fn_strlwr(fo.name); if (!(opt_cmd == CMD_COMPRESS || opt_cmd == CMD_DECOMPRESS)) { fo.fd = opt_output_name ? -2 : -1; return 1; } if (fn_is_same_file(fi.name,fo.name)) { if (opt_cmd == CMD_COMPRESS) error(&fi,"can't compress to same file"); else error(&fi,"can't decompress to same file"); return 0; } fo.open_flags = O_CREAT | O_WRONLY; if (opt_force) fo.open_flags |= O_TRUNC; else fo.open_flags |= O_EXCL; #if defined(__MINT__) fo.open_flags |= O_TRUNC | O_DENYRW; #endif fo.st.st_mode = fix_mode_for_open(fi.st.st_mode); if (opt_cmd == CMD_DECOMPRESS && opt_path && (h->flags & F_H_PATH)) { /* create missing directories */ char *name; int n = 0; name = fo.name; while (name[n]) { while (name[n] && name[n] != '/') n++; if (name[n] == '/') { name[n] = 0; (void) acc_mkdir(name, 0777); name[n] = DIR_SEP[0]; n++; } } } f_open(&fo,0); if (fo.fd < 0) { if ((fo.open_flags & O_EXCL) && errno == EEXIST) error(&fo,"already exists; not overwritten"); else p_error(&fo,"can't open output file"); return 0; } return 1; } /************************************************************************* // close files **************************************************************************/ static lzo_bool p_close(int i, int o) { int r = 1; if (i && f_close(&fi) != 0) { p_error(&fi,"can't close input file"); r = 0; } if (o && f_close(&fo) != 0) { p_error(&fo,"can't close output file"); r = 0; } return r; } /************************************************************************* // compress **************************************************************************/ static void copy_perms(void) { #if defined(HAVE_UTIME) /* copy the time stamp */ struct utimbuf u; u.actime = fi.st.st_atime; u.modtime = fi.st.st_mtime; if (utime(fo.name,&u) != 0) p_warn(&fo,"can't copy file time"); #endif #if defined(HAVE_CHMOD) /* copy the protection mode */ fo.st.st_mode = fi.st.st_mode; if (chmod(fo.name, fo.st.st_mode) != 0) p_warn(&fo,"can't copy file mode"); #endif #if defined(HAVE_CHOWN) /* copy the ownership */ if (chown(fo.name, fi.st.st_uid, fi.st.st_gid) != 0) { /* ignore */ } #endif } static lzo_bool do_compress(const char *name, lzo_bool handle_perms) { lzo_bool ok = 1; header_t header; if (!p_open_fi(name)) return 0; if (!p_open_fo(NULL)) { if (opt_output_name || opt_stdout) e_exit(EXIT_ERROR); return 0; } ok = x_compress(&fi,&fo,&header); if (!ok) return 0; if (handle_perms) { if (!p_close(1,1)) return 0; copy_perms(); } return ok; } /************************************************************************* // decompress **************************************************************************/ static void restore_perms(const header_t *h) { #if defined(HAVE_UTIME) /* restore or copy the time stamp */ struct utimbuf u; if (opt_restore_time && (h->mtime_low || h->mtime_high)) { u.actime = u.modtime = get_mtime(h); if (u.actime) if (utime(fo.name,&u) != 0) p_warn(&fo,"can't restore file time"); } else if (fi.st.st_atime && fi.st.st_mtime) { u.actime = fi.st.st_atime; u.modtime = fi.st.st_mtime; if (utime(fo.name,&u) != 0) p_warn(&fo,"can't copy file time"); } #endif #if defined(HAVE_CHMOD) /* restore or copy the protection mode */ if (opt_restore_mode && h->mode) { fo.st.st_mode = fix_mode_for_chmod(h->mode); if (chmod(fo.name, fo.st.st_mode) != 0) p_warn(&fo,"can't restore file mode"); } else if (fi.st.st_mode > 0) { fo.st.st_mode = fi.st.st_mode; if (chmod(fo.name, fo.st.st_mode) != 0) p_warn(&fo,"can't copy file mode"); } #endif #if defined(HAVE_CHOWN) /* copy the ownership */ if (!opt_stdin) if (chown(fo.name, fi.st.st_uid, fi.st.st_gid) != 0) { /* ignore */ } #endif UNUSED(h); } static lzo_bool warn_multipart(file_t *ft, const header_t *h) { if (!((ft->part > 0) || (h->flags & F_MULTIPART))) return 1; if (opt_stdin && opt_stdout && opt_cmd == CMD_TEST && can_restore_name(ft,h)) return 1; if (opt_stdout || opt_output_name) { if (!ft->warn_multipart) warn(&fi,"this is a multipart archive (try option '-N')"); ft->warn_multipart = 1; } else if (opt_file && !can_restore_name(ft,h)) { ft->opt_name = 1; if (opt_cmd == CMD_TEST) { if (!ft->warn_multipart) warn(&fi,"this is a multipart archive (try option '-N')"); ft->warn_multipart = 1; } else if (can_restore_name(ft,h)) { if (!ft->warn_multipart) warn(&fi,"multipart archive -- restoring file names"); ft->warn_multipart = 1; } else { error(&fi,"multipart archive, but no filename stored (use option '-o')"); return 0; } } return 1; } static lzo_bool do_decompress(const char *name, lzo_bool handle_perms) { lzo_bool ok = 1; lzo_bool unlink_ok = 1; lzo_bool skip = 0; header_t header; int r; if (!p_open_fi(name)) return 0; for ( ; ok; fi.part++) { r = p_magic(&fi); if (r > 0) return 0; if (fi.part == 0) total_c_files++; if (fi.part > 0 && (opt_file || (r < 0 && handle_perms))) { if (!p_close(0,1)) return 0; if (!skip && handle_perms && (opt_file || (r < 0 && fi.part == 1))) restore_perms(&header); } if (r < 0) { assert(fi.part > 0); break; } if (!p_header(&fi,&header)) { /* use '--info -f -f' to try to list a corrupted header */ if (opt_cmd == CMD_INFO && opt_force >= 2) { (void) x_get_method(&header); do_info(&header,0,0); } return 0; } #if 0 /* debug */ do_info(&header,0,0); #endif if (!warn_multipart(&fi,&header)) return 0; skip = 0; ok = p_open_fo(&header); if (!ok) { unlink_ok = 0; if (opt_output_name || opt_stdout) e_exit(EXIT_ERROR); if (opt_cmd != CMD_TEST) skip = 1; } ok = x_decompress(&fi,&fo,&header,skip); } return ok && unlink_ok; } /************************************************************************* // process files **************************************************************************/ static lzo_bool do_one_file(const char *name, lzo_bool handle_perms) { lzo_bool ok; if (opt_cmd == CMD_COMPRESS) ok = do_compress(name,handle_perms); else ok = do_decompress(name,handle_perms); if (!p_close(1,0)) ok = 0; if (opt_file && !p_close(0,1)) ok = 0; if (ok && opt_unlink) { #if defined(HAVE_CHMOD) (void) chmod(fi.name, 0777); #endif if (unlink(fi.name) != 0) p_warn(&fi,"can't unlink file"); } if (fi.fd == -1) fi.name[0] = 0; if (fo.fd == -1) fo.name[0] = 0; return ok; } static void do_files(int i, int argc, char *argv[]) { lzo_bool handle_perms; if (opt_cmd == CMD_COMPRESS) handle_perms = !opt_stdin; else if (opt_cmd == CMD_DECOMPRESS) handle_perms = 1; else handle_perms = 0; if (opt_stdin) { assert(opt_stdout || opt_output_name || opt_output_path); assert(i == argc); assert(num_files == 0); if (!check_stdin(&fi) || !open_stdin(&fi)) return; } if (opt_stdout) { assert(!opt_output_name); if (!check_stdout(&fo) || !open_stdout(&fo)) return; handle_perms = 0; } if (opt_output_name) { assert(!opt_stdout); handle_perms &= (num_files == 1); } if (opt_stdin) do_one_file(NULL,handle_perms); else { for ( ; i < argc; i++) do_one_file(argv[i],handle_perms); } (void) p_close(1,1); if (opt_cmd == CMD_LIST) do_list_total(); if (opt_cmd == CMD_TEST) do_test_total(); } /************************************************************************* // check options **************************************************************************/ static void check_not_both(lzo_bool e1, lzo_bool e2, int c1, int c2) { if (e1 && e2) { fprintf(stderr,"%s: ",argv0); fprintf(stderr,"cannot use both '-%c' and '-%c'\n", c1, c2); e_usage(); } } void check_options(int i, int argc) { assert(i <= argc); if (opt_keep) opt_unlink = 0; if (!(opt_cmd == CMD_COMPRESS || opt_cmd == CMD_DECOMPRESS)) opt_unlink = 0; if (opt_stdin == OPT_STDIN_GUESSED && i != argc) opt_stdin = 0; if (opt_stdin) { opt_unlink = 0; #if 0 /* gzip: always use stdout */ opt_stdout = 1; #else if (!opt_output_name && !opt_output_path) opt_stdout = 1; #endif } if (opt_stdout) { check_not_both(1, opt_output_name != NULL, 'c', 'o'); check_not_both(1, opt_output_path != NULL, 'c', 'p'); check_not_both(1, opt_suffix[0] != 0, 'c', 'S'); opt_output_name = NULL; opt_output_path = NULL; opt_suffix[0] = 0; if (opt_unlink && !opt_force) { fprintf(stderr,"%s: both '-c' and '-U' given (use '-f' to force)\n",argv0); e_usage(); } } if (opt_output_name) { check_not_both(1, opt_output_path != NULL, 'o', 'p'); check_not_both(1, opt_suffix[0] != 0, 'o', 'S'); opt_output_path = NULL; opt_suffix[0] = 0; } /* check number of remaining args */ if (opt_stdin) { if (opt_cmd == CMD_COMPRESS && opt_output_path) { fprintf(stderr,"%s: cannot use '-p' when compressing stdin\n",argv0); e_usage(); } /* No more args allowed */ if (i != argc) { fprintf(stderr,"%s: no filename allowed when reading from stdin\n",argv0); e_usage(); } } else { if (i == argc) { fprintf(stderr,"%s: nothing to do !\n",argv0); e_usage(); } if (opt_stdout || opt_output_name) { #if 1 /* Allow multiple files */ if (i + 1 != argc) { opt_name = 1; } #else /* Exactly one input file */ if (i + 1 != argc) { fprintf(stderr,"%s: only one file allowed\n",argv0); e_usage(); } #endif } } opt_file = !opt_stdout && !opt_output_name; } /************************************************************************* // misc **************************************************************************/ void e_help(void) { if (opt_pgm == PGM_LZOP) help(); else if (opt_pgm == PGM_UNLZOP) help(); else if (opt_pgm == PGM_OCAT) { if (opt_stdin) check_stdin(&fi); if (opt_stdout) check_stdout(&fo); usage(); } else help(); e_exit(EXIT_USAGE); } void set_term(FILE *f) { if (f) con_term = f; else con_term = acc_isatty(STDOUT_FILENO) ? stdout : stderr; } void set_cmd(int cmd) { if (cmd == CMD_COMPRESS && (opt_pgm == PGM_UNLZOP || opt_pgm == PGM_OCAT)) return; #if 0 if (opt_cmd != CMD_NONE && cmd != opt_cmd) { fprintf(stderr,"%s: multiple commands given\n",argv0); e_usage(); } opt_cmd = cmd; #else /* gzip: commands have a certain priority */ if (cmd > opt_cmd) opt_cmd = cmd; #endif } lzo_bool set_method(int m, int l) { if (x_set_method(m,l) != 0) return 0; set_cmd(CMD_COMPRESS); return 1; } void set_output_name(const char *n, lzo_bool allow_m) { #if 1 if (done_output_name > 0) { fprintf(stderr,"%s: option '-o' more than once given\n",argv0); e_usage(); } #endif if (!n || !n[0] || (!allow_m && n[0] == '-')) { fprintf(stderr,"%s: missing output name\n",argv0); e_usage(); } if (strlen(n) >= PATH_MAX) { fprintf(stderr,"%s: output name too long\n",argv0); e_usage(); } opt_output_name = n; done_output_name++; } void set_output_path(const char *n, lzo_bool allow_m) { int r; struct stat st; file_t f; #if 1 if (done_output_path > 0) { fprintf(stderr,"%s: option '-p' more than once given\n",argv0); e_usage(); } #endif if (!n || (!allow_m && n[0] == '-')) { fprintf(stderr,"%s: missing path\n",argv0); e_usage(); } if (strlen(n) >= PATH_MAX) { fprintf(stderr,"%s: path too long\n",argv0); e_usage(); } if (n[0]) { r = stat(n, &st); if (r != 0) { strcpy(f.name,n); p_fatal(&f,"invalid path"); } #if defined(S_ISDIR) if (!S_ISDIR(st.st_mode)) { strcpy(f.name,n); fatal(&f,"invalid path - must be a directory"); } #endif } #if defined(HAVE_ACCESS) && defined(W_OK) { const char *p = n[0] ? n : "."; if (access(p,W_OK) != 0) { strcpy(f.name,p); p_fatal(&f,"can't write to path"); } } #endif opt_output_path = n; done_output_path++; } lzo_bool set_suffix(const char *n) { size_t l; const char *p; static const char * const invalid_suffixes[] = { "ace", "arc", "arj", "bz", "bz2", "gz", "lha", "lzh", #if !defined(NRVP) "nrv", "tnv", #endif "rar", "raw", "sz", "tar", "taz", "tbz", "tgz", "tsz", "upx", "Z", "zip", "zoo", NULL }; const char * const *is = invalid_suffixes; #if 1 if (done_suffix > 0) { fprintf(stderr,"%s: option '-S' more than once given\n",argv0); e_usage(); return 0; } #endif while (n && *n == '.') n++; if (!n || *n == 0 || *n == '-') return 0; #if 1 || defined(DOSISH) if (strchr(n,'.')) return 0; #endif for (p = n; *p; p++) if (strchr("+*?=/\\ \t\n\r\a", *p)) return 0; for ( ; *is; is++) if (strcasecmp(n,*is) == 0) return 0; l = strlen(n); if (l + 1 > SUFFIX_MAX || (opt_shortname && l > 3)) { fprintf(stderr,"%s: suffix '%s' is too long\n",argv0,n); e_usage(); return 0; } opt_suffix[0] = '.'; strcpy(opt_suffix + 1, n); done_suffix++; return 1; } /************************************************************************* // get options **************************************************************************/ static char* prepare_shortopts(char *buf, const char *n, const struct acc_getopt_longopt_t *longopts) { char *o = buf; for ( ; n && *n; n++) if (*n != ' ') *o++ = *n; *o = 0; for ( ; longopts && longopts->name; longopts++) { int v = longopts->val; if (v > 0 && v < 256 && strchr(buf,v) == NULL) { *o++ = (char) v; if (longopts->has_arg >= 1) *o++ = ':'; if (longopts->has_arg >= 2) *o++ = ':'; *o = 0; } } return buf; } static int do_option(acc_getopt_p g, int optc) { #define mfx_optarg g->optarg int i = 0; int m = -1; switch (optc) { case 'c': opt_stdout = 1; break; case 'C': opt_checksum = (opt_checksum >= 1) ? opt_checksum + 1 : 1; opt_decompress_safe = 1; break; case 'd': set_cmd(CMD_DECOMPRESS); break; case 'f': opt_force++; break; case 'F': opt_checksum = 0; opt_decompress_safe = 0; break; case 'h': case 'H': case '?': set_cmd(CMD_HELP); break; case 'h'+256: /* according to GNU standards */ set_term(stdout); opt_console = CON_NONE; help(); e_exit(EXIT_OK); break; case 'i': case 'i'+256: set_cmd(CMD_INFO); break; case 'I': set_cmd(CMD_SYSINFO); break; case 'k': opt_keep = 1; break; case 'l': set_cmd(CMD_LIST); break; case 'L': set_cmd(CMD_LICENSE); break; case 'n': opt_name = 0; opt_path = 0; break; case 'N': opt_name = 1; break; case 'o': set_output_name(mfx_optarg,1); break; case 'p': case 'p'+256: if (mfx_optarg && mfx_optarg[0]) set_output_path(mfx_optarg,0); else if (optc == 'p') set_output_path("",0); else set_output_path(NULL,0); break; case 'P': opt_path = 1; opt_name = 1; break; case 'q': opt_verbose = 0; break; case 'S': if (!set_suffix(mfx_optarg)) { fprintf(stderr,"%s: invalid suffix '%s'\n",argv0,mfx_optarg); e_usage(); } break; case 't': set_cmd(CMD_TEST); break; case 'T': if (!(mfx_optarg && isdigit(mfx_optarg[0]))) { fprintf(stderr,"%s: invalid '--threads=' args: '%s'\n",argv0,mfx_optarg); e_usage(); } opt_num_threads = atoi(mfx_optarg); if (opt_num_threads < 1 || opt_num_threads > MAX_NUM_THREADS) { fprintf(stderr,"%s: invalid number of threads: %d\n",argv0,opt_num_threads); e_usage(); } #if !defined(WITH_THREADS) opt_num_threads = 1; #endif break; case 'U': opt_unlink = 1; break; case 'v': opt_verbose = (opt_verbose < 2) ? 2 : opt_verbose + 1; break; case 'V': set_cmd(CMD_VERSION); break; case 'V'+256: /* according to GNU standards */ set_term(stdout); opt_console = CON_NONE; fprintf(stdout,"lzop %s\n",LZOP_VERSION_STRING); fprintf(stdout,"LZO library %s\n",lzo_version_string()); fprintf(stdout,"Copyright (C) 1996-2010 Markus Franz Xaver Johannes Oberhumer\n"); e_exit(EXIT_OK); break; case 'x': set_cmd(CMD_DECOMPRESS); opt_name = 1; opt_path = 1; opt_restore_mode = 1; opt_restore_time = 1; if (!opt_output_name && !opt_output_path) { set_output_path("",0); --done_output_path; } opt_unlink = 0; break; case 'Z'+256: set_cmd(CMD_LS); if (mfx_optarg && mfx_optarg[0]) { opt_ls_flags = mfx_optarg; for (i = 0; opt_ls_flags[i]; i++) if (!strchr("FGQ",opt_ls_flags[i])) { fprintf(stderr,"%s: invalid '--ls' flags: '%s'\n",argv0,mfx_optarg); e_usage(); } } break; #ifdef MAINT case 520: opt_noheader++; break; #endif case 522: opt_stdin = 0; break; case 523: opt_restore_mode = 0; break; case 524: opt_restore_time = 0; break; case 525: opt_nowarn = 1; break; case 526: opt_ignorewarn = 1; break; case 527: opt_crc32 = 1; break; case 512: opt_console = CON_NONE; break; case 513: opt_console = CON_ANSI_MONO; break; case 514: opt_console = CON_ANSI_COLOR; break; case 515: set_cmd(CMD_INTRO); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!set_method(0,optc - '0')) e_method(optc); break; #if defined(WITH_NRV) case 811: if (m < 0) m = M_NRV1A; /* fallthrough */ case 812: if (m < 0) m = M_NRV1B; /* fallthrough */ case 813: if (m < 0) m = M_NRV2A; /* fallthrough */ case 814: if (m < 0) m = M_NRV2B; i = 1; if (mfx_optarg && isdigit(mfx_optarg[0]) && !mfx_optarg[1]) i = mfx_optarg[0] - '0'; if (!set_method(m,i)) e_usage(); break; #endif #if defined(WITH_ZLIB) case 801: i = 6; if (mfx_optarg && mfx_optarg[0] && !mfx_optarg[1]) i = mfx_optarg[0] - '0'; if (!set_method(M_ZLIB,i)) e_usage(); break; #endif case 521: if (!(mfx_optarg && isdigit(mfx_optarg[0]))) { fprintf(stderr,"%s: invalid '--filter=' args: '%s'\n",argv0,mfx_optarg); e_usage(); } if (strcmp(mfx_optarg,"0") == 0) { opt_filter = 0; break; } opt_filter = atoi(mfx_optarg); if (opt_filter < 1 || opt_filter > 16) { fprintf(stderr,"%s: invalid filter: %d\n",argv0,opt_filter); e_usage(); } break; case '\0': return -1; case ':': return -2; default: fprintf(stderr,"%s: internal error in getopt (%d)\n",argv0,optc); return -3; } UNUSED(i); UNUSED(m); return 0; #undef mfx_optarg } static void handle_opterr(acc_getopt_p g, const char *f, void *v) { struct A { va_list ap; }; struct A *a = (struct A *) v; fprintf( stderr, "%s: ", g->progname); if (a) vfprintf(stderr, f, a->ap); else fprintf( stderr, "UNKNOWN GETOPT ERROR"); fprintf( stderr, "\n"); } static int get_options(int argc, char **argv) { static const struct acc_getopt_longopt_t longopts[] = { {"best", 0, 0, '9'}, /* compress better */ {"decompress", 0, 0, 'd'}, /* decompress */ {"fast", 0, 0, '1'}, /* compress faster */ {"help", 0, 0, 'h'+256}, /* give help */ {"info", 0, 0, 'i'+256}, {"license", 0, 0, 'L'}, /* display software license */ {"list", 0, 0, 'l'}, /* list .lzo file contents */ {"ls", 2, 0, 'Z'+256}, /* list .lzo file contents */ {"sysinfo", 0, 0, 'I'}, {"test", 0, 0, 't'}, /* test compressed file integrity */ {"uncompress", 0, 0, 'd'}, /* decompress */ {"version", 0, 0, 'V'+256}, /* display version number */ #if defined(WITH_NRV) {"nrv1a", 0x22, 0, 811}, {"nrv2a", 0x22, 0, 813}, {"nrv2b", 0x22, 0, 814}, #endif #if defined(WITH_ZLIB) {"zlib", 0x22, 0, 801}, #endif {"checksum", 0, 0, 'C'}, {"crc32", 0x10, 0, 527}, /* use a crc32 checksum instead of adler32 */ {"delete", 0, 0, 'U'}, {"extract", 0, 0, 'x'}, {"filter", 1, 0, 521}, {"force", 0, 0, 'f'}, /* force overwrite of output file */ {"ignore-warn",0, 0, 526}, /* ignore any warnings */ {"keep", 0, 0, 'k'}, {"name", 0, 0, 'N'}, /* restore original name */ {"no-checksum",0, 0, 'F'}, #ifdef MAINT {"no-header", 0, 0, 520}, #endif {"no-mode", 0, 0, 523}, /* don't restore original mode */ {"no-name", 0, 0, 'n'}, /* don't restore original name */ {"no-stdin", 0, 0, 522}, {"no-time", 0, 0, 524}, /* don't restore original time */ {"no-warn", 0, 0, 525}, /* do not display any warnings */ {"output", 1, 0, 'o'}, {"path", 1, 0, 'p'+256}, {"quiet", 0, 0, 'q'}, /* quiet mode */ {"silent", 0, 0, 'q'}, /* quiet mode */ {"stdout", 0, 0, 'c'}, /* write output on standard output */ {"suffix", 1, 0, 'S'}, /* use given suffix instead of .lzo */ {"threads", 0x21, 0, 'T'}, /* number of threads */ {"to-stdout", 0, 0, 'c'}, /* write output on standard output */ {"unlink", 0, 0, 'U'}, {"verbose", 0, 0, 'v'}, /* verbose mode */ {"no-color", 0, 0, 512}, {"mono", 0, 0, 513}, {"color", 0, 0, 514}, {"intro", 0, 0, 515}, { 0, 0, 0, 0 } }; acc_getopt_t mfx_getopt; int optc; int i; char shortopts[128]; prepare_shortopts(shortopts, "123456789hH?PVp::", longopts), acc_getopt_init(&mfx_getopt, 1, argc, argv); mfx_getopt.progname = argv0; mfx_getopt.opterr = handle_opterr; while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, NULL)) >= 0) { if (do_option(&mfx_getopt, optc) != 0) e_usage(); } /* accept "-" as synonym for stdin */ for (i = mfx_getopt.optind; i < argc; i++) if (strcmp(argv[i], "-") == 0) opt_stdin = OPT_STDIN_REQUESTED; for (i = mfx_getopt.optind; i < argc; i++) if (strcmp(argv[i], "-") != 0) break; return i; } #if defined(OPTIONS_VAR) static void get_envoptions(int argc, char **argv) { /* only some options are allowed in the environment variable */ static const struct acc_getopt_longopt_t longopts[] = { {"best", 0, 0, '9'}, /* compress better */ {"checksum", 0, 0, 'C'}, {"crc32", 0x10, 0, 527}, /* use a crc32 checksum instead of adler32 */ {"delete", 0, 0, 'U'}, {"fast", 0, 0, '1'}, /* compress faster */ {"ignore-warn",0, 0, 526}, /* ignore any warnings */ {"keep", 0, 0, 'k'}, {"name", 0, 0, 'N'}, /* restore original name */ {"no-checksum",0, 0, 'F'}, {"no-mode", 0, 0, 523}, /* don't restore original mode */ {"no-name", 0, 0, 'n'}, /* don't restore original name */ {"no-time", 0, 0, 524}, /* don't restore original time */ {"no-stdin", 0, 0, 522}, {"no-warn", 0, 0, 525}, /* do not display any warnings */ {"quiet", 0, 0, 'q'}, /* quiet mode */ {"silent", 0, 0, 'q'}, /* quiet mode */ {"threads", 0x21, 0, 'T'}, /* number of threads */ {"unlink", 0, 0, 'U'}, {"verbose", 0, 0, 'v'}, /* verbose mode */ {"no-color", 0, 0, 512}, {"mono", 0, 0, 513}, {"color", 0, 0, 514}, { 0, 0, 0, 0 } }; char *env, *p; int i, optc; int nargc; char **nargv = NULL; static const char sep[] = " \t"; acc_getopt_t mfx_getopt; char shortopts[128]; env = (char *) getenv(OPTIONS_VAR); if (env == NULL || !env[0]) return; p = (char *) malloc(strlen(env)+1); if (p == NULL) return; strcpy(p,env); env = p; nargc = 1; for (;;) { while (*p && strchr(sep,*p)) p++; if (*p == '\0') break; nargc++; while (*p && !strchr(sep,*p)) p++; if (*p == '\0') break; p++; } if (nargc > 1) nargv = (char **) calloc(nargc+1,sizeof(char *)); if (nargv == NULL) { free(env); return; } nargv[0] = argv[0]; p = env; nargc = 1; for (;;) { while (*p && strchr(sep,*p)) p++; if (*p == '\0') break; nargv[nargc++] = p; while (*p && !strchr(sep,*p)) p++; if (*p == '\0') break; *p++ = '\0'; } nargv[nargc] = NULL; #if 0 /* debug */ fprintf(stderr,"%3d\n",nargc); for (i = 0; i <= nargc; i++) fprintf(stderr,"%3d '%s'\n",i,nargv[i]); #endif for (i = 1; i < nargc; i++) if (nargv[i][0] != '-' || !nargv[i][1] || strcmp(nargv[i],"--") == 0) e_envopt(nargv[i]); prepare_shortopts(shortopts, "123456789P", longopts); acc_getopt_init(&mfx_getopt, 1, nargc, nargv); mfx_getopt.progname = argv0; mfx_getopt.opterr = handle_opterr; while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, NULL)) >= 0) { if (do_option(&mfx_getopt, optc) != 0) e_envopt(NULL); } if (mfx_getopt.optind < nargc) e_envopt(nargv[mfx_getopt.optind]); free(nargv); free(env); UNUSED(argc); if (opt_checksum) opt_checksum = -1; /* reset to default */ } #endif /* defined(OPTIONS_VAR) */ #define ACC_WANT_ACC_CHK_CH 1 #undef ACCCHK_ASSERT #include "miniacc.h" #undef ACCCHK_ASSERT static void sanity_check(void) { #if (ACC_CC_MSC && ((_MSC_VER) < 700)) #else #define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT(expr) #include "miniacc.h" #endif #undef ACCCHK_ASSERT #undef ACC_WANT_ACC_CHK_CH } /************************************************************************* // main entry point **************************************************************************/ int __acc_cdecl_main main(int argc, char *argv[]) { int i; lzo_bool foreground = 0; static char default_argv0[] = "lzop"; int cmdline_cmd = CMD_NONE; sanity_check(); #if defined(__MINT__) __binmode(1); __set_binmode(stdout, 0); __set_binmode(stderr, 0); #endif acc_wildargv(&argc, &argv); #if defined(__DJGPP__) opt_shortname = !_USE_LFN; #elif (ACC_OS_DOS16 || ACC_OS_WIN16 || ACC_OS_DOS32) opt_shortname = 1; #endif current_time = fix_time(time(NULL)); if (!argv[0] || !argv[0][0]) argv[0] = default_argv0; argv0 = argv[0]; progname = fn_basename(argv0); #if defined(DOSISH) if (strcasecmp(progname,"lzop.exe") == 0) progname = default_argv0; else if (strcasecmp(progname,"lzop.ttp") == 0) progname = default_argv0; #endif /* For compatibility with gzip, use program name as an option. */ if (strncasecmp(progname, "un", 2) == 0) /* unlzop */ opt_pgm = PGM_UNLZOP; #if 0 if (progname[0] && strcasecmp(progname+1, "cat") == 0) /* ocat */ opt_pgm = PGM_OCAT; #endif set_term(stderr); opt_stdin = acc_isatty(STDIN_FILENO) ? 0 : OPT_STDIN_GUESSED; UNUSED(foreground); #ifdef SIGINT foreground = signal(SIGINT, SIG_IGN) != SIG_IGN; if (foreground) (void) signal(SIGINT, e_sighandler); #endif #ifdef SIGBREAK if (foreground) (void) signal(SIGBREAK, e_sighandler); #endif #ifdef SIGTERM if (signal(SIGTERM, SIG_IGN) != SIG_IGN) (void) signal(SIGTERM, e_sighandler); #endif #ifdef SIGHUP if (signal(SIGHUP, SIG_IGN) != SIG_IGN) (void) signal(SIGHUP, e_sighandler); #endif #if defined(HAVE_UMASK) u_mask = (MODE_T) umask(0700); (void) umask(u_mask); #endif u_mask &= 0777; #if defined(WITH_LZO) if (lzo_init() != LZO_E_OK) { head(); fprintf(stderr,"lzo_init() failed - check your LZO installation !\n"); if (LZO_VERSION != lzo_version()) fprintf(stderr,"library version conflict (%x, %x) - check your LZO installation !\n", LZO_VERSION, lzo_version()); e_exit(EXIT_LZO_INIT); } #if 0 if (lzo_version() < LZO_VERSION) { head(); fprintf(stderr,"library version conflict (%x, %x) - check your LZO installation !\n", LZO_VERSION, lzo_version()); e_exit(EXIT_LZO_INIT); } #endif #endif #if defined(WITH_NRV) if (nrv_init() != NRV_E_OK) { e_exit(EXIT_LZO_INIT); } #endif ACC_COMPILE_TIME_ASSERT(sizeof(lzo_uint32) >= 4) #if defined(SIZEOF_SIZE_T) ACC_COMPILE_TIME_ASSERT(sizeof(size_t) == SIZEOF_SIZE_T) #endif ACC_COMPILE_TIME_ASSERT(sizeof(fi.name) >= 2*(PATH_MAX)) assert(STDIN_FILENO >= 0); assert(STDOUT_FILENO >= 0); assert(STDERR_FILENO >= 0); f_init(); #if defined(OPTIONS_VAR) get_envoptions(argc,argv); #endif assert(cmdline_cmd == CMD_NONE); i = get_options(argc,argv); assert(i <= argc); set_term(NULL); cmdline_cmd = opt_cmd; switch (opt_cmd) { case CMD_NONE: /* For compatibility with gzip, use program name as an option. */ if (opt_pgm == PGM_UNLZOP) { set_cmd(CMD_DECOMPRESS); break; } #if 0 if (opt_pgm == PGM_OCAT) { set_cmd(CMD_DECOMPRESS); if (i == argc) opt_stdin = OPT_STDIN_REQUESTED; if (!opt_output_name) opt_stdout = 1; break; } #endif /* default - compress */ if (!set_method(0,3)) e_method('3'); break; case CMD_COMPRESS: break; case CMD_DECOMPRESS: break; case CMD_TEST: opt_checksum = 1; opt_decompress_safe = 1; break; case CMD_LIST: break; case CMD_LS: break; case CMD_INFO: break; case CMD_SYSINFO: sysinfo(); e_exit(EXIT_OK); break; case CMD_LICENSE: license(); e_exit(EXIT_OK); break; case CMD_HELP: help(); e_exit(EXIT_OK); break; case CMD_INTRO: opt_console = CON_SCREEN; (void) ((con_intro(con_term) || (help(), 0))); e_exit(EXIT_OK); case CMD_VERSION: version(); e_exit(EXIT_OK); break; default: /* ??? */ break; } if (opt_cmd != CMD_COMPRESS) { opt_method = 0; opt_level = 0; opt_filter = 0; } if (!opt_stdin && !opt_stdout && opt_verbose > 0) { if (argc == 1) { /* no arguments */ (void) (opt_pgm == PGM_LZOP && con_intro(con_term)); e_help(); } #if 0 else if (cmdline_cmd == CMD_NONE && i == argc) { /* no command and no file */ e_help(); } #endif } set_term(stderr); check_options(i,argc); num_files = argc - i; if (!x_enter(NULL)) e_memory(); do_files(i,argc,argv); x_leave(NULL); do_exit(); return exit_code; } /* vi:ts=4:et */