#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
+#include <time.h>
+#include <utime.h>
#include "ar.h"
extern char *basename(const char *);
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 */
}
static void
-put_to_header(char *buf, int i, int n, ulong x)
+put_header(char *buf, int *i, int n, uint32_t x)
{
while (--n >= 0) {
- buf[i++] = (uchar) ((uint) x & 0xFF);
+ buf[(*i)++] = (uchar) (x & 0xFF);
x >>= 8;
}
}
-static ulong
-get_from_header(char *buf, int i, int n)
+static void
+put_header_tmp(char *buf, int i, int n, uint32_t x)
+{
+ put_header(buf, &i, n, x);
+}
+
+void
+put_string(char *buf, int *n, size_t size, char *p)
+{
+ memcpy(buf + *n, p, size);
+ *n += size;
+}
+
+static uint32_t
+get_header(char *buf, int *i, int size)
{
- ulong s;
+ uint32_t s;
+ int n;
s = 0;
- while (--n >= 0)
- s = (s << 8) + buf[i + n]; /* little endian */
+ for (n = size-1; n >= 0; n--) {
+ s = (s << 8) + (unsigned char)buf[*i + n]; /* little endian */
+ }
+ *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)
{
return s & 0xFF;
}
+#if 0
int
get_byte(char *buf)
{
memcpy(buf, p, size);
}
+#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);
+}
+
+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);
+}
+
+
+/*
+ * 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_byte(&buf[0]);
- headersum = get_byte(&buf[1]);
+ headersize = get_header(buf, &pos, 1);
+ headersum = get_header(buf, &pos, 1);
- fread_crc(buf + 21, headersize - (21 - 2), fp); /* CRC not used */
-
- buf += 2;
+ fread_crc(buf + 21, headersize - (21 - pos), fp); /* CRC not used */
- if (calc_headersum(buf, headersize) != headersum)
+ if (calc_headersum(buf+pos, 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);
+ 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);
+ if (pos + h->namelen > headersize+2) {
+ warn("path name is too long");
+ h->namelen = headersize+2-pos;
+ }
+ get_string(buf, &pos, h->namelen, h->filename);
h->filename[h->namelen] = 0;
- h->file_crc = get_word(&buf[20+h->namelen]);
+ 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;
+ }
+ }
+
return 1; /* success */
}
+/*
+ * 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;
+ char dirname[1024] = "";
+ int dirnamelen = 0;
+ int pos = 0;
- headersize = get_byte(&buf[0]);
- headersum = get_byte(&buf[1]);
+ headersize = get_header(buf, &pos, 1);
+ headersum = get_header(buf, &pos, 1);
fread_crc(buf + 21, headersize - (21 - 2), fp); /* CRC not used */
- buf += 2;
-
- if (calc_headersum(buf, headersize) != headersum)
+ if (calc_headersum(&buf[pos], 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);
+ 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_word(&buf[20+h->namelen]);
- h->os_id = get_byte(&buf[20+h->namelen+2]);
+ h->file_crc = get_header(buf, &pos, 2);
+ h->os_id = get_header(buf, &pos, 1);
- ext_headersize = get_word(&buf[20+h->namelen+3]);
+ ext_headersize = get_header(buf, &pos, 2);
while (ext_headersize != 0) {
- fprintf(stderr, "There's an extended header of size %u.\n",
- ext_headersize);
+ char extbuf[4096];
+ uchar ext_type;
+ int extpos = 0;
+
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;
+ 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 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;
+ case 0x54:
+ h->mtime = get_header(extbuf, &extpos, 4);
+ break;
+ default:
+ break;
+ }
+ extpos = ext_headersize - 2;
+ ext_headersize = get_header(extbuf, &extpos, 2);
}
+ if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
+ dirname[dirnamelen++] = '/';
+ }
+
+ strcat(dirname, h->filename);
+ h->namelen = strlen(dirname);
+ strcpy(h->filename, dirname);
+
return 1; /* success */
}
+/*
+ * 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)
{
int headersize;
int headersum;
int ext_headersize;
- char extbuf[1024];
- uchar ext_type;
int remainder;
char dirname[1024] = "";
int dirnamelen = 0;
+ int pos = 0;
- headersize = get_word(&buf[0]);
+ headersize = get_header(buf, &pos, 2);
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]);
+ 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);
- ext_headersize = get_word(&buf[24]);
+ ext_headersize = get_header(buf, &pos, 2);
- remainder = headersize - 26;
+ remainder = headersize - pos;
while (ext_headersize != 0) {
- char *p = extbuf;
+ char extbuf[4096];
+ uchar ext_type;
+ int extpos = 0;
remainder -= ext_headersize;
- fread_crc(p, ext_headersize, fp);
- ext_type = get_byte(p++);
+ 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 */
case 1:
/* filename header */
h->namelen = ext_headersize - 3;
- get_char(p, h->filename, h->namelen);
+ get_string(extbuf, &extpos, h->namelen, h->filename);
h->filename[h->namelen] = 0;
break;
case 2:
/* dirname header */
dirnamelen = ext_headersize - 3;
- get_char(p, dirname, dirnamelen);
+ get_string(extbuf, &extpos, dirnamelen, dirname);
dirname[dirnamelen] = 0;
break;
+ default:
+ break;
}
- ext_headersize = get_word(&extbuf[ext_headersize - 2]);
+ extpos = ext_headersize - 2;
+ ext_headersize = get_header(extbuf, &extpos, 2);
}
+
if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
dirname[dirnamelen++] = '/';
}
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);
void
write_header_lv0(FILE *fp, struct lzh_header *h)
{
- char buf[4096], *p = buf;
+ char buf[4096];
int sum;
int headersize;
+ int pos = 0;
- headersize = 22 + h->namelen;
+ headersize = 22;
+ if (!opts.generic)
+ headersize += 12; /* extended header size */
- 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);
+ if (headersize + h->namelen > 255) {
+ warn("path name is too long");
+ h->namelen = 255 - headersize;
+ headersize = 255;
+ }
+ else {
+ headersize += h->namelen;
+ }
- headersize += 0; /* size of ext-header (old style) */
- put_byte(&buf[0], headersize);
+ 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, 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 */
+ }
sum = calc_headersum(buf+2, headersize);
- put_byte(&buf[1], sum);
+ put_header_tmp(buf, 1, 1, sum);
fwrite_crc(buf, headersize+2, fp);
}
void
write_header_lv1(FILE *fp, struct lzh_header *h)
{
- char buf[4096], *p = buf;
+ char buf[4096];
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);
+ int extsize = 0;
+ int pos = 0;
+ int extpos;
+ char *dirname, *fname;
+ int dirnamelen;
+
+ fname = xbasename(h->filename);
+ dirname = h->filename;
+ dirnamelen = fname - dirname;
+ h->namelen = strlen(fname);
+
+ headersize = 25;
+
+ 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, 1); /* level */
+ if (headersize + h->namelen > 255)
+ put_header(buf, &pos, 1, 0); /* length of pathname */
+ else {
+ put_header(buf, &pos, 1, h->namelen); /* length of pathname */
+ put_string(buf, &pos, h->namelen, fname);
+ headersize += h->namelen;
+ }
+ put_header_tmp(buf, 0, 1, headersize); /* header size */
+ put_header(buf, &pos, 2, h->file_crc);
if (opts.generic)
- put_byte(&buf[22+h->namelen+2], '\0');
+ put_header(buf, &pos, 1, '\0');
else
- put_byte(&buf[22+h->namelen+2], 'U');
- put_word(&buf[22+h->namelen+3], 0x0000); /* next header size */
+ put_header(buf, &pos, 1, 'U');
+
+ 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 */
+
+ if (h->namelen > 0) {
+ put_header(buf, &pos, 2, 3 + h->namelen);
+ put_header(buf, &pos, 1, 1); /* 0x01: filename header */
+ put_string(buf, &pos, h->namelen, fname); /* filename */
+ }
+
+ if (dirnamelen > 0) {
+ put_header(buf, &pos, 2, 3 + dirnamelen);
+ put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
+ put_string(buf, &pos, dirnamelen, dirname); /* dirname */
+ }
+
+ extsize = pos - extpos;
+ put_header(buf, &pos, 2, 0); /* next header size (end of header) */
+
+ put_header_tmp(buf, 7, 4, h->compsize+extsize); /* packed size */
sum = calc_headersum(buf+2, headersize);
- put_byte(&buf[1], sum);
+ put_header_tmp(buf, 1, 1, sum);
- fwrite_crc(buf, headersize+2, fp);
+ fwrite_crc(buf, headersize+2+extsize, fp);
}
void
write_header_lv2(FILE *fp, struct lzh_header *h)
{
- char buf[4096], *p = buf, *crcptr;
- int sum;
- int headersize, next_headersize;
+ char buf[4096], *crcptr;
+ int 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);
+ 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_byte(&buf[23], '\0');
+ put_header(buf, &pos, 1, '\0');
else
- put_byte(&buf[23], 'U');
-
- headersize = 24;
+ put_header(buf, &pos, 1, 'U');
- /* 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;
+ 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);
+ fname = xbasename(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;
+ put_header(buf, &pos, 2, 3 + len);
+ put_header(buf, &pos, 1, 1); /* 0x01: filename header */
+ put_string(buf, &pos, len, fname); /* filename */
{
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;
+ put_header(buf, &pos, 2, 3 + dirnamelen);
+ put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
+ put_string(buf, &pos, dirnamelen, dirname); /* dirname */
}
- p = buf + headersize;
- next_headersize = 0;
- put_word(p, next_headersize); /* next header size */
- headersize += next_headersize;
- headersize += 2;
+ put_header(buf, &pos, 2, 0); /* next header size (end of header) */
/* padding */
- if (headersize % 256 == 0) {
- put_byte(&buf[headersize], 0);
- headersize++;
+ if (pos % 256 == 0) {
+ put_header(buf, &pos, 1, 0);
}
+ headersize = pos;
- put_word(&buf[0], headersize);
+ put_header_tmp(buf, 0, 2, headersize);
- crc = INIT_CRC;
- for (p = buf; p - buf < headersize; p++)
- UPDATE_CRC(*p);
+ {
+ int i;
- put_word(crcptr, crc);
+ 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);
}
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
if (replace_flag) {
if (opts.quiet < 2)
printf("Replacing %s ", h->filename);
- skip(arcfile, h);
}
else {
if (opts.quiet < 2)
static int
add(int replace_flag, char *filename, int namelen)
{
- long headerpos, arcpos;
- uint r;
struct lzh_header h;
struct stat st;
stat(h.filename, &st);
+ h.mtime = st.st_mtime;
if (S_ISDIR(st.st_mode)) {
DIR *dir;
struct dirent *ent;
extract(int to_file, struct lzh_header *h)
{
int n;
- uint ext_headersize;
uchar buffer[MAXDICSIZ];
outfile = NULL;
}
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) {
if (to_file) {
fprintf(stdout, "\n");
- if (outfile)
+ if (outfile) {
+ struct utimbuf ut;
+
fclose(outfile);
+
+ ut.actime = ut.modtime = h->mtime;
+ utime(h->filename, &ut);
+ }
}
outfile = NULL;
}
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);
}
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 */
int
main(int argc, char *argv[])
{
- int i, j, cmd, count, nfiles, found, done;
+ int i, cmd, count, nfiles, found, done;
char *archive_file;
struct lzh_header h;
+ int arc_count;
- 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;
+
argv++;
argc--;
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");
- remove(archive_file);
- if (xrename(temp_name, archive_file) == -1)
- error("fail to rename(): %s -> %s",temp_name,archive_file);
-
+ 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");
+ }
+ else {
+ unlink(archive_file);
+ if (xrename(temp_name, archive_file) == -1)
+ error("fail to rename(): %s -> %s",temp_name,archive_file);
+ }
exit(0);
break;
case 'r':
case 'd':
+ if (argc == 0) {
+ message("No files given in argument, do nothing.");
+ exit(0);
+ }
outfile = open_tempfile();
case 'x':
case 'p':
case 'l':
case 'v':
/* Open archive. */
- arcfile = fopen(archive_file, "rb");
+ if (opts.archive_to_stdio) {
+ arcfile = stdin;
+ }
+ else {
+ arcfile = fopen(archive_file, "rb");
+ }
if (arcfile == NULL)
- error("Can't open archive '%s'", argv[2]);
+ error("Can't open archive '%s'", archive_file);
break;
default:
/* change directory to extract dir */
if (cmd == 'x') {
- struct stat *stbuf;
-
if (opts.outdir) {
if (mkdir(opts.outdir, 0777) == -1) {
if (errno != EEXIST)
}
}
+ 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 'r':
- if (found) {
- if (add(1, *argv, strlen(*argv)))
+ 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 'a':
case 'd':
if (found) {
- count += (cmd == 'D');
+ count++;
+ message("'%s' deleted", h.filename);
skip(arcfile, &h);
}
else
break;
case 'x':
case 'p':
- if (found) {
+ if (found != 0) {
extract(cmd == 'x', &h);
if (++count == nfiles)
done = 1;
break;
case 'l':
case 'v':
- if (found) {
+ if (found != 0) {
if (count == 0)
list_start();
list(&h);
}
}
+ 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;
}