home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / ZIP19P1.ZIP / os2 / os2zip.c < prev    next >
C/C++ Source or Header  |  1993-01-23  |  21KB  |  922 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 __EMX__
  16. #define __32BIT__
  17. #endif
  18.  
  19. #include "zip.h"
  20.  
  21. #include <stdlib.h>
  22. #include <time.h>
  23. #include <ctype.h>
  24.  
  25. #ifdef __WATCOMC__
  26. #include <malloc.h>
  27. unsigned char __near _osmode = OS2_MODE;
  28. #endif
  29.  
  30. #define INCL_NOPM
  31. #define INCL_DOSNLS
  32. #define INCL_DOSERRORS
  33. #include <os2.h>
  34.  
  35. #include "os2zip.h"
  36.  
  37.  
  38. #define EAID     0x0009
  39.  
  40.  
  41. #ifdef __32BIT__
  42. #define DosFindFirst(p1, p2, p3, p4, p5, p6) \
  43.         DosFindFirst(p1, p2, p3, p4, p5, p6, 1)
  44. #else
  45. #define DosQueryCurrentDisk DosQCurDisk
  46. #define DosQueryFSAttach(p1, p2, p3, p4, p5) \
  47.         DosQFSAttach(p1, p2, p3, p4, p5, 0)
  48. #define DosQueryPathInfo(p1, p2, p3, p4) \
  49.         DosQPathInfo(p1, p2, p3, p4, 0)
  50. #define DosSetPathInfo(p1, p2, p3, p4, p5) \
  51.         DosSetPathInfo(p1, p2, p3, p4, p5, 0)
  52. #define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \
  53.         DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0)
  54. #define DosFindFirst(p1, p2, p3, p4, p5, p6) \
  55.         DosFindFirst(p1, p2, p3, p4, p5, p6, 0)
  56. #define DosMapCase DosCaseMap
  57. #endif
  58.  
  59.  
  60. #ifndef UTIL
  61.  
  62. extern int noisy;
  63.  
  64. #ifndef S_IFMT
  65. #define S_IFMT 0xF000
  66. #endif
  67.  
  68. static int attributes = A_DIR | A_HIDDEN | A_SYSTEM;
  69.  
  70. static char *getdirent(char *);
  71. static void free_dircontents(struct _dircontents *);
  72.  
  73. #ifdef __32BIT__
  74. static HDIR hdir;
  75. static ULONG count;
  76. static FILEFINDBUF3 find;
  77. #else
  78. static HDIR hdir;
  79. static USHORT count;
  80. static FILEFINDBUF find;
  81. #endif
  82.  
  83.  
  84. DIR *opendir(char *name)
  85. {
  86.   struct stat statb;
  87.   DIR *dirp;
  88.   char c;
  89.   char *s;
  90.   struct _dircontents *dp;
  91.   char nbuf[MAXPATHLEN + 1];
  92.   int len;
  93.  
  94.   strcpy(nbuf, name);
  95.   len = strlen (nbuf);
  96.   s = nbuf + len;
  97.  
  98.   if ( ((c = nbuf[strlen(nbuf) - 1]) == '\\' || c == '/') &&
  99.        (strlen(nbuf) > 1) )
  100.   {
  101.     nbuf[strlen(nbuf) - 1] = 0;
  102.  
  103.     if ( nbuf[strlen(nbuf) - 1] == ':' )
  104.       strcat(nbuf, "\\.");
  105.   }
  106.   else
  107.     if ( nbuf[strlen(nbuf) - 1] == ':' )
  108.       strcat(nbuf, ".");
  109.  
  110.   if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
  111.     return NULL;
  112.  
  113.   if ( (dirp = malloc(sizeof(DIR))) == NULL )
  114.     return NULL;
  115.  
  116.   if ( nbuf[strlen(nbuf) - 1] == '.' )
  117.     strcpy(nbuf + strlen(nbuf) - 1, "*.*");
  118.   else
  119.     if ( ((c = nbuf[strlen(nbuf) - 1]) == '\\' || c == '/') &&
  120.          (strlen(nbuf) == 1) )
  121.       strcat(nbuf, "*.*");
  122.     else
  123.       strcat(nbuf, "\\*.*");
  124.  
  125.   dirp -> dd_loc = 0;
  126.   dirp -> dd_contents = dirp -> dd_cp = NULL;
  127.  
  128.   if ((s = getdirent(nbuf)) == NULL)
  129.     return dirp;
  130.  
  131.   do
  132.   {
  133.     if (((dp = malloc(sizeof(struct _dircontents))) == NULL) ||
  134.         ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL)      )
  135.     {
  136.       if (dp)
  137.         free(dp);
  138.       free_dircontents(dirp -> dd_contents);
  139.  
  140.       return NULL;
  141.     }
  142.  
  143.     if (dirp -> dd_contents)
  144.     {
  145.       dirp -> dd_cp -> _d_next = dp;
  146.       dirp -> dd_cp = dirp -> dd_cp -> _d_next;
  147.     }
  148.     else
  149.       dirp -> dd_contents = dirp -> dd_cp = dp;
  150.  
  151.     strcpy(dp -> _d_entry, s);
  152.     dp -> _d_next = NULL;
  153.  
  154.     dp -> _d_size = find.cbFile;
  155.     dp -> _d_mode = find.attrFile;
  156.     dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite);
  157.     dp -> _d_date = *(unsigned *) &(find.fdateLastWrite);
  158.   }
  159.   while ((s = getdirent(NULL)) != NULL);
  160.  
  161.   dirp -> dd_cp = dirp -> dd_contents;
  162.  
  163.   return dirp;
  164. }
  165.  
  166.  
  167. void closedir(DIR * dirp)
  168. {
  169.   free_dircontents(dirp -> dd_contents);
  170.   free(dirp);
  171. }
  172.  
  173.  
  174. struct direct *readdir(DIR * dirp)
  175. {
  176.   static struct direct dp;
  177.  
  178.   if (dirp -> dd_cp == NULL)
  179.     return NULL;
  180.  
  181.   dp.d_namlen = dp.d_reclen =
  182.     strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry));
  183.  
  184.   dp.d_ino = 0;
  185.  
  186.   dp.d_size = dirp -> dd_cp -> _d_size;
  187.   dp.d_mode = dirp -> dd_cp -> _d_mode;
  188.   dp.d_time = dirp -> dd_cp -> _d_time;
  189.   dp.d_date = dirp -> dd_cp -> _d_date;
  190.  
  191.   dirp -> dd_cp = dirp -> dd_cp -> _d_next;
  192.   dirp -> dd_loc++;
  193.  
  194.   return &dp;
  195. }
  196.  
  197.  
  198. void seekdir(DIR * dirp, long off)
  199. {
  200.   long i = off;
  201.   struct _dircontents *dp;
  202.  
  203.   if (off >= 0)
  204.   {
  205.     for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next);
  206.  
  207.     dirp -> dd_loc = off - (i + 1);
  208.     dirp -> dd_cp = dp;
  209.   }
  210. }
  211.  
  212.  
  213. long telldir(DIR * dirp)
  214. {
  215.   return dirp -> dd_loc;
  216. }
  217.  
  218.  
  219. static void free_dircontents(struct _dircontents * dp)
  220. {
  221.   struct _dircontents *odp;
  222.  
  223.   while (dp)
  224.   {
  225.     if (dp -> _d_entry)
  226.       free(dp -> _d_entry);
  227.  
  228.     dp = (odp = dp) -> _d_next;
  229.     free(odp);
  230.   }
  231. }
  232.  
  233.  
  234. static char *getdirent(char *dir)
  235. {
  236.   int done;
  237.   static int lower;
  238.  
  239.   if (dir != NULL)
  240.   {                                    /* get first entry */
  241.     hdir = HDIR_CREATE;
  242.     count = 1;
  243.     done = DosFindFirst(dir, &hdir, attributes, &find, sizeof(find), &count);
  244.     lower = IsFileSystemFAT(dir);
  245.   }
  246.   else                                 /* get next entry */
  247.     done = DosFindNext(hdir, &find, sizeof(find), &count);
  248.  
  249.   if (done == 0)
  250.   {
  251.     if ( lower )
  252.       StringLower(find.achName);
  253.     return find.achName;
  254.   }
  255.   else
  256.   {
  257.     DosFindClose(hdir);
  258.     return NULL;
  259.   }
  260. }
  261.  
  262.  
  263. /* FAT / HPFS detection */
  264.  
  265. int IsFileSystemFAT(char *dir)
  266. {
  267.   static USHORT nLastDrive = -1, nResult;
  268.   ULONG lMap;
  269.   BYTE bData[64], bName[3];
  270. #ifdef __32BIT__
  271.   ULONG nDrive, cbData;
  272.   PFSQBUFFER2 pData = (PFSQBUFFER2) bData;
  273. #else
  274.   USHORT nDrive, cbData;
  275.   PFSQBUFFER pData = (PFSQBUFFER) bData;
  276. #endif
  277.  
  278.   if ( _osmode == DOS_MODE )
  279.     return TRUE;
  280.   else
  281.   {
  282.     /* We separate FAT and HPFS+other file systems here.
  283.        at the moment I consider other systems to be similar to HPFS,
  284.        i.e. support long file names and beeing case sensitive */
  285.  
  286.     if ( isalpha(dir[0]) && (dir[1] == ':') )
  287.       nDrive = to_up(dir[0]) - '@';
  288.     else
  289.       DosQueryCurrentDisk(&nDrive, &lMap);
  290.  
  291.     if ( nDrive == nLastDrive )
  292.       return nResult;
  293.  
  294.     bName[0] = (char) (nDrive + '@');
  295.     bName[1] = ':';
  296.     bName[2] = 0;
  297.  
  298.     nLastDrive = nDrive;
  299.     cbData = sizeof(bData);
  300.  
  301.     if ( !DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData) )
  302.       nResult = !strcmp(pData -> szFSDName + pData -> cbName, "FAT");
  303.     else
  304.       nResult = FALSE;
  305.  
  306.     /* End of this ugly code */
  307.     return nResult;
  308.   }
  309. }
  310.  
  311.  
  312. /* access mode bits and time stamp */
  313.  
  314. int GetFileMode(char *name)
  315. {
  316. #ifdef __32BIT__
  317.   FILESTATUS3 fs;
  318.   return DosQueryPathInfo(name, 1, &fs, sizeof(fs)) ? -1 : fs.attrFile;
  319. #else
  320.   USHORT mode;
  321.   return DosQFileMode(name, &mode, 0L) ? -1 : mode;
  322. #endif
  323. }
  324.  
  325. long GetFileTime(char *name)
  326. {
  327. #ifdef __32BIT__
  328.   FILESTATUS3 fs;
  329. #else
  330.   FILESTATUS fs;
  331. #endif
  332.   USHORT nDate, nTime;
  333.  
  334.   if ( DosQueryPathInfo(name, 1, (PBYTE) &fs, sizeof(fs)) )
  335.     return -1;
  336.  
  337.   nDate = * (USHORT *) &fs.fdateLastWrite;
  338.   nTime = * (USHORT *) &fs.ftimeLastWrite;
  339.  
  340.   return ((ULONG) nDate) << 16 | nTime;
  341. }
  342.  
  343. void SetFileTime(char *path, long stamp)
  344. {
  345.   FILESTATUS fs;
  346.   USHORT fd, ft;
  347.   USHORT nLength;
  348.   char szName[CCHMAXPATH];
  349.  
  350.   if ( DosQueryPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)) )
  351.     return;
  352.  
  353.   fd = (USHORT) (stamp >> 16);
  354.   ft = (USHORT) stamp;
  355.   fs.fdateLastWrite = fs.fdateCreation = * (FDATE *) &fd;
  356.   fs.ftimeLastWrite = fs.ftimeCreation = * (FTIME *) &ft;
  357.  
  358.   DosSetPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0);
  359. }
  360.  
  361.  
  362. /* FAT / HPFS name conversion stuff */
  363.  
  364. int IsFileNameValid(char *name)
  365. {
  366.   HFILE hf;
  367. #ifdef __32BIT__
  368.   ULONG uAction;
  369. #else
  370.   USHORT uAction;
  371. #endif
  372.  
  373.   switch( DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN,
  374.                   OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0) )
  375.   {
  376.   case ERROR_INVALID_NAME:
  377.   case ERROR_FILENAME_EXCED_RANGE:
  378.     return FALSE;
  379.   case NO_ERROR:
  380.     DosClose(hf);
  381.   default:
  382.     return TRUE;
  383.   }
  384. }
  385.  
  386.  
  387. void ChangeNameForFAT(char *name)
  388. {
  389.   char *src, *dst, *next, *ptr, *dot, *start;
  390.   static char invalid[] = ":;,=+\"[]<>| \t";
  391.  
  392.   if ( isalpha(name[0]) && (name[1] == ':') )
  393.     start = name + 2;
  394.   else
  395.     start = name;
  396.  
  397.   src = dst = start;
  398.   if ( (*src == '/') || (*src == '\\') )
  399.     src++, dst++;
  400.  
  401.   while ( *src )
  402.   {
  403.     for ( next = src; *next && (*next != '/') && (*next != '\\'); next++ );
  404.  
  405.     for ( ptr = src, dot = NULL; ptr < next; ptr++ )
  406.       if ( *ptr == '.' )
  407.       {
  408.         dot = ptr; /* remember last dot */
  409.         *ptr = '_';
  410.       }
  411.  
  412.     if ( dot == NULL )
  413.       for ( ptr = src; ptr < next; ptr++ )
  414.         if ( *ptr == '_' )
  415.           dot = ptr; /* remember last _ as if it were a dot */
  416.  
  417.     if ( dot && (dot > src) &&
  418.          ((next - dot <= 4) ||
  419.           ((next - src > 8) && (dot - src > 3))) )
  420.     {
  421.       if ( dot )
  422.         *dot = '.';
  423.  
  424.       for ( ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++ )
  425.         *dst++ = *ptr;
  426.  
  427.       for ( ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++ )
  428.         *dst++ = *ptr;
  429.     }
  430.     else
  431.     {
  432.       if ( dot && (next - src == 1) )
  433.         *dot = '.';           /* special case: "." as a path component */
  434.  
  435.       for ( ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++ )
  436.         *dst++ = *ptr;
  437.     }
  438.  
  439.     *dst++ = *next; /* either '/' or 0 */
  440.  
  441.     if ( *next )
  442.     {
  443.       src = next + 1;
  444.  
  445.       if ( *src == 0 ) /* handle trailing '/' on dirs ! */
  446.         *dst = 0;
  447.     }
  448.     else
  449.       break;
  450.   }
  451.  
  452.   for ( src = start; *src != 0; ++src )
  453.     if ( (strchr(invalid, *src) != NULL) || (*src == ' ') )
  454.       *src = '_';
  455. }
  456.  
  457.  
  458. /* .LONGNAME EA code */
  459.  
  460. typedef struct
  461. {
  462.   ULONG cbList;               /* length of value + 22 */
  463. #ifdef __32BIT__
  464.   ULONG oNext;
  465. #endif
  466.   BYTE fEA;                   /* 0 */
  467.   BYTE cbName;                /* length of ".LONGNAME" = 9 */
  468.   USHORT cbValue;             /* length of value + 4 */
  469.   BYTE szName[10];            /* ".LONGNAME" */
  470.   USHORT eaType;              /* 0xFFFD for length-preceded ASCII */
  471.   USHORT eaSize;              /* length of value */
  472.   BYTE szValue[CCHMAXPATH];
  473. }
  474. FEALST;
  475.  
  476. typedef struct
  477. {
  478.   ULONG cbList;
  479. #ifdef __32BIT__
  480.   ULONG oNext;
  481. #endif
  482.   BYTE cbName;
  483.   BYTE szName[10];            /* ".LONGNAME" */
  484. }
  485. GEALST;
  486.  
  487.  
  488. char *GetLongNameEA(char *name)
  489. {
  490.   EAOP eaop;
  491.   GEALST gealst;
  492.   static FEALST fealst;
  493.  
  494.   if ( _osmode == DOS_MODE )
  495.     return NULL;
  496.  
  497.   eaop.fpGEAList = (PGEALIST) &gealst;
  498.   eaop.fpFEAList = (PFEALIST) &fealst;
  499.   eaop.oError = 0;
  500.  
  501.   strcpy(gealst.szName, ".LONGNAME");
  502.   gealst.cbName  = (BYTE) strlen(gealst.szName);
  503. #ifdef __32BIT__
  504.   gealst.oNext   = 0;
  505. #endif
  506.  
  507.   gealst.cbList  = sizeof(gealst);
  508.   fealst.cbList  = sizeof(fealst);
  509.  
  510.   if ( DosQueryPathInfo(name, FIL_QUERYEASFROMLIST,
  511.                         (PBYTE) &eaop, sizeof(eaop)) )
  512.     return NULL;
  513.  
  514.   if ( fealst.cbValue > 4 && fealst.eaType == 0xFFFD )
  515.   {
  516.     fealst.szValue[fealst.eaSize] = 0;
  517.     return fealst.szValue;
  518.   }
  519.  
  520.   return NULL;
  521. }
  522.  
  523.  
  524. char *GetLongPathEA(char *name)
  525. {
  526.   static char nbuf[CCHMAXPATH + 1];
  527.   char *comp, *next, *ea, sep;
  528.   BOOL bFound = FALSE;
  529.  
  530.   nbuf[0] = 0;
  531.   next = name;
  532.  
  533.   while ( *next )
  534.   {
  535.     comp = next;
  536.  
  537.     while ( *next != '\\' && *next != '/' && *next != 0 )
  538.       next++;
  539.  
  540.     sep = *next;
  541.     *next = 0;
  542.  
  543.     ea = GetLongNameEA(name);
  544.     strcat(nbuf, ea ? ea : comp);
  545.     bFound = bFound || (ea != NULL);
  546.  
  547.     *next = sep;
  548.  
  549.     if ( *next )
  550.     {
  551.       strcat(nbuf, "\\");
  552.       next++;
  553.     }
  554.   }
  555.  
  556.   return nbuf[0] && bFound ? nbuf : NULL;
  557. }
  558.  
  559.  
  560. /* general EA code */
  561.  
  562. typedef struct
  563. {
  564.   USHORT nID;
  565.   USHORT nSize;
  566.   ULONG lSize;
  567. }
  568. EAHEADER, *PEAHEADER;
  569.  
  570.  
  571. #ifdef __32BIT__
  572.  
  573. /* Perhaps due to bugs in the current OS/2 2.0 kernel, the success or
  574.    failure of the DosEnumAttribute() and DosQueryPathInfo() system calls
  575.    depends on the area where the return buffers are allocated. This
  576.    differs for the various compilers, for some alloca() works, for some
  577.    malloc() works, for some, both work. We'll have to live with that. */
  578.  
  579. /* The use of malloc() is not very convenient, because it requires
  580.    backtracking (i.e. free()) at error returns. We do that for system
  581.    calls that may fail, but not for malloc() calls, because they are VERY
  582.    unlikely to fail. If ever, we just leave some memory allocated ... */
  583.  
  584. #if defined(__GNUC__) || defined(__IBMC__)
  585. #define alloc alloca
  586. #endif
  587.  
  588. #ifdef __WATCOMC__
  589. #define alloc malloc
  590. #define __FREE__
  591. #endif
  592.  
  593. #ifndef alloc
  594. #error memory allocation type (alloca or malloc) not specified
  595. #endif
  596.  
  597. void GetEAs(char *path, char **bufptr, unsigned *size,
  598.                         char **cbufptr, unsigned *csize)
  599. {
  600.   FILESTATUS4 fs;
  601.   PDENA2 pDENA, pFound;
  602.   EAOP2 eaop;
  603.   PGEA2 pGEA;
  604.   PGEA2LIST pGEAlist;
  605.   PFEA2LIST pFEAlist;
  606.   PEAHEADER pEAblock;
  607.   ULONG ulAttributes, ulMemoryBlock;
  608.   ULONG nLength;
  609.   char szName[CCHMAXPATH];
  610.  
  611.   *size = *csize = 0;
  612.  
  613.   if ( _osmode == DOS_MODE )
  614.     return;
  615.  
  616.   strcpy(szName, path);
  617.   nLength = strlen(szName);
  618.   if ( szName[nLength - 1] == '/' )
  619.     szName[nLength - 1] = 0;
  620.  
  621.   if ( DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs))
  622.     || fs.cbList <= 2 * sizeof(ULONG)
  623.     || (pDENA = alloc((size_t) fs.cbList)) == NULL )
  624.     return;
  625.  
  626.   ulAttributes = -1;
  627.  
  628.   if ( DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, fs.cbList,
  629.                         &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
  630.     || ulAttributes == 0
  631.     || (pGEAlist = alloc((size_t) fs.cbList)) == NULL )
  632.   {
  633. #ifdef __FREE__
  634.     free(pDENA);
  635. #endif
  636.     return;
  637.   }
  638.  
  639.   pGEA = pGEAlist -> list;
  640.   pFound = pDENA;
  641.  
  642.   while ( ulAttributes-- )
  643.   {
  644.     if ( !(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea) )
  645.     {
  646.       pGEA -> cbName = pFound -> cbName;
  647.       strcpy(pGEA -> szName, pFound -> szName);
  648.  
  649.       nLength = sizeof(GEA2) + strlen(pGEA -> szName);
  650.       nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
  651.  
  652.       pGEA -> oNextEntryOffset = ulAttributes ? nLength : 0;
  653.       pGEA   = (PGEA2)  ((PCH) pGEA + nLength);
  654.     }
  655.  
  656.     pFound = (PDENA2) ((PCH) pFound + pFound -> oNextEntryOffset);
  657.   }
  658.  
  659.   if ( pGEA == pGEAlist -> list ) /* no attributes to save */
  660.   {
  661. #ifdef __FREE__
  662.     free(pDENA);
  663.     free(pGEAlist);
  664. #endif
  665.     return;
  666.   }
  667.  
  668.   pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
  669.  
  670.   pFEAlist = (PVOID) pDENA;  /* reuse buffer */
  671.   pFEAlist -> cbList = fs.cbList;
  672.  
  673.   eaop.fpGEA2List = pGEAlist;
  674.   eaop.fpFEA2List = pFEAlist;
  675.   eaop.oError = 0;
  676.  
  677.   if ( DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
  678.                         (PBYTE) &eaop, sizeof(eaop)) )
  679.   {
  680. #ifdef __FREE__
  681.     free(pDENA);
  682.     free(pGEAlist);
  683. #endif
  684.     return;
  685.   }
  686.  
  687.   /* The maximum compressed size is (in case of STORE type) the
  688.      uncompressed size plus the size of the compression type field
  689.      plus the size of the CRC field. */
  690.  
  691.   ulAttributes = pFEAlist -> cbList;
  692.   ulMemoryBlock = ulAttributes + sizeof(USHORT) + sizeof(ULONG);
  693.   pEAblock = (PEAHEADER) malloc(sizeof(EAHEADER) + ulMemoryBlock);
  694.  
  695.   if ( pEAblock == NULL )
  696.     return;
  697.  
  698.   *bufptr = (char *) pEAblock;
  699.   *size = sizeof(EAHEADER);
  700.  
  701.   pEAblock -> nID = EAID;
  702.   pEAblock -> nSize = sizeof(pEAblock -> lSize);
  703.   pEAblock -> lSize = ulAttributes; /* uncompressed size */
  704.  
  705.   nLength = memcompress((char *) (pEAblock + 1), ulMemoryBlock,
  706.                         (char *) pFEAlist, ulAttributes);
  707.   *size += nLength;
  708.   pEAblock -> nSize += nLength;
  709.  
  710.   if ( (pEAblock = (PEAHEADER) malloc(sizeof(EAHEADER))) == NULL )
  711.     return;
  712.  
  713.   *cbufptr = (char *) pEAblock;
  714.   *csize = sizeof(EAHEADER);
  715.  
  716.   pEAblock -> nID = EAID;
  717.   pEAblock -> nSize = sizeof(pEAblock -> lSize);
  718.   pEAblock -> lSize = ulAttributes;
  719.  
  720.   if ( noisy )
  721.     printf(" (%ld bytes EA's)", ulAttributes);
  722. }
  723.  
  724. #else /* !__32BIT__ */
  725.  
  726. typedef struct
  727. {
  728.   ULONG oNextEntryOffset;
  729.   BYTE fEA;
  730.   BYTE cbName;
  731.   USHORT cbValue;
  732.   CHAR szName[1];
  733. }
  734. FEA2, *PFEA2;
  735.  
  736. typedef struct
  737. {
  738.   ULONG cbList;
  739.   FEA2 list[1];
  740. }
  741. FEA2LIST, *PFEA2LIST;
  742.  
  743. void GetEAs(char *path, char **bufptr, unsigned *size,
  744.                         char **cbufptr, unsigned *csize)
  745. {
  746.   FILESTATUS2 fs;
  747.   PDENA1 pDENA, pFound;
  748.   EAOP eaop;
  749.   PGEALIST pGEAlist;
  750.   PGEA pGEA;
  751.   PFEALIST pFEAlist;
  752.   PFEA pFEA;
  753.   PFEA2LIST pFEA2list;
  754.   PFEA2 pFEA2;
  755.   EAHEADER *pEAblock;
  756.   ULONG ulAttributes;
  757.   USHORT nLength, nMaxSize;
  758.   char szName[CCHMAXPATH];
  759.  
  760.   *size = *csize = 0;
  761.  
  762.   if ( _osmode == DOS_MODE )
  763.     return;
  764.  
  765.   strcpy(szName, path);
  766.   nLength = strlen(szName);
  767.   if ( szName[nLength - 1] == '/' )
  768.     szName[nLength - 1] = 0;
  769.  
  770.   if ( DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs))
  771.     || fs.cbList <= 2 * sizeof(ULONG) )
  772.     return;
  773.  
  774.   ulAttributes = -1;
  775.   nMaxSize = (USHORT) min(fs.cbList * 2, 65520L);
  776.  
  777.   if ( (pDENA = malloc((size_t) nMaxSize)) == NULL )
  778.     return;
  779.  
  780.   if ( DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, fs.cbList,
  781.                         &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
  782.     || ulAttributes == 0
  783.     || (pGEAlist = malloc(nMaxSize)) == NULL )
  784.   {
  785.     free(pDENA);
  786.     return;
  787.   }
  788.  
  789.   pGEA = pGEAlist -> list;
  790.   pFound = pDENA;
  791.  
  792.   while ( ulAttributes-- )
  793.   {
  794.     nLength = strlen(pFound -> szName);
  795.  
  796.     if ( !(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea) )
  797.     {
  798.       pGEA -> cbName = pFound -> cbName;
  799.       strcpy(pGEA -> szName, pFound -> szName);
  800.  
  801.       pGEA = (PGEA) ((PCH) (pGEA++) + nLength);
  802.     }
  803.  
  804.     pFound = (PDENA1) ((PCH) (pFound++) + nLength);
  805.   }
  806.  
  807.   if ( pGEA == pGEAlist -> list )
  808.   {
  809.     free(pDENA);
  810.     free(pGEAlist);
  811.     return;
  812.   }
  813.  
  814.   pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
  815.  
  816.   pFEAlist = (PFEALIST) pDENA; /* reuse buffer */
  817.   pFEAlist -> cbList = fs.cbList;
  818.   pFEA = pFEAlist -> list;
  819.  
  820.   eaop.fpGEAList = pGEAlist;
  821.   eaop.fpFEAList = pFEAlist;
  822.   eaop.oError = 0;
  823.  
  824.   if ( DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
  825.                     (PBYTE) &eaop, sizeof(eaop)) )
  826.   {
  827.     free(pDENA);
  828.     free(pGEAlist);
  829.     return;
  830.   }
  831.  
  832.   /* now convert into new OS/2 2.0 32-bit format */
  833.  
  834.   pFEA2list = (PFEA2LIST) pGEAlist;  /* reuse buffer */
  835.   pFEA2 = pFEA2list -> list;
  836.  
  837.   while ( (PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList )
  838.   {
  839.     nLength = sizeof(FEA) + pFEA -> cbName + 1 + pFEA -> cbValue;
  840.     memcpy((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset), pFEA, nLength);
  841.     memset((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset) + nLength, 0, 3);
  842.     pFEA = (PFEA) ((PCH) pFEA + nLength);
  843.  
  844.     nLength = sizeof(FEA2) + pFEA2 -> cbName + 1 + pFEA2 -> cbValue;
  845.     nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
  846.     /* rounded up to 4-byte boundary */
  847.     pFEA2 -> oNextEntryOffset =
  848.       ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList) ? nLength : 0;
  849.     pFEA2 = (PFEA2) ((PCH) pFEA2 + nLength);
  850.   }
  851.  
  852.   pFEA2list -> cbList = (PCH) pFEA2 - (PCH) pFEA2list;
  853.   ulAttributes = pFEA2list -> cbList;
  854.  
  855.   pEAblock = (PEAHEADER) pDENA; /* reuse buffer */
  856.  
  857.   *bufptr = (char *) pEAblock;
  858.   *size = sizeof(EAHEADER);
  859.  
  860.   pEAblock -> nID = EAID;
  861.   pEAblock -> nSize = sizeof(pEAblock -> lSize);
  862.   pEAblock -> lSize = ulAttributes; /* uncompressed size */
  863.  
  864.   nLength = (USHORT) memcompress((char *) (pEAblock + 1),
  865.     nMaxSize - sizeof(EAHEADER), (char *) pFEA2list, ulAttributes);
  866.  
  867.   *size += nLength;
  868.   pEAblock -> nSize += nLength;
  869.  
  870.   pEAblock = (PEAHEADER) pGEAlist;
  871.  
  872.   *cbufptr = (char *) pEAblock;
  873.   *csize = sizeof(EAHEADER);
  874.  
  875.   pEAblock -> nID = EAID;
  876.   pEAblock -> nSize = sizeof(pEAblock -> lSize);
  877.   pEAblock -> lSize = ulAttributes;
  878.  
  879.   if ( noisy )
  880.     printf(" (%ld bytes EA's)", ulAttributes);
  881. }
  882.  
  883. #endif /* __32BIT__ */
  884.  
  885.  
  886. #endif /* UTIL */
  887.  
  888.  
  889. /* Initialize the table of uppercase characters including handling of
  890.    country dependent characters. */
  891.  
  892. void init_upper()
  893. {
  894.   COUNTRYCODE cc;
  895.   unsigned nCnt, nU;
  896.  
  897.   for ( nCnt = 0; nCnt < sizeof(upper); nCnt++ )
  898.     upper[nCnt] = lower[nCnt] = (unsigned char) nCnt;
  899.  
  900.   cc.country = cc.codepage = 0;
  901.   DosMapCase(sizeof(upper), &cc, (PCHAR) upper);
  902.  
  903.   for ( nCnt = 0; nCnt < 256; nCnt++ )
  904.   {
  905.     nU = upper[nCnt];
  906.     if (nU != nCnt && lower[nU] == (unsigned char) nU)
  907.       lower[nU] = (unsigned char) nCnt;
  908.   }
  909.  
  910.   for ( nCnt = 'A'; nCnt <= 'Z'; nCnt++ )
  911.     lower[nCnt] = (unsigned char) (nCnt - 'A' + 'a');
  912. }
  913.  
  914.  
  915. char *StringLower(char *szArg)
  916. {
  917.   unsigned char *szPtr;
  918.   for ( szPtr = szArg; *szPtr; szPtr++ )
  919.     *szPtr = lower[*szPtr];
  920.   return szArg;
  921. }
  922.