}
static void
-put_header(char *buf, int *i, int n, uint32_t x)
-{
- while (--n >= 0) {
- buf[(*i)++] = (uchar) (x & 0xFF);
- x >>= 8;
- }
-}
-
-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)
-{
- uint32_t s;
- int n;
-
- s = 0;
- 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)
-{
- 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);
-}
-
-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);
-}
-
-#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 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);
- 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_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_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");
- }
-
- 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 ext_headersize;
- int remainder;
- char dirname[1024] = "";
- int dirnamelen = 0;
- int pos = 0;
-
- headersize = get_header(buf, &pos, 2);
-
- fread_crc(buf + 21, 26 - 21, fp); /* CRC not used */
-
- 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_header(buf, &pos, 2);
-
- remainder = headersize - pos;
-
- while (ext_headersize != 0) {
- char extbuf[4096];
- uchar ext_type;
- int extpos = 0;
-
- remainder -= ext_headersize;
-
- 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;
- }
- 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);
-
- while (remainder > 0) {
- fgetc(fp); /* skip padding */
- remainder--;
- }
-
- return 1; /* success */
-}
-
-static int
-read_header(FILE *fp, struct lzh_header *h)
-{
- 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;
- }
-
- return 1; /* success */
-}
-
-
-void
-write_header_lv0(FILE *fp, struct lzh_header *h)
-{
- char buf[4096];
- int sum;
- int headersize;
- int pos = 0;
-
- headersize = 22;
- if (!opts.generic)
- headersize += 12; /* extended header size */
-
- if (headersize + h->namelen > 255) {
- warn("path name is too long");
- h->namelen = 255 - headersize;
- headersize = 255;
- }
- else {
- headersize += 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, 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_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];
- int sum;
- int headersize;
- 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_header(buf, &pos, 1, '\0');
- else
- 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_header_tmp(buf, 1, 1, sum);
-
- fwrite_crc(buf, headersize+2+extsize, fp);
-}
-
-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 = xbasename(h->filename);
- len = strlen(fname);
-
- 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) {
- dirnamelen = ptr - h->filename;
- strncpy(dirname, h->filename, dirnamelen);
- dirname[dirnamelen+ 1] = 0;
- }
- }
-
- 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;
--- /dev/null
+#include <string.h>
+#include <time.h>
+#include "ar.h"
+
+static void
+put_header(char *buf, int *i, int n, uint32_t x)
+{
+ while (--n >= 0) {
+ buf[(*i)++] = (uchar) (x & 0xFF);
+ x >>= 8;
+ }
+}
+
+static void
+put_header_tmp(char *buf, int i, int n, uint32_t x)
+{
+ put_header(buf, &i, n, x);
+}
+
+static 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)
+{
+ uint32_t s;
+ int n;
+
+ s = 0;
+ for (n = size-1; n >= 0; n--) {
+ s = (s << 8) + (unsigned char)buf[*i + n]; /* little endian */
+ }
+ *i += size;
+ return s;
+}
+
+static 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)
+{
+ int i;
+ uint s;
+
+ s = 0;
+ for (i = 0; i < size; i++)
+ s += buf[i];
+ return s & 0xFF;
+}
+
+#if 0
+static int
+get_byte(char *buf)
+{
+ return *(unsigned char*)buf;
+}
+
+static uint16_t
+get_word(char *buf)
+{
+ return get_byte(buf) | (get_byte(buf+1) << 8);
+}
+
+static 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);
+}
+
+static void
+get_char(char *buf, char *p, size_t size)
+{
+ memcpy(p, buf, size);
+}
+
+static void
+put_byte(char *buf, int c)
+{
+ *buf = (unsigned char)(c & 0xff);
+}
+
+static void
+put_word(char *buf, uint16_t c)
+{
+ put_byte(buf, c);
+ put_byte(buf+1, c>>8);
+}
+
+static 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);
+}
+
+static void
+put_char(char *buf, char *p, size_t size)
+{
+ memcpy(buf, p, size);
+}
+
+#endif
+static 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);
+}
+
+static 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 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);
+ 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_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_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");
+ }
+
+ 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 ext_headersize;
+ int remainder;
+ char dirname[1024] = "";
+ int dirnamelen = 0;
+ int pos = 0;
+
+ headersize = get_header(buf, &pos, 2);
+
+ fread_crc(buf + 21, 26 - 21, fp); /* CRC not used */
+
+ 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_header(buf, &pos, 2);
+
+ remainder = headersize - pos;
+
+ while (ext_headersize != 0) {
+ char extbuf[4096];
+ uchar ext_type;
+ int extpos = 0;
+
+ remainder -= ext_headersize;
+
+ 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;
+ }
+ 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);
+
+ while (remainder > 0) {
+ fgetc(fp); /* skip padding */
+ remainder--;
+ }
+
+ return 1; /* success */
+}
+
+int
+read_header(FILE *fp, struct lzh_header *h)
+{
+ 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;
+ }
+
+ return 1; /* success */
+}
+
+
+static void
+write_header_lv0(FILE *fp, struct lzh_header *h)
+{
+ char buf[4096];
+ int sum;
+ int headersize;
+ int pos = 0;
+
+ headersize = 22;
+ if (!opts.generic)
+ headersize += 12; /* extended header size */
+
+ if (headersize + h->namelen > 255) {
+ warn("path name is too long");
+ h->namelen = 255 - headersize;
+ headersize = 255;
+ }
+ else {
+ headersize += 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, 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_header_tmp(buf, 1, 1, sum);
+
+ fwrite_crc(buf, headersize+2, fp);
+}
+
+static void
+write_header_lv1(FILE *fp, struct lzh_header *h)
+{
+ char buf[4096];
+ int sum;
+ int headersize;
+ 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_header(buf, &pos, 1, '\0');
+ else
+ 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_header_tmp(buf, 1, 1, sum);
+
+ fwrite_crc(buf, headersize+2+extsize, fp);
+}
+
+static 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 = xbasename(h->filename);
+ len = strlen(fname);
+
+ 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) {
+ dirnamelen = ptr - h->filename;
+ strncpy(dirname, h->filename, dirnamelen);
+ dirname[dirnamelen+ 1] = 0;
+ }
+ }
+
+ 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;
+ }
+}
EXEEXT=
endif
OBJS1 = ar.o io.o encode.o decode.o maketree.o maketbl.o huf.o \
- strlib.o pathlib.o filelib.o
+ strlib.o pathlib.o filelib.o header.o
OBJS2 = getopt_long.o
OBJS = $(OBJS1) $(OBJS2)
/* ar.c */
struct lha_method *which_method P_((char *id));
-void put_string P_((char *buf, int *n, size_t size, char *p));
-void get_string P_((char *buf, int *i, size_t size, char *p));
-time_t ftime_to_time_t P_((uint32_t ftime));
-uint32_t time_t_to_ftime P_((time_t t));
-void write_header_lv0 P_((FILE *fp, struct lzh_header *h));
-void write_header_lv1 P_((FILE *fp, struct lzh_header *h));
-void write_header_lv2 P_((FILE *fp, struct lzh_header *h));
-void write_header P_((FILE *fp, struct lzh_header *h));
int get_line P_((char *s, int n));
void parse_args P_((int argc, char **argv));
FILE *open_tempfile P_((void));
int copy_stream P_((FILE *rfp, FILE *wfp));
int move_file_to_stream P_((char *file, FILE *wfp));
int xrename P_((char *from, char *to));
+/* header.c */
+int read_header P_((FILE *fp, struct lzh_header *h));
+void write_header P_((FILE *fp, struct lzh_header *h));