1 /*---------------------------------------------------------------------------
5 OS/2-specific routines for use with Info-ZIP's UnZip 5.1 and later.
7 This file contains the OS/2 versions of the file name/attribute/time/etc
8 code. Most or all of the routines which make direct use of OS/2 system
9 calls (i.e., the non-lowercase routines) are Kai Uwe Rommel's. The read-
10 dir() suite was written by Michael Rendell and ported to OS/2 by Kai Uwe;
11 it is in the public domain.
13 Contains: GetCountryInfo()
15 SetFileTime() (TIMESTAMP only)
16 stamp_file() (TIMESTAMP only)
24 [ seekdir() ] not used
25 [ telldir() ] not used
47 ---------------------------------------------------------------------------*/
50 #define UNZIP_INTERNAL
54 extern ZCONST
char Far TruncEAs
[];
56 /* local prototypes */
59 static int SetFileTime(ZCONST
char *name
, ulg stamp
);
61 #if defined(USE_EF_UT_TIME) || defined(TIMESTAMP)
62 static ulg Utime2DosDateTime
OF((time_t uxtime
));
64 static int getOS2filetimes
OF((__GPRO__
65 ulg
*pM_dt
, ulg
*pA_dt
, ulg
*pC_dt
));
66 static void SetPathAttrTimes
OF((__GPRO__
int flags
, int dir
));
67 static int SetEAs
OF((__GPRO__
const char *path
,
69 static int SetACL
OF((__GPRO__
const char *path
,
71 static int EvalExtraFields
OF((__GPRO__
const char *path
,
72 void *extra_field
, unsigned ef_len
));
73 static int isfloppy
OF((int nDrive
));
74 static int IsFileNameValid
OF((const char *name
));
75 static void map2fat
OF((char *pathcomp
, char **pEndFAT
));
76 static int SetLongNameEA
OF((char *name
, char *longname
));
77 static void InitNLS
OF((void));
80 /*****************************/
81 /* Strings used in os2.c */
82 /*****************************/
85 static char Far CantAllocateWildcard
[] =
86 "warning: cannot allocate wildcard buffers\n";
88 static char Far Creating
[] = " creating: %-22s ";
89 static char Far ConversionFailed
[] = "mapname: conversion of %s failed\n";
90 static char Far Labelling
[] = "labelling %c: %-22s\n";
91 static char Far ErrSetVolLabel
[] = "mapname: error setting volume label\n";
92 static char Far PathTooLong
[] = "checkdir error: path too long: %s\n";
93 static char Far CantCreateDir
[] = "checkdir error: cannot create %s\n\
94 unable to process %s.\n";
95 static char Far DirIsntDirectory
[] =
96 "checkdir error: %s exists but is not directory\n\
97 unable to process %s.\n";
98 static char Far PathTooLongTrunc
[] =
99 "checkdir warning: path too long; truncating\n %s\n\
101 #if (!defined(SFX) || defined(SFX_EXDIR))
102 static char Far CantCreateExtractDir
[] =
103 "checkdir: cannot create extraction directory: %s\n";
107 # if (_MSC_VER >= 600) || defined(__IBMC__)
108 # include <direct.h> /* have special MSC/IBM C mkdir prototype */
109 # else /* own prototype because dir.h conflicts? */
110 int mkdir(const char *path
);
112 # define MKDIR(path,mode) mkdir(path)
114 # define MKDIR(path,mode) mkdir(path,mode)
120 USHORT
DosDevIOCtl32(PVOID pData
, USHORT cbData
, PVOID pParms
, USHORT cbParms
,
121 USHORT usFunction
, USHORT usCategory
, HFILE hDevice
)
123 ULONG ulParmLengthInOut
= cbParms
, ulDataLengthInOut
= cbData
;
124 return (USHORT
) DosDevIOCtl(hDevice
, usCategory
, usFunction
,
125 pParms
, cbParms
, &ulParmLengthInOut
,
126 pData
, cbData
, &ulDataLengthInOut
);
129 # define DosDevIOCtl DosDevIOCtl32
131 # define DosDevIOCtl DosDevIOCtl2
141 EFHEADER
, *PEFHEADER
;
146 #define DosFindFirst(p1, p2, p3, p4, p5, p6) \
147 DosFindFirst(p1, p2, p3, p4, p5, p6, 1)
153 ULONG oNextEntryOffset
;
166 FEA2LIST
, *PFEA2LIST
;
168 #define DosQueryCurrentDisk DosQCurDisk
169 #define DosQueryFSAttach(p1, p2, p3, p4, p5) \
170 DosQFSAttach(p1, p2, p3, p4, p5, 0)
171 #define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \
172 DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0)
173 #define DosFindFirst(p1, p2, p3, p4, p5, p6) \
174 DosFindFirst(p1, p2, p3, p4, p5, p6, 0)
175 #define DosMapCase DosCaseMap
176 #define DosSetPathInfo(p1, p2, p3, p4, p5) \
177 DosSetPathInfo(p1, p2, p3, p4, p5, 0)
178 #define DosQueryPathInfo(p1, p2, p3, p4) \
179 DosQPathInfo(p1, p2, p3, p4, 0)
180 #define DosQueryFileInfo DosQFileInfo
181 #define DosMapCase DosCaseMap
182 #define DosQueryCtryInfo DosGetCtryInfo
184 #endif /* !__32BIT__ */
191 * @(#) dir.h 1.4 87/11/06 Public Domain.
195 #define A_HIDDEN 0x02
196 #define A_SYSTEM 0x04
199 #define A_ARCHIVE 0x20
202 const int attributes
= A_DIR
| A_HIDDEN
| A_SYSTEM
;
205 extern DIR *opendir(__GPRO__ ZCONST
char *);
206 extern struct direct
*readdir(__GPRO__
DIR *);
207 extern void seekdir(DIR *, long);
208 extern long telldir(DIR *);
209 extern void closedir(DIR *);
210 #define rewinddir(dirp) seekdir(dirp, 0L)
212 int IsFileSystemFAT(__GPRO__ ZCONST
char *dir
);
213 char *StringLower(char *szArg
);
219 * @(#)dir.c 1.4 87/11/06 Public Domain.
224 # define S_IFMT 0xF000
229 static char *getdirent(__GPRO__ ZCONST
char *);
230 static void free_dircontents(struct _dircontents
*);
236 int GetCountryInfo(void)
246 ctryc
.country
= ctryc
.codepage
= 0;
248 if ( DosQueryCtryInfo(sizeof(ctryi
), &ctryc
, &ctryi
, &cbInfo
) != NO_ERROR
)
251 return ctryi
.fsDateFmt
;
255 long GetFileTime(ZCONST
char *name
)
264 if ( DosQueryPathInfo((PSZ
) name
, 1, (PBYTE
) &fs
, sizeof(fs
)) )
267 nDate
= * (USHORT
*) &fs
.fdateLastWrite
;
268 nTime
= * (USHORT
*) &fs
.ftimeLastWrite
;
270 return ((ULONG
) nDate
) << 16 | nTime
;
276 static int SetFileTime(ZCONST
char *name
, ulg stamp
) /* swiped from Zip */
281 if (DosQueryPathInfo((PSZ
) name
, FIL_STANDARD
, (PBYTE
) &fs
, sizeof(fs
)))
284 fd
= (USHORT
) (stamp
>> 16);
286 fs
.fdateLastWrite
= fs
.fdateCreation
= * (FDATE
*) &fd
;
287 fs
.ftimeLastWrite
= fs
.ftimeCreation
= * (FTIME
*) &ft
;
289 if (DosSetPathInfo((PSZ
) name
, FIL_STANDARD
, (PBYTE
) &fs
, sizeof(fs
), 0))
296 int stamp_file(ZCONST
char *fname
, time_t modtime
)
298 return SetFileTime(fname
, Utime2DosDateTime(modtime
));
301 #endif /* TIMESTAMP */
304 /* The following DOS date/time structures are machine-dependent as they
305 * assume "little-endian" byte order. For OS/2-specific code, which
306 * is run on x86 CPUs (or emulators?), this assumption is valid; but
307 * care should be taken when using this code as template for other ports.
310 ULONG timevalue
; /* combined value, useful for comparisons */
312 FTIME ft
; /* system file time record:
314 * USHORT minutes : 6;
315 * USHORT hours : 5; */
316 FDATE fd
; /* system file date record:
319 * USHORT year : 7; */
321 } F_DATE_TIME
, *PF_DATE_TIME
;
324 #if defined(USE_EF_UT_TIME) || defined(TIMESTAMP)
326 static ulg
Utime2DosDateTime(uxtime
)
329 F_DATE_TIME dosfiletime
;
332 /* round up to even seconds */
333 /* round up (down if "up" overflows) to even seconds */
334 if (((ulg
)uxtime
) & 1)
335 uxtime
= (uxtime
+ 1 > uxtime
) ? uxtime
+ 1 : uxtime
- 1;
337 t
= localtime(&(uxtime
));
338 if (t
== (struct tm
*)NULL
) {
339 /* time conversion error; use current time instead, hoping
340 that localtime() does not reject it as well! */
341 time_t now
= time(NULL
);
344 if (t
->tm_year
< 80) {
345 dosfiletime
._fdt
.ft
.twosecs
= 0;
346 dosfiletime
._fdt
.ft
.minutes
= 0;
347 dosfiletime
._fdt
.ft
.hours
= 0;
348 dosfiletime
._fdt
.fd
.day
= 1;
349 dosfiletime
._fdt
.fd
.month
= 1;
350 dosfiletime
._fdt
.fd
.year
= 0;
352 dosfiletime
._fdt
.ft
.twosecs
= t
->tm_sec
>> 1;
353 dosfiletime
._fdt
.ft
.minutes
= t
->tm_min
;
354 dosfiletime
._fdt
.ft
.hours
= t
->tm_hour
;
355 dosfiletime
._fdt
.fd
.day
= t
->tm_mday
;
356 dosfiletime
._fdt
.fd
.month
= t
->tm_mon
+ 1;
357 dosfiletime
._fdt
.fd
.year
= t
->tm_year
- 80;
359 return dosfiletime
.timevalue
;
361 } /* end function Utime2DosDateTime() */
363 #endif /* USE_EF_UT_TIME || TIMESTAMP */
366 static int getOS2filetimes(__GPRO__ ulg
*pM_dt
, ulg
*pA_dt
, ulg
*pC_dt
)
368 #ifdef USE_EF_UT_TIME
369 unsigned eb_izux_flg
;
373 /* Copy and/or convert time and date variables, if necessary; */
374 /* return a flag indicating which time stamps are available. */
375 #ifdef USE_EF_UT_TIME
380 ((eb_izux_flg
= ef_scan_for_izux(G
.extra_field
,
381 G
.lrec
.extra_field_length
, 0, G
.lrec
.last_mod_dos_datetime
,
382 &z_utime
, NULL
)) & EB_UT_FL_MTIME
))
384 TTrace((stderr
, "getOS2filetimes: UT e.f. modif. time = %lu\n",
386 *pM_dt
= Utime2DosDateTime(z_utime
.mtime
);
387 if (eb_izux_flg
& EB_UT_FL_ATIME
) {
388 TTrace((stderr
, "getOS2filetimes: UT e.f. access time = %lu\n",
390 *pA_dt
= Utime2DosDateTime(z_utime
.atime
);
392 if (eb_izux_flg
& EB_UT_FL_CTIME
) {
393 TTrace((stderr
, "getOS2filetimes: UT e.f. creation time = %lu\n",
395 *pC_dt
= Utime2DosDateTime(z_utime
.ctime
);
397 /* no creation time value supplied, set it to modification time */
399 eb_izux_flg
|= EB_UT_FL_CTIME
;
401 return (int)eb_izux_flg
;
403 #endif /* USE_EF_UT_TIME */
404 *pC_dt
= *pM_dt
= G
.lrec
.last_mod_dos_datetime
;
405 TTrace((stderr
, "\ngetOS2filetimes: DOS dir modific./creation time = %lu\n",
407 return (EB_UT_FL_MTIME
| EB_UT_FL_CTIME
);
411 static void SetPathAttrTimes(__GPRO__
int flags
, int dir
)
421 char szName
[CCHMAXPATH
];
422 ulg Mod_dt
, Acc_dt
, Cre_dt
;
425 strcpy(szName
, G
.filename
);
426 nLength
= strlen(szName
);
427 if (szName
[nLength
- 1] == '/')
428 szName
[nLength
- 1] = 0;
432 if ( DosQueryPathInfo(szName
, FIL_STANDARD
, (PBYTE
) &fs
, sizeof(fs
)) )
437 /* for regular files, open them and operate on the file handle, to
438 work around certain network operating system bugs ... */
440 if ( DosOpen(szName
, &hFile
, &nAction
, 0, 0,
441 OPEN_ACTION_OPEN_IF_EXISTS
| OPEN_ACTION_CREATE_IF_NEW
,
442 OPEN_SHARE_DENYREADWRITE
| OPEN_ACCESS_READWRITE
, 0) )
445 if ( DosQueryFileInfo(hFile
, FIL_STANDARD
, (PBYTE
) &fs
, sizeof(fs
)) )
449 /* set date/time stamps */
450 gotTimes
= getOS2filetimes(__G__
&Mod_dt
, &Acc_dt
, &Cre_dt
);
451 if (gotTimes
& EB_UT_FL_MTIME
) {
452 fs
.fdateLastWrite
= ((F_DATE_TIME
*)&Mod_dt
)->_fdt
.fd
;
453 fs
.ftimeLastWrite
= ((F_DATE_TIME
*)&Mod_dt
)->_fdt
.ft
;
455 if (gotTimes
& EB_UT_FL_ATIME
) {
456 fs
.fdateLastAccess
= ((F_DATE_TIME
*)&Acc_dt
)->_fdt
.fd
;
457 fs
.ftimeLastAccess
= ((F_DATE_TIME
*)&Acc_dt
)->_fdt
.ft
;
459 if (gotTimes
& EB_UT_FL_CTIME
) {
460 fs
.fdateCreation
= ((F_DATE_TIME
*)&Cre_dt
)->_fdt
.fd
;
461 fs
.ftimeCreation
= ((F_DATE_TIME
*)&Cre_dt
)->_fdt
.ft
;
465 fs
.attrFile
= flags
; /* hidden, system, archive, read-only */
469 DosSetPathInfo(szName
, FIL_STANDARD
, (PBYTE
) &fs
, sizeof(fs
), 0);
473 DosSetFileInfo(hFile
, FIL_STANDARD
, (PBYTE
) &fs
, sizeof(fs
));
481 ULONG cbList
; /* length of value + 22 */
486 BYTE cbName
; /* length of ".LONGNAME" = 9 */
487 USHORT cbValue
; /* length of value + 4 */
488 BYTE szName
[10]; /* ".LONGNAME" */
489 USHORT eaType
; /* 0xFFFD for length-preceded ASCII */
490 USHORT eaSize
; /* length of value */
491 BYTE szValue
[CCHMAXPATH
];
496 static int SetEAs(__GPRO__
const char *path
, void *ef_block
)
497 { /* returns almost-PK errors */
498 EFHEADER
*pEAblock
= (PEFHEADER
) ef_block
;
511 char szName
[CCHMAXPATH
];
514 if ( ef_block
== NULL
|| pEAblock
-> nID
!= EF_OS2
)
515 return PK_OK
; /* not an OS/2 extra field: assume OK */
517 if ( pEAblock
->nSize
< 4 || (pEAblock
->lSize
> 0L && pEAblock
->nSize
<= 10) )
518 return IZ_EF_TRUNC
; /* no compressed data! */
520 strcpy(szName
, path
);
521 nLength
= strlen(szName
);
522 if (szName
[nLength
- 1] == '/')
523 szName
[nLength
- 1] = 0;
525 if ( (pFEA2list
= (PFEA2LIST
) malloc((size_t) pEAblock
-> lSize
)) == NULL
)
528 if ( (error
= memextract(__G__ (uch
*)pFEA2list
, pEAblock
->lSize
,
529 (uch
*)(pEAblock
+1), (ulg
)(pEAblock
->nSize
- 4))) != PK_OK
)
536 eaop
.fpGEA2List
= NULL
;
537 eaop
.fpFEA2List
= pFEA2list
;
539 pFEAlist
= (PVOID
) pFEA2list
;
540 pFEA2
= pFEA2list
-> list
;
541 pFEA
= pFEAlist
-> list
;
545 nLength2
= pFEA2
-> oNextEntryOffset
;
546 nLength
= sizeof(FEA
) + pFEA2
-> cbName
+ 1 + pFEA2
-> cbValue
;
548 memcpy(pFEA
, (PCH
) pFEA2
+ sizeof(pFEA2
-> oNextEntryOffset
), nLength
);
550 pFEA2
= (PFEA2
) ((PCH
) pFEA2
+ nLength2
);
551 pFEA
= (PFEA
) ((PCH
) pFEA
+ nLength
);
553 while ( nLength2
!= 0 );
555 pFEAlist
-> cbList
= (PCH
) pFEA
- (PCH
) pFEAlist
;
557 eaop
.fpGEAList
= NULL
;
558 eaop
.fpFEAList
= pFEAlist
;
562 DosSetPathInfo(szName
, FIL_QUERYEASIZE
, (PBYTE
) &eaop
, sizeof(eaop
), 0);
564 if (!uO
.tflag
&& QCOND2
)
565 Info(slide
, 0, ((char *)slide
, " (%ld bytes EAs)", pFEA2list
-> cbList
));
572 static int SetACL(__GPRO__
const char *path
, void *ef_block
)
573 { /* returns almost-PK errors */
574 EFHEADER
*pACLblock
= (PEFHEADER
) ef_block
;
578 if ( ef_block
== NULL
|| pACLblock
-> nID
!= EF_ACL
)
579 return PK_OK
; /* not an OS/2 extra field: assume OK */
581 if (pACLblock
->nSize
< 4 || (pACLblock
->lSize
> 0L && pACLblock
->nSize
<= 10))
582 return IZ_EF_TRUNC
; /* no compressed data! */
584 if ( (szACL
= malloc((size_t) pACLblock
-> lSize
)) == NULL
)
587 if ( (error
= memextract(__G__ (uch
*)szACL
, pACLblock
->lSize
,
588 (uch
*)(pACLblock
+1), (ulg
)(pACLblock
->nSize
- 4))) != PK_OK
)
594 if (acl_set(NULL
, path
, szACL
) == 0)
595 if (!uO
.tflag
&& QCOND2
)
596 Info(slide
, 0, ((char *)slide
, " (%ld bytes ACL)", strlen(szACL
)));
605 char *GetLoadPath(__GPRO
)
607 #ifdef __32BIT__ /* generic for 32-bit API */
612 DosGetInfoBlocks(&pptib
, &pppib
);
613 szPath
= pppib
-> pib_pchenv
;
614 #else /* 16-bit, note: requires large data model */
619 DosGetEnv(&selEnv
, &offCmd
);
620 szPath
= MAKEP(selEnv
, 0);
623 while (*szPath
) /* find end of process environment */
624 szPath
= strchr(szPath
, 0) + 1;
626 return szPath
+ 1; /* .exe file name follows environment */
628 } /* end function GetLoadPath() */
636 DIR *opendir(__GPRO__
const char *name
)
642 struct _dircontents
*dp
;
643 char nbuf
[MAXPATHLEN
+ 1];
647 if ((len
= strlen(nbuf
)) == 0)
650 if ( ((c
= nbuf
[len
- 1]) == '\\' || c
== '/') && (len
> 1) )
655 if ( nbuf
[len
- 1] == ':' )
657 strcpy(nbuf
+len
, "\\.");
662 if ( nbuf
[len
- 1] == ':' )
664 strcpy(nbuf
+len
, ".");
668 /* GRR: Borland and Watcom C return non-zero on wildcards... < 0 ? */
669 if (stat(nbuf
, &statb
) < 0 || (statb
.st_mode
& S_IFMT
) != S_IFDIR
)
671 Trace((stderr
, "opendir: stat(%s) returns negative or not directory\n",
676 if ( (dirp
= malloc(sizeof(DIR))) == NULL
)
679 if ( nbuf
[len
- 1] == '.' && (len
== 1 || nbuf
[len
- 2] != '.') )
680 strcpy(nbuf
+len
-1, "*");
682 if ( ((c
= nbuf
[len
- 1]) == '\\' || c
== '/') && (len
== 1) )
683 strcpy(nbuf
+len
, "*");
685 strcpy(nbuf
+len
, "\\*");
687 /* len is no longer correct (but no longer needed) */
688 Trace((stderr
, "opendir: nbuf = [%s]\n", nbuf
));
691 dirp
-> dd_contents
= dirp
-> dd_cp
= NULL
;
693 if ((s
= getdirent(__G__ nbuf
)) == NULL
)
698 if (((dp
= malloc(sizeof(struct _dircontents
))) == NULL
) ||
699 ((dp
-> _d_entry
= malloc(strlen(s
) + 1)) == NULL
) )
703 free_dircontents(dirp
-> dd_contents
);
708 if (dirp
-> dd_contents
)
710 dirp
-> dd_cp
-> _d_next
= dp
;
711 dirp
-> dd_cp
= dirp
-> dd_cp
-> _d_next
;
714 dirp
-> dd_contents
= dirp
-> dd_cp
= dp
;
716 strcpy(dp
-> _d_entry
, s
);
717 dp
-> _d_next
= NULL
;
719 dp
-> _d_size
= G
.os2
.find
.cbFile
;
720 dp
-> _d_mode
= G
.os2
.find
.attrFile
;
721 dp
-> _d_time
= *(unsigned *) &(G
.os2
.find
.ftimeLastWrite
);
722 dp
-> _d_date
= *(unsigned *) &(G
.os2
.find
.fdateLastWrite
);
724 while ((s
= getdirent(__G__ NULL
)) != NULL
);
726 dirp
-> dd_cp
= dirp
-> dd_contents
;
732 void closedir(DIR * dirp
)
734 free_dircontents(dirp
-> dd_contents
);
739 struct direct
*readdir(__GPRO__
DIR * dirp
)
741 /* moved to os2data.h so it can be global */
742 /* static struct direct dp; */
744 if (dirp
-> dd_cp
== NULL
)
747 G
.os2
.dp
.d_namlen
= G
.os2
.dp
.d_reclen
=
748 strlen(strcpy(G
.os2
.dp
.d_name
, dirp
-> dd_cp
-> _d_entry
));
752 G
.os2
.dp
.d_size
= dirp
-> dd_cp
-> _d_size
;
753 G
.os2
.dp
.d_mode
= dirp
-> dd_cp
-> _d_mode
;
754 G
.os2
.dp
.d_time
= dirp
-> dd_cp
-> _d_time
;
755 G
.os2
.dp
.d_date
= dirp
-> dd_cp
-> _d_date
;
757 dirp
-> dd_cp
= dirp
-> dd_cp
-> _d_next
;
765 #if 0 /* not used in unzip; retained for possibly future use */
767 void seekdir(DIR * dirp
, long off
)
770 struct _dircontents
*dp
;
774 for (dp
= dirp
-> dd_contents
; --i
>= 0 && dp
; dp
= dp
-> _d_next
);
776 dirp
-> dd_loc
= off
- (i
+ 1);
782 long telldir(DIR * dirp
)
784 return dirp
-> dd_loc
;
791 static void free_dircontents(struct _dircontents
* dp
)
793 struct _dircontents
*odp
;
798 free(dp
-> _d_entry
);
800 dp
= (odp
= dp
) -> _d_next
;
806 static char *getdirent(__GPRO__ ZCONST
char *dir
)
809 /* moved to os2data.h so it can be global */
810 /* static int lower; */
813 { /* get first entry */
814 G
.os2
.hdir
= HDIR_SYSTEM
;
816 done
= DosFindFirst((PSZ
) dir
, &G
.os2
.hdir
, attributes
,
817 &G
.os2
.find
, sizeof(G
.os2
.find
), &G
.os2
.count
);
818 G
.os2
.lower
= IsFileSystemFAT(__G__ dir
);
820 else /* get next entry */
821 done
= DosFindNext(G
.os2
.hdir
,
822 &G
.os2
.find
, sizeof(G
.os2
.find
), &G
.os2
.count
);
827 StringLower(G
.os2
.find
.achName
);
828 return G
.os2
.find
.achName
;
832 DosFindClose(G
.os2
.hdir
);
839 int IsFileSystemFAT(__GPRO__ ZCONST
char *dir
) /* FAT / HPFS detection */
841 /* moved to os2data.h so they can be global */
842 /* static USHORT nLastDrive=(USHORT)(-1), nResult; */
847 ULONG nDrive
, cbData
;
848 PFSQBUFFER2 pData
= (PFSQBUFFER2
) bData
;
850 USHORT nDrive
, cbData
;
851 PFSQBUFFER pData
= (PFSQBUFFER
) bData
;
854 /* We separate FAT and HPFS+other file systems here.
855 at the moment I consider other systems to be similar to HPFS,
856 i.e. support long file names and case sensitive */
858 if ( isalpha(dir
[0]) && (dir
[1] == ':') )
859 nDrive
= toupper(dir
[0]) - '@';
861 DosQueryCurrentDisk(&nDrive
, &lMap
);
863 if ( nDrive
== G
.os2
.nLastDrive
)
864 return G
.os2
.nResult
;
866 bName
[0] = (char) (nDrive
+ '@');
870 G
.os2
.nLastDrive
= nDrive
;
871 cbData
= sizeof(bData
);
873 if ( !DosQueryFSAttach(bName
, 0, FSAIL_QUERYNAME
, (PVOID
) pData
, &cbData
) )
874 G
.os2
.nResult
= !strcmp((char *) (pData
-> szFSDName
) + pData
-> cbName
,
877 G
.os2
.nResult
= FALSE
;
879 /* End of this ugly code */
880 return G
.os2
.nResult
;
881 } /* end function IsFileSystemFAT() */
887 /************************/
888 /* Function do_wild() */
889 /************************/
891 char *do_wild(__G__ wildspec
)
893 char *wildspec
; /* only used first time on a given dir */
895 /* moved to os2data.h so they can be global */
897 static DIR *dir
= NULL
;
898 static char *dirname
, *wildname
, matchname
[FILNAMSIZ
];
899 static int firstcall
=TRUE
, have_dirname
, dirnamelen
;
905 /* Even when we're just returning wildspec, we *always* do so in
906 * matchname[]--calling routine is allowed to append four characters
907 * to the returned string, and wildspec may be a pointer to argv[].
909 if (G
.os2
.firstcall
) { /* first call: must initialize everything */
910 G
.os2
.firstcall
= FALSE
;
912 if (!iswild(wildspec
)) {
913 strcpy(G
.os2
.matchname
, wildspec
);
914 G
.os2
.have_dirname
= FALSE
;
916 return G
.os2
.matchname
;
919 /* break the wildspec into a directory part and a wildcard filename */
920 if ((G
.os2
.wildname
= strrchr(wildspec
, '/')) == NULL
&&
921 (G
.os2
.wildname
= strrchr(wildspec
, ':')) == NULL
) {
923 G
.os2
.dirnamelen
= 1;
924 G
.os2
.have_dirname
= FALSE
;
925 G
.os2
.wildname
= wildspec
;
927 ++G
.os2
.wildname
; /* point at character after '/' or ':' */
928 G
.os2
.dirnamelen
= G
.os2
.wildname
- wildspec
;
929 if ((G
.os2
.dirname
= (char *)malloc(G
.os2
.dirnamelen
+1)) == NULL
) {
930 Info(slide
, 1, ((char *)slide
,
931 LoadFarString(CantAllocateWildcard
)));
932 strcpy(G
.os2
.matchname
, wildspec
);
933 return G
.os2
.matchname
; /* but maybe filespec was not a wildcard */
935 strncpy(G
.os2
.dirname
, wildspec
, G
.os2
.dirnamelen
);
936 G
.os2
.dirname
[G
.os2
.dirnamelen
] = '\0'; /* terminate for strcpy below */
937 G
.os2
.have_dirname
= TRUE
;
939 Trace((stderr
, "do_wild: dirname = [%s]\n", G
.os2
.dirname
));
941 if ((G
.os2
.dir
= opendir(__G__ G
.os2
.dirname
)) != NULL
) {
942 if (G
.os2
.have_dirname
) {
943 strcpy(G
.os2
.matchname
, G
.os2
.dirname
);
944 fnamestart
= G
.os2
.matchname
+ G
.os2
.dirnamelen
;
946 fnamestart
= G
.os2
.matchname
;
947 while ((file
= readdir(__G__ G
.os2
.dir
)) != NULL
) {
948 Trace((stderr
, "do_wild: readdir returns %s\n", file
->d_name
));
949 strcpy(fnamestart
, file
->d_name
);
950 if (strrchr(fnamestart
, '.') == (char *)NULL
)
951 strcat(fnamestart
, ".");
952 if (match(fnamestart
, G
.os2
.wildname
, 1) && /* 1 == ignore case */
953 /* skip "." and ".." directory entries */
954 strcmp(fnamestart
, ".") && strcmp(fnamestart
, "..")) {
955 Trace((stderr
, "do_wild: match() succeeds\n"));
956 /* remove trailing dot */
957 fnamestart
+= strlen(fnamestart
) - 1;
958 if (*fnamestart
== '.')
960 return G
.os2
.matchname
;
963 /* if we get to here directory is exhausted, so close it */
969 Trace((stderr
, "do_wild: opendir(%s) returns NULL\n", G
.os2
.dirname
));
973 /* return the raw wildspec in case that works (e.g., directory not
974 * searchable, but filespec was not wild and file is readable) */
975 strcpy(G
.os2
.matchname
, wildspec
);
976 return G
.os2
.matchname
;
979 /* last time through, might have failed opendir but returned raw wildspec */
980 if (G
.os2
.dir
== NULL
) {
981 G
.os2
.firstcall
= TRUE
; /* nothing left to try--reset for new wildspec */
982 if (G
.os2
.have_dirname
)
987 /* If we've gotten this far, we've read and matched at least one entry
988 * successfully (in a previous call), so dirname has been copied into
991 if (G
.os2
.have_dirname
) {
992 /* strcpy(G.os2.matchname, G.os2.dirname); */
993 fnamestart
= G
.os2
.matchname
+ G
.os2
.dirnamelen
;
995 fnamestart
= G
.os2
.matchname
;
996 while ((file
= readdir(__G__ G
.os2
.dir
)) != NULL
) {
997 Trace((stderr
, "do_wild: readdir returns %s\n", file
->d_name
));
998 strcpy(fnamestart
, file
->d_name
);
999 if (strrchr(fnamestart
, '.') == (char *)NULL
)
1000 strcat(fnamestart
, ".");
1001 if (match(fnamestart
, G
.os2
.wildname
, 1)) { /* 1 == ignore case */
1002 Trace((stderr
, "do_wild: match() succeeds\n"));
1003 /* remove trailing dot */
1004 fnamestart
+= strlen(fnamestart
) - 1;
1005 if (*fnamestart
== '.')
1007 return G
.os2
.matchname
;
1011 closedir(G
.os2
.dir
); /* have read at least one dir entry; nothing left */
1013 G
.os2
.firstcall
= TRUE
; /* reset for new wildspec */
1014 if (G
.os2
.have_dirname
)
1015 free(G
.os2
.dirname
);
1016 return (char *)NULL
;
1018 } /* end function do_wild() */
1023 /* scan extra fields for something we happen to know */
1025 static int EvalExtraFields(__GPRO__
const char *path
,
1026 void *extra_field
, unsigned ef_len
)
1028 char *ef_ptr
= extra_field
;
1032 while (ef_len
>= sizeof(EFHEADER
))
1034 pEFblock
= (PEFHEADER
) ef_ptr
;
1036 if (pEFblock
-> nSize
> (ef_len
- EB_HEADSIZE
))
1037 return PK_ERR
; /* claimed EFblock length exceeds EF size! */
1039 switch (pEFblock
-> nID
)
1042 rc
= SetEAs(__G__ path
, ef_ptr
);
1045 rc
= (uO
.X_flag
) ? SetACL(__G__ path
, ef_ptr
) : PK_OK
;
1050 /* handled elsewhere */
1054 TTrace((stderr
,"EvalExtraFields: unknown extra field block, ID=%d\n",
1059 ef_ptr
+= (pEFblock
-> nSize
+ EB_HEADSIZE
);
1060 ef_len
-= (pEFblock
-> nSize
+ EB_HEADSIZE
);
1071 /************************/
1072 /* Function mapattr() */
1073 /************************/
1078 /* set archive bit (file is not backed up): */
1079 G
.pInfo
->file_attr
= (unsigned)(G
.crec
.external_file_attributes
| 32) & 0xff;
1087 /************************/
1088 /* Function mapname() */
1089 /************************/
1092 * There are presently two possibilities in OS/2: the output filesystem is
1093 * FAT, or it is HPFS. If the former, we need to map to FAT, obviously, but
1094 * we *also* must map to HPFS and store that version of the name in extended
1095 * attributes. Either way, we need to map to HPFS, so the main mapname
1096 * routine does that. In the case that the output file system is FAT, an
1097 * extra filename-mapping routine is called in checkdir(). While it should
1098 * be possible to determine the filesystem immediately upon entry to mapname(),
1099 * it is conceivable that the DOS APPEND utility could be added to OS/2 some-
1100 * day, allowing a FAT directory to be APPENDed to an HPFS drive/path. There-
1101 * fore we simply check the filesystem at each path component.
1103 * Note that when alternative IFSes become available/popular, everything will
1104 * become immensely more complicated. For example, a Minix filesystem would
1105 * have limited filename lengths like FAT but no extended attributes in which
1106 * to store the longer versions of the names. A BSD Unix filesystem would
1107 * support paths of length 1024 bytes or more, but it is not clear that FAT
1108 * EAs would allow such long .LONGNAME fields or that OS/2 would properly
1109 * restore such fields when moving files from FAT to the new filesystem.
1111 * GRR: some or all of the following chars should be checked in either
1112 * mapname (HPFS) or map2fat (FAT), depending: ,=^+'"[]<>|\t&
1114 /* return 0 if no error, 1 if caution (filename */
1115 int mapname(__G__ renamed
) /* truncated), 2 if warning (skip file because */
1116 __GDEF
/* dir doesn't exist), 3 if error (skip file), */
1117 int renamed
; /* or 10 if out of memory (skip file) */
1118 { /* [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
1119 char pathcomp
[FILNAMSIZ
]; /* path-component buffer */
1120 char *pp
, *cp
=(char *)NULL
; /* character pointers */
1121 char *lastsemi
=(char *)NULL
; /* pointer to last semi-colon in pathcomp */
1122 int quote
= FALSE
; /* flag: next char is literal */
1124 register unsigned workch
; /* hold the character being tested */
1127 /*---------------------------------------------------------------------------
1128 Initialize various pointers and counters and stuff.
1129 ---------------------------------------------------------------------------*/
1131 /* can create path as long as not just freshening, or if user told us */
1132 G
.create_dirs
= (!uO
.fflag
|| renamed
);
1134 G
.os2
.created_dir
= FALSE
; /* not yet */
1135 G
.os2
.renamed_fullpath
= FALSE
;
1136 G
.os2
.fnlen
= strlen(G
.filename
);
1138 /* GRR: for VMS, convert to internal format now or later? or never? */
1140 cp
= G
.filename
- 1; /* point to beginning of renamed name... */
1142 if (*cp
== '\\') /* convert backslashes to forward */
1145 /* use temporary rootpath if user gave full pathname */
1146 if (G
.filename
[0] == '/') {
1147 G
.os2
.renamed_fullpath
= TRUE
;
1148 pathcomp
[0] = '/'; /* copy the '/' and terminate */
1151 } else if (isalpha(G
.filename
[0]) && G
.filename
[1] == ':') {
1152 G
.os2
.renamed_fullpath
= TRUE
;
1154 *pp
++ = *cp
++; /* copy the "d:" (+ '/', possibly) */
1157 *pp
++ = *cp
++; /* otherwise add "./"? */
1162 /* pathcomp is ignored unless renamed_fullpath is TRUE: */
1163 if ((error
= checkdir(__G__ pathcomp
, INIT
)) != 0) /* init path buffer */
1164 return error
; /* ...unless no mem or vol label on hard disk */
1166 *pathcomp
= '\0'; /* initialize translation buffer */
1167 pp
= pathcomp
; /* point to translation buffer */
1168 if (!renamed
) { /* cp already set if renamed */
1169 if (uO
.jflag
) /* junking directories */
1170 /* GRR: watch out for VMS version... */
1171 cp
= (char *)strrchr(G
.filename
, '/');
1172 if (cp
== (char *)NULL
) /* no '/' or not junking dirs */
1173 cp
= G
.filename
; /* point to internal zipfile-member pathname */
1175 ++cp
; /* point to start of last component of path */
1178 /*---------------------------------------------------------------------------
1179 Begin main loop through characters in filename.
1180 ---------------------------------------------------------------------------*/
1182 while ((workch
= (uch
)*cp
++) != 0) {
1184 if (quote
) { /* if character quoted, */
1185 *pp
++ = (char)workch
; /* include it literally */
1189 case '/': /* can assume -j flag not given */
1191 if ((error
= checkdir(__G__ pathcomp
, APPEND_DIR
)) > 1)
1193 pp
= pathcomp
; /* reset conversion buffer for next piece */
1194 lastsemi
= (char *)NULL
; /* leave directory semi-colons alone */
1198 *pp
++ = '_'; /* drive names not stored in zipfile, */
1199 break; /* so no colons allowed */
1201 case ';': /* start of VMS version? */
1202 lastsemi
= pp
; /* remove VMS version later... */
1203 *pp
++ = ';'; /* but keep semicolon for now */
1206 case '\026': /* control-V quote for special chars */
1207 quote
= TRUE
; /* set flag for next character */
1210 case ' ': /* keep spaces unless specifically */
1211 if (uO
.sflag
) /* requested to change to underscore */
1218 /* allow ASCII 255 and European characters in filenames: */
1219 if (isprint(workch
) || workch
>= 127)
1220 *pp
++ = (char)workch
;
1223 } /* end while loop */
1225 *pp
= '\0'; /* done with pathcomp: terminate it */
1227 /* if not saving them, remove VMS version numbers (appended "###") */
1228 if (!uO
.V_flag
&& lastsemi
) {
1229 pp
= lastsemi
+ 1; /* semi-colon was kept: expect #s after */
1230 while (isdigit((uch
)(*pp
)))
1232 if (*pp
== '\0') /* only digits between ';' and end: nuke */
1236 /*---------------------------------------------------------------------------
1237 Report if directory was created (and no file to create: filename ended
1238 in '/'), check name to be sure it exists, and combine path and name be-
1240 ---------------------------------------------------------------------------*/
1242 if (G
.filename
[G
.os2
.fnlen
-1] == '/') {
1243 checkdir(__G__ G
.filename
, GETPATH
);
1244 if (G
.os2
.created_dir
) {
1246 Info(slide
, 0, ((char *)slide
, LoadFarString(Creating
),
1248 if (G
.extra_field
) { /* zipfile extra field has extended attribs */
1249 int err
= EvalExtraFields(__G__ G
.filename
, G
.extra_field
,
1250 G
.lrec
.extra_field_length
);
1252 if (err
== IZ_EF_TRUNC
) {
1254 Info(slide
, 1, ((char *)slide
, "%-22s ", G
.filename
));
1255 Info(slide
, 1, ((char *)slide
, LoadFarString(TruncEAs
),
1256 makeword(G
.extra_field
+2)-10, "\n"));
1257 } else if (!uO
.qflag
)
1258 (*G
.message
)((zvoid
*)&G
, (uch
*)"\n", 1L, 0);
1259 } else if (!uO
.qflag
)
1260 (*G
.message
)((zvoid
*)&G
, (uch
*)"\n", 1L, 0);
1262 /* set date/time stamps */
1263 SetPathAttrTimes(__G__ G
.pInfo
->file_attr
& ~A_ARCHIVE
, 1);
1265 return IZ_CREATED_DIR
; /* dir time already set */
1267 } else if (G
.extra_field
&& uO
.overwrite_all
) {
1268 /* overwrite EAs of existing directory since user requested it */
1269 int err
= EvalExtraFields(__G__ G
.filename
, G
.extra_field
,
1270 G
.lrec
.extra_field_length
);
1272 if (err
== IZ_EF_TRUNC
) {
1273 Info(slide
, 0x421, ((char *)slide
, "%-22s ", G
.filename
));
1274 Info(slide
, 0x401, ((char *)slide
, LoadFarString(TruncEAs
),
1275 makeword(G
.extra_field
+2)-10, "\n"));
1278 /* set date/time stamps (dirs only have creation times) */
1279 SetPathAttrTimes(__G__ G
.pInfo
->file_attr
& ~A_ARCHIVE
, 1);
1281 return 2; /* dir existed already; don't look for data to extract */
1284 if (*pathcomp
== '\0') {
1285 Info(slide
, 1, ((char *)slide
, LoadFarString(ConversionFailed
),
1290 checkdir(__G__ pathcomp
, APPEND_NAME
); /* returns 1 if truncated: care? */
1291 checkdir(__G__ G
.filename
, GETPATH
);
1292 Trace((stderr
, "mapname returns with filename = [%s] (error = %d)\n\n",
1293 G
.filename
, error
));
1295 if (G
.pInfo
->vollabel
) { /* set the volume label now */
1296 VOLUMELABEL FSInfoBuf
;
1297 /* GRR: "VOLUMELABEL" defined for IBM C and emx, but haven't checked MSC... */
1299 strcpy(FSInfoBuf
.szVolLabel
, G
.filename
);
1300 FSInfoBuf
.cch
= (BYTE
)strlen(FSInfoBuf
.szVolLabel
);
1303 Info(slide
, 0, ((char *)slide
, LoadFarString(Labelling
),
1304 (char)(G
.os2
.nLabelDrive
+ 'a' - 1), G
.filename
));
1305 if (DosSetFSInfo(G
.os2
.nLabelDrive
, FSIL_VOLSER
, (PBYTE
)&FSInfoBuf
,
1306 sizeof(VOLUMELABEL
)))
1308 Info(slide
, 1, ((char *)slide
, LoadFarString(ErrSetVolLabel
)));
1311 return 2; /* success: skip the "extraction" quietly */
1316 } /* end function mapname() */
1322 /***********************/
1323 /* Function checkdir() */
1324 /***********************/
1326 int checkdir(__G__ pathcomp
, flag
)
1331 * returns: 1 - (on APPEND_NAME) truncated filename
1332 * 2 - path doesn't exist, not allowed to create
1333 * 3 - path doesn't exist, tried to create and failed; or
1334 * path exists and is not a directory, but is supposed to be
1335 * 4 - path is too long
1336 * 10 - can't allocate memory for filename buffers
1339 /* moved to os2data.h so they can be global */
1341 static int rootlen
= 0; /* length of rootpath */
1342 static char *rootpath
; /* user's "extract-to" directory */
1343 static char *buildpathHPFS
; /* full path (so far) to extracted file, */
1344 static char *buildpathFAT
; /* both HPFS/EA (main) and FAT versions */
1345 static char *endHPFS
; /* corresponding pointers to end of */
1346 static char *endFAT
; /* buildpath ('\0') */
1350 # define FUNCTION (flag & FN_MASK)
1354 /*---------------------------------------------------------------------------
1355 APPEND_DIR: append the path component to the path being built and check
1356 for its existence. If doesn't exist and we are creating directories, do
1357 so for this one; else signal success or error as appropriate.
1358 ---------------------------------------------------------------------------*/
1360 if (FUNCTION
== APPEND_DIR
) {
1362 int longdirEA
, too_long
=FALSE
;
1364 Trace((stderr
, "appending dir segment [%s]\n", pathcomp
));
1365 while ((*G
.os2
.endHPFS
= *p
++) != '\0') /* copy to HPFS filename */
1367 if (IsFileNameValid(G
.os2
.buildpathHPFS
)) {
1370 while ((*G
.os2
.endFAT
= *p
++) != '\0') /* copy to FAT filename, too */
1374 /* GRR: check error return? */
1375 map2fat(pathcomp
, &G
.os2
.endFAT
); /* map, put in FAT fn, update endFAT */
1378 /* GRR: could do better check, see if overrunning buffer as we go:
1379 * check endHPFS-G.os2.buildpathHPFS after each append, set warning variable
1380 * if within 20 of FILNAMSIZ; then if var set, do careful check when
1381 * appending. Clear variable when begin new path. */
1383 /* next check: need to append '/', at least one-char name, '\0' */
1384 if ((G
.os2
.endHPFS
-G
.os2
.buildpathHPFS
) > FILNAMSIZ
-3)
1385 too_long
= TRUE
; /* check if extracting dir? */
1386 #ifdef MSC /* MSC 6.00 bug: stat(non-existent-dir) == 0 [exists!] */
1387 if (GetFileTime(G
.os2
.buildpathFAT
) == -1 || stat(G
.os2
.buildpathFAT
, &G
.statbuf
))
1389 if (stat(G
.os2
.buildpathFAT
, &G
.statbuf
)) /* path doesn't exist */
1392 if (!G
.create_dirs
) { /* told not to create (freshening) */
1393 free(G
.os2
.buildpathHPFS
);
1394 free(G
.os2
.buildpathFAT
);
1395 return 2; /* path doesn't exist: nothing to do */
1397 if (too_long
) { /* GRR: should allow FAT extraction w/o EAs */
1398 Info(slide
, 1, ((char *)slide
, LoadFarString(PathTooLong
),
1399 G
.os2
.buildpathHPFS
));
1400 free(G
.os2
.buildpathHPFS
);
1401 free(G
.os2
.buildpathFAT
);
1402 return 4; /* no room for filenames: fatal */
1404 if (MKDIR(G
.os2
.buildpathFAT
, 0777) == -1) { /* create the directory */
1405 Info(slide
, 1, ((char *)slide
, LoadFarString(CantCreateDir
),
1406 G
.os2
.buildpathFAT
, G
.filename
));
1407 free(G
.os2
.buildpathHPFS
);
1408 free(G
.os2
.buildpathFAT
);
1409 return 3; /* path didn't exist, tried to create, failed */
1411 G
.os2
.created_dir
= TRUE
;
1412 /* only set EA if creating directory */
1413 /* GRR: need trailing '/' before function call? */
1418 SetLongNameEA(G
.os2
.buildpathFAT
, pathcomp
);
1419 Trace((stderr
, "APPEND_DIR: SetLongNameEA() returns %d\n", e
));
1421 } else if (!S_ISDIR(G
.statbuf
.st_mode
)) {
1422 Info(slide
, 1, ((char *)slide
, LoadFarString(DirIsntDirectory
),
1423 G
.os2
.buildpathFAT
, G
.filename
));
1424 free(G
.os2
.buildpathHPFS
);
1425 free(G
.os2
.buildpathFAT
);
1426 return 3; /* path existed but wasn't dir */
1429 Info(slide
, 1, ((char *)slide
, LoadFarString(PathTooLong
),
1430 G
.os2
.buildpathHPFS
));
1431 free(G
.os2
.buildpathHPFS
);
1432 free(G
.os2
.buildpathFAT
);
1433 return 4; /* no room for filenames: fatal */
1435 *G
.os2
.endHPFS
++ = '/';
1436 *G
.os2
.endFAT
++ = '/';
1437 *G
.os2
.endHPFS
= *G
.os2
.endFAT
= '\0';
1438 Trace((stderr
, "buildpathHPFS now = [%s]\n", G
.os2
.buildpathHPFS
));
1439 Trace((stderr
, "buildpathFAT now = [%s]\n", G
.os2
.buildpathFAT
));
1442 } /* end if (FUNCTION == APPEND_DIR) */
1444 /*---------------------------------------------------------------------------
1445 GETPATH: copy full FAT path to the string pointed at by pathcomp (want
1446 filename to reflect name used on disk, not EAs; if full path is HPFS,
1447 buildpathFAT and buildpathHPFS will be identical). Also free both paths.
1448 ---------------------------------------------------------------------------*/
1450 if (FUNCTION
== GETPATH
) {
1451 Trace((stderr
, "getting and freeing FAT path [%s]\n", G
.os2
.buildpathFAT
));
1452 Trace((stderr
, "freeing HPFS path [%s]\n", G
.os2
.buildpathHPFS
));
1453 strcpy(pathcomp
, G
.os2
.buildpathFAT
);
1454 free(G
.os2
.buildpathFAT
);
1455 free(G
.os2
.buildpathHPFS
);
1456 G
.os2
.buildpathHPFS
= G
.os2
.buildpathFAT
= G
.os2
.endHPFS
= G
.os2
.endFAT
= (char *)NULL
;
1460 /*---------------------------------------------------------------------------
1461 APPEND_NAME: assume the path component is the filename; append it and
1462 return without checking for existence.
1463 ---------------------------------------------------------------------------*/
1465 if (FUNCTION
== APPEND_NAME
) {
1469 Trace((stderr
, "appending filename [%s]\n", pathcomp
));
1470 while ((*G
.os2
.endHPFS
= *p
++) != '\0') { /* copy to HPFS filename */
1472 if ((G
.os2
.endHPFS
-G
.os2
.buildpathHPFS
) >= FILNAMSIZ
) {
1473 *--G
.os2
.endHPFS
= '\0';
1474 Info(slide
, 1, ((char *)slide
, LoadFarString(PathTooLongTrunc
),
1475 G
.filename
, G
.os2
.buildpathHPFS
));
1476 error
= 1; /* filename truncated */
1480 /* GRR: how can longnameEA ever be set before this point??? we don't want
1481 * to save the original name to EAs if user renamed it, do we?
1483 * if (!G.os2.longnameEA && ((G.os2.longnameEA = !IsFileNameValid(name)) != 0))
1485 if (G
.pInfo
->vollabel
|| IsFileNameValid(G
.os2
.buildpathHPFS
)) {
1486 G
.os2
.longnameEA
= FALSE
;
1488 while ((*G
.os2
.endFAT
= *p
++) != '\0') /* copy to FAT filename, too */
1491 G
.os2
.longnameEA
= TRUE
;
1492 if ((G
.os2
.lastpathcomp
= (char *)malloc(strlen(pathcomp
)+1)) ==
1495 Info(slide
, 1, ((char *)slide
,
1496 "checkdir warning: cannot save longname EA: out of memory\n"));
1497 G
.os2
.longnameEA
= FALSE
;
1498 error
= 1; /* can't set .LONGNAME extended attribute */
1499 } else /* used and freed in close_outfile() */
1500 strcpy(G
.os2
.lastpathcomp
, pathcomp
);
1501 map2fat(pathcomp
, &G
.os2
.endFAT
); /* map, put in FAT fn, update endFAT */
1503 Trace((stderr
, "buildpathHPFS: %s\nbuildpathFAT: %s\n",
1504 G
.os2
.buildpathHPFS
, G
.os2
.buildpathFAT
));
1506 return error
; /* could check for existence, prompt for new name... */
1508 } /* end if (FUNCTION == APPEND_NAME) */
1510 /*---------------------------------------------------------------------------
1511 INIT: allocate and initialize buffer space for the file currently being
1512 extracted. If file was renamed with an absolute path, don't prepend the
1514 ---------------------------------------------------------------------------*/
1516 if (FUNCTION
== INIT
) {
1517 Trace((stderr
, "initializing buildpathHPFS and buildpathFAT to "));
1518 if ((G
.os2
.buildpathHPFS
= (char *)malloc(G
.os2
.fnlen
+G
.os2
.rootlen
+1)) == (char *)NULL
)
1520 if ((G
.os2
.buildpathFAT
= (char *)malloc(G
.os2
.fnlen
+G
.os2
.rootlen
+1)) == (char *)NULL
) {
1521 free(G
.os2
.buildpathHPFS
);
1524 if (G
.pInfo
->vollabel
) { /* use root or renamed path, but don't store */
1525 /* GRR: for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
1526 if (G
.os2
.renamed_fullpath
&& pathcomp
[1] == ':')
1527 *G
.os2
.buildpathHPFS
= (char)ToLower(*pathcomp
);
1528 else if (!G
.os2
.renamed_fullpath
&& G
.os2
.rootlen
> 1 && G
.os2
.rootpath
[1] == ':')
1529 *G
.os2
.buildpathHPFS
= (char)ToLower(*G
.os2
.rootpath
);
1532 DosQueryCurrentDisk(&G
.os2
.nLabelDrive
, &lMap
);
1533 *G
.os2
.buildpathHPFS
= (char)(G
.os2
.nLabelDrive
- 1 + 'a');
1535 G
.os2
.nLabelDrive
= *G
.os2
.buildpathHPFS
- 'a' + 1; /* save for mapname() */
1536 if (uO
.volflag
== 0 || *G
.os2
.buildpathHPFS
< 'a' || /* no labels/bogus? */
1537 (uO
.volflag
== 1 && !isfloppy(G
.os2
.nLabelDrive
))) { /* -$: no fixed */
1538 free(G
.os2
.buildpathHPFS
);
1539 free(G
.os2
.buildpathFAT
);
1540 return IZ_VOL_LABEL
; /* skipping with message */
1542 *G
.os2
.buildpathHPFS
= '\0';
1543 } else if (G
.os2
.renamed_fullpath
) /* pathcomp = valid data */
1544 strcpy(G
.os2
.buildpathHPFS
, pathcomp
);
1545 else if (G
.os2
.rootlen
> 0)
1546 strcpy(G
.os2
.buildpathHPFS
, G
.os2
.rootpath
);
1548 *G
.os2
.buildpathHPFS
= '\0';
1549 G
.os2
.endHPFS
= G
.os2
.buildpathHPFS
;
1550 G
.os2
.endFAT
= G
.os2
.buildpathFAT
;
1551 while ((*G
.os2
.endFAT
= *G
.os2
.endHPFS
) != '\0') {
1555 Trace((stderr
, "[%s]\n", G
.os2
.buildpathHPFS
));
1559 /*---------------------------------------------------------------------------
1560 ROOT: if appropriate, store the path in rootpath and create it if neces-
1561 sary; else assume it's a zipfile member and return. This path segment
1562 gets used in extracting all members from every zipfile specified on the
1563 command line. Note that under OS/2 and MS-DOS, if a candidate extract-to
1564 directory specification includes a drive letter (leading "x:"), it is
1565 treated just as if it had a trailing '/'--that is, one directory level
1566 will be created if the path doesn't exist, unless this is otherwise pro-
1567 hibited (e.g., freshening).
1568 ---------------------------------------------------------------------------*/
1570 #if (!defined(SFX) || defined(SFX_EXDIR))
1571 if (FUNCTION
== ROOT
) {
1572 Trace((stderr
, "initializing root path to [%s]\n", pathcomp
));
1573 if (pathcomp
== (char *)NULL
) {
1577 if ((G
.os2
.rootlen
= strlen(pathcomp
)) > 0) {
1578 int had_trailing_pathsep
=FALSE
, has_drive
=FALSE
, xtra
=2;
1580 if (isalpha(pathcomp
[0]) && pathcomp
[1] == ':')
1581 has_drive
= TRUE
; /* drive designator */
1582 if (pathcomp
[G
.os2
.rootlen
-1] == '/') {
1583 pathcomp
[--G
.os2
.rootlen
] = '\0';
1584 had_trailing_pathsep
= TRUE
;
1586 if (has_drive
&& (G
.os2
.rootlen
== 2)) {
1587 if (!had_trailing_pathsep
) /* i.e., original wasn't "x:/" */
1588 xtra
= 3; /* room for '.' + '/' + 0 at end of "x:" */
1589 } else if (G
.os2
.rootlen
> 0) { /* need not check "x:." and "x:/" */
1590 #ifdef MSC /* MSC 6.00 bug: stat(non-existent-dir) == 0 [exists!] */
1591 if (GetFileTime(pathcomp
) == -1 ||
1592 SSTAT(pathcomp
, &G
.statbuf
) || !S_ISDIR(G
.statbuf
.st_mode
))
1594 if (SSTAT(pathcomp
, &G
.statbuf
) || !S_ISDIR(G
.statbuf
.st_mode
))
1596 { /* path does not exist */
1597 if (!G
.create_dirs
/* || iswild(pathcomp) */
1600 return 2; /* treat as stored file */
1602 /* create directory (could add loop here to scan pathcomp
1603 * and create more than one level, but really necessary?) */
1604 if (MKDIR(pathcomp
, 0777) == -1) {
1605 Info(slide
, 1, ((char *)slide
,
1606 LoadFarString(CantCreateExtractDir
), pathcomp
));
1607 G
.os2
.rootlen
= 0; /* path didn't exist, tried to create, */
1608 return 3; /* failed: file exists, or need 2+ levels */
1612 if ((G
.os2
.rootpath
= (char *)malloc(G
.os2
.rootlen
+xtra
)) == (char *)NULL
) {
1616 strcpy(G
.os2
.rootpath
, pathcomp
);
1617 if (xtra
== 3) /* had just "x:", make "x:." */
1618 G
.os2
.rootpath
[G
.os2
.rootlen
++] = '.';
1619 G
.os2
.rootpath
[G
.os2
.rootlen
++] = '/';
1620 G
.os2
.rootpath
[G
.os2
.rootlen
] = '\0';
1621 Trace((stderr
, "rootpath now = [%s]\n", G
.os2
.rootpath
));
1625 #endif /* !SFX || SFX_EXDIR */
1627 /*---------------------------------------------------------------------------
1628 END: free rootpath, immediately prior to program exit.
1629 ---------------------------------------------------------------------------*/
1631 if (FUNCTION
== END
) {
1632 Trace((stderr
, "freeing rootpath\n"));
1633 if (G
.os2
.rootlen
> 0) {
1634 free(G
.os2
.rootpath
);
1640 return 99; /* should never reach */
1642 } /* end function checkdir() */
1648 /***********************/
1649 /* Function isfloppy() */ /* more precisely, is it removable? */
1650 /***********************/
1652 static int isfloppy(nDrive
)
1653 int nDrive
; /* 1 == A:, 2 == B:, etc. */
1655 uch ParmList
[1] = {0};
1656 uch DataArea
[1] = {0};
1668 Name
[0] = (char) (nDrive
+ 'A' - 1);
1672 rc
= DosOpen(Name
, &handle
, &action
, 0L, FILE_NORMAL
, FILE_OPEN
,
1673 OPEN_FLAGS_DASD
| OPEN_FLAGS_FAIL_ON_ERROR
|
1674 OPEN_ACCESS_READONLY
| OPEN_SHARE_DENYNONE
, 0L);
1676 if (rc
== ERROR_NOT_READY
) /* must be removable */
1678 else if (rc
) { /* other error: do default a/b heuristic instead */
1679 Trace((stderr
, "error in DosOpen(DASD): guessing...\n", rc
));
1680 return (nDrive
== 1 || nDrive
== 2)? TRUE
: FALSE
;
1683 rc
= DosDevIOCtl(DataArea
, sizeof(DataArea
), ParmList
, sizeof(ParmList
),
1684 DSK_BLOCKREMOVABLE
, IOCTL_DISK
, handle
);
1687 if (rc
) { /* again, just check for a/b */
1688 Trace((stderr
, "error in DosDevIOCtl category IOCTL_DISK, function "
1689 "DSK_BLOCKREMOVABLE\n (rc = 0x%04x): guessing...\n", rc
));
1690 return (nDrive
== 1 || nDrive
== 2)? TRUE
: FALSE
;
1692 return DataArea
[0] ? FALSE
: TRUE
;
1694 } /* end function isfloppy() */
1700 static int IsFileNameValid(const char *name
)
1709 switch( DosOpen((PSZ
) name
, &hf
, &uAction
, 0, 0, FILE_OPEN
,
1710 OPEN_ACCESS_READONLY
| OPEN_SHARE_DENYNONE
, 0) )
1712 case ERROR_INVALID_NAME
:
1713 case ERROR_FILENAME_EXCED_RANGE
:
1726 /**********************/
1727 /* Function map2fat() */
1728 /**********************/
1730 static void map2fat(pathcomp
, pEndFAT
)
1731 char *pathcomp
, **pEndFAT
;
1733 char *ppc
= pathcomp
; /* variable pointer to pathcomp */
1734 char *pEnd
= *pEndFAT
; /* variable pointer to buildpathFAT */
1735 char *pBegin
= *pEndFAT
; /* constant pointer to start of this comp. */
1736 char *last_dot
= (char *)NULL
; /* last dot not converted to underscore */
1737 int dotname
= FALSE
; /* flag: path component begins with dot */
1738 /* ("." and ".." don't count) */
1739 register unsigned workch
; /* hold the character being tested */
1742 /* Only need check those characters which are legal in HPFS but not
1743 * in FAT: to get here, must already have passed through mapname.
1744 * (GRR: oops, small bug--if char was quoted, no longer have any
1745 * knowledge of that.) Also must truncate path component to ensure
1748 while ((workch
= (uch
)*ppc
++) != 0) {
1750 case '[': /* add '"' '+' ',' '=' ?? */
1752 *pEnd
++ = '_'; /* convert brackets to underscores */
1756 if (pEnd
== *pEndFAT
) { /* nothing appended yet... */
1757 if (*ppc
== '\0') /* don't bother appending a */
1758 break; /* "./" component to the path */
1759 else if (*ppc
== '.' && ppc
[1] == '\0') { /* "../" */
1760 *pEnd
++ = '.'; /* add first dot, unchanged... */
1761 ++ppc
; /* skip second dot, since it will */
1762 } else { /* be "added" at end of if-block */
1763 *pEnd
++ = '_'; /* FAT doesn't allow null filename */
1764 dotname
= TRUE
; /* bodies, so map .exrc -> _.exrc */
1765 } /* (extra '_' now, "dot" below) */
1766 } else if (dotname
) { /* found a second dot, but still */
1767 dotname
= FALSE
; /* have extra leading underscore: */
1768 *pEnd
= '\0'; /* remove it by shifting chars */
1769 pEnd
= *pEndFAT
+ 1; /* left one space (e.g., .p1.p2: */
1770 while (pEnd
[1]) { /* __p1 -> _p1_p2 -> _p1.p2 when */
1771 *pEnd
= pEnd
[1]; /* finished) [opt.: since first */
1772 ++pEnd
; /* two chars are same, can start */
1773 } /* shifting at second position] */
1775 last_dot
= pEnd
; /* point at last dot so far... */
1776 *pEnd
++ = '_'; /* convert dot to underscore for now */
1780 *pEnd
++ = (char)workch
;
1783 } /* end while loop */
1785 *pEnd
= '\0'; /* terminate buildpathFAT */
1787 /* NOTE: keep in mind that pEnd points to the end of the path
1788 * component, and *pEndFAT still points to the *beginning* of it...
1789 * Also note that the algorithm does not try to get too fancy:
1790 * if there are no dots already, the name either gets truncated
1791 * at 8 characters or the last underscore is converted to a dot
1792 * (only if more characters are saved that way). In no case is
1793 * a dot inserted between existing characters.
1795 if (last_dot
== (char *)NULL
) { /* no dots: check for underscores... */
1796 char *plu
= strrchr(pBegin
, '_'); /* pointer to last underscore */
1798 if (plu
== (char *)NULL
) { /* no dots, no underscores: truncate at 8 */
1799 *pEndFAT
+= 8; /* chars (could insert '.' and keep 11...) */
1800 if (*pEndFAT
> pEnd
)
1801 *pEndFAT
= pEnd
; /* oops...didn't have 8 chars to truncate */
1804 } else if (MIN(plu
- pBegin
, 8) + MIN(pEnd
- plu
- 1, 3) > 8) {
1805 last_dot
= plu
; /* be lazy: drop through to next if-block */
1806 } else if ((pEnd
- *pEndFAT
) > 8) {
1807 *pEndFAT
+= 8; /* more fits into just basename than if */
1808 **pEndFAT
= '\0'; /* convert last underscore to dot */
1810 *pEndFAT
= pEnd
; /* whole thing fits into 8 chars or less */
1813 if (last_dot
!= (char *)NULL
) { /* one dot (or two, in the case of */
1814 *last_dot
= '.'; /* "..") is OK: put it back in */
1816 if ((last_dot
- pBegin
) > 8) {
1821 q
= last_dot
= pBegin
+ 8;
1822 for (i
= 0; (i
< 4) && *p
; ++i
) /* too many chars in basename: */
1823 *q
++ = *p
++; /* shift ".ext" left and */
1824 *q
= '\0'; /* truncate/terminate it */
1826 } else if ((pEnd
- last_dot
) > 4) { /* too many chars in extension */
1827 *pEndFAT
= last_dot
+ 4;
1830 *pEndFAT
= pEnd
; /* filename is fine; point at terminating zero */
1832 if ((last_dot
- pBegin
) > 0 && last_dot
[-1] == ' ')
1833 last_dot
[-1] = '_'; /* NO blank in front of '.'! */
1835 } /* end function map2fat() */
1841 static int SetLongNameEA(char *name
, char *longname
)
1846 eaop
.fpFEAList
= (PFEALIST
) &fealst
;
1847 eaop
.fpGEAList
= NULL
;
1850 strcpy((char *) fealst
.szName
, ".LONGNAME");
1851 strcpy((char *) fealst
.szValue
, longname
);
1853 fealst
.cbList
= sizeof(fealst
) - CCHMAXPATH
+ strlen((char *) fealst
.szValue
);
1854 fealst
.cbName
= (BYTE
) strlen((char *) fealst
.szName
);
1855 fealst
.cbValue
= sizeof(USHORT
) * 2 + strlen((char *) fealst
.szValue
);
1861 fealst
.eaType
= 0xFFFD;
1862 fealst
.eaSize
= strlen((char *) fealst
.szValue
);
1864 return DosSetPathInfo(name
, FIL_QUERYEASIZE
,
1865 (PBYTE
) &eaop
, sizeof(eaop
), 0);
1872 /****************************/
1873 /* Function close_outfile() */
1874 /****************************/
1876 /* GRR: need to return error level!! */
1878 void close_outfile(__G
) /* only for extracted files, not directories */
1883 /* set extra fields, both stored-in-zipfile and .LONGNAME flavors */
1884 if (G
.extra_field
) { /* zipfile extra field may have extended attribs */
1885 int err
= EvalExtraFields(__G__ G
.filename
, G
.extra_field
,
1886 G
.lrec
.extra_field_length
);
1888 if (err
== IZ_EF_TRUNC
) {
1890 Info(slide
, 1, ((char *)slide
, "%-22s ", G
.filename
));
1891 Info(slide
, 1, ((char *)slide
, LoadFarString(TruncEAs
),
1892 makeword(G
.extra_field
+2)-10, uO
.qflag
? "\n" : ""));
1896 if (G
.os2
.longnameEA
) {
1900 SetLongNameEA(G
.filename
, G
.os2
.lastpathcomp
);
1901 Trace((stderr
, "close_outfile: SetLongNameEA() returns %d\n", e
));
1902 free(G
.os2
.lastpathcomp
);
1905 /* set date/time and permissions */
1906 SetPathAttrTimes(__G__ G
.pInfo
->file_attr
, 0);
1908 } /* end function close_outfile() */
1914 /******************************/
1915 /* Function check_for_newer() */
1916 /******************************/
1918 int check_for_newer(__G__ filename
) /* return 1 if existing file newer or equal; */
1920 char *filename
; /* 0 if older; -1 if doesn't exist yet */
1922 ulg existing
, archive
;
1923 #ifdef USE_EF_UT_TIME
1927 if ((existing
= (ulg
)GetFileTime(filename
)) == (ulg
)-1)
1928 return DOES_NOT_EXIST
;
1930 #ifdef USE_EF_UT_TIME
1931 if (G
.extra_field
&&
1935 (ef_scan_for_izux(G
.extra_field
, G
.lrec
.extra_field_length
, 0,
1936 G
.lrec
.last_mod_dos_datetime
, &z_utime
, NULL
)
1939 TTrace((stderr
, "check_for_newer: using Unix extra field mtime\n"));
1940 archive
= Utime2DosDateTime(z_utime
.mtime
);
1942 archive
= G
.lrec
.last_mod_dos_datetime
;
1944 #else /* !USE_EF_UT_TIME */
1945 archive
= G
.lrec
.last_mod_dos_datetime
;
1946 #endif /* ?USE_EF_UT_TIME */
1948 return (existing
>= archive
);
1949 } /* end function check_for_newer() */
1957 /*************************/
1958 /* Function dateformat() */
1959 /*************************/
1963 /*-----------------------------------------------------------------------------
1964 For those operating systems which support it, this function returns a value
1965 which tells how national convention says that numeric dates are displayed.
1966 Return values are DF_YMD, DF_DMY and DF_MDY.
1967 -----------------------------------------------------------------------------*/
1969 switch (GetCountryInfo()) {
1977 return DF_MDY
; /* default if error */
1979 } /* end function dateformat() */
1985 /************************/
1986 /* Function version() */
1987 /************************/
1993 #if defined(__IBMC__) || defined(__WATCOMC__) || defined(_MSC_VER)
1997 len
= sprintf((char *)slide
, LoadFarString(CompiledWith
),
1999 #if defined(__GNUC__)
2000 # ifdef __EMX__ /* __EMX__ is defined as "1" only (sigh) */
2001 "emx+gcc ", __VERSION__
,
2003 "gcc/2 ", __VERSION__
,
2005 #elif defined(__IBMC__)
2007 # if (__IBMC__ < 200)
2008 (sprintf(buf
, "C Set/2 %d.%02d", __IBMC__
/100,__IBMC__%100
), buf
),
2009 # elif (__IBMC__ < 300)
2010 (sprintf(buf
, "C Set++ %d.%02d", __IBMC__
/100,__IBMC__%100
), buf
),
2012 (sprintf(buf
, "Visual Age C++ %d.%02d", __IBMC__
/100,__IBMC__%100
), buf
),
2014 #elif defined(__WATCOMC__)
2015 "Watcom C", (sprintf(buf
, " (__WATCOMC__ = %d)", __WATCOMC__
), buf
),
2016 #elif defined(__TURBOC__)
2017 # ifdef __BORLANDC__
2019 # if (__BORLANDC__ < 0x0460)
2021 # elif (__BORLANDC__ == 0x0460)
2022 " 1.5", /* from Kai Uwe: three less than DOS */
2024 " 2.0", /* (__BORLANDC__ == 0x0500)? */
2027 "Turbo C", /* these are probably irrelevant */
2028 # if (__TURBOC__ >= 661)
2030 # elif (__TURBOC__ == 661)
2032 # elif (__TURBOC__ == 397)
2041 (sprintf(buf
, "%d.%02d", _MSC_VER
/100, _MSC_VER%100
), buf
),
2046 "unknown compiler", "",
2047 #endif /* ?compilers */
2051 /* GRR: does IBM C/2 identify itself as IBM rather than Microsoft? */
2052 #if (defined(MSC) || (defined(__WATCOMC__) && !defined(__386__)))
2053 # if defined(M_I86HM) || defined(__HUGE__)
2055 # elif defined(M_I86LM) || defined(__LARGE__)
2057 # elif defined(M_I86MM) || defined(__MEDIUM__)
2058 " (16-bit, medium)",
2059 # elif defined(M_I86CM) || defined(__COMPACT__)
2060 " (16-bit, compact)",
2061 # elif defined(M_I86SM) || defined(__SMALL__)
2063 # elif defined(M_I86TM) || defined(__TINY__)
2069 " 2.x/3.x (32-bit)",
2079 (*G
.message
)((zvoid
*)&G
, slide
, (ulg
)len
, 0);
2080 /* MSC can't handle huge macro expansions */
2082 /* temporary debugging code for Borland compilers only */
2083 /* __TCPLUSPLUS__, __BCPLUSPLUS__ not defined for v1.5 */
2084 #if (defined(__TURBOC__) && defined(DEBUG))
2085 Info(slide
, 0, ((char *)slide
, "\t(__TURBOC__ = 0x%04x = %d)\n", __TURBOC__
,
2088 Info(slide
, 0, ((char *)slide
, "\t(__BORLANDC__ = 0x%04x)\n",__BORLANDC__
));
2090 Info(slide
, 0, ((char *)slide
, "\tdebug(__BORLANDC__ not defined)\n"));
2092 #endif /* __TURBOC__ && DEBUG */
2094 } /* end function version() */
2100 /* This table can be static because it is pseudo-constant */
2101 static unsigned char cUpperCase
[256], cLowerCase
[256];
2102 static BOOL bInitialized
=FALSE
;
2104 /* Initialize the tables of upper- and lowercase characters, including
2105 handling of country-dependent characters. */
2107 static void InitNLS(void)
2112 if (bInitialized
== FALSE
) {
2113 bInitialized
= TRUE
;
2115 for ( nCnt
= 0; nCnt
< 256; nCnt
++ )
2116 cUpperCase
[nCnt
] = cLowerCase
[nCnt
] = (unsigned char) nCnt
;
2118 cc
.country
= cc
.codepage
= 0;
2119 DosMapCase(sizeof(cUpperCase
), &cc
, (PCHAR
) cUpperCase
);
2121 for ( nCnt
= 0; nCnt
< 256; nCnt
++ ) {
2122 nU
= cUpperCase
[nCnt
];
2123 if (nU
!= nCnt
&& cLowerCase
[nU
] == (unsigned char) nU
)
2124 cLowerCase
[nU
] = (unsigned char) nCnt
;
2127 for ( nCnt
= 'A'; nCnt
<= 'Z'; nCnt
++ )
2128 cLowerCase
[nCnt
] = (unsigned char) (nCnt
- 'A' + 'a');
2133 int IsUpperNLS(int nChr
)
2135 return (cUpperCase
[nChr
] == (unsigned char) nChr
);
2139 int ToLowerNLS(int nChr
)
2141 return cLowerCase
[nChr
];
2145 char *StringLower(char *szArg
)
2147 unsigned char *szPtr
;
2149 for ( szPtr
= (unsigned char *) szArg
; *szPtr
; szPtr
++ )
2150 *szPtr
= cLowerCase
[*szPtr
];
2155 #if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
2156 void DebugMalloc(void)
2158 _dump_allocated(0); /* print out debug malloc memory statistics */
2163 #if defined(REENTRANT) && defined(USETHREADID)
2164 ulg
GetThreadId(void)
2166 PTIB pptib
; /* Address of a pointer to the
2167 Thread Information Block */
2168 PPIB pppib
; /* Address of a pointer to the
2169 Process Information Block */
2171 DosGetInfoBlocks(&pptib
, &pppib
);
2172 return pptib
->tib_ptib2
->tib2_ultid
;
2174 #endif /* defined(REENTRANT) && defined(USETHREADID) */
2177 void os2GlobalsCtor(__GPRO
)
2179 G
.os2
.nLastDrive
= (USHORT
)(-1);
2180 G
.os2
.firstcall
= TRUE
;
2183 G
.os2
.rexx_mes
= "0";