home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip22.zip / os2 / os2zip.c < prev    next >
C/C++ Source or Header  |  1997-07-20  |  28KB  |  1,195 lines

  1. /*
  2.  * @(#)dir.c 1.4 87/11/06 Public Domain.
  3.  *
  4.  *  A public domain implementation of BSD directory routines for
  5.  *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
  6.  *  August 1897
  7.  *  Ported to OS/2 by Kai Uwe Rommel
  8.  *  December 1989, February 1990
  9.  *  Change for HPFS support, October 1990
  10.  */
  11.  
  12. /* does also contain EA access code for use in ZIP */
  13.  
  14.  
  15. #ifdef OS2
  16.  
  17.  
  18. #if defined(__EMX__) && !defined(__32BIT__)
  19. #  define __32BIT__
  20. #endif
  21.  
  22. #include "zip.h"
  23.  
  24. #include <stdlib.h>
  25. #include <time.h>
  26. #include <ctype.h>
  27. #ifndef __BORLANDC__
  28. #include <malloc.h>
  29. #endif
  30.  
  31. #define INCL_NOPM
  32. #define INCL_DOSNLS
  33. #define INCL_DOSERRORS
  34. #include <os2.h>
  35.  
  36. #include "os2zip.h"
  37. #include "os2acl.h"
  38.  
  39.  
  40. #ifndef max
  41. #define max(a, b) ((a) < (b) ? (b) : (a))
  42. #endif
  43.  
  44.  
  45. #ifdef __32BIT__
  46. #define DosFindFirst(p1, p2, p3, p4, p5, p6) \
  47.         DosFindFirst(p1, p2, p3, p4, p5, p6, 1)
  48. #else
  49. #define DosQueryCurrentDisk DosQCurDisk
  50. #define DosQueryFSAttach(p1, p2, p3, p4, p5) \
  51.         DosQFSAttach(p1, p2, p3, p4, p5, 0)
  52. #define DosQueryFSInfo(d, l, b, s) \
  53.         DosQFSInfo(d, l, b, s)
  54. #define DosQueryPathInfo(p1, p2, p3, p4) \
  55.         DosQPathInfo(p1, p2, p3, p4, 0)
  56. #define DosSetPathInfo(p1, p2, p3, p4, p5) \
  57.         DosSetPathInfo(p1, p2, p3, p4, p5, 0)
  58. #define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \
  59.         DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0)
  60. #define DosFindFirst(p1, p2, p3, p4, p5, p6) \
  61.         DosFindFirst(p1, p2, p3, p4, p5, p6, 0)
  62. #define DosMapCase DosCaseMap
  63. #endif
  64.  
  65.  
  66. #ifndef UTIL
  67.  
  68. extern int noisy;
  69.  
  70. #ifndef S_IFMT
  71. #define S_IFMT 0xF000
  72. #endif
  73.  
  74. static int attributes = _A_DIR | _A_HIDDEN | _A_SYSTEM;
  75.  
  76. static char *getdirent(char *);
  77. static void free_dircontents(struct _dircontents *);
  78.  
  79. #ifdef __32BIT__
  80. static HDIR hdir;
  81. static ULONG count;
  82. static FILEFINDBUF3 find;
  83. #else
  84. static HDIR hdir;
  85. static USHORT count;
  86. static FILEFINDBUF find;
  87. #endif
  88.  
  89. DIR *opendir(const char *name)
  90. {
  91.   struct stat statb;
  92.   DIR *dirp;
  93.   char c;
  94.   char *s;
  95.   struct _dircontents *dp;
  96.   char nbuf[MAXPATHLEN + 1];
  97.   int len;
  98.  
  99.   attributes = hidden_files ? (_A_DIR | _A_HIDDEN | _A_SYSTEM) : _A_DIR;
  100.  
  101.   strcpy(nbuf, name);
  102.   if ((len = strlen(nbuf)) == 0)
  103.     return NULL;
  104.  
  105.   if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1))
  106.   {
  107.     nbuf[len - 1] = 0;
  108.     --len;
  109.  
  110.     if (nbuf[len - 1] == ':')
  111.     {
  112.       strcpy(nbuf+len, "\\.");
  113.       len += 2;
  114.     }
  115.   }
  116.   else
  117.     if (nbuf[len - 1] == ':')
  118.     {
  119.       strcpy(nbuf+len, ".");
  120.       ++len;
  121.     }
  122.  
  123. #ifndef __BORLANDC__
  124.   /* when will we ever see a Borland compiler that can properly stat !!! */
  125.   if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
  126.     return NULL;
  127. #endif
  128.  
  129.   if ((dirp = malloc(sizeof(DIR))) == NULL)
  130.     return NULL;
  131.  
  132.   if (nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.'))
  133.     strcpy(nbuf+len-1, "*.*");
  134.   else
  135.     if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1))
  136.       strcpy(nbuf+len, "*");
  137.     else
  138.       strcpy(nbuf+len, "\\*");
  139.  
  140.   /* len is no longer correct (but no longer needed) */
  141.  
  142.   dirp -> dd_loc = 0;
  143.   dirp -> dd_contents = dirp -> dd_cp = NULL;
  144.  
  145.   if ((s = getdirent(nbuf)) == NULL)
  146.     return dirp;
  147.  
  148.   do
  149.   {
  150.     if (((dp = malloc(sizeof(struct _dircontents))) == NULL) ||
  151.         ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL)      )
  152.     {
  153.       if (dp)
  154.         free(dp);
  155.       free_dircontents(dirp -> dd_contents);
  156.  
  157.       return NULL;
  158.     }
  159.  
  160.     if (dirp -> dd_contents)
  161.     {
  162.       dirp -> dd_cp -> _d_next = dp;
  163.       dirp -> dd_cp = dirp -> dd_cp -> _d_next;
  164.     }
  165.     else
  166.       dirp -> dd_contents = dirp -> dd_cp = dp;
  167.  
  168.     strcpy(dp -> _d_entry, s);
  169.     dp -> _d_next = NULL;
  170.  
  171.     dp -> _d_size = find.cbFile;
  172.     dp -> _d_mode = find.attrFile;
  173.     dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite);
  174.     dp -> _d_date = *(unsigned *) &(find.fdateLastWrite);
  175.   }
  176.   while ((s = getdirent(NULL)) != NULL);
  177.  
  178.   dirp -> dd_cp = dirp -> dd_contents;
  179.  
  180.   return dirp;
  181. }
  182.  
  183. void closedir(DIR * dirp)
  184. {
  185.   free_dircontents(dirp -> dd_contents);
  186.   free(dirp);
  187. }
  188.  
  189. struct dirent *readdir(DIR * dirp)
  190. {
  191.   static struct dirent dp;
  192.  
  193.   if (dirp -> dd_cp == NULL)
  194.     return NULL;
  195.  
  196.   dp.d_namlen = dp.d_reclen =
  197.     strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry));
  198.  
  199.   dp.d_ino = 0;
  200.  
  201.   dp.d_size = dirp -> dd_cp -> _d_size;
  202.   dp.d_mode = dirp -> dd_cp -> _d_mode;
  203.   dp.d_time = dirp -> dd_cp -> _d_time;
  204.   dp.d_date = dirp -> dd_cp -> _d_date;
  205.  
  206.   dirp -> dd_cp = dirp -> dd_cp -> _d_next;
  207.   dirp -> dd_loc++;
  208.  
  209.   return &dp;
  210. }
  211.  
  212. void seekdir(DIR * dirp, long off)
  213. {
  214.   long i = off;
  215.   struct _dircontents *dp;
  216.  
  217.   if (off >= 0)
  218.   {
  219.     for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next);
  220.  
  221.     dirp -> dd_loc = off - (i + 1);
  222.     dirp -> dd_cp = dp;
  223.   }
  224. }
  225.  
  226. long telldir(DIR * dirp)
  227. {
  228.   return dirp -> dd_loc;
  229. }
  230.  
  231. static void free_dircontents(struct _dircontents * dp)
  232. {
  233.   struct _dircontents *odp;
  234.  
  235.   while (dp)
  236.   {
  237.     if (dp -> _d_entry)
  238.       free(dp -> _d_entry);
  239.  
  240.     dp = (odp = dp) -> _d_next;
  241.     free(odp);
  242.   }
  243. }
  244.  
  245. static char *getdirent(char *dir)
  246. {
  247.   int done;
  248.   static int lower;
  249.  
  250.   if (dir != NULL)
  251.   {                                    /* get first entry */
  252.     hdir = HDIR_SYSTEM;
  253.     count = 1;
  254.     done = DosFindFirst(dir, &hdir, attributes, &find, sizeof(find), &count);
  255.     lower = IsFileSystemFAT(dir);
  256.   }
  257.   else                                 /* get next entry */
  258.     done = DosFindNext(hdir, &find, sizeof(find), &count);
  259.  
  260.   if (done == 0)
  261.   {
  262.     if (lower)
  263.       StringLower(find.achName);
  264.     return find.achName;
  265.   }
  266.   else
  267.   {
  268.     DosFindClose(hdir);
  269.     return NULL;
  270.   }
  271. }
  272.  
  273. /* FAT / HPFS detection */
  274.  
  275. int IsFileSystemFAT(char *dir)
  276. {
  277.   static USHORT nLastDrive = -1, nResult;
  278.   ULONG lMap;
  279.   BYTE bData[64];
  280.   char bName[3];
  281. #ifdef __32BIT__
  282.   ULONG nDrive, cbData;
  283.   PFSQBUFFER2 pData = (PFSQBUFFER2) bData;
  284. #else
  285.   USHORT nDrive, cbData;
  286.   PFSQBUFFER pData = (PFSQBUFFER) bData;
  287. #endif
  288.  
  289.   /* We separate FAT and HPFS+other file systems here.
  290.      at the moment I consider other systems to be similar to HPFS,
  291.      i.e. support long file names and beeing case sensitive */
  292.  
  293.   if (isalpha(dir[0]) && (dir[1] == ':'))
  294.     nDrive = to_up(dir[0]) - '@';
  295.   else
  296.     DosQueryCurrentDisk(&nDrive, &lMap);
  297.  
  298.   if (nDrive == nLastDrive)
  299.     return nResult;
  300.  
  301.   bName[0] = (char) (nDrive + '@');
  302.   bName[1] = ':';
  303.   bName[2] = 0;
  304.  
  305.   nLastDrive = nDrive;
  306.   cbData = sizeof(bData);
  307.  
  308.   if (!DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData))
  309.     nResult = !strcmp((char *) pData -> szFSDName + pData -> cbName, "FAT");
  310.   else
  311.     nResult = FALSE;
  312.  
  313.   /* End of this ugly code */
  314.   return nResult;
  315. }
  316.  
  317. /* access mode bits and time stamp */
  318.  
  319. int GetFileMode(char *name)
  320. {
  321. #ifdef __32BIT__
  322.   FILESTATUS3 fs;
  323.   return DosQueryPathInfo(name, 1, &fs, sizeof(fs)) ? -1 : fs.attrFile;
  324. #else
  325.   USHORT mode;
  326.   return DosQFileMode(name, &mode, 0L) ? -1 : mode;
  327. #endif
  328. }
  329.  
  330. long GetFileTime(char *name)
  331. {
  332. #ifdef __32BIT__
  333.   FILESTATUS3 fs;
  334. #else
  335.   FILESTATUS fs;
  336. #endif
  337.   USHORT nDate, nTime;
  338.   DATETIME dtCurrent;
  339.  
  340.   if (strcmp(name, "-") == 0)
  341.   {
  342.     DosGetDateTime(&dtCurrent);
  343.     fs.fdateLastWrite.day     = dtCurrent.day;
  344.     fs.fdateLastWrite.month   = dtCurrent.month;
  345.     fs.fdateLastWrite.year    = dtCurrent.year - 1980;
  346.     fs.ftimeLastWrite.hours   = dtCurrent.hours;
  347.     fs.ftimeLastWrite.minutes = dtCurrent.minutes;
  348.     fs.ftimeLastWrite.twosecs = dtCurrent.seconds / 2;
  349.   }
  350.   else
  351.     if (DosQueryPathInfo(name, 1, (PBYTE) &fs, sizeof(fs)))
  352.       return -1;
  353.  
  354.   nDate = * (USHORT *) &fs.fdateLastWrite;
  355.   nTime = * (USHORT *) &fs.ftimeLastWrite;
  356.  
  357.   return ((ULONG) nDate) << 16 | nTime;
  358. }
  359.  
  360. void SetFileTime(char *path, long stamp)
  361. {
  362.   FILESTATUS fs;
  363.   USHORT fd, ft;
  364.  
  365.   if (DosQueryPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)))
  366.     return;
  367.  
  368.   fd = (USHORT) (stamp >> 16);
  369.   ft = (USHORT) stamp;
  370.   fs.fdateLastWrite = fs.fdateCreation = * (FDATE *) &fd;
  371.   fs.ftimeLastWrite = fs.ftimeCreation = * (FTIME *) &ft;
  372.  
  373.   DosSetPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0);
  374. }
  375.  
  376. /* read volume label */
  377.  
  378. char *getVolumeLabel(int drive, unsigned long *vtime, unsigned long *vmode,
  379.                      time_t *utim)
  380. {
  381.   static FSINFO fi;
  382.  
  383.   if (DosQueryFSInfo(drive ? drive - 'A' + 1 : 0,
  384.                      FSIL_VOLSER, (PBYTE) &fi, sizeof(fi)))
  385.     return NULL;
  386.  
  387.   time(utim);
  388.   *vtime = unix2dostime(utim);
  389.   *vmode = _A_VOLID | _A_ARCHIVE;
  390.  
  391.   return (fi.vol.cch > 0) ? fi.vol.szVolLabel : NULL;
  392. }
  393.  
  394. /* FAT / HPFS name conversion stuff */
  395.  
  396. int IsFileNameValid(char *name)
  397. {
  398.   HFILE hf;
  399. #ifdef __32BIT__
  400.   ULONG uAction;
  401. #else
  402.   USHORT uAction;
  403. #endif
  404.  
  405.   switch(DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN,
  406.                  OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0))
  407.   {
  408.   case ERROR_INVALID_NAME:
  409.   case ERROR_FILENAME_EXCED_RANGE:
  410.     return FALSE;
  411.   case NO_ERROR:
  412.     DosClose(hf);
  413.   default:
  414.     return TRUE;
  415.   }
  416. }
  417.  
  418. void ChangeNameForFAT(char *name)
  419. {
  420.   char *src, *dst, *next, *ptr, *dot, *start;
  421.   static char invalid[] = ":;,=+\"[]<>| \t";
  422.  
  423.   if (isalpha(name[0]) && (name[1] == ':'))
  424.     start = name + 2;
  425.   else
  426.     start = name;
  427.  
  428.   src = dst = start;
  429.   if ((*src == '/') || (*src == '\\'))
  430.     src++, dst++;
  431.  
  432.   while (*src)
  433.   {
  434.     for (next = src; *next && (*next != '/') && (*next != '\\'); next++);
  435.  
  436.     for (ptr = src, dot = NULL; ptr < next; ptr++)
  437.       if (*ptr == '.')
  438.       {
  439.         dot = ptr; /* remember last dot */
  440.         *ptr = '_';
  441.       }
  442.  
  443.     if (dot == NULL)
  444.       for (ptr = src; ptr < next; ptr++)
  445.         if (*ptr == '_')
  446.           dot = ptr; /* remember last _ as if it were a dot */
  447.  
  448.     if (dot && (dot > src) &&
  449.         ((next - dot <= 4) ||
  450.          ((next - src > 8) && (dot - src > 3))))
  451.     {
  452.       if (dot)
  453.         *dot = '.';
  454.  
  455.       for (ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++)
  456.         *dst++ = *ptr;
  457.  
  458.       for (ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++)
  459.         *dst++ = *ptr;
  460.     }
  461.     else
  462.     {
  463.       if (dot && (next - src == 1))
  464.         *dot = '.';           /* special case: "." as a path component */
  465.  
  466.       for (ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++)
  467.         *dst++ = *ptr;
  468.     }
  469.  
  470.     *dst++ = *next; /* either '/' or 0 */
  471.  
  472.     if (*next)
  473.     {
  474.       src = next + 1;
  475.  
  476.       if (*src == 0) /* handle trailing '/' on dirs ! */
  477.         *dst = 0;
  478.     }
  479.     else
  480.       break;
  481.   }
  482.  
  483.   for (src = start; *src != 0; ++src)
  484.     if ((strchr(invalid, *src) != NULL) || (*src == ' '))
  485.       *src = '_';
  486. }
  487.  
  488. /* .LONGNAME EA code */
  489.  
  490. typedef struct
  491. {
  492.   ULONG cbList;               /* length of value + 22 */
  493. #ifdef __32BIT__
  494.   ULONG oNext;
  495. #endif
  496.   BYTE fEA;                   /* 0 */
  497.   BYTE cbName;                /* length of ".LONGNAME" = 9 */
  498.   USHORT cbValue;             /* length of value + 4 */
  499.   BYTE szName[10];            /* ".LONGNAME" */
  500.   USHORT eaType;              /* 0xFFFD for length-preceded ASCII */
  501.   USHORT eaSize;              /* length of value */
  502.   BYTE szValue[CCHMAXPATH];
  503. }
  504. FEALST;
  505.  
  506. typedef struct
  507. {
  508.   ULONG cbList;
  509. #ifdef __32BIT__
  510.   ULONG oNext;
  511. #endif
  512.   BYTE cbName;
  513.   BYTE szName[10];            /* ".LONGNAME" */
  514. }
  515. GEALST;
  516.  
  517. char *GetLongNameEA(char *name)
  518. {
  519.   EAOP eaop;
  520.   GEALST gealst;
  521.   static FEALST fealst;
  522.   char *ptr;
  523.  
  524.   eaop.fpGEAList = (PGEALIST) &gealst;
  525.   eaop.fpFEAList = (PFEALIST) &fealst;
  526.   eaop.oError = 0;
  527.  
  528.   strcpy((char *) gealst.szName, ".LONGNAME");
  529.   gealst.cbName  = (BYTE) strlen((char *) gealst.szName);
  530. #ifdef __32BIT__
  531.   gealst.oNext   = 0;
  532. #endif
  533.  
  534.   gealst.cbList  = sizeof(gealst);
  535.   fealst.cbList  = sizeof(fealst);
  536.  
  537.   if (DosQueryPathInfo(name, FIL_QUERYEASFROMLIST,
  538.                        (PBYTE) &eaop, sizeof(eaop)))
  539.     return NULL;
  540.  
  541.   if (fealst.cbValue > 4 && fealst.eaType == 0xFFFD)
  542.   {
  543.     fealst.szValue[fealst.eaSize] = 0;
  544.  
  545.     for (ptr = fealst.szValue; *ptr; ptr++)
  546.       if (*ptr == '/' || *ptr == '\\')
  547.         *ptr = '!';
  548.  
  549.     return (char *) fealst.szValue;
  550.   }
  551.  
  552.   return NULL;
  553. }
  554.  
  555. char *GetLongPathEA(char *name)
  556. {
  557.   static char nbuf[CCHMAXPATH + 1];
  558.   char *comp, *next, *ea, sep;
  559.   BOOL bFound = FALSE;
  560.  
  561.   nbuf[0] = 0;
  562.   next = name;
  563.  
  564.   while (*next)
  565.   {
  566.     comp = next;
  567.  
  568.     while (*next != '\\' && *next != '/' && *next != 0)
  569.       next++;
  570.  
  571.     sep = *next;
  572.     *next = 0;
  573.  
  574.     ea = GetLongNameEA(name);
  575.     strcat(nbuf, ea ? ea : comp);
  576.     bFound = bFound || (ea != NULL);
  577.  
  578.     *next = sep;
  579.  
  580.     if (*next)
  581.     {
  582.       strcat(nbuf, "\\");
  583.       next++;
  584.     }
  585.   }
  586.  
  587.   return (nbuf[0] != 0) && bFound ? nbuf : NULL;
  588. }
  589.  
  590. /* general EA code */
  591.  
  592. typedef struct
  593. {
  594.   USHORT nID;
  595.   USHORT nSize;
  596.   ULONG lSize;
  597. }
  598. EFHEADER, *PEFHEADER;
  599.  
  600. #ifdef __32BIT__
  601.  
  602. /* Perhaps due to bugs in the current OS/2 2.0 kernel, the success or
  603.    failure of the DosEnumAttribute() and DosQueryPathInfo() system calls
  604.    depends on the area where the return buffers are allocated. This
  605.    differs for the various compilers, for some alloca() works, for some
  606.    malloc() works, for some, both work. We'll have to live with that. */
  607.  
  608. /* The use of malloc() is not very convenient, because it requires
  609.    backtracking (i.e. free()) at error returns. We do that for system
  610.    calls that may fail, but not for malloc() calls, because they are VERY
  611.    unlikely to fail. If ever, we just leave some memory allocated
  612.    over the usually short lifetime of a zip process ... */
  613.  
  614. #ifdef __GNUC__
  615. #define alloc(x) alloca(x)
  616. #define unalloc(x)
  617. #else
  618. #define alloc(x) malloc(x)
  619. #define unalloc(x) free(x)
  620. #endif
  621.  
  622. void GetEAs(char *path, char **bufptr, size_t *size,
  623.                         char **cbufptr, size_t *csize)
  624. {
  625.   FILESTATUS4 fs;
  626.   PDENA2 pDENA, pFound;
  627.   EAOP2 eaop;
  628.   PGEA2 pGEA;
  629.   PGEA2LIST pGEAlist;
  630.   PFEA2LIST pFEAlist;
  631.   PEFHEADER pEAblock;
  632.   ULONG ulAttributes, ulMemoryBlock;
  633.   ULONG nLength;
  634.   ULONG nBlock;
  635.   char szName[CCHMAXPATH];
  636.  
  637.   *size = *csize = 0;
  638.  
  639.   strcpy(szName, path);
  640.   nLength = strlen(szName);
  641.   if (szName[nLength - 1] == '/')
  642.     szName[nLength - 1] = 0;
  643.  
  644.   if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs)))
  645.     return;
  646.   nBlock = max(fs.cbList, 65535);
  647.   if ((pDENA = alloc((size_t) nBlock)) == NULL)
  648.     return;
  649.  
  650.   ulAttributes = -1;
  651.  
  652.   if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, nBlock,
  653.                        &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
  654.     || ulAttributes == 0
  655.     || (pGEAlist = alloc((size_t) nBlock)) == NULL)
  656.   {
  657.     unalloc(pDENA);
  658.     return;
  659.   }
  660.  
  661.   pGEA = pGEAlist -> list;
  662.   memset(pGEAlist, 0, nBlock);
  663.   pFound = pDENA;
  664.  
  665.   while (ulAttributes--)
  666.   {
  667.     if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
  668.     {
  669.       pGEA -> cbName = pFound -> cbName;
  670.       strcpy(pGEA -> szName, pFound -> szName);
  671.  
  672.       nLength = sizeof(GEA2) + strlen(pGEA -> szName);
  673.       nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
  674.  
  675.       pGEA -> oNextEntryOffset = ulAttributes ? nLength : 0;
  676.       pGEA   = (PGEA2)  ((PCH) pGEA + nLength);
  677.     }
  678.  
  679.     pFound = (PDENA2) ((PCH) pFound + pFound -> oNextEntryOffset);
  680.   }
  681.  
  682.   if (pGEA == pGEAlist -> list) /* no attributes to save */
  683.   {
  684.     unalloc(pDENA);
  685.     unalloc(pGEAlist);
  686.     return;
  687.   }
  688.  
  689.   pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
  690.  
  691.   pFEAlist = (PVOID) pDENA;  /* reuse buffer */
  692.   pFEAlist -> cbList = nBlock;
  693.  
  694.   eaop.fpGEA2List = pGEAlist;
  695.   eaop.fpFEA2List = pFEAlist;
  696.   eaop.oError = 0;
  697.  
  698.   if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
  699.                        (PBYTE) &eaop, sizeof(eaop)))
  700.   {
  701.     unalloc(pDENA);
  702.     unalloc(pGEAlist);
  703.     return;
  704.   }
  705.  
  706.   /* The maximum compressed size is (in case of STORE type) the
  707.      uncompressed size plus the size of the compression type field
  708.      plus the size of the CRC field. */
  709.  
  710.   ulAttributes = pFEAlist -> cbList;
  711.   ulMemoryBlock = ulAttributes + sizeof(USHORT) + sizeof(ULONG);
  712.   pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER) + ulMemoryBlock);
  713.  
  714.   if (pEAblock == NULL)
  715.   {
  716.     unalloc(pDENA);
  717.     unalloc(pGEAlist);
  718.     return;
  719.   }
  720.  
  721.   *bufptr = (char *) pEAblock;
  722.   *size = sizeof(EFHEADER);
  723.  
  724.   pEAblock -> nID = EF_OS2EA;
  725.   pEAblock -> nSize = sizeof(pEAblock -> lSize);
  726.   pEAblock -> lSize = ulAttributes; /* uncompressed size */
  727.  
  728.   nLength = memcompress((char *) (pEAblock + 1), ulMemoryBlock,
  729.                         (char *) pFEAlist, ulAttributes);
  730.   *size += nLength;
  731.   pEAblock -> nSize += nLength;
  732.  
  733.   if ((pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER))) == NULL)
  734.   {
  735.     unalloc(pDENA);
  736.     unalloc(pGEAlist);
  737.     return;
  738.   }
  739.  
  740.   *cbufptr = (char *) pEAblock;
  741.   *csize = sizeof(EFHEADER);
  742.  
  743.   pEAblock -> nID = EF_OS2EA;
  744.   pEAblock -> nSize = sizeof(pEAblock -> lSize);
  745.   pEAblock -> lSize = ulAttributes;
  746.  
  747.   if (noisy)
  748.     printf(" (%ld bytes EA's)", ulAttributes);
  749.  
  750.   unalloc(pDENA);
  751.   unalloc(pGEAlist);
  752. }
  753.  
  754. #else /* !__32BIT__ */
  755.  
  756. typedef struct
  757. {
  758.   ULONG oNextEntryOffset;
  759.   BYTE fEA;
  760.   BYTE cbName;
  761.   USHORT cbValue;
  762.   CHAR szName[1];
  763. }
  764. FEA2, *PFEA2;
  765.  
  766. typedef struct
  767. {
  768.   ULONG cbList;
  769.   FEA2 list[1];
  770. }
  771. FEA2LIST, *PFEA2LIST;
  772.  
  773. void GetEAs(char *path, char **bufptr, size_t *size,
  774.                         char **cbufptr, size_t *csize)
  775. {
  776.   FILESTATUS2 fs;
  777.   PDENA1 pDENA, pFound;
  778.   EAOP eaop;
  779.   PGEALIST pGEAlist;
  780.   PGEA pGEA;
  781.   PFEALIST pFEAlist;
  782.   PFEA pFEA;
  783.   PFEA2LIST pFEA2list;
  784.   PFEA2 pFEA2;
  785.   EFHEADER *pEAblock;
  786.   ULONG ulAttributes;
  787.   USHORT nLength, nMaxSize;
  788.   char szName[CCHMAXPATH];
  789.  
  790.   *size = *csize = 0;
  791.  
  792.   strcpy(szName, path);
  793.   nLength = strlen(szName);
  794.   if (szName[nLength - 1] == '/')
  795.     szName[nLength - 1] = 0;
  796.  
  797.   if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs))
  798.       || fs.cbList <= 2 * sizeof(ULONG))
  799.     return;
  800.  
  801.   ulAttributes = -1;
  802.   nMaxSize = (USHORT) min(fs.cbList * 2, 65520L);
  803.  
  804.   if ((pDENA = malloc((size_t) nMaxSize)) == NULL)
  805.     return;
  806.  
  807.   if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, fs.cbList,
  808.                        &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
  809.     || ulAttributes == 0
  810.     || (pGEAlist = malloc(nMaxSize)) == NULL)
  811.   {
  812.     free(pDENA);
  813.     return;
  814.   }
  815.  
  816.   pGEA = pGEAlist -> list;
  817.   pFound = pDENA;
  818.  
  819.   while (ulAttributes--)
  820.   {
  821.     nLength = strlen(pFound -> szName);
  822.  
  823.     if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
  824.     {
  825.       pGEA -> cbName = pFound -> cbName;
  826.       strcpy(pGEA -> szName, pFound -> szName);
  827.  
  828.       pGEA++;
  829.       pGEA = (PGEA) (((PCH) pGEA) + nLength);
  830.     }
  831.  
  832.     pFound++;
  833.     pFound = (PDENA1) (((PCH) pFound) + nLength);
  834.   }
  835.  
  836.   if (pGEA == pGEAlist -> list)
  837.   {
  838.     free(pDENA);
  839.     free(pGEAlist);
  840.     return;
  841.   }
  842.  
  843.   pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
  844.  
  845.   pFEAlist = (PFEALIST) pDENA; /* reuse buffer */
  846.   pFEAlist -> cbList = fs.cbList;
  847.   pFEA = pFEAlist -> list;
  848.  
  849.   eaop.fpGEAList = pGEAlist;
  850.   eaop.fpFEAList = pFEAlist;
  851.   eaop.oError = 0;
  852.  
  853.   if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
  854.                        (PBYTE) &eaop, sizeof(eaop)))
  855.   {
  856.     free(pDENA);
  857.     free(pGEAlist);
  858.     return;
  859.   }
  860.  
  861.   /* now convert into new OS/2 2.0 32-bit format */
  862.  
  863.   pFEA2list = (PFEA2LIST) pGEAlist;  /* reuse buffer */
  864.   pFEA2 = pFEA2list -> list;
  865.  
  866.   while ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList)
  867.   {
  868.     nLength = sizeof(FEA) + pFEA -> cbName + 1 + pFEA -> cbValue;
  869.     memcpy((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset), pFEA, nLength);
  870.     memset((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset) + nLength, 0, 3);
  871.     pFEA = (PFEA) ((PCH) pFEA + nLength);
  872.  
  873.     nLength = sizeof(FEA2) + pFEA2 -> cbName + 1 + pFEA2 -> cbValue;
  874.     nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
  875.     /* rounded up to 4-byte boundary */
  876.     pFEA2 -> oNextEntryOffset =
  877.       ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList) ? nLength : 0;
  878.     pFEA2 = (PFEA2) ((PCH) pFEA2 + nLength);
  879.   }
  880.  
  881.   pFEA2list -> cbList = (PCH) pFEA2 - (PCH) pFEA2list;
  882.   ulAttributes = pFEA2list -> cbList;
  883.  
  884.   pEAblock = (PEFHEADER) pDENA; /* reuse buffer */
  885.  
  886.   *bufptr = (char *) pEAblock;
  887.   *size = sizeof(EFHEADER);
  888.  
  889.   pEAblock -> nID = EF_OS2EA;
  890.   pEAblock -> nSize = sizeof(pEAblock -> lSize);
  891.   pEAblock -> lSize = ulAttributes; /* uncompressed size */
  892.  
  893.   nLength = (USHORT) memcompress((char *) (pEAblock + 1),
  894.     nMaxSize - sizeof(EFHEADER), (char *) pFEA2list, ulAttributes);
  895.  
  896.   *size += nLength;
  897.   pEAblock -> nSize += nLength;
  898.  
  899.   pEAblock = (PEFHEADER) pGEAlist;
  900.  
  901.   *cbufptr = (char *) pEAblock;
  902.   *csize = sizeof(EFHEADER);
  903.  
  904.   pEAblock -> nID = EF_OS2EA;
  905.   pEAblock -> nSize = sizeof(pEAblock -> lSize);
  906.   pEAblock -> lSize = ulAttributes;
  907.  
  908.   if (noisy)
  909.     printf(" (%ld bytes EA's)", ulAttributes);
  910. }
  911.  
  912. #endif /* __32BIT__ */
  913.  
  914. void GetACL(char *path, char **bufptr, size_t *size,
  915.                         char **cbufptr, size_t *csize)
  916. {
  917.   static char *buffer;
  918.   char *cbuffer;
  919.   long bytes, cbytes;
  920.   PEFHEADER pACLblock;
  921.  
  922.   if (buffer == NULL) /* avoid frequent allocation (for every file) */
  923.     if ((buffer = malloc(ACL_BUFFERSIZE)) == NULL)
  924.       return;
  925.  
  926.   if (acl_get(NULL, path, buffer))
  927.     return; /* this will be the most likely case */
  928.  
  929.   bytes = strlen(buffer);
  930.  
  931.   cbytes = bytes + sizeof(USHORT) + sizeof(ULONG);
  932.   if ((*bufptr = realloc(*bufptr, *size + sizeof(EFHEADER) + cbytes)) == NULL)
  933.     return;
  934.  
  935.   pACLblock = (PEFHEADER) (*bufptr + *size);
  936.  
  937.   cbuffer = (char *) (pACLblock + 1);
  938.   cbytes = memcompress(cbuffer, cbytes, buffer, bytes);
  939.  
  940.   *size += sizeof(EFHEADER) + cbytes;
  941.  
  942.   pACLblock -> nID = EF_ACL;
  943.   pACLblock -> nSize = sizeof(pACLblock -> lSize) + cbytes;
  944.   pACLblock -> lSize = bytes; /* uncompressed size */
  945.  
  946.   if ((*cbufptr = realloc(*cbufptr, *csize + sizeof(EFHEADER))) == NULL)
  947.     return;
  948.  
  949.   pACLblock = (PEFHEADER) (*cbufptr + *csize);
  950.   *csize += sizeof(EFHEADER);
  951.  
  952.   pACLblock -> nID = EF_ACL;
  953.   pACLblock -> nSize = sizeof(pACLblock -> lSize);
  954.   pACLblock -> lSize = bytes;
  955.  
  956.   if (noisy)
  957.     printf(" (%ld bytes ACL)", bytes);
  958. }
  959.  
  960. #ifdef USE_EF_UT_TIME
  961.  
  962. int GetExtraTime(struct zlist far *z, iztimes *z_utim)
  963. {
  964.   int eb_c_size = EB_HEADSIZE + EB_UT_LEN(1);
  965.   int eb_l_size = eb_c_size;
  966.   char *eb_c_ptr;
  967.   char *eb_l_ptr;
  968.  
  969.   eb_c_ptr = realloc(z->cextra, (z->cext + eb_c_size));
  970.   if (eb_c_ptr == NULL)
  971.     return ZE_MEM;
  972.   z->cextra = eb_c_ptr;
  973.   eb_c_ptr += z->cext;
  974.   z->cext += eb_c_size;
  975.  
  976.   eb_c_ptr[0]  = 'U';
  977.   eb_c_ptr[1]  = 'T';
  978.   eb_c_ptr[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
  979.   eb_c_ptr[3]  = 0;
  980.   eb_c_ptr[4]  = EB_UT_FL_MTIME;
  981.   eb_c_ptr[5]  = (char)(z_utim->mtime);
  982.   eb_c_ptr[6]  = (char)(z_utim->mtime >> 8);
  983.   eb_c_ptr[7]  = (char)(z_utim->mtime >> 16);
  984.   eb_c_ptr[8]  = (char)(z_utim->mtime >> 24);
  985.  
  986.   if (z_utim->mtime != z_utim->atime || z_utim->mtime != z_utim->ctime)
  987.   {
  988.     eb_c_ptr[4]  = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
  989.     eb_l_size = EB_HEADSIZE + EB_UT_LEN(3); /* only on HPFS they can differ */
  990.   /* so only then it makes sense to store all three time stamps */
  991.   }
  992.  
  993.   eb_l_ptr = realloc(z->extra, (z->ext + eb_l_size));
  994.   if (eb_l_ptr == NULL)
  995.     return ZE_MEM;
  996.   z->extra = eb_l_ptr;
  997.   eb_l_ptr += z->ext;
  998.   z->ext += eb_l_size;
  999.  
  1000.   memcpy(eb_l_ptr, eb_c_ptr, eb_c_size);
  1001.  
  1002.   if (eb_l_size > eb_c_size)
  1003.   {
  1004.     eb_l_ptr[2]  = EB_UT_LEN(3);
  1005.     eb_l_ptr[9]  = (char)(z_utim->atime);
  1006.     eb_l_ptr[10] = (char)(z_utim->atime >> 8);
  1007.     eb_l_ptr[11] = (char)(z_utim->atime >> 16);
  1008.     eb_l_ptr[12] = (char)(z_utim->atime >> 24);
  1009.     eb_l_ptr[13] = (char)(z_utim->ctime);
  1010.     eb_l_ptr[14] = (char)(z_utim->ctime >> 8);
  1011.     eb_l_ptr[15] = (char)(z_utim->ctime >> 16);
  1012.     eb_l_ptr[16] = (char)(z_utim->ctime >> 24);
  1013.   }
  1014.  
  1015.   return ZE_OK;
  1016. }
  1017.  
  1018. #endif /* USE_EF_UT_TIME */
  1019.  
  1020. int set_extra_field(struct zlist far *z, iztimes *z_utim)
  1021. {
  1022.   /* store EA data in local header, and size only in central headers */
  1023.   GetEAs(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
  1024.  
  1025.   /* store ACL data in local header, and size only in central headers */
  1026.   GetACL(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
  1027.  
  1028. #ifdef USE_EF_UT_TIME
  1029.   /* store extended time stamps in both headers */
  1030.   return GetExtraTime(z, z_utim);
  1031. #else /* !USE_EF_UT_TIME */
  1032.   return ZE_OK;
  1033. #endif /* ?USE_EF_UT_TIME */
  1034. }
  1035.  
  1036. #endif /* !UTIL */
  1037.  
  1038. /* Initialize the table of uppercase characters including handling of
  1039.    country dependent characters. */
  1040.  
  1041. void init_upper()
  1042. {
  1043.   COUNTRYCODE cc;
  1044.   unsigned nCnt, nU;
  1045.  
  1046.   for (nCnt = 0; nCnt < sizeof(upper); nCnt++)
  1047.     upper[nCnt] = lower[nCnt] = (unsigned char) nCnt;
  1048.  
  1049.   cc.country = cc.codepage = 0;
  1050.   DosMapCase(sizeof(upper), &cc, (PCHAR) upper);
  1051.  
  1052.   for (nCnt = 0; nCnt < 256; nCnt++)
  1053.   {
  1054.     nU = upper[nCnt];
  1055.     if (nU != nCnt && lower[nU] == (unsigned char) nU)
  1056.       lower[nU] = (unsigned char) nCnt;
  1057.   }
  1058.  
  1059.   for (nCnt = 'A'; nCnt <= 'Z'; nCnt++)
  1060.     lower[nCnt] = (unsigned char) (nCnt - 'A' + 'a');
  1061. }
  1062.  
  1063. char *StringLower(char *szArg)
  1064. {
  1065.   unsigned char *szPtr;
  1066.   for (szPtr = (unsigned char *) szArg; *szPtr; szPtr++)
  1067.     *szPtr = lower[*szPtr];
  1068.   return szArg;
  1069. }
  1070.  
  1071. #if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
  1072. void DebugMalloc(void)
  1073. {
  1074.   _dump_allocated(0); /* print out debug malloc memory statistics */
  1075. }
  1076. #endif
  1077.  
  1078.  
  1079. /******************************/
  1080. /*  Function version_local()  */
  1081. /******************************/
  1082.  
  1083. void version_local()
  1084. {
  1085.     static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
  1086. #if defined(__IBMC__) || defined(__WATCOMC__) || defined(_MSC_VER)
  1087.     char buf[80];
  1088. #endif
  1089.  
  1090.     printf(CompiledWith,
  1091.  
  1092. #ifdef __GNUC__
  1093. #  ifdef __EMX__  /* __EMX__ is defined as "1" only (sigh) */
  1094.       "emx+gcc ", __VERSION__,
  1095. #  else
  1096.       "gcc/2 ", __VERSION__,
  1097. #  endif
  1098. #elif defined(__IBMC__)
  1099.       "IBM ",
  1100. #  if (__IBMC__ < 200)
  1101.       (sprintf(buf, "C Set/2 %d.%02d", __IBMC__/100,__IBMC__%100), buf),
  1102. #  elif (__IBMC__ < 300)
  1103.       (sprintf(buf, "C Set++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
  1104. #  else
  1105.       (sprintf(buf, "Visual Age C++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
  1106. #  endif
  1107. #elif defined(__WATCOMC__)
  1108.       "Watcom C", (sprintf(buf, " (__WATCOMC__ = %d)", __WATCOMC__), buf),
  1109. #elif defined(__TURBOC__)
  1110. #  ifdef __BORLANDC__
  1111.       "Borland C++",
  1112. #    if (__BORLANDC__ < 0x0460)
  1113.         " 1.0",
  1114. #    elif (__BORLANDC__ == 0x0460)
  1115.         " 1.5",
  1116. #    else
  1117.         " 2.0",
  1118. #    endif
  1119. #  else
  1120.       "Turbo C",
  1121. #    if (__TURBOC__ >= 661)
  1122.        "++ 1.0 or later",
  1123. #    elif (__TURBOC__ == 661)
  1124.        " 3.0?",
  1125. #    elif (__TURBOC__ == 397)
  1126.        " 2.0",
  1127. #    else
  1128.        " 1.0 or 1.5?",
  1129. #    endif
  1130. #  endif
  1131. #elif defined(MSC)
  1132.       "Microsoft C ",
  1133. #  ifdef _MSC_VER
  1134.       (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
  1135. #  else
  1136.       "5.1 or earlier",
  1137. #  endif
  1138. #else
  1139.       "unknown compiler", "",
  1140. #endif /* __GNUC__ */
  1141.  
  1142.       "OS/2",
  1143.  
  1144. /* GRR:  does IBM C/2 identify itself as IBM rather than Microsoft? */
  1145. #if (defined(MSC) || (defined(__WATCOMC__) && !defined(__386__)))
  1146. #  if defined(M_I86HM) || defined(__HUGE__)
  1147.       " (16-bit, huge)",
  1148. #  elif defined(M_I86LM) || defined(__LARGE__)
  1149.       " (16-bit, large)",
  1150. #  elif defined(M_I86MM) || defined(__MEDIUM__)
  1151.       " (16-bit, medium)",
  1152. #  elif defined(M_I86CM) || defined(__COMPACT__)
  1153.       " (16-bit, compact)",
  1154. #  elif defined(M_I86SM) || defined(__SMALL__)
  1155.       " (16-bit, small)",
  1156. #  elif defined(M_I86TM) || defined(__TINY__)
  1157.       " (16-bit, tiny)",
  1158. #  else
  1159.       " (16-bit)",
  1160. #  endif
  1161. #else
  1162.       " 2.x/3.x (32-bit)",
  1163. #endif
  1164.  
  1165. #ifdef __DATE__
  1166.       " on ", __DATE__
  1167. #else
  1168.       "", ""
  1169. #endif
  1170.     );
  1171.  
  1172.     /* temporary debugging code for Borland compilers only */
  1173. #ifdef __TURBOC__
  1174.     printf("\t(__TURBOC__ = 0x%04x = %d)\n", __TURBOC__, __TURBOC__);
  1175. #ifdef __BORLANDC__
  1176.     printf("\t(__BORLANDC__ = 0x%04x)\n",__BORLANDC__);
  1177. #else
  1178.     printf("\tdebug(__BORLANDC__ not defined)\n");
  1179. #endif
  1180. #ifdef __TCPLUSPLUS__
  1181.     printf("\t(__TCPLUSPLUS__ = 0x%04x)\n", __TCPLUSPLUS__);
  1182. #else
  1183.     printf("\tdebug(__TCPLUSPLUS__ not defined)\n");
  1184. #endif
  1185. #ifdef __BCPLUSPLUS__
  1186.     printf("\t(__BCPLUSPLUS__ = 0x%04x)\n\n", __BCPLUSPLUS__);
  1187. #else
  1188.     printf("\tdebug(__BCPLUSPLUS__ not defined)\n\n");
  1189. #endif
  1190. #endif /* __TURBOC__ */
  1191.  
  1192. } /* end function version_local() */
  1193.  
  1194. #endif /* OS2 */
  1195.