diff options
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 681 |
1 files changed, 681 insertions, 0 deletions
diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..db50f56 --- /dev/null +++ b/src/util.c @@ -0,0 +1,681 @@ +/* util.c -- + + This file is part of the lzop file compressor. + + Copyright (C) 1996-2010 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + lzop and the LZO library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + <markus@oberhumer.com> + http://www.oberhumer.com/opensource/lzop/ + */ + + +#include "conf.h" + + +/************************************************************************* +// filename util +**************************************************************************/ + +static const char dir_sep[] = DIR_SEP; + +#define fn_is_sep(c) (strchr(dir_sep,c) != NULL) + +#if defined(DOSISH) +#define fn_is_drive(n) (n[0] && n[1] == ':') +#define fn_skip_drive(n) (fn_is_drive(n) ? (n) + 2 : (n)) +#else +#define fn_is_drive(n) (0) +#define fn_skip_drive(n) (n) +#endif + + +unsigned fn_baseindex(const char *name) +{ + const char *n, *nn; + + n = fn_skip_drive(name); + for (nn = n; *nn; nn++) + if (fn_is_sep(*nn)) + n = nn + 1; + return (unsigned) (n - name); +} + + +const char *fn_basename(const char *name) +{ + return name + fn_baseindex(name); +} + + +void fn_addslash(char *name, lzo_bool slash) +{ + char *p; + + name = fn_skip_drive(name); + p = name + strlen(name); + while (p > name && fn_is_sep(p[-1])) + *p-- = 0; + if (p > name) + { + if (slash) + *p++ = dir_sep[0]; + *p = 0; + } +} + + +char *fn_strlwr(char *n) +{ + char *p; + for (p = n; *p; p++) + *p = (char) fn_tolower(*p); + return n; +} + + +int fn_strcmp(const char *n1, const char *n2) +{ + for (;;) + { + if (*n1 != *n2) + { + int c = fn_tolower(*n1) - fn_tolower(*n2); + if (c) + return c; + } + if (*n1 == 0) + return 0; + n1++; n2++; + } +} + + +lzo_bool fn_is_same_file(const char *n1, const char *n2) +{ + /* very simple... */ + if (fn_strcmp(n1,n2) == 0) + return 1; + return 0; +} + + +int fn_has_suffix(const char *name) +{ + size_t l; + size_t s; + + name = fn_skip_drive(name); + l = strlen(name); + if (l > 4 && name[l-4] == '.') + { + if (strcasecmp(&name[l-3],"lzo") == 0) + return SUFF_LZO; + if (strcasecmp(&name[l-3],"nrv") == 0) + return SUFF_NRV; + if (strcasecmp(&name[l-3],"tar") == 0) + return SUFF_TAR; + if (strcasecmp(&name[l-3],"tnv") == 0) + return SUFF_TNV; + if (strcasecmp(&name[l-3],"tzo") == 0) + return SUFF_TZO; + } + + if (l > 5 && name[l-5] == '.') + { + if (strcasecmp(&name[l-4],"lzop") == 0) + return SUFF_LZOP; + } + + s = strlen(opt_suffix); + if (s > 0 && l > s) + { + if (strcasecmp(&name[l-s],opt_suffix) == 0) + return SUFF_USER; + } + + return SUFF_NONE; +} + + +int fn_cleanpath(const char *name, char *newname, size_t size, int flags) +{ + size_t l = 0; + size_t n = 0; + int slashes = 0; +#define add(x) if (l >= size) return -1; else newname[l++] = (x) + + name = fn_skip_drive(name); + while (*name && fn_is_sep(*name)) + name++; + while (name[n]) + { + size_t last_n; + assert(!fn_is_sep(name[n])); + last_n = n++; + while (name[n] && !fn_is_sep(name[n])) + n++; + if (n - last_n == 2 && name[n-2] == '.' && name[n-1] == '.') + { + if (flags & 1) + return -2; + while (l > 0) { + if (newname[--l] == '/') + { + --slashes; + break; + } + } + /* newname[l] = 0; printf("del %s\n", newname); */ + } + else if (n - last_n == 1 && name[n-1] == '.') + { + if (flags & 2) + return -3; + } + else + { + if (l > 0) + { ++slashes; add('/'); } + while (last_n < n) + { add(name[last_n++]); } + /* newname[l] = 0; printf("add %s\n", newname); */ + } + while (name[n] && fn_is_sep(name[n])) + n++; + } + add('\0'); + return slashes; +#undef add +} + + +/************************************************************************* +// time util +**************************************************************************/ + +time_t fix_time(time_t t) +{ + if (t == (time_t) -1) + t = 0; + return t; +} + +time_t get_mtime(const header_t *h) +{ + lzop_ulong_t t; + t = h->mtime_high; + t <<= 16; t <<= 16; + t |= h->mtime_low; + return t == (lzop_ulong_t)(time_t)t ? (time_t)t : (time_t)0; +} + + +#if defined(HAVE_LOCALTIME) +void tm2str(char *s, size_t size, const struct tm *tmp) +{ + assert(size >= 18); +#if defined(HAVE_SNPRINTF) + snprintf(s, size, "%04d-%02d-%02d %02d:%02d:%02d", +#else + sprintf(s, "%04d-%02d-%02d %02d:%02d:%02d", +#endif + (int) tmp->tm_year + 1900, (int) tmp->tm_mon + 1, + (int) tmp->tm_mday, + (int) tmp->tm_hour, (int) tmp->tm_min, (int) tmp->tm_sec); +} +#endif + + +void time2str(char *s, size_t size, const time_t *t) +{ +#if defined(HAVE_LOCALTIME) + tm2str(s, size, localtime(t)); +#elif defined(HAVE_CTIME) + const char *p = ctime(t); + assert(size >= 18); + memset(s, ' ', 16); + memcpy(s + 2, p + 4, 6); + memcpy(s + 11, p + 11, 5); + s[16] = 0; +#else + s[0] = 0; + UNUSED(size); +#endif +} + + +void time2ls(char *s, size_t size, const time_t *t) +{ +#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) + const char *fmt = "%b %e %Y"; +#if defined(HAVE_DIFFTIME) +# if (ACC_OS_DOS16) + /* do not introduce any floating point dependencies */ + long d = (long)current_time - (long)*t; +# else + const double d = difftime(current_time, *t); +# endif + if (d <= 6 * 30 * 24 * 3600L && d >= -3600L) + fmt = "%b %e %H:%M"; +#endif + assert(size >= 13); + if (strftime(s, 13, fmt, localtime(t)) == 13) + s[0] = 0; +#else + s[0] = 0; + UNUSED(size); + UNUSED(t); +#endif +} + + +/************************************************************************* +// +**************************************************************************/ + +lzo_bool file_exists(const char *name) +{ + int fd, r; + struct stat st; + + /* return true if we can open it */ + fd = open(name, O_RDONLY, 0); + if (fd >= 0) + { + (void) close(fd); + return 1; + } + + /* return true if we can stat it */ + r = stat(name, &st); + if (r != -1) + return 1; + + /* return true if we can lstat it */ +#if defined(HAVE_LSTAT) + r = lstat(name, &st); + if (r != -1) + return 1; +#endif + + return 0; +} + + +/************************************************************************* +// Some systems have very exotic mode values. +// Convert them to standard values for portable use in our header. +**************************************************************************/ + +lzo_uint32 fix_mode_for_header(lzo_uint32 mode) +{ + lzo_uint32 m = mode; + + if (mode == 0) + return 0; + + /* This function can only deal with S_ISREG and S_ISDIR modes. */ + assert(S_ISREG(mode) || S_ISDIR(mode)); + +#if defined(ACC_OS_TOS) && defined(__PUREC__) + m = 0444; + if (mode & S_IWRITE) + m |= 0200; + if (mode & S_IEXEC) + m |= 0111; + if (S_ISREG(mode)) + m |= 0100000 | 0400; + else if (S_ISDIR(mode)) + m |= 0040000 | 0700; +#elif defined(DOSISH) + m &= 0777; + if (S_ISREG(mode)) + m |= 0100000 | 0400; + else if (S_ISDIR(mode)) + m |= 0040000 | 0700; +#else + m &= 07777; + if (S_ISREG(mode)) + m |= 0100000; + else if (S_ISDIR(mode)) + m |= 0040000 | 0700; +#endif + + if ((m & 0777) == 0) + m |= (0644 & ~u_mask); + return m; +} + + +MODE_T fix_mode_for_chmod(lzo_uint32 mode) +{ + MODE_T m = (MODE_T) (mode & 07777); + if ((m & 0777) == 0) + m |= (MODE_T) (0644 & ~u_mask); + return m; +} + + +MODE_T fix_mode_for_ls(lzo_uint32 mode) +{ + MODE_T m = (MODE_T) mode; + if ((m & 0777) == 0) + m |= (MODE_T) (0644 & ~u_mask); + return m; +} + + +MODE_T fix_mode_for_open(MODE_T mode) +{ + MODE_T m = (MODE_T) (mode & 0666); +#if defined(ACC_OS_TOS) && defined(__PUREC__) + m = S_IWRITE | S_IREAD; +#else + if ((m & 0777) == 0) + m |= (MODE_T) (0644 & ~u_mask); + m |= 0600; +#endif + return m; +} + + +/************************************************************************* +// ls util - adapted from GNU fileutils 3.16 +**************************************************************************/ + +/* Return a character indicating the type of file described by + file mode BITS: + 'd' for directories + 'b' for block special files + 'c' for character special files + 'm' for multiplexor files + 'l' for symbolic links + 's' for sockets + 'p' for fifos + '-' for regular files + '?' for any other file type. */ + +static char ftypelet(unsigned mode) +{ + if (S_ISREG(mode)) return '-'; + if (S_ISDIR(mode)) return 'd'; +#ifdef S_ISBLK + if (S_ISBLK(mode)) return 'b'; +#endif +#ifdef S_ISCHR + if (S_ISCHR(mode)) return 'c'; +#endif +#ifdef S_ISFIFO + if (S_ISFIFO(mode)) return 'p'; +#endif +#ifdef S_ISLNK + if (S_ISLNK(mode)) return 'l'; +#endif +#ifdef S_ISSOCK + if (S_ISSOCK(mode)) return 's'; +#endif +#ifdef S_ISMPC + if (S_ISMPC(mode)) return 'm'; +#endif +#ifdef S_ISNWK + if (S_ISNWK(mode)) return 'n'; +#endif +#ifdef S_ISOFD + if (S_ISOFD(mode)) return 'M'; /* Cray migrated dmf file. */ +#endif +#ifdef S_ISOFL + if (S_ISOFL(mode)) return 'M'; /* Cray migrated dmf file. */ +#endif + return '?'; +} + + +/* Set the read, write, and execute flags. */ +static void set_rwx(unsigned mode, char *str) +{ + str[0] = (char) ((mode & 4) ? 'r' : '-'); + str[1] = (char) ((mode & 2) ? 'w' : '-'); + str[2] = (char) ((mode & 1) ? 'x' : '-'); +} + + +/* Set the 's' and 't' flags in file attributes string. */ +static void set_st(unsigned mode, char *str) +{ +#ifdef S_ISUID + if (mode & S_ISUID) + str[3] = (char) (str[3] == 'x' ? 's' : 'S'); +#endif +#ifdef S_ISGID + if (mode & S_ISGID) + str[6] = (char) (str[6] == 'x' ? 's' : 'S'); +#endif +#ifdef S_ISVTX + if (mode & S_ISVTX) + str[9] = (char) (str[9] == 'x' ? 't' : 'T'); +#endif + UNUSED(mode); + UNUSED(str); +} + + +void mode_string(MODE_T m, char *str) +{ + unsigned mode = (unsigned) m; + str[0] = ftypelet(mode); + set_rwx((mode & 0700) >> 6, &str[1]); + set_rwx((mode & 0070) >> 3, &str[4]); + set_rwx((mode & 0007) >> 0, &str[7]); + set_st(mode, str); +} + + +/************************************************************************* +// adapted from the djgpp port of cpio 2.4.2 by Eli Zaretskii +**************************************************************************/ + +#if defined(DOSISH) + +/* If the original file name includes characters illegal for MS-DOS and + MS-Windows, massage it to make it suitable and return a pointer to + static storage with a new name. If the original name is legit, + return it instead. Return NULL if the rename failed (shouldn't happen). + + The file name changes are: (1) any name that is reserved by a DOS + device driver (such as 'prn.txt' or 'aux.c') is prepended with a '_'; + and (2) illegal characters are replaced with '_' or '-' (well, almost; + look at the code below for details). */ + +#define is_slash(x) fn_is_sep(x) + +char *maybe_rename_file(const char *original_name) +{ + static char dosified_name[PATH_MAX+1]; + static const char illegal_chars_dos[] = ".+, ;=[]|<>\":?*"; + const char *illegal_chars = illegal_chars_dos; + int idx, dot_idx; + const char *s = original_name; + char *d = dosified_name; + + /* Support for Win32 VFAT systems, when available. */ +#if defined(__DJGPP__) + if (_use_lfn(original_name)) + illegal_chars = illegal_chars_dos + 8; +#elif (ACC_OS_WIN32 || ACC_OS_WIN64 || ACC_OS_CYGWIN) + illegal_chars = illegal_chars_dos + 8; +#endif + + /* Get past the drive letter, if any. */ + if (fn_is_drive(s)) + { + *d++ = *s++; + *d++ = *s++; + } + + for (idx = 0, dot_idx = -1; *s; s++, d++) + { + if (strchr(illegal_chars, *s)) + { + /* Dots are special on DOS: it doesn't allow them as the leading + character, and a file name cannot have more than a single dot. + We leave the first non-leading dot alone, unless it comes too + close to the beginning of the name: we want sh.lex.c to become + sh_lex.c, not sh.lex-c. */ + if (*s == '.') + { + if (idx == 0 + && (is_slash(s[1]) || s[1] == '\0' + || (s[1] == '.' && (is_slash(s[2]) || s[2] == '\0')))) + { + /* Copy "./" and "../" verbatim. */ + *d++ = *s++; + if (*s == '.') + *d++ = *s++; + *d = *s; + } + else if (idx == 0) + *d = '_'; + else if (dot_idx >= 0) + { + if (dot_idx < 5) /* 5 is merely a heuristic ad-hoc'ery */ + { + d[dot_idx - idx] = '_'; /* replace previous dot */ + *d = '.'; + } + else + *d = '-'; + } + else + *d = '.'; + + if (*s == '.') + dot_idx = idx; + } + else if (*s == '+' && s[1] == '+') + { + if (idx - 2 == dot_idx) /* .c++, .h++ etc. */ + { + *d++ = 'x'; + *d = 'x'; + } + else + { + /* libg++ etc. */ + memcpy (d, "plus", 4); + d += 3; + } + s++; + idx++; + } + else + *d = '_'; + } + else + *d = *s; + if (is_slash(*s)) + { + idx = 0; + dot_idx = -1; + } + else + idx++; + } + + *d = '\0'; + +#if defined(S_ISCHR) + /* We could have a file in an archive whose name is reserved + on MS-DOS by a device driver. Trying to extract such a + file would fail at best and wedge us at worst. We need to + rename such files. */ + + if (idx > 0) + { + struct stat st_buf; + char *base = d - idx; + int i = 0; + + /* The list of character devices is not constant: it depends on + what device drivers did they install in their CONFIG.SYS. + 'stat' will tell us if the basename of the file name is a + characer device. */ + while (stat(base, &st_buf) == 0 && S_ISCHR(st_buf.st_mode)) + { + size_t blen = strlen(base); + + /* I don't believe any DOS character device names begin with a + '_'. But in case they invent such a device, let us try twice. */ + if (++i > 2) + return (char *)0; + + /* Prepend a '_'. */ + memmove(base + 1, base, blen + 1); + base[0] = '_'; + } + } +#endif + + return dosified_name; +} + +#endif /* DOSISH */ + + +/************************************************************************* +// +**************************************************************************/ + +#if (ACC_CC_MSC && (_MSC_VER >= 1000 && _MSC_VER < 1200)) + /* avoid '-W4' warnings in <windows.h> */ +# pragma warning(disable: 4201 4214 4514) +#endif +#if (ACC_CC_MSC && (_MSC_VER >= 1300)) + /* avoid '-Wall' warnings in <windows.h> */ +# pragma warning(disable: 4255) +#endif + +#define ACC_WANT_ACC_INCI_H 1 +#define ACC_WANT_ACCLIB_GETOPT 1 +#define ACC_WANT_ACCLIB_HALLOC 1 +#define ACC_WANT_ACCLIB_HMEMCPY 1 +#define ACC_WANT_ACCLIB_HSREAD 1 +#define ACC_WANT_ACCLIB_MISC 1 +#define ACC_WANT_ACCLIB_WILDARGV 1 +#if (ACC_HAVE_MM_HUGE_PTR) +# define ACC_WANT_ACCLIB_HREAD 1 +#endif +#include "miniacc.h" +#undef ACC_WANT_ACC_INCI_H +#undef ACC_WANT_ACCLIB_HALLOC +#undef ACC_WANT_ACCLIB_MISC +#undef ACC_WANT_ACCLIB_WILDARGV +#undef ACC_WANT_ACCLIB_HREAD + +#if (__ACCLIB_REQUIRE_HMEMCPY_CH) && !defined(__ACCLIB_HMEMCPY_CH_INCLUDED) +# define ACC_WANT_ACCLIB_HMEMCPY 1 +# include "acc/acclib/hmemcpy.ch" +# undef ACC_WANT_ACCLIB_HMEMCPY +#endif + + +/* +vi:ts=4:et +*/ + |