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