signature=c941eaacc313f17809befbc98ab1b68e,lzop/src/lzop.c at master · mirror/lzop · GitHub

/* 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

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

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值