summaryrefslogtreecommitdiff
path: root/os2/os2zip.c
diff options
context:
space:
mode:
Diffstat (limited to 'os2/os2zip.c')
-rw-r--r--os2/os2zip.c1213
1 files changed, 1213 insertions, 0 deletions
diff --git a/os2/os2zip.c b/os2/os2zip.c
new file mode 100644
index 0000000..83bc3bc
--- /dev/null
+++ b/os2/os2zip.c
@@ -0,0 +1,1213 @@
+/*
+ * @(#)dir.c 1.4 87/11/06 Public Domain.
+ *
+ * A public domain implementation of BSD directory routines for
+ * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
+ * August 1987
+ *
+ * Ported to OS/2 by Kai Uwe Rommel
+ * Addition of other OS/2 file system specific code
+ * Placed into the public domain
+ */
+
+/* does also contain EA access code for use in ZIP */
+
+
+#ifdef OS2
+
+
+#if defined(__EMX__) && !defined(__32BIT__)
+# define __32BIT__
+#endif
+
+#include "zip.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#ifndef __BORLANDC__
+#include <malloc.h>
+#endif
+
+#define INCL_NOPM
+#define INCL_DOSNLS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include "os2zip.h"
+#include "os2acl.h"
+
+
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+
+#ifdef __32BIT__
+#define DosFindFirst(p1, p2, p3, p4, p5, p6) \
+ DosFindFirst(p1, p2, p3, p4, p5, p6, 1)
+#else
+#define DosQueryCurrentDisk DosQCurDisk
+#define DosQueryFSAttach(p1, p2, p3, p4, p5) \
+ DosQFSAttach(p1, p2, p3, p4, p5, 0)
+#define DosQueryFSInfo(d, l, b, s) \
+ DosQFSInfo(d, l, b, s)
+#define DosQueryPathInfo(p1, p2, p3, p4) \
+ DosQPathInfo(p1, p2, p3, p4, 0)
+#define DosSetPathInfo(p1, p2, p3, p4, p5) \
+ DosSetPathInfo(p1, p2, p3, p4, p5, 0)
+#define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \
+ DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0)
+#define DosFindFirst(p1, p2, p3, p4, p5, p6) \
+ DosFindFirst(p1, p2, p3, p4, p5, p6, 0)
+#define DosMapCase DosCaseMap
+#endif
+
+
+#ifndef UTIL
+
+extern int noisy;
+
+#ifndef S_IFMT
+#define S_IFMT 0xF000
+#endif
+
+static int attributes = _A_DIR | _A_HIDDEN | _A_SYSTEM;
+
+static char *getdirent(char *);
+static void free_dircontents(struct _dircontents *);
+
+#ifdef __32BIT__
+static HDIR hdir;
+static ULONG count;
+static FILEFINDBUF3 find;
+#else
+static HDIR hdir;
+static USHORT count;
+static FILEFINDBUF find;
+#endif
+
+DIR *opendir(const char *name)
+{
+ struct stat statb;
+ DIR *dirp;
+ char c;
+ char *s;
+ struct _dircontents *dp;
+ char nbuf[MAXPATHLEN + 1];
+ int len;
+
+ attributes = hidden_files ? (_A_DIR | _A_HIDDEN | _A_SYSTEM) : _A_DIR;
+
+ strcpy(nbuf, name);
+ if ((len = strlen(nbuf)) == 0)
+ return NULL;
+
+ if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1))
+ {
+ nbuf[len - 1] = 0;
+ --len;
+
+ if (nbuf[len - 1] == ':')
+ {
+ strcpy(nbuf+len, "\\.");
+ len += 2;
+ }
+ }
+ else
+ if (nbuf[len - 1] == ':')
+ {
+ strcpy(nbuf+len, ".");
+ ++len;
+ }
+
+#ifndef __BORLANDC__
+ /* when will we ever see a Borland compiler that can properly stat !!! */
+ if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
+ return NULL;
+#endif
+
+ if ((dirp = malloc(sizeof(DIR))) == NULL)
+ return NULL;
+
+ if (nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.'))
+ strcpy(nbuf+len-1, "*.*");
+ else
+ if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1))
+ strcpy(nbuf+len, "*");
+ else
+ strcpy(nbuf+len, "\\*");
+
+ /* len is no longer correct (but no longer needed) */
+
+ dirp -> dd_loc = 0;
+ dirp -> dd_contents = dirp -> dd_cp = NULL;
+
+ if ((s = getdirent(nbuf)) == NULL)
+ return dirp;
+
+ do
+ {
+ if (((dp = malloc(sizeof(struct _dircontents))) == NULL) ||
+ ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL) )
+ {
+ if (dp)
+ free(dp);
+ free_dircontents(dirp -> dd_contents);
+
+ return NULL;
+ }
+
+ if (dirp -> dd_contents)
+ {
+ dirp -> dd_cp -> _d_next = dp;
+ dirp -> dd_cp = dirp -> dd_cp -> _d_next;
+ }
+ else
+ dirp -> dd_contents = dirp -> dd_cp = dp;
+
+ strcpy(dp -> _d_entry, s);
+ dp -> _d_next = NULL;
+
+ dp -> _d_size = find.cbFile;
+ dp -> _d_mode = find.attrFile;
+ dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite);
+ dp -> _d_date = *(unsigned *) &(find.fdateLastWrite);
+ }
+ while ((s = getdirent(NULL)) != NULL);
+
+ dirp -> dd_cp = dirp -> dd_contents;
+
+ return dirp;
+}
+
+void closedir(DIR * dirp)
+{
+ free_dircontents(dirp -> dd_contents);
+ free(dirp);
+}
+
+struct dirent *readdir(DIR * dirp)
+{
+ static struct dirent dp;
+
+ if (dirp -> dd_cp == NULL)
+ return NULL;
+
+ dp.d_namlen = dp.d_reclen =
+ strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry));
+
+ dp.d_ino = 0;
+
+ dp.d_size = dirp -> dd_cp -> _d_size;
+ dp.d_mode = dirp -> dd_cp -> _d_mode;
+ dp.d_time = dirp -> dd_cp -> _d_time;
+ dp.d_date = dirp -> dd_cp -> _d_date;
+
+ dirp -> dd_cp = dirp -> dd_cp -> _d_next;
+ dirp -> dd_loc++;
+
+ return &dp;
+}
+
+void seekdir(DIR * dirp, long off)
+{
+ long i = off;
+ struct _dircontents *dp;
+
+ if (off >= 0)
+ {
+ for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next);
+
+ dirp -> dd_loc = off - (i + 1);
+ dirp -> dd_cp = dp;
+ }
+}
+
+long telldir(DIR * dirp)
+{
+ return dirp -> dd_loc;
+}
+
+static void free_dircontents(struct _dircontents * dp)
+{
+ struct _dircontents *odp;
+
+ while (dp)
+ {
+ if (dp -> _d_entry)
+ free(dp -> _d_entry);
+
+ dp = (odp = dp) -> _d_next;
+ free(odp);
+ }
+}
+
+static char *getdirent(char *dir)
+{
+ int done;
+ static int lower;
+
+ if (dir != NULL)
+ { /* get first entry */
+ hdir = HDIR_SYSTEM;
+ count = 1;
+ done = DosFindFirst(dir, &hdir, attributes, &find, sizeof(find), &count);
+ lower = IsFileSystemFAT(dir);
+ }
+ else /* get next entry */
+ done = DosFindNext(hdir, &find, sizeof(find), &count);
+
+ if (done == 0)
+ {
+ if (lower)
+ StringLower(find.achName);
+ return find.achName;
+ }
+ else
+ {
+ DosFindClose(hdir);
+ return NULL;
+ }
+}
+
+/* FAT / HPFS detection */
+
+int IsFileSystemFAT(char *dir)
+{
+ static USHORT nLastDrive = -1, nResult;
+ ULONG lMap;
+ BYTE bData[64];
+ char bName[3];
+#ifdef __32BIT__
+ ULONG nDrive, cbData;
+ PFSQBUFFER2 pData = (PFSQBUFFER2) bData;
+#else
+ USHORT nDrive, cbData;
+ PFSQBUFFER pData = (PFSQBUFFER) bData;
+#endif
+
+ /* We separate FAT and HPFS+other file systems here.
+ at the moment I consider other systems to be similar to HPFS,
+ i.e. support long file names and being case sensitive */
+
+ if (isalpha(dir[0]) && (dir[1] == ':'))
+ nDrive = to_up(dir[0]) - '@';
+ else
+ DosQueryCurrentDisk(&nDrive, &lMap);
+
+ if (nDrive == nLastDrive)
+ return nResult;
+
+ bName[0] = (char) (nDrive + '@');
+ bName[1] = ':';
+ bName[2] = 0;
+
+ nLastDrive = nDrive;
+ cbData = sizeof(bData);
+
+ if (!DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData))
+ nResult = !strcmp((char *) pData -> szFSDName + pData -> cbName, "FAT");
+ else
+ nResult = FALSE;
+
+ /* End of this ugly code */
+ return nResult;
+}
+
+/* access mode bits and time stamp */
+
+int GetFileMode(char *name)
+{
+#ifdef __32BIT__
+ FILESTATUS3 fs;
+ return DosQueryPathInfo(name, 1, &fs, sizeof(fs)) ? -1 : fs.attrFile;
+#else
+ USHORT mode;
+ return DosQFileMode(name, &mode, 0L) ? -1 : mode;
+#endif
+}
+
+ulg GetFileTime(char *name)
+{
+#ifdef __32BIT__
+ FILESTATUS3 fs;
+#else
+ FILESTATUS fs;
+#endif
+ USHORT nDate, nTime;
+ DATETIME dtCurrent;
+
+ if (strcmp(name, "-") == 0)
+ {
+ DosGetDateTime(&dtCurrent);
+ fs.fdateLastWrite.day = dtCurrent.day;
+ fs.fdateLastWrite.month = dtCurrent.month;
+ fs.fdateLastWrite.year = dtCurrent.year - 1980;
+ fs.ftimeLastWrite.hours = dtCurrent.hours;
+ fs.ftimeLastWrite.minutes = dtCurrent.minutes;
+ fs.ftimeLastWrite.twosecs = dtCurrent.seconds / 2;
+ }
+ else
+ if (DosQueryPathInfo(name, 1, (PBYTE) &fs, sizeof(fs)))
+ return -1;
+
+ nDate = * (USHORT *) &fs.fdateLastWrite;
+ nTime = * (USHORT *) &fs.ftimeLastWrite;
+
+ return ((ULONG) nDate) << 16 | nTime;
+}
+
+void SetFileTime(char *path, ulg stamp)
+{
+ FILESTATUS fs;
+ USHORT fd, ft;
+
+ if (DosQueryPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)))
+ return;
+
+ fd = (USHORT) (stamp >> 16);
+ ft = (USHORT) stamp;
+ fs.fdateLastWrite = fs.fdateCreation = * (FDATE *) &fd;
+ fs.ftimeLastWrite = fs.ftimeCreation = * (FTIME *) &ft;
+
+ DosSetPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0);
+}
+
+/* read volume label */
+
+char *getVolumeLabel(int drive, unsigned long *vtime, unsigned long *vmode,
+ time_t *utim)
+{
+ static FSINFO fi;
+
+ if (DosQueryFSInfo(drive ? drive - 'A' + 1 : 0,
+ FSIL_VOLSER, (PBYTE) &fi, sizeof(fi)))
+ return NULL;
+
+ time(utim);
+ *vtime = unix2dostime(utim);
+ *vmode = _A_VOLID | _A_ARCHIVE;
+
+ return (fi.vol.cch > 0) ? fi.vol.szVolLabel : NULL;
+}
+
+/* FAT / HPFS name conversion stuff */
+
+int IsFileNameValid(char *name)
+{
+ HFILE hf;
+#ifdef __32BIT__
+ ULONG uAction;
+#else
+ USHORT uAction;
+#endif
+
+ switch(DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN,
+ OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0))
+ {
+ case ERROR_INVALID_NAME:
+ case ERROR_FILENAME_EXCED_RANGE:
+ return FALSE;
+ case NO_ERROR:
+ DosClose(hf);
+ default:
+ return TRUE;
+ }
+}
+
+void ChangeNameForFAT(char *name)
+{
+ char *src, *dst, *next, *ptr, *dot, *start;
+ static char invalid[] = ":;,=+\"[]<>| \t";
+
+ if (isalpha(name[0]) && (name[1] == ':'))
+ start = name + 2;
+ else
+ start = name;
+
+ src = dst = start;
+ if ((*src == '/') || (*src == '\\'))
+ src++, dst++;
+
+ while (*src)
+ {
+ for (next = src; *next && (*next != '/') && (*next != '\\'); next++);
+
+ for (ptr = src, dot = NULL; ptr < next; ptr++)
+ if (*ptr == '.')
+ {
+ dot = ptr; /* remember last dot */
+ *ptr = '_';
+ }
+
+ if (dot == NULL)
+ for (ptr = src; ptr < next; ptr++)
+ if (*ptr == '_')
+ dot = ptr; /* remember last _ as if it were a dot */
+
+ if (dot && (dot > src) &&
+ ((next - dot <= 4) ||
+ ((next - src > 8) && (dot - src > 3))))
+ {
+ if (dot)
+ *dot = '.';
+
+ for (ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++)
+ *dst++ = *ptr;
+
+ for (ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++)
+ *dst++ = *ptr;
+ }
+ else
+ {
+ if (dot && (next - src == 1))
+ *dot = '.'; /* special case: "." as a path component */
+
+ for (ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++)
+ *dst++ = *ptr;
+ }
+
+ *dst++ = *next; /* either '/' or 0 */
+
+ if (*next)
+ {
+ src = next + 1;
+
+ if (*src == 0) /* handle trailing '/' on dirs ! */
+ *dst = 0;
+ }
+ else
+ break;
+ }
+
+ for (src = start; *src != 0; ++src)
+ if ((strchr(invalid, *src) != NULL) || (*src == ' '))
+ *src = '_';
+}
+
+/* .LONGNAME EA code */
+
+typedef struct
+{
+ ULONG cbList; /* length of value + 22 */
+#ifdef __32BIT__
+ ULONG oNext;
+#endif
+ BYTE fEA; /* 0 */
+ BYTE cbName; /* length of ".LONGNAME" = 9 */
+ USHORT cbValue; /* length of value + 4 */
+ BYTE szName[10]; /* ".LONGNAME" */
+ USHORT eaType; /* 0xFFFD for length-preceded ASCII */
+ USHORT eaSize; /* length of value */
+ BYTE szValue[CCHMAXPATH];
+}
+FEALST;
+
+typedef struct
+{
+ ULONG cbList;
+#ifdef __32BIT__
+ ULONG oNext;
+#endif
+ BYTE cbName;
+ BYTE szName[10]; /* ".LONGNAME" */
+}
+GEALST;
+
+char *GetLongNameEA(const char *name)
+{
+ EAOP eaop;
+ GEALST gealst;
+ static FEALST fealst;
+ char *ptr;
+
+ eaop.fpGEAList = (PGEALIST) &gealst;
+ eaop.fpFEAList = (PFEALIST) &fealst;
+ eaop.oError = 0;
+
+ strcpy((char *) gealst.szName, ".LONGNAME");
+ gealst.cbName = (BYTE) strlen((char *) gealst.szName);
+#ifdef __32BIT__
+ gealst.oNext = 0;
+#endif
+
+ gealst.cbList = sizeof(gealst);
+ fealst.cbList = sizeof(fealst);
+
+ if (DosQueryPathInfo(name, FIL_QUERYEASFROMLIST,
+ (PBYTE) &eaop, sizeof(eaop)))
+ return NULL;
+
+ if (fealst.cbValue > 4 && fealst.eaType == 0xFFFD)
+ {
+ fealst.szValue[fealst.eaSize] = 0;
+
+ for (ptr = fealst.szValue; *ptr; ptr++)
+ if (*ptr == '/' || *ptr == '\\')
+ *ptr = '!';
+
+ return (char *) fealst.szValue;
+ }
+
+ return NULL;
+}
+
+char *GetLongPathEA(const char *name)
+{
+ static char nbuf[CCHMAXPATH + 1];
+ char tempbuf[CCHMAXPATH + 1];
+ char *comp, *next, *ea, sep;
+ BOOL bFound = FALSE;
+
+ nbuf[0] = 0;
+ strncpy(tempbuf, name, CCHMAXPATH);
+ tempbuf[CCHMAXPATH] = '\0';
+ next = tempbuf;
+
+ while (*next)
+ {
+ comp = next;
+
+ while (*next != '\\' && *next != '/' && *next != 0)
+ next++;
+
+ sep = *next;
+ *next = 0;
+
+ ea = GetLongNameEA(tempbuf);
+ strcat(nbuf, ea ? ea : comp);
+ bFound = bFound || (ea != NULL);
+
+ if (sep)
+ {
+ strcat(nbuf, "\\");
+ *next++ = sep;
+ }
+ }
+
+ return (nbuf[0] != 0) && bFound ? nbuf : NULL;
+}
+
+/* general EA code */
+
+typedef struct
+{
+ USHORT nID;
+ USHORT nSize;
+ ULONG lSize;
+}
+EFHEADER, *PEFHEADER;
+
+#ifdef __32BIT__
+
+/* Perhaps due to bugs in the current OS/2 2.0 kernel, the success or
+ failure of the DosEnumAttribute() and DosQueryPathInfo() system calls
+ depends on the area where the return buffers are allocated. This
+ differs for the various compilers, for some alloca() works, for some
+ malloc() works, for some, both work. We'll have to live with that. */
+
+/* The use of malloc() is not very convenient, because it requires
+ backtracking (i.e. free()) at error returns. We do that for system
+ calls that may fail, but not for malloc() calls, because they are VERY
+ unlikely to fail. If ever, we just leave some memory allocated
+ over the usually short lifetime of a zip process ... */
+
+#ifdef __GNUC__
+#define alloc(x) alloca(x)
+#define unalloc(x)
+#else
+#define alloc(x) malloc(x)
+#define unalloc(x) free(x)
+#endif
+
+void GetEAs(char *path, char **bufptr, size_t *size,
+ char **cbufptr, size_t *csize)
+{
+ FILESTATUS4 fs;
+ PDENA2 pDENA, pFound;
+ EAOP2 eaop;
+ PGEA2 pGEA;
+ PGEA2LIST pGEAlist;
+ PFEA2LIST pFEAlist;
+ PEFHEADER pEAblock;
+ ULONG ulAttributes, ulMemoryBlock;
+ ULONG nLength;
+ ULONG nBlock;
+ char szName[CCHMAXPATH];
+
+ *size = *csize = 0;
+
+ strcpy(szName, path);
+ nLength = strlen(szName);
+ if (szName[nLength - 1] == '/')
+ szName[nLength - 1] = 0;
+
+ if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs)))
+ return;
+ nBlock = max(fs.cbList, 65535);
+ if ((pDENA = alloc((size_t) nBlock)) == NULL)
+ return;
+
+ ulAttributes = -1;
+
+ if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, nBlock,
+ &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
+ || ulAttributes == 0
+ || (pGEAlist = alloc((size_t) nBlock)) == NULL)
+ {
+ unalloc(pDENA);
+ return;
+ }
+
+ pGEA = pGEAlist -> list;
+ memset(pGEAlist, 0, nBlock);
+ pFound = pDENA;
+
+ while (ulAttributes--)
+ {
+ if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
+ {
+ pGEA -> cbName = pFound -> cbName;
+ strcpy(pGEA -> szName, pFound -> szName);
+
+ nLength = sizeof(GEA2) + strlen(pGEA -> szName);
+ nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
+
+ pGEA -> oNextEntryOffset = ulAttributes ? nLength : 0;
+ pGEA = (PGEA2) ((PCH) pGEA + nLength);
+ }
+
+ pFound = (PDENA2) ((PCH) pFound + pFound -> oNextEntryOffset);
+ }
+
+ if (pGEA == pGEAlist -> list) /* no attributes to save */
+ {
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+ return;
+ }
+
+ pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
+
+ pFEAlist = (PVOID) pDENA; /* reuse buffer */
+ pFEAlist -> cbList = nBlock;
+
+ eaop.fpGEA2List = pGEAlist;
+ eaop.fpFEA2List = pFEAlist;
+ eaop.oError = 0;
+
+ if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
+ (PBYTE) &eaop, sizeof(eaop)))
+ {
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+ return;
+ }
+
+ /* The maximum compressed size is (in case of STORE type) the
+ uncompressed size plus the size of the compression type field
+ plus the size of the CRC field + 2*5 deflate overhead bytes
+ for uncompressable data.
+ (5 bytes per 32Kb block, max compressed size = 2 blocks) */
+
+ ulAttributes = pFEAlist -> cbList;
+ ulMemoryBlock = ulAttributes +
+ sizeof(USHORT) + sizeof(ULONG) + EB_DEFLAT_EXTRA;
+ pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER) + ulMemoryBlock);
+
+ if (pEAblock == NULL)
+ {
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+ return;
+ }
+
+ *bufptr = (char *) pEAblock;
+ *size = sizeof(EFHEADER);
+
+ pEAblock -> nID = EF_OS2EA;
+ pEAblock -> nSize = sizeof(pEAblock -> lSize);
+ pEAblock -> lSize = ulAttributes; /* uncompressed size */
+
+ nLength = memcompress((char *) (pEAblock + 1), ulMemoryBlock,
+ (char *) pFEAlist, ulAttributes);
+ *size += nLength;
+ pEAblock -> nSize += nLength;
+
+ if ((pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER))) == NULL)
+ {
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+ return;
+ }
+
+ *cbufptr = (char *) pEAblock;
+ *csize = sizeof(EFHEADER);
+
+ pEAblock -> nID = EF_OS2EA;
+ pEAblock -> nSize = sizeof(pEAblock -> lSize);
+ pEAblock -> lSize = ulAttributes;
+
+ if (noisy)
+ printf(" (%ld bytes EA's)", ulAttributes);
+
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+}
+
+#else /* !__32BIT__ */
+
+typedef struct
+{
+ ULONG oNextEntryOffset;
+ BYTE fEA;
+ BYTE cbName;
+ USHORT cbValue;
+ CHAR szName[1];
+}
+FEA2, *PFEA2;
+
+typedef struct
+{
+ ULONG cbList;
+ FEA2 list[1];
+}
+FEA2LIST, *PFEA2LIST;
+
+void GetEAs(char *path, char **bufptr, size_t *size,
+ char **cbufptr, size_t *csize)
+{
+ FILESTATUS2 fs;
+ PDENA1 pDENA, pFound;
+ EAOP eaop;
+ PGEALIST pGEAlist;
+ PGEA pGEA;
+ PFEALIST pFEAlist;
+ PFEA pFEA;
+ PFEA2LIST pFEA2list;
+ PFEA2 pFEA2;
+ EFHEADER *pEAblock;
+ ULONG ulAttributes;
+ USHORT nLength, nMaxSize;
+ char szName[CCHMAXPATH];
+
+ *size = *csize = 0;
+
+ strcpy(szName, path);
+ nLength = strlen(szName);
+ if (szName[nLength - 1] == '/')
+ szName[nLength - 1] = 0;
+
+ if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs))
+ || fs.cbList <= 2 * sizeof(ULONG))
+ return;
+
+ ulAttributes = -1;
+ nMaxSize = (USHORT) min(fs.cbList * 2, 65520L);
+
+ if ((pDENA = malloc((size_t) nMaxSize)) == NULL)
+ return;
+
+ if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, fs.cbList,
+ &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
+ || ulAttributes == 0
+ || (pGEAlist = malloc(nMaxSize)) == NULL)
+ {
+ free(pDENA);
+ return;
+ }
+
+ pGEA = pGEAlist -> list;
+ pFound = pDENA;
+
+ while (ulAttributes--)
+ {
+ nLength = strlen(pFound -> szName);
+
+ if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
+ {
+ pGEA -> cbName = pFound -> cbName;
+ strcpy(pGEA -> szName, pFound -> szName);
+
+ pGEA++;
+ pGEA = (PGEA) (((PCH) pGEA) + nLength);
+ }
+
+ pFound++;
+ pFound = (PDENA1) (((PCH) pFound) + nLength);
+ }
+
+ if (pGEA == pGEAlist -> list)
+ {
+ free(pDENA);
+ free(pGEAlist);
+ return;
+ }
+
+ pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
+
+ pFEAlist = (PFEALIST) pDENA; /* reuse buffer */
+ pFEAlist -> cbList = fs.cbList;
+ pFEA = pFEAlist -> list;
+
+ eaop.fpGEAList = pGEAlist;
+ eaop.fpFEAList = pFEAlist;
+ eaop.oError = 0;
+
+ if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
+ (PBYTE) &eaop, sizeof(eaop)))
+ {
+ free(pDENA);
+ free(pGEAlist);
+ return;
+ }
+
+ /* now convert into new OS/2 2.0 32-bit format */
+
+ pFEA2list = (PFEA2LIST) pGEAlist; /* reuse buffer */
+ pFEA2 = pFEA2list -> list;
+
+ while ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList)
+ {
+ nLength = sizeof(FEA) + pFEA -> cbName + 1 + pFEA -> cbValue;
+ memcpy((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset), pFEA, nLength);
+ memset((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset) + nLength, 0, 3);
+ pFEA = (PFEA) ((PCH) pFEA + nLength);
+
+ nLength = sizeof(FEA2) + pFEA2 -> cbName + 1 + pFEA2 -> cbValue;
+ nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
+ /* rounded up to 4-byte boundary */
+ pFEA2 -> oNextEntryOffset =
+ ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList) ? nLength : 0;
+ pFEA2 = (PFEA2) ((PCH) pFEA2 + nLength);
+ }
+
+ pFEA2list -> cbList = (PCH) pFEA2 - (PCH) pFEA2list;
+ ulAttributes = pFEA2list -> cbList;
+
+ pEAblock = (PEFHEADER) pDENA; /* reuse buffer */
+
+ *bufptr = (char *) pEAblock;
+ *size = sizeof(EFHEADER);
+
+ pEAblock -> nID = EF_OS2EA;
+ pEAblock -> nSize = sizeof(pEAblock -> lSize);
+ pEAblock -> lSize = ulAttributes; /* uncompressed size */
+
+ nLength = (USHORT) memcompress((char *) (pEAblock + 1),
+ nMaxSize - sizeof(EFHEADER), (char *) pFEA2list, ulAttributes);
+
+ *size += nLength;
+ pEAblock -> nSize += nLength;
+
+ pEAblock = (PEFHEADER) pGEAlist;
+
+ *cbufptr = (char *) pEAblock;
+ *csize = sizeof(EFHEADER);
+
+ pEAblock -> nID = EF_OS2EA;
+ pEAblock -> nSize = sizeof(pEAblock -> lSize);
+ pEAblock -> lSize = ulAttributes;
+
+ if (noisy)
+ printf(" (%ld bytes EA's)", ulAttributes);
+}
+
+#endif /* __32BIT__ */
+
+void GetACL(char *path, char **bufptr, size_t *size,
+ char **cbufptr, size_t *csize)
+{
+ static char *buffer;
+ char *cbuffer;
+ long bytes, cbytes;
+ PEFHEADER pACLblock;
+
+ if (buffer == NULL) /* avoid frequent allocation (for every file) */
+ if ((buffer = malloc(ACL_BUFFERSIZE)) == NULL)
+ return;
+
+ if (acl_get(NULL, path, buffer))
+ return; /* this will be the most likely case */
+
+ bytes = strlen(buffer);
+
+ /* The maximum compressed size is (in case of STORE type) the
+ uncompressed size plus the size of the compression type field
+ plus the size of the CRC field + 2*5 deflate overhead bytes
+ for uncompressable data.
+ (5 bytes per 32Kb block, max compressed size = 2 blocks) */
+
+ cbytes = bytes + sizeof(USHORT) + sizeof(ULONG) + EB_DEFLAT_EXTRA;
+ if ((*bufptr = realloc(*bufptr, *size + sizeof(EFHEADER) + cbytes)) == NULL)
+ return;
+
+ pACLblock = (PEFHEADER) (*bufptr + *size);
+
+ cbuffer = (char *) (pACLblock + 1);
+ cbytes = memcompress(cbuffer, cbytes, buffer, bytes);
+
+ *size += sizeof(EFHEADER) + cbytes;
+
+ pACLblock -> nID = EF_ACL;
+ pACLblock -> nSize = sizeof(pACLblock -> lSize) + cbytes;
+ pACLblock -> lSize = bytes; /* uncompressed size */
+
+ if ((*cbufptr = realloc(*cbufptr, *csize + sizeof(EFHEADER))) == NULL)
+ return;
+
+ pACLblock = (PEFHEADER) (*cbufptr + *csize);
+ *csize += sizeof(EFHEADER);
+
+ pACLblock -> nID = EF_ACL;
+ pACLblock -> nSize = sizeof(pACLblock -> lSize);
+ pACLblock -> lSize = bytes;
+
+ if (noisy)
+ printf(" (%ld bytes ACL)", bytes);
+}
+
+#ifdef USE_EF_UT_TIME
+
+int GetExtraTime(struct zlist far *z, iztimes *z_utim)
+{
+ int eb_c_size = EB_HEADSIZE + EB_UT_LEN(1);
+ int eb_l_size = eb_c_size;
+ char *eb_c_ptr;
+ char *eb_l_ptr;
+ unsigned long ultime;
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid) return ZE_OK; /* skip silently no correct tz info */
+#endif
+
+ eb_c_ptr = realloc(z->cextra, (z->cext + eb_c_size));
+ if (eb_c_ptr == NULL)
+ return ZE_MEM;
+ z->cextra = eb_c_ptr;
+ eb_c_ptr += z->cext;
+ z->cext += eb_c_size;
+
+ eb_c_ptr[0] = 'U';
+ eb_c_ptr[1] = 'T';
+ eb_c_ptr[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ eb_c_ptr[3] = 0;
+ eb_c_ptr[4] = EB_UT_FL_MTIME;
+ ultime = (unsigned long) z_utim->mtime;
+ eb_c_ptr[5] = (char)(ultime);
+ eb_c_ptr[6] = (char)(ultime >> 8);
+ eb_c_ptr[7] = (char)(ultime >> 16);
+ eb_c_ptr[8] = (char)(ultime >> 24);
+
+ if (z_utim->mtime != z_utim->atime || z_utim->mtime != z_utim->ctime)
+ {
+ eb_c_ptr[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
+ eb_l_size = EB_HEADSIZE + EB_UT_LEN(3); /* only on HPFS they can differ */
+ /* so only then it makes sense to store all three time stamps */
+ }
+
+ eb_l_ptr = realloc(z->extra, (z->ext + eb_l_size));
+ if (eb_l_ptr == NULL)
+ return ZE_MEM;
+ z->extra = eb_l_ptr;
+ eb_l_ptr += z->ext;
+ z->ext += eb_l_size;
+
+ memcpy(eb_l_ptr, eb_c_ptr, eb_c_size);
+
+ if (eb_l_size > eb_c_size)
+ {
+ eb_l_ptr[2] = EB_UT_LEN(3);
+ ultime = (unsigned long) z_utim->atime;
+ eb_l_ptr[9] = (char)(ultime);
+ eb_l_ptr[10] = (char)(ultime >> 8);
+ eb_l_ptr[11] = (char)(ultime >> 16);
+ eb_l_ptr[12] = (char)(ultime >> 24);
+ ultime = (unsigned long) z_utim->ctime;
+ eb_l_ptr[13] = (char)(ultime);
+ eb_l_ptr[14] = (char)(ultime >> 8);
+ eb_l_ptr[15] = (char)(ultime >> 16);
+ eb_l_ptr[16] = (char)(ultime >> 24);
+ }
+
+ return ZE_OK;
+}
+
+#endif /* USE_EF_UT_TIME */
+
+int set_extra_field(struct zlist far *z, iztimes *z_utim)
+{
+ /* store EA data in local header, and size only in central headers */
+ GetEAs(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
+
+ /* store ACL data in local header, and size only in central headers */
+ GetACL(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
+
+#ifdef USE_EF_UT_TIME
+ /* store extended time stamps in both headers */
+ return GetExtraTime(z, z_utim);
+#else /* !USE_EF_UT_TIME */
+ return ZE_OK;
+#endif /* ?USE_EF_UT_TIME */
+}
+
+#endif /* !UTIL */
+
+/* Initialize the table of uppercase characters including handling of
+ country dependent characters. */
+
+void init_upper()
+{
+ COUNTRYCODE cc;
+ unsigned nCnt, nU;
+
+ for (nCnt = 0; nCnt < sizeof(upper); nCnt++)
+ upper[nCnt] = lower[nCnt] = (unsigned char) nCnt;
+
+ cc.country = cc.codepage = 0;
+ DosMapCase(sizeof(upper), &cc, (PCHAR) upper);
+
+ for (nCnt = 0; nCnt < 256; nCnt++)
+ {
+ nU = upper[nCnt];
+ if (nU != nCnt && lower[nU] == (unsigned char) nU)
+ lower[nU] = (unsigned char) nCnt;
+ }
+
+ for (nCnt = 'A'; nCnt <= 'Z'; nCnt++)
+ lower[nCnt] = (unsigned char) (nCnt - 'A' + 'a');
+}
+
+char *StringLower(char *szArg)
+{
+ unsigned char *szPtr;
+ for (szPtr = (unsigned char *) szArg; *szPtr; szPtr++)
+ *szPtr = lower[*szPtr];
+ return szArg;
+}
+
+#if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
+void DebugMalloc(void)
+{
+ _dump_allocated(0); /* print out debug malloc memory statistics */
+}
+#endif
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if defined(__IBMC__) || defined(__WATCOMC__) || defined(_MSC_VER)
+ char buf[80];
+#endif
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+# ifdef __EMX__ /* __EMX__ is defined as "1" only (sigh) */
+ "emx+gcc ", __VERSION__,
+# else
+ "gcc/2 ", __VERSION__,
+# endif
+#elif defined(__IBMC__)
+ "IBM ",
+# if (__IBMC__ < 200)
+ (sprintf(buf, "C Set/2 %d.%02d", __IBMC__/100,__IBMC__%100), buf),
+# elif (__IBMC__ < 300)
+ (sprintf(buf, "C Set++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
+# else
+ (sprintf(buf, "Visual Age C++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
+# endif
+#elif defined(__WATCOMC__)
+ "Watcom C", (sprintf(buf, " (__WATCOMC__ = %d)", __WATCOMC__), buf),
+#elif defined(__TURBOC__)
+# ifdef __BORLANDC__
+ "Borland C++",
+# if (__BORLANDC__ < 0x0460)
+ " 1.0",
+# elif (__BORLANDC__ == 0x0460)
+ " 1.5",
+# else
+ " 2.0",
+# endif
+# else
+ "Turbo C",
+# if (__TURBOC__ >= 661)
+ "++ 1.0 or later",
+# elif (__TURBOC__ == 661)
+ " 3.0?",
+# elif (__TURBOC__ == 397)
+ " 2.0",
+# else
+ " 1.0 or 1.5?",
+# endif
+# endif
+#elif defined(MSC)
+ "Microsoft C ",
+# ifdef _MSC_VER
+ (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
+# else
+ "5.1 or earlier",
+# endif
+#else
+ "unknown compiler", "",
+#endif /* __GNUC__ */
+
+ "OS/2",
+
+/* GRR: does IBM C/2 identify itself as IBM rather than Microsoft? */
+#if (defined(MSC) || (defined(__WATCOMC__) && !defined(__386__)))
+# if defined(M_I86HM) || defined(__HUGE__)
+ " (16-bit, huge)",
+# elif defined(M_I86LM) || defined(__LARGE__)
+ " (16-bit, large)",
+# elif defined(M_I86MM) || defined(__MEDIUM__)
+ " (16-bit, medium)",
+# elif defined(M_I86CM) || defined(__COMPACT__)
+ " (16-bit, compact)",
+# elif defined(M_I86SM) || defined(__SMALL__)
+ " (16-bit, small)",
+# elif defined(M_I86TM) || defined(__TINY__)
+ " (16-bit, tiny)",
+# else
+ " (16-bit)",
+# endif
+#else
+ " 2.x/3.x (32-bit)",
+#endif
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+ /* temporary debugging code for Borland compilers only */
+#ifdef __TURBOC__
+ printf("\t(__TURBOC__ = 0x%04x = %d)\n", __TURBOC__, __TURBOC__);
+#ifdef __BORLANDC__
+ printf("\t(__BORLANDC__ = 0x%04x)\n",__BORLANDC__);
+#else
+ printf("\tdebug(__BORLANDC__ not defined)\n");
+#endif
+#ifdef __TCPLUSPLUS__
+ printf("\t(__TCPLUSPLUS__ = 0x%04x)\n", __TCPLUSPLUS__);
+#else
+ printf("\tdebug(__TCPLUSPLUS__ not defined)\n");
+#endif
+#ifdef __BCPLUSPLUS__
+ printf("\t(__BCPLUSPLUS__ = 0x%04x)\n\n", __BCPLUSPLUS__);
+#else
+ printf("\tdebug(__BCPLUSPLUS__ not defined)\n\n");
+#endif
+#endif /* __TURBOC__ */
+
+} /* end function version_local() */
+
+#endif /* OS2 */