summaryrefslogtreecommitdiff
path: root/src/lzop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lzop.c')
-rw-r--r--src/lzop.c3201
1 files changed, 3201 insertions, 0 deletions
diff --git a/src/lzop.c b/src/lzop.c
new file mode 100644
index 0000000..5571e89
--- /dev/null
+++ b/src/lzop.c
@@ -0,0 +1,3201 @@
+/* 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
+*/
+