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