#include <string.h>
#include <ctype.h>
#include <errno.h>
-#include <dirent.h>
#include <sys/stat.h>
+#include <time.h>
+#include <utime.h>
+#include <unistd.h>
#include "ar.h"
-extern char *basename(const char *);
-
struct lha_method methods[] = {
/* id, dicbit, pbit, maxmatch */
/* note: dicbit == 0 means no compress */
+ /* (1U << pbit) > np(dicbit+1) */
{"-lh0-", 0, 0, 0}, /* 0: no compress */
{"-lh1-", 12, 0, 60}, /* 1: 2^12 = 4KB dynamic huffman (LHarc) */
{"-lh2-", 13, 0,256}, /* 2: 2^13 = 8KB dynamic huffman */
{"-lh7-", 16, 5,256}, /* 7: 2^16 = 64KB static huffman (pos and len)*/
{"-lzs-", 11, 0, 17}, /* 8: 2^11 = 2KB (LArc) */
{"-lz5-", 12, 0, 17}, /* 9: 2^12 = 4KB (LArc) */
- {"-lz4-", 0, 0, 0}, /* 1: no compress (LArc) */
- {"-lhd-", 0, 0, 0}, /* 1: directory */
+ {"-lz4-", 0, 0, 0}, /*10: no compress (LArc) */
+ {"-lhd-", 0, 0, 0}, /*11: directory */
};
struct lha_opts opts;
return NULL;
}
-init_opts()
-{
- opts.nocompress = 0;
- opts.outdir = NULL;
- opts.quiet = 0;
- opts.header_level = 2;
- opts.generic = 0;
- opts.verbose = 0;
-
- /* default is the -lh5- method */
- opts.method = &methods[5];
-}
-
-#define FNAME_MAX (255 - 25) /* max strlen(filename) */
-
-int unpackable; /* global, set in io.c */
-ulong compsize, origsize; /* global */
-
-static char *temp_name;
-
static void
print_usage()
{
exit(0);
}
-static uint
+uint
ratio(ulong a, ulong b)
{ /* [(1000a + [b/2]) / b] */
int i;
return (uint) ((a + (b >> 1)) / b);
}
-static char*
-os_string(char id)
-{
- int i;
- static struct os {
- char id;
- char *name;
- } os_types[] = {
- {'M', "MS-DOS"}, /* Microsoft */
- {'U', "Unix"}, /* Unix or POSIX compliant OS */
- {'J', "Java"}, /* Sun Microsystems */
- {'\0', "generic"},
- {'w', "Win9x"}, /* reserved by UNLHA32.DLL */
- {'W', "WinNT"}, /* reserved by UNLHA32.DLL */
- {'2', "OS/2"}, /* IBM OS/2 */
- {'9', "OS9"}, /* unknown */
- {'K', "OS/68K"}, /* unknown */
- {'3', "OS/386"}, /* unknown */
- {'H', "Human"}, /* SHARP Human68K */
- {'C', "CP/M"}, /* Digital Research */
- {'F', "FLEX"}, /* unknown */
- {'m', "Mac"}, /* Apple */
- {'R', "Runser"}, /* unknown */
- {'T', "TownsOS"}, /* Fujitsu FM-TOWNS */
- {'X', "XOSK"}, /* unknown */
- };
-
- for (i = 0; i < sizeof(os_types)/sizeof(os_types[0]); i++) {
- if (id == os_types[i].id)
- return os_types[i].name;
- }
-
- return "Unknown";
-}
-
-static void
-put_to_header(char *buf, int i, int n, ulong x)
-{
- while (--n >= 0) {
- buf[i++] = (uchar) ((uint) x & 0xFF);
- x >>= 8;
- }
-}
-
-static ulong
-get_from_header(char *buf, int i, int n)
-{
- ulong s;
-
- s = 0;
- while (--n >= 0)
- s = (s << 8) + buf[i + n]; /* little endian */
- return s;
-}
-
-static uint
-calc_headersum(char *buf, int size)
-{
- int i;
- uint s;
-
- s = 0;
- for (i = 0; i < size; i++)
- s += buf[i];
- return s & 0xFF;
-}
-
-int
-get_byte(char *buf)
-{
- return *(unsigned char*)buf;
-}
-
-uint16_t
-get_word(char *buf)
-{
- return get_byte(buf) | (get_byte(buf+1) << 8);
-}
-
-uint32_t
-get_dword(char *buf)
-{
- return get_byte(buf) |
- (get_byte(buf+1) << 8) |
- (get_byte(buf+2) << 16) |
- (get_byte(buf+3) << 24);
-}
-
-void
-get_char(char *buf, char *p, size_t size)
-{
- memcpy(p, buf, size);
-}
-
-void
-put_byte(char *buf, int c)
-{
- *buf = (unsigned char)(c & 0xff);
-}
-
-void
-put_word(char *buf, uint16_t c)
-{
- put_byte(buf, c);
- put_byte(buf+1, c>>8);
-}
-
-void
-put_dword(char *buf, uint32_t c)
-{
- put_byte(buf, c);
- put_byte(buf+1, c>>8);
- put_byte(buf+2, c>>16);
- put_byte(buf+3, c>>24);
-}
-
-void
-put_char(char *buf, char *p, size_t size)
-{
- memcpy(buf, p, size);
-}
-
-static int
-read_header_lv0(FILE *fp, char *buf, struct lzh_header *h)
-{
- int headersize;
- int headersum;
- int ext_headersize;
-
- headersize = get_byte(&buf[0]);
- headersum = get_byte(&buf[1]);
-
- fread_crc(buf + 21, headersize - (21 - 2), fp); /* CRC not used */
-
- buf += 2;
-
- if (calc_headersum(buf, headersize) != headersum)
- error("Header sum error");
-
- get_char(&buf[0], h->method, 5);
- h->compsize = get_dword(&buf[5]);
- h->origsize = get_dword(&buf[9]);
- h->ftime = get_dword(&buf[13]);
- /* attrib = get_byte(&buf[17]); */
- h->level = get_byte(&buf[18]); /* header level */
- h->namelen = get_byte(&buf[19]);
- get_char(&buf[20], h->filename, h->namelen);
- h->filename[h->namelen] = 0;
- h->file_crc = get_word(&buf[20+h->namelen]);
- h->os_id = 0; /* generic */
-
- return 1; /* success */
-}
-
-static int
-read_header_lv1(FILE *fp, char *buf, struct lzh_header *h)
-{
- int headersize;
- int headersum;
- int ext_headersize;
-
- headersize = get_byte(&buf[0]);
- headersum = get_byte(&buf[1]);
-
- fread_crc(buf + 21, headersize - (21 - 2), fp); /* CRC not used */
-
- buf += 2;
-
- if (calc_headersum(buf, headersize) != headersum)
- error("Header sum error");
-
- get_char(&buf[0], h->method, 5);
- h->compsize = get_dword(&buf[5]);
- h->origsize = get_dword(&buf[9]);
- h->ftime = get_dword(&buf[13]);
- /* attrib = get_byte(&buf[17]); */
- h->level = get_byte(&buf[18]); /* header level */
- h->namelen = get_byte(&buf[19]);
- get_char(&buf[20], h->filename, h->namelen);
- h->filename[h->namelen] = 0;
- h->file_crc = get_word(&buf[20+h->namelen]);
- h->os_id = get_byte(&buf[20+h->namelen+2]);
-
- ext_headersize = get_word(&buf[20+h->namelen+3]);
-
- while (ext_headersize != 0) {
- fprintf(stderr, "There's an extended header of size %u.\n",
- ext_headersize);
- h->compsize -= ext_headersize;
-
- /* skip ext header */
- if (fseek(arcfile, ext_headersize - 2, SEEK_CUR))
- error("Can't read");
- ext_headersize = fgetc(arcfile);
- ext_headersize += (uint) fgetc(arcfile) << 8;
- }
-
- return 1; /* success */
-}
-
-static int
-read_header_lv2(FILE *fp, char *buf, struct lzh_header *h)
-{
- int headersize;
- int headersum;
- int ext_headersize;
- char extbuf[1024];
- uchar ext_type;
- int remainder;
- char dirname[1024] = "";
- int dirnamelen = 0;
-
- headersize = get_word(&buf[0]);
-
- fread_crc(buf + 21, 26 - 21, fp); /* CRC not used */
-
- get_char(&buf[2], h->method, 5);
- h->compsize = get_dword(&buf[7]);
- h->origsize = get_dword(&buf[11]);
- h->ftime = get_dword(&buf[15]);
- /* attrib = get_byte(&buf[19]); */
- h->level = get_byte(&buf[20]); /* header level */
- h->file_crc = get_word(&buf[21]);
- h->os_id = get_byte(&buf[23]);
-
- ext_headersize = get_word(&buf[24]);
-
- remainder = headersize - 26;
-
- while (ext_headersize != 0) {
- char *p = extbuf;
-
- remainder -= ext_headersize;
-
- fread_crc(p, ext_headersize, fp);
- ext_type = get_byte(p++);
- switch (ext_type) {
- case 0:
- /* header crc */
- break;
- case 1:
- /* filename header */
- h->namelen = ext_headersize - 3;
- get_char(p, h->filename, h->namelen);
- h->filename[h->namelen] = 0;
- break;
- case 2:
- /* dirname header */
- dirnamelen = ext_headersize - 3;
- get_char(p, dirname, dirnamelen);
- dirname[dirnamelen] = 0;
- break;
- }
- ext_headersize = get_word(&extbuf[ext_headersize - 2]);
- }
- if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
- dirname[dirnamelen++] = '/';
- }
-
- strcat(dirname, h->filename);
- h->namelen = strlen(dirname);
- strcpy(h->filename, dirname);
-
- while (remainder > 0) {
- fgetc(fp); /* skip padding */
- remainder--;
- }
-
- return 1; /* success */
-}
-
-static int
-read_header(FILE *fp, struct lzh_header *h)
-{
- int headersize;
- int headersum;
- char buf[4096];
- int ext_headersize;
- int ret;
-
- ret = fgetc(fp);
- buf[0] = (uchar)ret;
- if (buf[0] == 0 || ret == EOF)
- return 0; /* end of archive */
- fread_crc(buf + 1, 21 - 1, fp);
- switch (buf[20]) {
- case 0:
- return read_header_lv0(fp, buf, h);
- break;
- case 1:
- return read_header_lv1(fp, buf, h);
- break;
- case 2:
- return read_header_lv2(fp, buf, h);
- break;
- default:
- error("unknown level (%d)\n", buf[20]);
- break;
- }
-
- return 1; /* success */
-}
-
-
-void
-write_header_lv0(FILE *fp, struct lzh_header *h)
-{
- char buf[4096], *p = buf;
- int sum;
- int headersize;
-
- headersize = 22 + h->namelen;
-
- put_byte(&buf[0], 0); /* dummy */
- put_byte(&buf[1], 0); /* dummy */
- put_char(&buf[2], h->method, 5);
- put_dword(&buf[7], h->compsize); /* packed size */
- put_dword(&buf[11], h->origsize); /* original size */
- put_dword(&buf[15], h->ftime); /* ftime */
- put_byte(&buf[19], 0x20); /* attribute */
- put_byte(&buf[20], 0); /* level */
- put_byte(&buf[21], h->namelen); /* length of pathname */
- put_char(&buf[22], h->filename, h->namelen);
- put_word(&buf[22+h->namelen], h->file_crc);
-
- headersize += 0; /* size of ext-header (old style) */
- put_byte(&buf[0], headersize);
-
- sum = calc_headersum(buf+2, headersize);
- put_byte(&buf[1], sum);
-
- fwrite_crc(buf, headersize+2, fp);
-}
-
void
-write_header_lv1(FILE *fp, struct lzh_header *h)
-{
- char buf[4096], *p = buf;
- int sum;
- int headersize;
-
- headersize = 25 + h->namelen;
-
- put_byte(&buf[0], headersize);
- put_byte(&buf[1], 0); /* dummy */
- put_char(&buf[2], h->method, 5);
- put_dword(&buf[7], h->compsize); /* packed size */
- put_dword(&buf[11], h->origsize); /* original size */
- put_dword(&buf[15], h->ftime); /* ftime */
- put_byte(&buf[19], 0x20); /* attribute */
- put_byte(&buf[20], 1); /* level */
- put_byte(&buf[21], h->namelen); /* length of pathname */
- put_char(&buf[22], h->filename, h->namelen);
- put_word(&buf[22+h->namelen], h->file_crc);
- if (opts.generic)
- put_byte(&buf[22+h->namelen+2], '\0');
- else
- put_byte(&buf[22+h->namelen+2], 'U');
- put_word(&buf[22+h->namelen+3], 0x0000); /* next header size */
-
- sum = calc_headersum(buf+2, headersize);
- put_byte(&buf[1], sum);
-
- fwrite_crc(buf, headersize+2, fp);
-}
-
-void
-write_header_lv2(FILE *fp, struct lzh_header *h)
-{
- char buf[4096], *p = buf, *crcptr;
- int sum;
- int headersize, next_headersize;
- extern ushort crctable[];
- char dirname[1024] = "", *fname;
- int dirnamelen, len;
-
- put_word(&buf[0], 0); /* dummy */
- put_char(&buf[2], h->method, 5);
- put_dword(&buf[7], h->compsize); /* packed size */
- put_dword(&buf[11], h->origsize); /* original size */
- put_dword(&buf[15], h->ftime); /* time_t */
- put_byte(&buf[19], 0x20); /* DOS attribute (0x20 fixed) */
- put_byte(&buf[20], 2); /* level */
- put_word(&buf[21], h->file_crc);
- if (opts.generic)
- put_byte(&buf[23], '\0');
- else
- put_byte(&buf[23], 'U');
-
- headersize = 24;
-
- /* ext-header */
- p = buf + headersize;
- next_headersize = 3 + 2;
- put_word(p, next_headersize); /* next header size */
- put_byte(p+2, 0); /* 0x00: header crc */
- crcptr = p+3;
- put_word(p+3, 0); /* crc (dummy) */
- headersize += next_headersize;
-
- fname = basename(h->filename);
- len = strlen(fname);
-
- p = buf + headersize;
- next_headersize = 3 + len;
- put_word(p, next_headersize); /* next header size */
- put_byte(p+2, 1); /* 0x01: filename header */
- put_char(p+3, fname, len); /* filename */
- headersize += next_headersize;
-
- {
- char *ptr;
-
- ptr = strrchr(h->filename, '/');
- if (ptr) {
- /* 0123 */
- /* abc/ */
- /* 3 - 0 = 3 */
- dirnamelen = ptr - h->filename;
- strncpy(dirname, h->filename, dirnamelen);
- dirname[dirnamelen+ 1] = 0;
- }
- }
-
- if (*dirname) {
- p = buf + headersize;
- next_headersize = 3 + dirnamelen;
- put_word(p, next_headersize); /* next header size */
- put_byte(p+2, 2); /* 0x02: dirname header */
- put_char(p+3, dirname, dirnamelen); /* dirname */
- headersize += next_headersize;
- }
-
- p = buf + headersize;
- next_headersize = 0;
- put_word(p, next_headersize); /* next header size */
- headersize += next_headersize;
- headersize += 2;
-
- /* padding */
- if (headersize % 256 == 0) {
- put_byte(&buf[headersize], 0);
- headersize++;
- }
-
- put_word(&buf[0], headersize);
-
- crc = INIT_CRC;
- for (p = buf; p - buf < headersize; p++)
- UPDATE_CRC(*p);
-
- put_word(crcptr, crc);
-
- fwrite_crc(buf, headersize, fp);
-}
-
-void
-write_header(FILE *fp, struct lzh_header *h)
-{
- switch (h->level) {
- case 0:
- write_header_lv0(fp, h);
- break;
- case 1:
- write_header_lv1(fp, h);
- break;
- case 2:
- write_header_lv2(fp, h);
- break;
- default:
- error("unknown level (%d)", h->level);
- break;
- }
-}
-
-static void
skip(FILE *fp, struct lzh_header *h)
{
- fseek(fp, h->compsize, SEEK_CUR);
+ int i;
+ if (opts.archive_to_stdio)
+ for (i = 0; i < h->compsize; i++)
+ fgetc(fp);
+ else
+ fseek(fp, h->compsize, SEEK_CUR);
}
static void
}
}
-static void
-store(void)
-{
- uint n;
- uchar buffer[MAXDICSIZ];
-
- origsize = 0;
- crc = INIT_CRC;
- while ((n = fread((char *) buffer, 1, sizeof(buffer), infile)) != 0) {
- fwrite_crc(buffer, n, outfile);
- origsize += n;
- }
- compsize = origsize;
-}
-
-static int
-add_dir(int replace_flag, struct lzh_header *h)
-{
- long headerpos, arcpos;
- uint r;
-
- h->origsize = h->compsize = 0;
- h->file_crc = INIT_CRC;
-
- headerpos = ftell(outfile);
- write_header(outfile, h);
- arcpos = ftell(outfile);
-
- if (opts.quiet < 2)
- printf(" %d.%d%%\n", r / 10, r % 10);
- return 1; /* success */
-}
-
-static int
-add_1(int replace_flag, struct lzh_header *h)
-{
- long headerpos, arcpos;
- uint r;
-
- if ((infile = fopen(h->filename, "rb")) == NULL) {
- fprintf(stderr, "Can't open %s\n", h->filename);
- return 0; /* failure */
- }
- if (replace_flag) {
- if (opts.quiet < 2)
- printf("Replacing %s ", h->filename);
- skip(arcfile, h);
- }
- else {
- if (opts.quiet < 2)
- printf("Adding %s ", h->filename);
- }
-
- headerpos = ftell(outfile);
- write_header(outfile, h);
- arcpos = ftell(outfile);
-
- origsize = compsize = 0;
- crc = INIT_CRC;
- if (opts.nocompress) {
- unpackable = 1;
- }
- else {
- unpackable = 0;
- encode();
- }
-
- if (unpackable) {
- memcpy(h->method, "-lh0-", sizeof(h->method)); /* store */
- rewind(infile);
- fseek(outfile, arcpos, SEEK_SET);
- store();
- }
- h->file_crc = crc ^ INIT_CRC;
- fclose(infile);
-
- h->compsize = compsize;
- h->origsize = origsize;
-
- fseek(outfile, headerpos, SEEK_SET);
- write_header(outfile, h);
- fseek(outfile, 0L, SEEK_END);
- r = ratio(compsize, origsize);
- if (opts.quiet < 2)
- printf(" %d.%d%%\n", r / 10, r % 10);
- return 1; /* success */
-}
-
-static int
-add(int replace_flag, char *filename, int namelen)
-{
- long headerpos, arcpos;
- uint r;
- struct lzh_header h;
- struct stat st;
-
- memset(&h, 0, sizeof(h));
-
- h.level = opts.header_level;
-
- strcpy(h.filename, filename);
- h.namelen = namelen;
-
- stat(h.filename, &st);
-
- if (S_ISDIR(st.st_mode)) {
- DIR *dir;
- struct dirent *ent;
-
- memcpy(h.method, "-lhd-", sizeof(h.method)); /* directory */
- add_dir(replace_flag, &h);
-
- dir = opendir(h.filename);
- if (dir == NULL)
- error("cannot open directory: \"%s\"", h.filename);
-
- while ((ent = readdir(dir)) != 0) {
- char filename[1024];
-
- if (string_equal(ent->d_name, ".") ||
- string_equal(ent->d_name, ".."))
- continue;
-
- h.namelen = path_addsep(h.filename, sizeof(h.filename));
-
- string_cat(filename, sizeof(filename),
- h.filename, ent->d_name, NULL);
-
- add(replace_flag, filename, strlen(filename));
- }
- closedir(dir);
- }
- else {
- memcpy(h.method, opts.method->id, sizeof(h.method)); /* compress */
- add_1(replace_flag, &h);
- }
-}
-
int
get_line(char *s, int n)
{
return i;
}
-static void
-extract(int to_file, struct lzh_header *h)
-{
- int n;
- uint ext_headersize;
- uchar buffer[MAXDICSIZ];
-
- outfile = NULL;
-
- if (to_file) {
- if (memcmp(h->method, "-lhd-", sizeof(h->method)) == 0) {
- /* directory */
- if (mkdir(h->filename, 0777) == -1) {
- if (errno != EEXIST)
- error("cannot make directory \"%s\"", opts.outdir);
- }
- }
- else {
- /* regular file */
- while ((outfile = fopen(h->filename, "wb")) == NULL) {
- fprintf(stderr, "Can't open %s\nNew filename: ", h->filename);
- if (get_line(h->filename, FNAME_MAX) == 0) {
- fprintf(stderr, "Not extracted\n");
- skip(arcfile, h);
- return;
- }
- h->namelen = strlen(h->filename);
- }
- }
- if (opts.quiet < 2)
- printf("Extracting %s ", h->filename);
- }
- else {
- outfile = stdout;
- if (opts.quiet < 2)
- printf("===== %s =====\n", h->filename);
- }
- crc = INIT_CRC;
- opts.method = which_method(h->method);
- if (opts.method == NULL) {
- fprintf(stderr, "Unknown method: %.5s\n", h->method);
- skip(arcfile, h);
- }
- else {
- crc = INIT_CRC;
- if (opts.method->dicbit != 0)
- decode_start();
- while (h->origsize != 0) {
- n = (uint) ((h->origsize > MAXDICSIZ) ? MAXDICSIZ : h->origsize);
- if (opts.method->dicbit != 0)
- decode(n, buffer);
- else if (fread((char *) buffer, 1, n, arcfile) != n)
- error("Can't read");
- fwrite_crc(buffer, n, outfile);
- if (outfile != stdout && opts.quiet < 1) {
- putc('.', stdout);
- }
- h->origsize -= n;
- }
- }
-
- if ((crc ^ INIT_CRC) != h->file_crc)
- error("CRC error");
-
- if (to_file) {
- fprintf(stdout, "\n");
- fclose(outfile);
- }
- else
- outfile = NULL;
-}
-
-static void
-list_start(void)
-{
- if (opts.quiet < 2)
- printf("%-14.14s %-7.7s %10.10s %10.10s %-5.5s %-4.4s %-5.5s %-4.4s\n",
- "Filename",
- "OS",
- "Original",
- "Compressed",
- "Ratio",
- "CRC",
- "Method",
- "Lv");
-}
-
-static void
-list(struct lzh_header *h)
-{
- uint r;
-
- printf("%-14.*s", h->namelen, h->filename);
- if (h->namelen > 14)
- printf("\n ");
- r = ratio(h->compsize, h->origsize);
- printf(" %-7s %10lu %10lu %u.%03u %04x %-6.6s [%d]\n",
- os_string(h->os_id),
- h->origsize,
- h->compsize,
- r / 1000,
- r % 1000,
- h->file_crc,
- h->method,
- h->level);
-}
-
static int
match(char *s1, char *s2)
{
int i;
if (argc == 0)
- return 1;
+ return -1;
for (i = 0; i < argc; i++)
- if (match(h->filename, argv[i]))
- return 1;
+ if (argv[i] && match(h->filename, argv[i]))
+ return i+1;
return 0;
}
-static void
-exitfunc(void)
-{
- fclose(outfile);
- remove(temp_name);
-}
-
#include "getopt_long.h"
-int
+void
parse_args(int argc, char **argv)
{
int c;
for (;;) {
- int this_option_optind = optind ? optind : 1;
+ /* int this_option_optind = optind ? optind : 1; */
int option_index = 0;
enum {
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "012go[567]q[012]vw:z",
+ c = getopt_long(argc, argv, "012fgo[567]q[012]vw:z",
long_options, &option_index);
if (c == -1) break; /* end of parsing options */
/* header level */
opts.header_level = c - '0';
break;
+ case 'f':
+ opts.force_extract = 1;
+ break;
case 'g':
opts.generic = 1;
+ opts.header_level = 0;
break;
case 'o':
/* compress method */
FILE *
open_tempfile()
{
- temp_name = tmpnam(NULL);
- outfile = fopen(temp_name, "wb");
+ FILE *outfile;
+
+ outfile = tmpfile();
if (outfile == NULL)
error("Can't open temporary file");
- atexit(exitfunc);
return outfile;
}
+static void
+op_add(int cmd, char *archive_file, int argc, char **argv)
+{
+ int i, count, found, done;
+ struct lzh_header h;
+ struct lzh_ostream w, *wp;
+ FILE *arcfile = NULL;
+ FILE *outfile = NULL;
+
+ wp = &w;
+
+ count = done = 0;
+
+ outfile = open_tempfile();
+ wp->fp = outfile;
+ wp->buf = 0;
+ if (*argv == 0)
+ error("archived files are not specified.");
+
+ arcfile = fopen(archive_file, "rb");
+ if (arcfile == NULL)
+ error("Can't open archive '%s'", archive_file);
+
+ while (!done && read_header(arcfile, &h)) {
+
+ found = search(argc, argv, &h);
+ if (found>0) {
+ argv[found-1] = 0;
+
+ if (cmd == 'u') {
+ time_t mtime;
+
+ if (file_mtime(h.filename, &mtime) == -1 || h.mtime > mtime) {
+ copy(arcfile, outfile, &h);
+ continue;
+ }
+ }
+
+ if (add(wp, 1, h.filename, h.namelen)) {
+ skip(arcfile, &h);
+ count++;
+ }
+ else
+ copy(arcfile, outfile, &h);
+ }
+ else
+ copy(arcfile, outfile, &h);
+ }
+
+ for (i = 0; i < argc; i++) {
+ if (argv[i]) {
+ count++;
+ add(wp, 0, argv[i], strlen(argv[i]));
+ }
+ }
+
+ if (opts.quiet < 2)
+ printf(" %d files\n", count);
+
+ if (count > 0) {
+ fputc(0, outfile); /* end of archive */
+ if (ferror(outfile))
+ error("Can't write");
+ if (!opts.archive_to_stdio)
+ unlink(archive_file);
+
+ fclose(arcfile);
+ rewind(outfile);
+ if (copy_stream_to_file(outfile, archive_file) == -1)
+ error("fail to copy_stream_to_file(): temp -> %s",archive_file);
+ }
+}
+
+static void
+op_create(int cmd, char *archive_file, int argc, char **argv)
+{
+ int i;
+ struct lzh_ostream w, *wp;
+ FILE *outfile = NULL;
+
+ wp = &w;
+
+ outfile = open_tempfile();
+ wp->fp = outfile;
+ wp->buf = 0;
+ if (*argv == 0)
+ error("archived files are not specified.");
+
+ for (i = 0; i < argc; i++) {
+ add(wp, 0, argv[i], strlen(argv[i]));
+ }
+
+ fputc(0, outfile); /* end of archive */
+ if (ferror(outfile))
+ error("Can't write");
+ rewind(outfile);
+ if (opts.archive_to_stdio) {
+ if (copy_stream(outfile, stdout) == -1)
+ error("fail to copy_stream_to_file(): temp -> %s","stdout");
+ }
+ else {
+ if (copy_stream_to_file(outfile, archive_file) == -1)
+ error("fail to copy_stream_to_file(): temp -> %s",archive_file);
+ }
+
+ return;
+}
+
+static void
+op_delete(int cmd, char *archive_file, int argc, char **argv)
+{
+ int count, found, done;
+ struct lzh_header h;
+ int arc_count;
+ struct lzh_ostream w, *wp;
+ FILE *arcfile = NULL;
+ FILE *outfile = NULL;
+
+ wp = &w;
+
+ count = done = 0;
+
+ if (argc == 0) {
+ message("No files given in argument, do nothing.");
+ return;
+ }
+ outfile = open_tempfile();
+
+ /* Open archive. */
+ if (opts.archive_to_stdio) {
+ arcfile = stdin;
+ }
+ else {
+ arcfile = fopen(archive_file, "rb");
+ }
+ if (arcfile == NULL)
+ error("Can't open archive '%s'", archive_file);
+
+ arc_count = 0;
+
+ while (!done && read_header(arcfile, &h)) {
+
+ arc_count++;
+
+ found = search(argc, argv, &h);
+ if (found) {
+ count++;
+ message("'%s' deleted", h.filename);
+ skip(arcfile, &h);
+ }
+ else
+ copy(arcfile, outfile, &h);
+ }
+
+ if (opts.quiet < 2)
+ printf(" %d files\n", count);
+
+ if (count > 0) {
+ fputc(0, outfile); /* end of archive */
+ if (ferror(outfile))
+ error("Can't write");
+ if (!opts.archive_to_stdio)
+ unlink(archive_file);
+
+ fclose(arcfile);
+ rewind(outfile);
+
+ if (arc_count > count) {
+ if (copy_stream_to_file(outfile, archive_file) == -1)
+ error("fail to copy_stream_to_file(): temp -> %s",archive_file);
+ }
+ else {
+ message("The archive file \"%s\" was removed because it would be empty.", archive_file);
+ }
+ }
+}
+
+static void
+op_extract(int cmd, char *archive_file, int argc, char **argv)
+{
+ int count, nfiles, found, done;
+ struct lzh_header h;
+ struct lzh_istream r, *rp;
+ FILE *arcfile = NULL;
+
+ rp = &r;
+
+ count = done = nfiles = 0;
+
+ /* Open archive. */
+ if (opts.archive_to_stdio) {
+ arcfile = stdin;
+ }
+ else {
+ arcfile = fopen(archive_file, "rb");
+ }
+ if (arcfile == NULL)
+ error("Can't open archive '%s'", archive_file);
+
+ /* change directory to extract dir */
+ if (cmd == 'x') {
+ if (opts.outdir) {
+ if (mkdir(opts.outdir, 0777) == -1) {
+ if (errno != EEXIST)
+ error("cannot make directory \"%s\"", opts.outdir);
+ }
+
+ if (chdir(opts.outdir) == -1)
+ error("cannot change directory \"%s\"", opts.outdir);
+ }
+ }
+
+ while (!done && read_header(arcfile, &h)) {
+
+ found = search(argc, argv, &h);
+ if (found != 0) {
+ rp->fp = arcfile;
+ rp->compsize = h.compsize;
+ extract(rp, cmd == 'x', &h);
+ if (++count == nfiles)
+ done = 1;
+ }
+ else
+ skip(arcfile, &h);
+ }
+
+ if (cmd != 'p') {
+ if (opts.quiet < 2)
+ printf(" %d files\n", count);
+ }
+}
+
+static void
+op_list(int cmd, char *archive_file, int argc, char **argv)
+{
+ int count, nfiles, found, done;
+ struct lzh_header h;
+ struct lzh_istream r, *rp;
+ FILE *arcfile = NULL;
+
+ rp = &r;
+
+ count = done = nfiles = 0;
+
+ /* Open archive. */
+ if (opts.archive_to_stdio) {
+ arcfile = stdin;
+ }
+ else {
+ arcfile = fopen(archive_file, "rb");
+ }
+ if (arcfile == NULL)
+ error("Can't open archive '%s'", archive_file);
+
+ while (!done && read_header(arcfile, &h)) {
+
+ found = search(argc, argv, &h);
+
+ if (found != 0) {
+ if (count == 0)
+ list_start();
+ list(&h);
+ if (++count == nfiles)
+ done = 1;
+ }
+ skip(arcfile, &h);
+ }
+
+ if (opts.quiet < 2)
+ printf(" %d files\n", count);
+}
+
int
main(int argc, char *argv[])
{
- int i, j, cmd, count, nfiles, found, done;
+ int cmd;
char *archive_file;
- struct lzh_header h;
- init_opts();
+ INITIALIZE_OPTS(opts);
if (argv[1] == 0)
print_usage();
archive_file = argv[0];
+ if (strcmp(archive_file, "-") == 0)
+ opts.archive_to_stdio = 1;
+ if (opts.archive_to_stdio)
+ opts.quiet = 2;
+
argv++;
argc--;
- temp_name = NULL;
-
make_crctable();
- count = done = nfiles = 0;
switch (cmd) {
case 'a':
- case 'c':
- outfile = open_tempfile();
- if (*argv == 0)
- error("archived files are not specified.");
- for (i = 0; i < argc; i++) {
- add(0, argv[i], strlen(argv[i]));
+ case 'u':
+ if (opts.archive_to_stdio || !file_exists(archive_file)) {
+ op_create(cmd, archive_file, argc, argv);
}
+ else {
+ op_add(cmd, archive_file, argc, argv);
+ }
+ break;
- fputc(0, outfile); /* end of archive */
- if (ferror(outfile))
- error("Can't write");
- remove(archive_file);
- if (xrename(temp_name, archive_file) == -1)
- error("fail to rename(): %s -> %s",temp_name,archive_file);
-
- exit(0);
+ case 'c':
+ op_create(cmd, archive_file, argc, argv);
break;
- case 'r':
+
case 'd':
- outfile = open_tempfile();
+ op_delete(cmd, archive_file, argc, argv);
+ break;
+
case 'x':
case 'p':
+ op_extract(cmd, archive_file, argc, argv);
+ break;
+
case 'l':
case 'v':
- /* Open archive. */
- arcfile = fopen(archive_file, "rb");
- if (arcfile == NULL)
- error("Can't open archive '%s'", argv[2]);
-
+ op_list(cmd, archive_file, argc, argv);
break;
+
default:
print_usage();
break;
}
-
- /* change directory to extract dir */
- if (cmd == 'x') {
- struct stat *stbuf;
-
- if (opts.outdir) {
- if (mkdir(opts.outdir, 0777) == -1) {
- if (errno != EEXIST)
- error("cannot make directory \"%s\"", opts.outdir);
- }
-
- if (chdir(opts.outdir) == -1)
- error("cannot change directory \"%s\"", opts.outdir);
- }
- }
-
- while (!done && read_header(arcfile, &h)) {
-
- compsize = h.compsize;
- origsize = h.origsize;
-
- found = search(argc, argv, &h);
- switch (cmd) {
- case 'r':
- if (found) {
- if (add(1, *argv, strlen(*argv)))
- count++;
- else
- copy(arcfile, outfile, &h);
- }
- else
- copy(arcfile, outfile, &h);
- break;
- case 'a':
- case 'd':
- if (found) {
- count += (cmd == 'D');
- skip(arcfile, &h);
- }
- else
- copy(arcfile, outfile, &h);
- break;
- case 'x':
- case 'p':
- if (found) {
- extract(cmd == 'x', &h);
- if (++count == nfiles)
- done = 1;
- }
- else
- skip(arcfile, &h);
- break;
- case 'l':
- case 'v':
- if (found) {
- if (count == 0)
- list_start();
- list(&h);
- if (++count == nfiles)
- done = 1;
- }
- skip(arcfile, &h);
- break;
- }
- }
-
- if (cmd != 'p') {
- if (opts.quiet < 2)
- printf(" %d files\n", count);
- }
return EXIT_SUCCESS;
}