#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;
}
-#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)
+void
+skip(FILE *fp, struct lzh_header *h)
{
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";
+ if (opts.archive_to_stdio)
+ for (i = 0; i < h->compsize; i++)
+ fgetc(fp);
+ else
+ fseek(fp, h->compsize, SEEK_CUR);
}
static void
-put_header(char *buf, int *i, int n, uint32_t x)
+copy(FILE *arcfile, FILE *outfile, struct lzh_header *h)
{
- while (--n >= 0) {
- buf[(*i)++] = (uchar) (x & 0xFF);
- x >>= 8;
+ uint n;
+ uchar buffer[MAXDICSIZ];
+
+ write_header(outfile, h);
+ while (h->compsize != 0) {
+ n = (uint) ((h->compsize > sizeof(buffer)) ? sizeof(buffer) : h->compsize);
+ if (fread((char *) buffer, 1, n, arcfile) != n)
+ error("Can't read");
+ if (fwrite((char *) buffer, 1, n, outfile) != n)
+ error("Can't write");
+ h->compsize -= n;
}
}
-static void
-put_header_tmp(char *buf, int i, int n, uint32_t x)
+int
+get_line(char *s, int n)
{
- put_header(buf, &i, n, x);
-}
+ int i, c;
-void
-put_string(char *buf, int *n, size_t size, char *p)
-{
- memcpy(buf + *n, p, size);
- *n += size;
+ i = 0;
+ while ((c = getchar()) != EOF && c != '\n')
+ if (i < n)
+ s[i++] = (char) c;
+ s[i] = '\0';
+ return i;
}
-static uint32_t
-get_header(char *buf, int *i, int size)
+static int
+match(char *s1, char *s2)
{
- uint32_t s;
- int n;
-
- s = 0;
- for (n = size-1; n >= 0; n--) {
- s = (s << 8) + (unsigned char)buf[*i + n]; /* little endian */
+ for (;;) {
+ while (*s2 == '*' || *s2 == '?') {
+ if (*s2++ == '*')
+ while (*s1 && *s1 != *s2)
+ s1++;
+ else if (*s1 == 0)
+ return 0;
+ else
+ s1++;
+ }
+ if (*s1 != *s2)
+ return 0;
+ if (*s1 == 0)
+ return 1;
+ s1++;
+ s2++;
}
- *i += size;
- return s;
-}
-
-void
-get_string(char *buf, int *i, size_t size, char *p)
-{
- memcpy(p, buf + *i, size);
- *i += size;
}
-static uint
-calc_headersum(char *buf, int size)
+static int
+search(int argc, char *argv[], struct lzh_header *h)
{
int i;
- uint s;
-
- s = 0;
- for (i = 0; i < size; i++)
- s += buf[i];
- return s & 0xFF;
-}
-
-#if 0
-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);
+ if (argc == 0)
+ return -1;
+ for (i = 0; i < argc; i++)
+ if (argv[i] && match(h->filename, argv[i]))
+ return i+1;
+ return 0;
}
-void
-get_char(char *buf, char *p, size_t size)
-{
- memcpy(p, buf, size);
-}
+#include "getopt_long.h"
void
-put_byte(char *buf, int c)
+parse_args(int argc, char **argv)
{
- *buf = (unsigned char)(c & 0xff);
-}
+ int c;
-void
-put_word(char *buf, uint16_t c)
-{
- put_byte(buf, c);
- put_byte(buf+1, c>>8);
-}
+ for (;;) {
+ /* int this_option_optind = optind ? optind : 1; */
+ int option_index = 0;
-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);
-}
+ enum {
+ LHA_OPT_HELP = 128,
+ LHA_OPT_VERSION,
+ };
-void
-put_char(char *buf, char *p, size_t size)
-{
- memcpy(buf, p, size);
-}
+ static struct option long_options[] = {
+ /* name, has_arg, *flag, val */
+ /* has_arg:
+ no_argument (0)
+ required_argument (1)
+ optional_argument (2)
+ flag:
+ NULL: getopt_long() return val
+ non-NULL: getopt_long() return 0, and *flag set val.
+ */
+ {"help", no_argument, NULL, LHA_OPT_HELP},
+ {"version", no_argument, NULL, LHA_OPT_VERSION},
+ {0, 0, 0, 0}
+ };
-#endif
-time_t
-ftime_to_time_t(uint32_t ftime)
-{
- struct tm tm;
- /* ftime is time structure on MS-DOS
-
- 32 24 16 8
- 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
- |-------------|-------|---------|---------|-----------|---------|
- year(-1980) month day hour minute second/2
- (1-127) (1-12) (1-31) (0-23) (0-59) (0-29)
- */
-
- memset(&tm, 0, sizeof(tm));
- tm.tm_year = (ftime >> 25) + 1980 - 1900;
- tm.tm_mon = ((ftime >> 21) & 0x0f) - 1;
- tm.tm_mday = (ftime >> 16) & 0x1f;
- tm.tm_hour = (ftime >> 11) & 0x1f;
- tm.tm_min = (ftime >> 5) & 0x3f;
- tm.tm_sec = (ftime & 0x1f) * 2;
-
- return mktime(&tm);
-}
+ c = getopt_long(argc, argv, "012fgo[567]q[012]vw:z",
+ long_options, &option_index);
-uint32_t
-time_t_to_ftime(time_t t)
-{
- struct tm tm;
- /* ftime is time structure on MS-DOS
-
- 32 24 16 8
- 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
- |-------------|-------|---------|---------|-----------|---------|
- year(-1980) month day hour minute second/2
- (1-127) (1-12) (1-31) (0-23) (0-59) (0-29)
- */
-
-#if HAVE_LOCALTIME_R
- localtime_r(&t, &tm);
-#else
- tm = *localtime(&t);
-#endif
-
- return (uint32_t)(tm.tm_year + 1900 - 1980) << 25
- | (uint32_t)(tm.tm_mon + 1) << 21
- | (uint32_t)(tm.tm_mday) << 16
- | (uint32_t)(tm.tm_hour) << 11
- | (uint32_t)(tm.tm_min) << 5
- | (uint32_t)(tm.tm_sec / 2);
-}
+ if (c == -1) break; /* end of parsing options */
+ switch (c) {
+ case '?':
+ print_usage();
+ break;
+ case 0:
+ /* set value by long option */
+ break;
+ case '0': case '1': case '2':
+ /* 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 */
+ {
+ int idx = 1; /* -o means -lh1- method */
-/*
- * level 0 header
- *
- *
- * offset size field name
- * ----------------------------------
- * 0 1 header size [*1]
- * 1 1 header sum
- * ---------------------------------------
- * 2 5 method ID ^
- * 7 4 packed size [*2] |
- * 11 4 original size |
- * 15 2 time |
- * 17 2 date |
- * 19 1 attribute | [*1] header size (X+Y+22)
- * 20 1 level (0x00 fixed) |
- * 21 1 name length |
- * 22 X pathname |
- * X +22 2 file crc (CRC-16) |
- * X +24 Y ext-header(old style) v
- * -------------------------------------------------
- * X+Y+24 data ^
- * : | [*2] packed size
- * : v
- * -------------------------------------------------
- *
- * ext-header(old style)
- * 0 1 ext-type ('U')
- * 1 1 minor version
- * 2 4 UNIX time
- * 6 2 mode
- * 8 2 uid
- * 10 2 gid
- *
- * attribute (MS-DOS)
- * bit1 read only
- * bit2 hidden
- * bit3 system
- * bit4 volume label
- * bit5 directory
- * bit6 archive bit (need to backup)
- *
- */
-static int
-read_header_lv0(FILE *fp, char *buf, struct lzh_header *h)
-{
- int headersize;
- int headersum;
- int ext_headersize;
- int pos = 0;
- int ext_size;
-
- headersize = get_header(buf, &pos, 1);
- headersum = get_header(buf, &pos, 1);
-
- fread_crc(buf + 21, headersize - (21 - pos), fp); /* CRC not used */
-
- if (calc_headersum(buf+pos, headersize) != headersum)
- error("Header sum error");
-
- get_string(buf, &pos, 5, h->method);
- h->compsize = get_header(buf, &pos, 4);
- h->origsize = get_header(buf, &pos, 4);
- h->mtime = ftime_to_time_t(get_header(buf, &pos, 4));
- /* attrib = */ get_header(buf, &pos, 1);
- h->level = get_header(buf, &pos, 1); /* header level */
- h->namelen = get_header(buf, &pos, 1);
- get_string(buf, &pos, h->namelen, h->filename);
- h->filename[h->namelen] = 0;
- h->file_crc = get_header(buf, &pos, 2);
- h->os_id = 0; /* generic */
-
- ext_size = headersize - pos;
-
- if (ext_size > 0) {
- if (ext_size > 1) {
- h->os_id = get_header(buf, &pos, 1);
- ext_size--;
- }
- if (ext_size > 1) {
- get_header(buf, &pos, 1); /* minor version */
- ext_size--;
- }
- if (ext_size > 4) {
- h->mtime = get_header(buf, &pos, 4);
- ext_size -= 4;
- }
- if (ext_size > 2) {
- get_header(buf, &pos, 2); /* mode */
- ext_size -= 2;
- }
- if (ext_size > 2) {
- get_header(buf, &pos, 2); /* uid */
- ext_size -= 2;
- }
- if (ext_size > 2) {
- get_header(buf, &pos, 2); /* gid */
- ext_size -= 2;
- }
- }
+ if (optarg)
+ idx = *optarg - '0'; /* -lh[567]- method */
- return 1; /* success */
-}
+ opts.method = &methods[idx];
+ }
+ break;
+ case 'q':
+ /* quiet mode */
+ opts.quiet = 2; /* -q is equivalent to -q2 */
+ if (optarg)
+ opts.quiet = *optarg - '0';
+ break;
+ case 'v':
+ /* verbose mode */
+ opts.verbose = 1;
+ break;
-/*
- * level 1 header
- *
- *
- * offset size field name
- * -----------------------------------
- * 0 1 header size [*1]
- * 1 1 header sum
- * -------------------------------------
- * 2 5 method ID ^
- * 7 4 skip size [*2] |
- * 11 4 original size |
- * 15 2 time |
- * 17 2 date |
- * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
- * 20 1 level (0x01 fixed) |
- * 21 1 name length |
- * 22 X filename |
- * X+ 22 2 file crc (CRC-16) |
- * X+ 24 1 OS ID |
- * X +25 Y ??? |
- * X+Y+25 2 next-header size v
- * -------------------------------------------------
- * X+Y+27 Z ext-header ^
- * : |
- * ----------------------------------- | [*2] skip size
- * X+Y+Z+27 data |
- * : v
- * -------------------------------------------------
- *
- */
-static int
-read_header_lv1(FILE *fp, char *buf, struct lzh_header *h)
-{
- int headersize;
- int headersum;
- int ext_headersize;
- int pos = 0;
-
- headersize = get_header(buf, &pos, 1);
- headersum = get_header(buf, &pos, 1);
-
- fread_crc(buf + 21, headersize - (21 - 2), fp); /* CRC not used */
-
- if (calc_headersum(&buf[pos], headersize) != headersum)
- error("Header sum error");
-
- get_string(buf, &pos, 5, h->method);
- h->compsize = get_header(buf, &pos, 4);
- h->origsize = get_header(buf, &pos, 4);
- h->mtime = ftime_to_time_t(get_header(buf, &pos, 4));
- get_header(buf, &pos, 1); /* attribute */
- h->level = get_header(buf, &pos, 1); /* header level */
- h->namelen = get_header(buf, &pos, 1);
- get_string(buf, &pos, h->namelen, h->filename);
- h->filename[h->namelen] = 0;
- h->file_crc = get_header(buf, &pos, 2);
- h->os_id = get_header(buf, &pos, 1);
-
- ext_headersize = get_header(buf, &pos, 2);
-
- while (ext_headersize != 0) {
- char extbuf[4096];
- uchar ext_type;
- int extpos = 0;
-
- h->compsize -= ext_headersize;
-
- if (fread(extbuf, ext_headersize, 1, fp) != 1) {
- error("can't read ext header");
- }
+ case 'w':
+ /* extract directory */
+ if (!optarg)
+ error("extract directory does not specified for `-w'");
+ if (*optarg == '=')
+ optarg++;
- ext_type = get_header(extbuf, &extpos, 1);
- switch (ext_type) {
- case 0x54:
- h->mtime = get_header(extbuf, &extpos, 4);
+ opts.outdir = optarg;
+ break;
+ case 'z': /* no compress */
+ opts.nocompress = 1;
+ break;
+ case LHA_OPT_HELP:
+ print_usage();
+ break;
+ case LHA_OPT_VERSION:
+ print_version();
break;
default:
break;
}
- extpos = ext_headersize - 2;
- ext_headersize = get_header(extbuf, &extpos, 2);
}
+}
+
+FILE *
+open_tempfile()
+{
+ FILE *outfile;
+
+ outfile = tmpfile();
+ if (outfile == NULL)
+ error("Can't open temporary file");
- return 1; /* success */
+ return outfile;
}
-/*
- * level 2 header
- *
- *
- * offset size field name
- * --------------------------------------------------
- * 0 2 total header size [*1] ^
- * ----------------------- |
- * 2 5 method ID |
- * 7 4 packed size [*2] |
- * 11 4 original size |
- * 15 4 time |
- * 19 1 RESERVED (0x20 fixed) | [*1] total header size
- * 20 1 level (0x02 fixed) | (X+26+(1))
- * 21 2 file crc (CRC-16) |
- * 23 1 OS ID |
- * 24 2 next-header size |
- * ----------------------------------- |
- * 26 X ext-header |
- * : |
- * ----------------------------------- |
- * X +26 (1) padding v
- * -------------------------------------------------
- * X +26+(1) data ^
- * : | [*2] packed size
- * : v
- * -------------------------------------------------
- *
- */
-static int
-read_header_lv2(FILE *fp, char *buf, struct lzh_header *h)
+static void
+op_add(int cmd, char *archive_file, int argc, char **argv)
{
- int headersize;
- int headersum;
- int ext_headersize;
- int remainder;
- char dirname[1024] = "";
- int dirnamelen = 0;
- int pos = 0;
+ int i, count, found, done;
+ struct lzh_header h;
+ struct lzh_ostream w, *wp;
+ FILE *arcfile = NULL;
+ FILE *outfile = NULL;
- headersize = get_header(buf, &pos, 2);
+ wp = &w;
- fread_crc(buf + 21, 26 - 21, fp); /* CRC not used */
+ count = done = 0;
- get_string(buf, &pos, 5, h->method);
- h->compsize = get_header(buf, &pos, 4);
- h->origsize = get_header(buf, &pos, 4);
- h->mtime = get_header(buf, &pos, 4);
- get_header(buf, &pos, 1); /* attrib */
- h->level = get_header(buf, &pos, 1); /* header level */
- h->file_crc = get_header(buf, &pos, 2);
- h->os_id = get_header(buf, &pos, 1);
+ outfile = open_tempfile();
+ wp->fp = outfile;
+ wp->buf = 0;
+ if (*argv == 0)
+ error("archived files are not specified.");
- ext_headersize = get_header(buf, &pos, 2);
+ arcfile = fopen(archive_file, "rb");
+ if (arcfile == NULL)
+ error("Can't open archive '%s'", archive_file);
- remainder = headersize - pos;
+ while (!done && read_header(arcfile, &h)) {
- while (ext_headersize != 0) {
- char extbuf[4096];
- uchar ext_type;
- int extpos = 0;
+ found = search(argc, argv, &h);
+ if (found>0) {
+ argv[found-1] = 0;
- remainder -= ext_headersize;
+ if (cmd == 'u') {
+ time_t mtime;
- if (fread(extbuf, ext_headersize, 1, fp) != 1) {
- error("can't read ext header");
- }
- ext_type = get_header(extbuf, &extpos, 1);
- switch (ext_type) {
- case 0:
- /* header crc */
- break;
- case 1:
- /* filename header */
- h->namelen = ext_headersize - 3;
- get_string(extbuf, &extpos, h->namelen, h->filename);
- h->filename[h->namelen] = 0;
- break;
- case 2:
- /* dirname header */
- dirnamelen = ext_headersize - 3;
- get_string(extbuf, &extpos, dirnamelen, dirname);
- dirname[dirnamelen] = 0;
- break;
- default:
- break;
+ 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);
}
- extpos = ext_headersize - 2;
- ext_headersize = get_header(extbuf, &extpos, 2);
+ else
+ copy(arcfile, outfile, &h);
}
- if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
- dirname[dirnamelen++] = '/';
+ for (i = 0; i < argc; i++) {
+ if (argv[i]) {
+ count++;
+ add(wp, 0, argv[i], strlen(argv[i]));
+ }
}
- strcat(dirname, h->filename);
- h->namelen = strlen(dirname);
- strcpy(h->filename, dirname);
+ if (opts.quiet < 2)
+ printf(" %d files\n", count);
- while (remainder > 0) {
- fgetc(fp); /* skip padding */
- remainder--;
- }
+ if (count > 0) {
+ fputc(0, outfile); /* end of archive */
+ if (ferror(outfile))
+ error("Can't write");
+ if (!opts.archive_to_stdio)
+ unlink(archive_file);
- return 1; /* success */
+ 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 int
-read_header(FILE *fp, struct lzh_header *h)
+static void
+op_create(int cmd, char *archive_file, int argc, char **argv)
{
- char buf[4096];
- 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;
- }
+ int i;
+ struct lzh_ostream w, *wp;
+ FILE *outfile = NULL;
- return 1; /* success */
-}
+ wp = &w;
+ outfile = open_tempfile();
+ wp->fp = outfile;
+ wp->buf = 0;
+ if (*argv == 0)
+ error("archived files are not specified.");
-void
-write_header_lv0(FILE *fp, struct lzh_header *h)
-{
- char buf[4096];
- int sum;
- int headersize;
- int pos = 0;
-
- headersize = 22 + h->namelen;
-
- put_header(buf, &pos, 1, 0); /* dummy */
- put_header(buf, &pos, 1, 0); /* dummy */
-
- put_string(buf, &pos, 5, h->method);
- put_header(buf, &pos, 4, h->compsize); /* packed size */
- put_header(buf, &pos, 4, h->origsize); /* original size */
- put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
- put_header(buf, &pos, 1, 0x20); /* attribute */
- put_header(buf, &pos, 1, 0); /* level */
- put_header(buf, &pos, 1, h->namelen); /* length of pathname */
- put_string(buf, &pos, h->namelen, h->filename);
- put_header(buf, &pos, 2, h->file_crc);
-
- if (!opts.generic) {
- /* extended header for Unix */
- put_header(buf, &pos, 1, 'U'); /* OS type */
- put_header(buf, &pos, 1, '\0'); /* minor version */
- put_header(buf, &pos, 4, h->mtime); /* time_t */
- put_header(buf, &pos, 2, 0100000); /* mode */
- put_header(buf, &pos, 2, 0); /* uid */
- put_header(buf, &pos, 2, 0); /* gid */
- headersize += pos; /* size of ext-header (old style) */
+ for (i = 0; i < argc; i++) {
+ add(wp, 0, argv[i], strlen(argv[i]));
}
- put_header_tmp(buf, 0, 1, headersize);
-
- sum = calc_headersum(buf+2, headersize);
- put_header_tmp(buf, 1, 1, sum);
+ 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);
+ }
- fwrite_crc(buf, headersize+2, fp);
+ return;
}
-void
-write_header_lv1(FILE *fp, struct lzh_header *h)
+static void
+op_delete(int cmd, char *archive_file, int argc, char **argv)
{
- char buf[4096];
- int sum;
- int headersize;
- int extsize = 0;
- int pos = 0;
- int extpos;
-
- headersize = 25 + h->namelen;
-
- put_header(buf, &pos, 1, headersize);
- put_header(buf, &pos, 1, 0); /* dummy */
- put_string(buf, &pos, 5, h->method);
- put_header(buf, &pos, 4, h->compsize); /* packed size */
- put_header(buf, &pos, 4, h->origsize); /* original size */
- put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
- put_header(buf, &pos, 1, 0x20); /* attribute */
- put_header(buf, &pos, 1, 1); /* level */
- put_header(buf, &pos, 1, h->namelen); /* length of pathname */
- put_string(buf, &pos, h->namelen, h->filename);
- put_header(buf, &pos, 2, h->file_crc);
- if (opts.generic)
- put_header(buf, &pos, 1, '\0');
- else
- put_header(buf, &pos, 1, 'U');
+ int count, found, done;
+ struct lzh_header h;
+ int arc_count;
+ struct lzh_ostream w, *wp;
+ FILE *arcfile = NULL;
+ FILE *outfile = NULL;
- extpos = pos;
- put_header(buf, &pos, 2, 7); /* next header size */
- put_header(buf, &pos, 1, 0x54); /* time stamp */
- put_header(buf, &pos, 4, h->mtime); /* time_t */
+ wp = &w;
- extsize = pos - extpos;
- put_header(buf, &pos, 2, 0); /* next header size (end of header) */
+ count = done = 0;
- put_header_tmp(buf, 7, 4, h->compsize+extsize); /* packed size */
+ if (argc == 0) {
+ message("No files given in argument, do nothing.");
+ return;
+ }
+ outfile = open_tempfile();
- sum = calc_headersum(buf+2, headersize);
- put_header_tmp(buf, 1, 1, sum);
+ /* 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);
- fwrite_crc(buf, headersize+2+extsize, fp);
-}
+ arc_count = 0;
-void
-write_header_lv2(FILE *fp, struct lzh_header *h)
-{
- char buf[4096], *crcptr;
- int headersize;
- extern ushort crctable[];
- char dirname[1024] = "", *fname;
- int dirnamelen, len;
- int pos = 0;
-
- put_header(buf, &pos, 2, 0); /* dummy */
- put_string(buf, &pos, 5, h->method);
- put_header(buf, &pos, 4, h->compsize); /* packed size */
- put_header(buf, &pos, 4, h->origsize); /* original size */
- put_header(buf, &pos, 4, h->mtime); /* time_t */
- put_header(buf, &pos, 1, 0x20); /* DOS attribute (0x20 fixed) */
- put_header(buf, &pos, 1, 2); /* level */
- put_header(buf, &pos, 2, h->file_crc);
- if (opts.generic)
- put_header(buf, &pos, 1, '\0');
- else
- put_header(buf, &pos, 1, 'U');
-
- put_header(buf, &pos, 2, 5);
- put_header(buf, &pos, 1, 0); /* 0x00: header crc */
- crcptr = &buf[pos];
- put_header(buf, &pos, 2, 0); /* crc (dummy) */
-
- fname = basename(h->filename);
- len = strlen(fname);
+ while (!done && read_header(arcfile, &h)) {
- put_header(buf, &pos, 2, 3 + len);
- put_header(buf, &pos, 1, 1); /* 0x01: filename header */
- put_string(buf, &pos, len, fname); /* filename */
+ arc_count++;
- {
- 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;
+ found = search(argc, argv, &h);
+ if (found) {
+ count++;
+ message("'%s' deleted", h.filename);
+ skip(arcfile, &h);
}
+ else
+ copy(arcfile, outfile, &h);
}
- if (*dirname) {
- put_header(buf, &pos, 2, 3 + dirnamelen);
- put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
- put_string(buf, &pos, dirnamelen, dirname); /* dirname */
- }
-
- put_header(buf, &pos, 2, 0); /* next header size (end of header) */
-
- /* padding */
- if (pos % 256 == 0) {
- put_header(buf, &pos, 1, 0);
- }
- headersize = pos;
-
- put_header_tmp(buf, 0, 2, headersize);
-
- {
- int i;
-
- crc = INIT_CRC;
- for (i = 0; i < headersize; i++)
- UPDATE_CRC(buf[i]);
- put_header_tmp(crcptr, 0, 2, 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)
-{
- 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
-copy(FILE *arcfile, FILE *outfile, struct lzh_header *h)
-{
- uint n;
- uchar buffer[MAXDICSIZ];
-
- write_header(outfile, h);
- while (h->compsize != 0) {
- n = (uint) ((h->compsize > sizeof(buffer)) ? sizeof(buffer) : h->compsize);
- if (fread((char *) buffer, 1, n, arcfile) != n)
- error("Can't read");
- if (fwrite((char *) buffer, 1, n, outfile) != n)
- error("Can't write");
- h->compsize -= n;
- }
-}
-
-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;
+ printf(" %d files\n", count);
- 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);
- }
- else {
- if (opts.quiet < 2)
- printf("Adding %s ", h->filename);
- }
-
- headerpos = ftell(outfile);
- write_header(outfile, h);
- arcpos = ftell(outfile);
+ if (count > 0) {
+ fputc(0, outfile); /* end of archive */
+ if (ferror(outfile))
+ error("Can't write");
+ if (!opts.archive_to_stdio)
+ unlink(archive_file);
- origsize = compsize = 0;
- crc = INIT_CRC;
- if (opts.nocompress) {
- unpackable = 1;
- }
- else {
- unpackable = 0;
- encode();
- }
+ fclose(arcfile);
+ rewind(outfile);
- if (unpackable) {
- memcpy(h->method, "-lh0-", sizeof(h->method)); /* store */
- rewind(infile);
- fseek(outfile, arcpos, SEEK_SET);
- store();
+ 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);
+ }
}
- 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)
+static void
+op_extract(int cmd, char *archive_file, int argc, char **argv)
{
+ int count, nfiles, found, done;
struct lzh_header h;
- struct stat st;
+ struct lzh_istream r, *rp;
+ FILE *arcfile = NULL;
- memset(&h, 0, sizeof(h));
+ rp = &r;
- h.level = opts.header_level;
-
- strcpy(h.filename, filename);
- h.namelen = namelen;
-
- stat(h.filename, &st);
-
- h.mtime = st.st_mtime;
- 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);
+ count = done = nfiles = 0;
- add(replace_flag, filename, strlen(filename));
- }
- closedir(dir);
+ /* Open archive. */
+ if (opts.archive_to_stdio) {
+ arcfile = stdin;
}
else {
- memcpy(h.method, opts.method->id, sizeof(h.method)); /* compress */
- add_1(replace_flag, &h);
+ arcfile = fopen(archive_file, "rb");
}
-}
-
-int
-get_line(char *s, int n)
-{
- int i, c;
-
- i = 0;
- while ((c = getchar()) != EOF && c != '\n')
- if (i < n)
- s[i++] = (char) c;
- s[i] = '\0';
- return i;
-}
-
-static void
-extract(int to_file, struct lzh_header *h)
-{
- int n;
- uchar buffer[MAXDICSIZ];
-
- outfile = NULL;
+ if (arcfile == NULL)
+ error("Can't open archive '%s'", archive_file);
- if (to_file) {
- if (memcmp(h->method, "-lhd-", sizeof(h->method)) == 0) {
- /* directory */
- if (mkdir(h->filename, 0777) == -1) {
+ /* 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);
}
- }
- else {
- /* regular file */
- if (file_exists(h->filename)) {
- if (!opts.force_extract) {
- message("'%s' has been already exist. skip", h->filename);
- skip(arcfile, h);
- return;
- }
- }
- 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");
- if (outfile) {
- struct utimbuf ut;
-
- fclose(outfile);
-
- ut.actime = ut.modtime = h->mtime;
- utime(h->filename, &ut);
+ if (chdir(opts.outdir) == -1)
+ error("cannot change directory \"%s\"", opts.outdir);
}
}
- 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);
-}
+ while (!done && read_header(arcfile, &h)) {
-static int
-match(char *s1, char *s2)
-{
- for (;;) {
- while (*s2 == '*' || *s2 == '?') {
- if (*s2++ == '*')
- while (*s1 && *s1 != *s2)
- s1++;
- else if (*s1 == 0)
- return 0;
- else
- s1++;
+ 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;
}
- if (*s1 != *s2)
- return 0;
- if (*s1 == 0)
- return 1;
- s1++;
- s2++;
+ else
+ skip(arcfile, &h);
}
-}
-
-static int
-search(int argc, char *argv[], struct lzh_header *h)
-{
- int i;
- if (argc == 0)
- return -1;
- for (i = 0; i < argc; i++)
- if (argv[i] && match(h->filename, argv[i]))
- return i+1;
- return 0;
+ if (cmd != 'p') {
+ if (opts.quiet < 2)
+ printf(" %d files\n", count);
+ }
}
static void
-exitfunc(void)
+op_list(int cmd, char *archive_file, int argc, char **argv)
{
- remove(temp_name);
-}
-
-#include "getopt_long.h"
-
-int
-parse_args(int argc, char **argv)
-{
- int c;
-
- for (;;) {
- /* int this_option_optind = optind ? optind : 1; */
- int option_index = 0;
-
- enum {
- LHA_OPT_HELP = 128,
- LHA_OPT_VERSION,
- };
-
- static struct option long_options[] = {
- /* name, has_arg, *flag, val */
- /* has_arg:
- no_argument (0)
- required_argument (1)
- optional_argument (2)
- flag:
- NULL: getopt_long() return val
- non-NULL: getopt_long() return 0, and *flag set val.
- */
- {"help", no_argument, NULL, LHA_OPT_HELP},
- {"version", no_argument, NULL, LHA_OPT_VERSION},
- {0, 0, 0, 0}
- };
-
- c = getopt_long(argc, argv, "012fgo[567]q[012]vw:z",
- long_options, &option_index);
+ int count, nfiles, found, done;
+ struct lzh_header h;
+ struct lzh_istream r, *rp;
+ FILE *arcfile = NULL;
- if (c == -1) break; /* end of parsing options */
+ rp = &r;
- switch (c) {
- case '?':
- print_usage();
- break;
- case 0:
- /* set value by long option */
- break;
- case '0': case '1': case '2':
- /* header level */
- opts.header_level = c - '0';
- break;
- case 'f':
- opts.force_extract = 1;
- break;
- case 'g':
- opts.generic = 1;
- break;
- case 'o':
- /* compress method */
- {
- int idx = 1; /* -o means -lh1- method */
+ count = done = nfiles = 0;
- if (optarg)
- idx = *optarg - '0'; /* -lh[567]- method */
+ /* 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);
- opts.method = &methods[idx];
- }
- break;
- case 'q':
- /* quiet mode */
- opts.quiet = 2; /* -q is equivalent to -q2 */
- if (optarg)
- opts.quiet = *optarg - '0';
- break;
- case 'v':
- /* verbose mode */
- opts.verbose = 1;
- break;
+ while (!done && read_header(arcfile, &h)) {
- case 'w':
- /* extract directory */
- if (!optarg)
- error("extract directory does not specified for `-w'");
- if (*optarg == '=')
- optarg++;
+ found = search(argc, argv, &h);
- opts.outdir = optarg;
- break;
- case 'z': /* no compress */
- opts.nocompress = 1;
- break;
- case LHA_OPT_HELP:
- print_usage();
- break;
- case LHA_OPT_VERSION:
- print_version();
- break;
- default:
- break;
+ if (found != 0) {
+ if (count == 0)
+ list_start();
+ list(&h);
+ if (++count == nfiles)
+ done = 1;
}
+ skip(arcfile, &h);
}
-}
-
-FILE *
-open_tempfile()
-{
- temp_name = tmpnam(NULL);
- outfile = fopen(temp_name, "wb");
- if (outfile == NULL)
- error("Can't open temporary file");
- atexit(exitfunc);
- return outfile;
+ if (opts.quiet < 2)
+ printf(" %d files\n", count);
}
int
main(int argc, char *argv[])
{
- int i, cmd, count, nfiles, found, done;
+ int cmd;
char *archive_file;
- struct lzh_header h;
- int arc_count;
INITIALIZE_OPTS(opts);
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 'u':
- case 'c':
- if (opts.archive_to_stdio)
- opts.quiet = 2;
-
- outfile = open_tempfile();
- if (*argv == 0)
- error("archived files are not specified.");
-
- if (!opts.archive_to_stdio && (cmd == 'a' || cmd == 'u')) {
- if (file_exists(archive_file)) {
- arcfile = fopen(archive_file, "rb");
- if (arcfile == NULL)
- error("Can't open archive '%s'", archive_file);
-
- break;
- }
- }
- for (i = 0; i < argc; i++) {
- add(0, argv[i], strlen(argv[i]));
- }
-
- fputc(0, outfile); /* end of archive */
- if (ferror(outfile))
- error("Can't write");
- fclose(outfile);
- if (opts.archive_to_stdio) {
- if (move_file_to_stream(temp_name, stdout) == -1)
- error("fail to move_file_to_stream(): %s -> %s",temp_name,"stdout");
+ if (opts.archive_to_stdio || !file_exists(archive_file)) {
+ op_create(cmd, archive_file, argc, argv);
}
else {
- unlink(archive_file);
- if (xrename(temp_name, archive_file) == -1)
- error("fail to rename(): %s -> %s",temp_name,archive_file);
+ op_add(cmd, archive_file, argc, argv);
}
- exit(0);
break;
- case 'r':
+
+ case 'c':
+ op_create(cmd, archive_file, argc, argv);
+ break;
+
case 'd':
- if (argc == 0) {
- message("No files given in argument, do nothing.");
- exit(0);
- }
- 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. */
- if (opts.archive_to_stdio) {
- arcfile = stdin;
- }
- else {
- arcfile = fopen(archive_file, "rb");
- }
- if (arcfile == NULL)
- error("Can't open archive '%s'", archive_file);
-
+ op_list(cmd, archive_file, argc, argv);
break;
+
default:
print_usage();
break;
}
-
- /* 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);
- }
- }
-
- arc_count = 0;
-
- while (!done && read_header(arcfile, &h)) {
-
- arc_count++;
-
- compsize = h.compsize;
- origsize = h.origsize;
-
- found = search(argc, argv, &h);
- switch (cmd) {
- case 'a':
- case 'u':
- if (found>0) {
- argv[found-1] = 0;
-
- if (cmd == 'u' && h.mtime > file_mtime(h.filename)) {
- copy(arcfile, outfile, &h);
- break;
- }
-
- if (add(1, h.filename, h.namelen)) {
- skip(arcfile, &h);
- count++;
- }
- else
- copy(arcfile, outfile, &h);
- }
- else
- copy(arcfile, outfile, &h);
- break;
- case 'd':
- if (found) {
- count++;
- message("'%s' deleted", h.filename);
- skip(arcfile, &h);
- }
- else
- copy(arcfile, outfile, &h);
- break;
- case 'x':
- case 'p':
- if (found != 0) {
- extract(cmd == 'x', &h);
- if (++count == nfiles)
- done = 1;
- }
- else
- skip(arcfile, &h);
- break;
- case 'l':
- case 'v':
- if (found != 0) {
- if (count == 0)
- list_start();
- list(&h);
- if (++count == nfiles)
- done = 1;
- }
- skip(arcfile, &h);
- break;
- }
- }
-
- if (cmd == 'a' || cmd == 'u') {
- for (i = 0; i < argc; i++) {
- if (argv[i]) {
- count++;
- add(0, argv[i], strlen(argv[i]));
- }
- }
- }
-
- if (cmd != 'p') {
- if (opts.quiet < 2)
- printf(" %d files\n", count);
- }
-
- if (count > 0 && (cmd == 'd' || cmd == 'a' || cmd == 'u')) {
- fputc(0, outfile); /* end of archive */
- if (ferror(outfile))
- error("Can't write");
- if (!opts.archive_to_stdio)
- unlink(archive_file);
- fclose(outfile);
- fclose(arcfile);
- if (cmd == 'd') {
- if (arc_count > count) {
- if (xrename(temp_name, archive_file) == -1)
- error("fail to rename(): %s -> %s",temp_name,archive_file);
- }
- else {
- message("The archive file \"%s\" was removed because it would be empty.", archive_file);
- }
- }
- else {
- if (xrename(temp_name, archive_file) == -1)
- error("fail to rename(): %s -> %s",temp_name,archive_file);
- }
- exit(0);
- }
return EXIT_SUCCESS;
}