/* Ver. 1.13b Symbolic Link Bug Fix 1994.08.22 N.Watazaki */
/* Ver. 1.14 Source All chagned 1995.01.14 N.Watazaki */
/* Ver. 1.14i bug fixed 2000.10.06 t.okamoto */
+/* Ver. 1.14i Contributed UTF-8 convertion for Mac OS X */
+/* 2002.06.29 Hiroto Sakai */
+/* Ver. 1.14i autoconfiscated & rewritten 2003.02.23 Koji Arai */
/* ------------------------------------------------------------------------ */
#include "lha.h"
#define strrchr xstrrchr
#endif
-/* ------------------------------------------------------------------------ */
static char *get_ptr;
#define GET_BYTE() (*get_ptr++ & 0xff)
int default_system_kanji_code = NONE;
#endif
-/* ------------------------------------------------------------------------ */
int
calc_sum(p, len)
- register char *p;
- register int len;
+ void *p;
+ int len;
{
- register int sum;
+ int sum = 0;
- for (sum = 0; len; len--)
- sum += *p++;
+ while (len--) sum += *(unsigned char*)p++;
return sum & 0xff;
}
}
#endif
-/* ------------------------------------------------------------------------ */
static int
get_word()
{
- int b0, b1;
+ int b0, b1;
int w;
#if DUMP_HEADER
return w;
}
-/* ------------------------------------------------------------------------ */
static void
put_word(v)
unsigned int v;
put_byte(v >> 8);
}
-/* ------------------------------------------------------------------------ */
static long
get_longword()
{
- long b0, b1, b2, b3;
+ long b0, b1, b2, b3;
long l;
#if DUMP_HEADER
return l;
}
-/* ------------------------------------------------------------------------ */
static void
put_longword(v)
- long v;
+ long v;
{
put_byte(v);
put_byte(v >> 8);
from_delim, to_delim,
case_to)
char *name;
- int len;
- int size;
+ int len; /* length of name */
+ int size; /* size of name buffer */
int from_code, to_code, case_to;
char *from_delim, *to_delim;
int i;
#ifdef MULTIBYTE_FILENAME
char tmp[FILENAME_LENGTH];
+ int to_code_save = NONE;
+
+ if (from_code == CODE_CAP) {
+ len = cap_to_sjis(tmp, name, sizeof(tmp));
+ strncpy(name, tmp, size);
+ name[size-1] = 0;
+ len = strlen(name);
+ from_code = CODE_SJIS;
+ }
+
+ if (to_code == CODE_CAP) {
+ to_code_save = CODE_CAP;
+ to_code = CODE_SJIS;
+ }
if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
for (i = 0; i < len; i++)
continue;
}
}
-}
-/* ------------------------------------------------------------------------ */
-/* */
-/* Generic stamp format: */
-/* */
-/* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 */
-/* |<------- year ----->|<- month ->|<--- day ---->| */
-/* */
-/* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */
-/* |<--- hour --->|<---- minute --->|<- second*2 ->| */
-/* */
-/* ------------------------------------------------------------------------ */
+#ifdef MULTIBYTE_FILENAME
+ if (to_code_save == CODE_CAP) {
+ len = sjis_to_cap(tmp, name, sizeof(tmp));
+ strncpy(name, tmp, size);
+ name[size-1] = 0;
+ len = strlen(name);
+ }
+#endif /* MULTIBYTE_FILENAME */
+}
/*
- * NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
- * returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or TZSET.
+ * Generic (MS-DOS style) time stamp format (localtime):
+ *
+ * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
+ * |<---- year-1980 --->|<- month ->|<--- day ---->|
+ *
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ * |<--- hour --->|<---- minute --->|<- second/2 ->|
+ *
*/
-#ifdef HAVE_FTIME
-#include <sys/timeb.h>
-#endif
-
-#if !defined(HAVE_MKTIME) && !defined(HAVE_TIMELOCAL)
-static long
-gettz()
+static time_t
+generic_to_unix_stamp(t)
+ long t;
{
-#ifdef HAVE_TZSET
-#if defined(_MINIX)
- extern long timezone; /* not defined in time.h */
-#endif
+ struct tm tm;
- tzset();
- return timezone;
-#elif HAVE_FTIME
- struct timeb buf;
-
- ftime(&buf);
- return buf.timezone * 60L;
-#elif HAVE_STRUCT_TM_TM_GMTOFF
- time_t tt;
-
- time(&tt);
- return -localtime(&tt)->tm_gmtoff;
-#elif GETTIMEOFDAY_HAS_2ND_ARG
- struct timeval tp;
- struct timezone tzp;
- gettimeofday(&tp, &tzp);/* specific to 4.3BSD */
- /*
- * return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L *
- * 60L : 0));
- */
- return (tzp.tz_minuteswest * 60L);
-#else
- /* Compile error will be caused */
- CANNOT GET TIMEZONE INFORMATION ON YOUR SYSTEM.
- TAKE THE ANOTHER WAY.
-#endif
-}
-#endif
+#define subbits(n, off, len) (((n) >> (off)) & ((1 << (len))-1))
-/* ------------------------------------------------------------------------ */
-static time_t
-generic_to_unix_stamp(t)
- long t;
-{
-#if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
- struct tm dostm;
-
- /*
- * special case: if MSDOS format date and time were zero, then we
- * set time to be zero here too.
- */
- if (t == 0)
- return (time_t) 0;
-
- dostm.tm_sec = (t & 0x1f) * 2;
- dostm.tm_min = t >> 5 & 0x3f;
- dostm.tm_hour = t >> 11 & 0x1f;
- dostm.tm_mday = t >> 16 & 0x1f;
- dostm.tm_mon = (t >> (16+5) & 0x0f) - 1; /* 0..11 */
- dostm.tm_year = (t >> (16+9) & 0x7f) + 80;
- dostm.tm_isdst = -1;
+ tm.tm_sec = subbits(t, 0, 5) * 2;
+ tm.tm_min = subbits(t, 5, 6);
+ tm.tm_hour = subbits(t, 11, 5);
+ tm.tm_mday = subbits(t, 16, 5);
+ tm.tm_mon = subbits(t, 21, 4) - 1;
+ tm.tm_year = subbits(t, 25, 7) + 80;
+ tm.tm_isdst = -1;
#if HAVE_MKTIME
- return (time_t) mktime(&dostm);
-#else /* HAVE_TIMELOCAL is defined */
- return (time_t) timelocal(&dostm);
+ return mktime(&tm);
+#else
+ return timelocal(&tm);
#endif
-
-#else /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
- int year, month, day, hour, min, sec;
- long longtime;
- static unsigned int dsboy[12] = {0, 31, 59, 90, 120, 151,
- 181, 212, 243, 273, 304, 334};
- unsigned int days;
-
- /*
- * special case: if MSDOS format date and time were zero, then we
- * set time to be zero here too.
- */
- if (t == 0)
- return (time_t) 0;
-
- year = ((int) (t >> 16 + 9) & 0x7f) + 1980;
- month = (int) (t >> 16 + 5) & 0x0f; /* 1..12 means Jan..Dec */
- day = (int) (t >> 16) & 0x1f; /* 1..31 means 1st,...31st */
-
- hour = ((int) t >> 11) & 0x1f;
- min = ((int) t >> 5) & 0x3f;
- sec = ((int) t & 0x1f) * 2;
-
- /* Calculate days since 1970.01.01 */
- days = (365 * (year - 1970) + /* days due to whole years */
- (year - 1970 + 1) / 4 + /* days due to leap years */
- dsboy[month - 1] + /* days since beginning of this year */
- day - 1); /* days since beginning of month */
-
- if ((year % 4 == 0) &&
- (year % 100 != 0 || year % 400 == 0) && /* 1999.5.24 t.oka */
- (month >= 3)) /* if this is a leap year and month */
- days++; /* is March or later, add a day */
-
- /* Knowing the days, we can find seconds */
- longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
- longtime += gettz(); /* adjust for timezone */
-
- /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00. */
- return (time_t) longtime;
-#endif /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
}
-/* ------------------------------------------------------------------------ */
static long
unix_to_generic_stamp(t)
- time_t t;
+ time_t t;
{
- struct tm *tm = localtime(&t);
-
- return ((((long) (tm->tm_year - 80)) << 25) +
- (((long) (tm->tm_mon + 1)) << 21) +
- (((long) tm->tm_mday) << 16) +
- (long) ((tm->tm_hour << 11) +
- (tm->tm_min << 5) +
- (tm->tm_sec / 2)));
+ struct tm *tm = localtime(&t);
+
+ tm->tm_year -= 80;
+ tm->tm_mon += 1;
+
+ return ((long)(tm->tm_year << 25) +
+ (tm->tm_mon << 21) +
+ (tm->tm_mday << 16) +
+ (tm->tm_hour << 11) +
+ (tm->tm_min << 5) +
+ (tm->tm_sec / 2));
}
static unsigned long
{
#if HAVE_UINT64_T
uint64_t t;
- uint64_t epoch = 0x019db1ded53e8000; /* 1970-01-01 00:00:00 (UTC) */
+ uint64_t epoch = ((uint64_t)0x019db1de << 32) + 0xd53e8000;
+ /* 0x019db1ded53e8000ULL: 1970-01-01 00:00:00 (UTC) */
- t = get_longword();
- t += (uint64_t)get_longword() << 32;
+ t = (unsigned long)get_longword();
+ t |= (uint64_t)(unsigned long)get_longword() << 32;
t = (t - epoch) / 10000000;
return t;
#else
#endif
}
-/* ------------------------------------------------------------------------ */
-/* build header functions */
-/* ------------------------------------------------------------------------ */
-
/*
* extended header
*
name_length = sizeof(hdr->name) - dir_length - 1;
hdr->name[name_length] = 0;
}
- strcat(dirname, hdr->name);
- strcpy(hdr->name, dirname);
+ strcat(dirname, hdr->name); /* ok */
+ strcpy(hdr->name, dirname); /* ok */
name_length += dir_length;
}
hdr->name[i] = '\0';
/* defaults for other type */
- hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
+ hdr->unix_mode = S_IFREG | UNIX_RW_RW_RW;
hdr->unix_gid = 0;
hdr->unix_uid = 0;
hdr->has_crc = FALSE;
return TRUE;
- }
+ }
error("Unkonwn header (lha file?)");
exit(1);
hdr->name[i] = '\0';
/* defaults for other type */
- hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
+ hdr->unix_mode = S_IFREG | UNIX_RW_RW_RW;
hdr->unix_gid = 0;
hdr->unix_uid = 0;
hdr->header_level = get_byte();
/* defaults for other type */
- hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
+ hdr->unix_mode = S_IFREG | UNIX_RW_RW_RW;
hdr->unix_gid = 0;
hdr->unix_uid = 0;
hdr->header_level = get_byte();
/* defaults for other type */
- hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
+ hdr->unix_mode = S_IFREG | UNIX_RW_RW_RW;
hdr->unix_gid = 0;
hdr->unix_uid = 0;
system_kanji_code,
archive_delim, system_delim, filename_case);
- if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
+ if (S_ISLNK(hdr->unix_mode)) {
char *p;
/* split symbolic link */
p = strchr(hdr->name, '|');
/* hdr->name is symbolic link name */
/* hdr->realname is real name */
*p = 0;
- strncpy(hdr->realname, p+1, sizeof(hdr->realname));
+ strcpy(hdr->realname, p+1); /* ok */
}
else
error("unknown symlink name \"%s\"", hdr->name);
continue;
/* found "-l??-" keyword (as METHOD type string) */
- /* size and checksum validate check */
-
/* level 0 or 1 header */
if ((p[I_HEADER_LEVEL] == 0 || p[I_HEADER_LEVEL] == 1)
&& p[I_HEADER_SIZE] > 20
&& p[I_HEADER_CHECKSUM] == calc_sum(p+2, p[I_HEADER_SIZE])) {
- if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
+ if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
fatal_error("cannot seek header");
return 0;
}
if (p[I_HEADER_LEVEL] == 2
&& p[I_HEADER_SIZE] >= 24
&& p[I_ATTRIBUTE] == 0x20) {
- if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
+ if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
fatal_error("cannot seek header");
return 0;
}
}
- if (fseek(fp, -n, SEEK_CUR) == -1)
+ if (fseeko(fp, -n, SEEK_CUR) == -1)
fatal_error("cannot seek header");
return -1;
}
-/* ------------------------------------------------------------------------ */
+
+/* remove leading `xxxx/..' */
+static char *
+remove_leading_dots(char *path)
+{
+ char *first = path;
+ char *ptr = 0;
+
+ if (strcmp(first, "..") == 0) {
+ warning("Removing leading `..' from member name.");
+ return first+1; /* change to "." */
+ }
+
+ if (strstr(first, "..") == 0)
+ return first;
+
+ while (path && *path) {
+
+ if (strcmp(path, "..") == 0)
+ ptr = path = path+2;
+ else if (strncmp(path, "../", 3) == 0)
+ ptr = path = path+3;
+ else
+ path = strchr(path, '/');
+
+ if (path && *path == '/') {
+ path++;
+ }
+ }
+
+ if (ptr) {
+ warning("Removing leading `%.*s' from member name.", ptr-first, first);
+ return ptr;
+ }
+
+ return first;
+}
+
void
init_header(name, v_stat, hdr)
char *name;
hdr->original_size = v_stat->st_size;
hdr->attribute = GENERIC_ATTRIBUTE;
hdr->header_level = header_level;
- strcpy(hdr->name, name);
- len = strlen(name);
+ len = str_safe_copy(hdr->name,
+ remove_leading_dots(name),
+ sizeof(hdr->name));
hdr->crc = 0x0000;
hdr->extend_type = EXTEND_UNIX;
hdr->unix_last_modified_stamp = v_stat->st_mtime;
memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
hdr->original_size = 0;
- if (len > 0 && hdr->name[len - 1] != '/')
- strcpy(&hdr->name[len++], "/");
+ if (len > 0 && hdr->name[len - 1] != '/') {
+ if (len < sizeof(hdr->name)-1)
+ strcpy(&hdr->name[len++], "/"); /* ok */
+ else
+ warning("the length of dirname \"%s\" is too long.",
+ hdr->name);
+ }
}
-#ifdef S_IFLNK
+#if defined(S_IFLNK) && !defined(__DJGPP__)
if (is_symlink(v_stat)) {
memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
}
}
-/* ------------------------------------------------------------------------ */
-/* Write unix extended header or generic header. */
-
static size_t
write_header_level0(data, hdr, pathname)
LzHeader *hdr;
header_size++;
}
- /* put hader size */
+ /* put header size */
setup_put(data + I_HEADER_SIZE);
put_word(header_size);
- /* put hader CRC in extended header */
+ /* put header CRC in extended header */
INITIALIZE_CRC(hcrc);
hcrc = calccrc(hcrc, data, (unsigned int) header_size);
setup_put(headercrc_ptr);
if (generic_format)
filename_case = TO_UPPER;
- if (hdr->header_level == HEADER_LEVEL0) {
+ if (hdr->header_level == 0) {
archive_delim = "\\";
}
- if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
+ if (S_ISLNK(hdr->unix_mode)) {
char *p;
p = strchr(hdr->name, '|');
if (p) {
*p1 |= 0x80;
*p2 |= 0x80;
}
+
+static int
+hex2int(int c)
+{
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return c - '0';
+
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ return c - 'a' + 10;
+
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ return c - 'A' + 10;
+ default:
+ return -1;
+ }
+}
+
+static int
+int2hex(int c)
+{
+ switch (c) {
+ case 0: case 1: case 2: case 3: case 4:
+ case 5: case 6: case 7: case 8: case 9:
+ return c + '0';
+
+ case 10: case 11: case 12: case 13: case 14: case 15:
+ return c + 'a' - 10;
+
+ default:
+ return -1;
+ }
+}
+
+int
+cap_to_sjis(char *dst, const char *src, size_t dstsize)
+{
+ int i, j;
+ size_t len = strlen(src);
+ int a, b;
+
+ for (i = j = 0; i < len && i < dstsize; i++) {
+ if (src[i] != ':') {
+ dst[j++] = src[i];
+ continue;
+ }
+
+ i++;
+ a = hex2int((unsigned char)src[i]);
+ b = hex2int((unsigned char)src[i+1]);
+
+ if (a == -1 || b == -1) {
+ /* leave as it */
+ dst[j++] = ':';
+ strncpy(dst+j, src+i, dstsize-j);
+ dst[dstsize-1] = 0;
+ return strlen(dst);
+ }
+
+ i++;
+
+ dst[j++] = a * 16 + b;
+ }
+ dst[j] = 0;
+ return j;
+}
+
+int
+sjis_to_cap(char *dst, const char *src, size_t dstsize)
+{
+ int i, j;
+ size_t len = strlen(src);
+ int a, b;
+
+ for (i = j = 0; i < len && i < dstsize; i++) {
+ if (src[i] == ':') {
+ strncpy(dst+j, ":3a", dstsize-j);
+ dst[dstsize-1] = 0;
+ j = strlen(dst);
+ continue;
+ }
+ if (isprint(src[i])) {
+ dst[j++] = src[i];
+ continue;
+ }
+
+ if (j + 3 >= dstsize) {
+ dst[j] = 0;
+ return j;
+ }
+
+ a = int2hex((unsigned char)src[i] / 16);
+ b = int2hex((unsigned char)src[i] % 16);
+
+ dst[j++] = ':';
+ dst[j++] = a;
+ dst[j++] = b;
+ }
+ dst[j] = 0;
+ return j;
+}
#endif /* MULTIBYTE_FILENAME */