1 /*
2 Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
3
4 See the accompanying file LICENSE, version 2007-Mar-04 or later
5 (the contents of which are also included in unzip.h) for terms of use.
6 If, for some reason, all these files are missing, the Info-ZIP license
7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /*---------------------------------------------------------------------------
10
11 win32.c
12
13 32-bit Windows-specific (NT/9x) routines for use with Info-ZIP's UnZip 5.3
14 and later.
15
16 Contains: GetLoadPath()
17 Opendir()
18 Readdir()
19 Closedir()
20 SetSD() set security descriptor on file
21 FindSDExtraField() extract SD e.f. block from extra field
22 IsWinNT() indicate type of WIN32 platform
23 test_NTSD() test integrity of NT security data
24 utime2NtfsFileTime()
25 utime2VFatFileTime()
26 FStampIsLocTime()
27 NtfsFileTime2utime()
28 VFatFileTime2utime()
29 getNTfiletime()
30 SetFileSize()
31 close_outfile()
32 defer_dir_attribs()
33 set_direc_attribs()
34 stamp_file()
35 isfloppy()
36 NTQueryVolInfo()
37 IsVolumeOldFAT()
38 do_wild()
39 mapattr()
40 mapname()
41 maskDOSdevice()
42 map2fat()
43 checkdir()
44 dateformat()
45 dateseparator()
46 version()
47 screensize()
48 zstat_win32()
49 conv_to_rule()
50 GetPlatformLocalTimezone()
51 getch_win32()
52
53 ---------------------------------------------------------------------------*/
54
55
56 #define UNZIP_INTERNAL
57 #include "../unzip.h"
58 #include <windows.h> /* must be AFTER unzip.h to avoid struct G problems */
59 #ifdef __RSXNT__
60 # include "../win32/rsxntwin.h"
61 #endif
62 #include "../win32/nt.h"
63
64 #ifndef FUNZIP /* most of this file is not used with fUnZip */
65
66 /* some non-MS runtime headers (e.g. lcc) may miss this definition */
67 #ifndef FILE_WRITE_ATTRIBUTES
68 # define FILE_WRITE_ATTRIBUTES 0x0100
69 #endif
70
71 #if (defined(__EMX__) || defined(__CYGWIN__))
72 # define MKDIR(path,mode) mkdir(path,mode)
73 #else
74 # define MKDIR(path,mode) mkdir(path)
75 #endif
76
77 #ifdef HAVE_WORKING_DIRENT_H
78 # undef HAVE_WORKING_DIRENT_H
79 #endif
80 /* The emxrtl dirent support of (__GO32__ || __EMX__) converts to lowercase! */
81 #if defined(__CYGWIN__)
82 # define HAVE_WORKING_DIRENT_H
83 #endif
84
85 #ifndef SFX
86 # ifdef HAVE_WORKING_DIRENT_H
87 # include <dirent.h> /* use readdir() */
88 # define zdirent dirent
89 # define zDIR DIR
90 # define Opendir opendir
91 # define Readdir readdir
92 # define Closedir closedir
93 # else /* !HAVE_WORKING_DIRENT_H */
94 typedef struct zdirent {
95 char reserved [21];
96 char ff_attrib;
97 short ff_ftime;
98 short ff_fdate;
99 long size;
100 char d_name[MAX_PATH];
101 int d_first;
102 HANDLE d_hFindFile;
103 } zDIR;
104
105 static zDIR *Opendir (const char *n);
106 static struct zdirent *Readdir (zDIR *d);
107 static void Closedir (zDIR *d);
108 # endif /* ?HAVE_WORKING_DIRENT_H */
109 #endif /* !SFX */
110
111 #ifdef SET_DIR_ATTRIB
112 typedef struct NTdirattr { /* struct for holding unix style directory */
113 struct NTdirattr *next; /* info until can be sorted and set at end */
114 char *fn; /* filename of directory */
115 FILETIME Modft; /* File time type defined in NT, `last modified' time */
116 FILETIME Accft; /* NT file time type, `last access' time */
117 FILETIME Creft; /* NT file time type, `file creation' time */
118 int gotTime;
119 unsigned perms; /* same as min_info.file_attr */
120 #ifdef NTSD_EAS
121 unsigned SDlen; /* length of SD data in buf */
122 #endif
123 char buf[1]; /* buffer stub for directory SD and name */
124 } NTdirattr;
125 #define NtAtt(d) ((NTdirattr *)d) /* typecast shortcut */
126 #endif /* SET_DIR_ATTRIB */
127
128
129 /* Function prototypes */
130 #ifdef NTSD_EAS
131 static int SetSD(__GPRO__ char *path, unsigned fperms,
132 uch *eb_ptr, unsigned eb_len);
133 static int FindSDExtraField(__GPRO__
134 uch *ef_ptr, unsigned ef_len,
135 uch **p_ebSD_ptr, unsigned *p_ebSD_len);
136 #endif
137
138 #ifndef NO_W32TIMES_IZFIX
139 static void utime2NtfsFileTime(time_t ut, FILETIME *pft);
140 #endif
141 static void utime2VFatFileTime(time_t ut, FILETIME *pft, int clipDosMin);
142 #if (defined(W32_STAT_BANDAID) && !defined(NO_W32TIMES_IZFIX))
143 static int NtfsFileTime2utime(const FILETIME *pft, time_t *ut);
144 #endif
145 #ifdef W32_STAT_BANDAID
146 static int VFatFileTime2utime(const FILETIME *pft, time_t *ut);
147 #endif
148 static int FStampIsLocTime(__GPRO__ const char *path);
149
150
151 static int getNTfiletime (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT,
152 FILETIME *pCreFT);
153 static int isfloppy (int nDrive);
154 static int NTQueryVolInfo (__GPRO__ const char *name);
155 static int IsVolumeOldFAT (__GPRO__ const char *name);
156 static void maskDOSdevice (__GPRO__ char *pathcomp);
157 static void map2fat (char *pathcomp, char **pEndFAT);
158
159
160 #if (defined(__MINGW32__) && !defined(USE_MINGW_GLOBBING))
161 int _CRT_glob = 0; /* suppress command line globbing by C RTL */
162 #endif
163
164 #ifdef ACORN_FTYPE_NFS
165 /* Acorn bits for NFS filetyping */
166 typedef struct {
167 uch ID[2];
168 uch size[2];
169 uch ID_2[4];
170 uch loadaddr[4];
171 uch execaddr[4];
172 uch attr[4];
173 } RO_extra_block;
174
175 #endif /* ACORN_FTYPE_NFS */
176
177 /* static int created_dir; */ /* used by mapname(), checkdir() */
178 /* static int renamed_fullpath; */ /* ditto */
179 /* static int fnlen; */ /* ditto */
180 /* static unsigned nLabelDrive; */ /* ditto */
181
182 extern char Far TruncNTSD[]; /* in extract.c */
183
184
185
186 #ifdef SFX
187
188 /**************************/
189 /* Function GetLoadPath() */
190 /**************************/
191
GetLoadPath(__GPRO)192 char *GetLoadPath(__GPRO)
193 {
194 #ifdef MSC
195 extern char *_pgmptr;
196 return _pgmptr;
197
198 #else /* use generic API call */
199
200 GetModuleFileName(NULL, G.filename, FILNAMSIZ);
201 _ISO_INTERN(G.filename); /* translate to codepage of C rtl's stdio */
202 return G.filename;
203 #endif
204
205 } /* end function GetLoadPath() */
206
207
208
209
210
211 #else /* !SFX */
212
213 #ifndef HAVE_WORKING_DIRENT_H
214
215 /**********************/ /* Borrowed from ZIP 2.0 sources */
216 /* Function Opendir() */ /* Difference: no special handling for */
217 /**********************/ /* hidden or system files. */
218
Opendir(n)219 static zDIR *Opendir(n)
220 const char *n; /* directory to open */
221 {
222 zDIR *d; /* malloc'd return value */
223 char *p; /* malloc'd temporary string */
224 WIN32_FIND_DATAA fd;
225 extent len = strlen(n);
226
227 /* Start searching for files in directory n */
228
229 if ((d = (zDIR *)malloc(sizeof(zDIR))) == NULL ||
230 (p = malloc(strlen(n) + 5)) == NULL)
231 {
232 if (d != (zDIR *)NULL)
233 free((void *)d);
234 return (zDIR *)NULL;
235 }
236 INTERN_TO_ISO(n, p);
237 if (len > 0) {
238 if (p[len-1] == ':')
239 p[len++] = '.'; /* x: => x:. */
240 else if (p[len-1] == '/' || p[len-1] == '\\')
241 --len; /* foo/ => foo */
242 }
243 strcpy(p+len, "/*");
244
245 if (INVALID_HANDLE_VALUE == (d->d_hFindFile = FindFirstFileA(p, &fd))) {
246 free((zvoid *)d);
247 free((zvoid *)p);
248 return NULL;
249 }
250 strcpy(d->d_name, fd.cFileName);
251
252 free((zvoid *)p);
253 d->d_first = 1;
254 return d;
255
256 } /* end of function Opendir() */
257
258
259
260
261 /**********************/ /* Borrowed from ZIP 2.0 sources */
262 /* Function Readdir() */ /* Difference: no special handling for */
263 /**********************/ /* hidden or system files. */
264
Readdir(d)265 static struct zdirent *Readdir(d)
266 zDIR *d; /* directory stream from which to read */
267 {
268 /* Return pointer to first or next directory entry, or NULL if end. */
269
270 if ( d->d_first )
271 d->d_first = 0;
272 else
273 {
274 WIN32_FIND_DATAA fd;
275
276 if ( !FindNextFileA(d->d_hFindFile, &fd) )
277 return NULL;
278
279 ISO_TO_INTERN(fd.cFileName, d->d_name);
280 }
281 return (struct zdirent *)d;
282
283 } /* end of function Readdir() */
284
285
286
287
288 /***********************/
289 /* Function Closedir() */ /* Borrowed from ZIP 2.0 sources */
290 /***********************/
291
Closedir(d)292 static void Closedir(d)
293 zDIR *d; /* directory stream to close */
294 {
295 FindClose(d->d_hFindFile);
296 free(d);
297 }
298
299 #endif /* !HAVE_WORKING_DIRENT_H */
300 #endif /* ?SFX */
301
302
303
304
305 #ifdef NTSD_EAS
306
307 /**********************/
308 /* Function SetSD() */ /* return almost-PK errors */
309 /**********************/
310
311 static int SetSD(__G__ path, fperms, eb_ptr, eb_len)
312 __GDEF
313 char *path;
314 unsigned fperms;
315 uch *eb_ptr;
316 unsigned eb_len;
317 {
318 ulg ntsd_ucSize;
319 VOLUMECAPS VolumeCaps;
320 uch *security_data;
321 int error;
322
323 ntsd_ucSize = makelong(eb_ptr + (EB_HEADSIZE+EB_UCSIZE_P));
324 if (ntsd_ucSize > 0L && eb_len <= (EB_NTSD_L_LEN + EB_CMPRHEADLEN))
325 return IZ_EF_TRUNC; /* no compressed data! */
326
327 /* provide useful input */
328 VolumeCaps.dwFileAttributes = fperms;
329 VolumeCaps.bUsePrivileges = (uO.X_flag > 1);
330
331 /* check target volume capabilities - just fall through
332 * and try if fail */
333 if (GetVolumeCaps(G.rootpath, path, &VolumeCaps) &&
334 !(VolumeCaps.dwFileSystemFlags & FS_PERSISTENT_ACLS))
335 return PK_OK;
336
337 /* allocate storage for uncompressed data */
338 security_data = (uch *)malloc((extent)ntsd_ucSize);
339 if (security_data == (uch *)NULL)
340 return PK_MEM4;
341
342 error = memextract(__G__ security_data, ntsd_ucSize,
343 (eb_ptr + (EB_HEADSIZE+EB_NTSD_L_LEN)), (ulg)(eb_len - EB_NTSD_L_LEN));
344
345 if (error == PK_OK) {
346 if (SecuritySet(path, &VolumeCaps, security_data)) {
347 error = PK_COOL;
348 if (!uO.tflag && QCOND2)
349 Info(slide, 0, ((char *)slide, " (%ld bytes security)",
350 ntsd_ucSize));
351 }
352 }
353
354 free(security_data);
355 return error;
356 }
357
358
359
360
361 /********************************/ /* scan extra fields for something */
362 /* Function FindSDExtraField() */ /* we happen to know */
363 /********************************/
364 /* Returns TRUE when a valid NTFS SD block is found.
365 * Address and size of the NTSD e.f. block are passed up to the caller.
366 * In case of more than one valid NTSD block in the e.f., the last block
367 * found is passed up.
368 * Returns FALSE and leaves the content of the ebSD_ptr and ebSD_len
369 * parameters untouched when no valid NTFS SD block is found. */
FindSDExtraField(__GPRO__ uch * ef_ptr,unsigned ef_len,uch ** p_ebSD_ptr,unsigned * p_ebSD_len)370 static int FindSDExtraField(__GPRO__
371 uch *ef_ptr, unsigned ef_len,
372 uch **p_ebSD_ptr, unsigned *p_ebSD_len)
373 {
374 int rc = FALSE;
375
376 if (!uO.X_flag)
377 return FALSE; /* user said don't process ACLs; for now, no other
378 extra block types are handled here */
379
380 while (ef_len >= EB_HEADSIZE)
381 {
382 unsigned eb_id = makeword(EB_ID + ef_ptr);
383 unsigned eb_len = makeword(EB_LEN + ef_ptr);
384
385 if (eb_len > (ef_len - EB_HEADSIZE)) {
386 /* discovered some extra field inconsistency! */
387 Trace((stderr,
388 "FindSDExtraField: block length %u > rest ef_size %u\n", eb_len,
389 ef_len - EB_HEADSIZE));
390 break;
391 }
392
393 switch (eb_id)
394 {
395 /* process security descriptor extra data if:
396 Caller is WinNT AND
397 Target local/remote drive supports acls AND
398 Target file is not a directory (else we defer processing
399 until later)
400 */
401 case EF_NTSD:
402 if (!IsWinNT())
403 break; /* OS not capable of handling NTFS attributes */
404
405 if (eb_len < EB_NTSD_L_LEN)
406 break; /* not a valid NTSD extra field */
407
408 /* check if we know how to handle this version */
409 if (*(ef_ptr + (EB_HEADSIZE+EB_NTSD_VERSION))
410 > (uch)EB_NTSD_MAX_VER)
411 break;
412
413 *p_ebSD_ptr = ef_ptr;
414 *p_ebSD_len = eb_len;
415 rc = TRUE;
416 break;
417
418 #ifdef DEBUG
419 case EF_OS2:
420 case EF_AV:
421 case EF_PKVMS:
422 case EF_PKW32:
423 case EF_PKUNIX:
424 case EF_IZVMS:
425 case EF_IZUNIX:
426 case EF_IZUNIX2:
427 case EF_TIME:
428 case EF_MAC3:
429 case EF_JLMAC:
430 case EF_ZIPIT:
431 case EF_VMCMS:
432 case EF_MVS:
433 case EF_ACL:
434 case EF_ATHEOS:
435 case EF_BEOS:
436 case EF_QDOS:
437 case EF_AOSVS:
438 case EF_SPARK:
439 case EF_MD5:
440 case EF_ASIUNIX:
441 break; /* shut up for other known e.f. blocks */
442 #endif /* DEBUG */
443
444 default:
445 Trace((stderr,
446 "FindSDExtraField: unknown extra field block, ID=%u\n",
447 eb_id));
448 break;
449 }
450
451 ef_ptr += (eb_len + EB_HEADSIZE);
452 ef_len -= (eb_len + EB_HEADSIZE);
453 }
454
455 return rc;
456 }
457
458
459
460
461 #ifndef SFX
462
463 /**************************/
464 /* Function test_NTSD() */ /* returns PK_WARN when NTSD data is invalid */
465 /**************************/
466
467 #ifdef __BORLANDC__
468 /* Turn off warning about not using all parameters for this function only */
469 #pragma argsused
470 #endif
471 int test_NTSD(__G__ eb, eb_size, eb_ucptr, eb_ucsize)
472 __GDEF
473 uch *eb;
474 unsigned eb_size;
475 uch *eb_ucptr;
476 ulg eb_ucsize;
477 {
478 return (ValidateSecurity(eb_ucptr) ? PK_OK : PK_WARN);
479 } /* end function test_NTSD() */
480
481 #endif /* !SFX */
482 #endif /* NTSD_EAS */
483
484
485
486
487 /**********************/
488 /* Function IsWinNT() */
489 /**********************/
490
IsWinNT(void)491 int IsWinNT(void) /* returns TRUE if real NT, FALSE if Win9x or Win32s */
492 {
493 static DWORD g_PlatformId = 0xFFFFFFFF; /* saved platform indicator */
494
495 if (g_PlatformId == 0xFFFFFFFF) {
496 /* note: GetVersionEx() doesn't exist on WinNT 3.1 */
497 if (GetVersion() < 0x80000000)
498 g_PlatformId = TRUE;
499 else
500 g_PlatformId = FALSE;
501 }
502 return (int)g_PlatformId;
503 }
504
505
506 /* DEBUG_TIME insertion: */
507 #ifdef DEBUG_TIME
508 static int show_NTFileTime(FILE *hdo, char *TTmsg, int isloc, FILETIME *pft);
509
show_NTFileTime(FILE * hdo,char * TTmsg,int isloc,FILETIME * pft)510 static int show_NTFileTime(FILE *hdo, char *TTmsg, int isloc, FILETIME *pft)
511 {
512 SYSTEMTIME w32tm;
513 int rval;
514
515 rval = FileTimeToSystemTime(pft, &w32tm);
516 if (!rval) {
517 fprintf(hdo, "%s\n %08lX,%08lX (%s) -> Conversion failed !!!\n",
518 TTmsg, (ulg)(pft->dwHighDateTime), (ulg)(pft->dwLowDateTime),
519 (isloc ? "local" : "UTC"));
520 } else {
521 fprintf(hdo, "%s\n %08lx,%08lx -> %04u-%02u-%02u, %02u:%02u:%02u %s\n",
522 TTmsg, (ulg)(pft->dwHighDateTime), (ulg)(pft->dwLowDateTime),
523 w32tm.wYear, w32tm.wMonth, w32tm.wDay, w32tm.wHour,
524 w32tm.wMinute, w32tm.wSecond, (isloc ? "local" : "UTC"));
525 }
526 return rval;
527 }
528 #define FTTrace(x) show_NTFileTime x
529 #else
530 #define FTTrace(x)
531 #endif /* DEBUG_TIME */
532 /* end of DEBUG_TIME insertion */
533
534 #ifndef IZ_USE_INT64
535 # if (defined(__GNUC__) || defined(ULONG_LONG_MAX))
536 typedef long long LLONG64;
537 typedef unsigned long long ULLNG64;
538 # define IZ_USE_INT64
539 # elif (defined(__WATCOMC__) && (__WATCOMC__ >= 1100))
540 typedef __int64 LLONG64;
541 typedef unsigned __int64 ULLNG64;
542 # define IZ_USE_INT64
543 # elif (defined(_MSC_VER) && (_MSC_VER >= 1100))
544 typedef __int64 LLONG64;
545 typedef unsigned __int64 ULLNG64;
546 # define IZ_USE_INT64
547 # elif (defined(__IBMC__) && (__IBMC__ >= 350))
548 typedef __int64 LLONG64;
549 typedef unsigned __int64 ULLNG64;
550 # define IZ_USE_INT64
551 # elif defined(HAVE_INT64)
552 typedef __int64 LLONG64;
553 typedef unsigned __int64 ULLNG64;
554 # define IZ_USE_INT64
555 # endif
556 #endif
557
558 /* scale factor and offset for conversion time_t -> FILETIME */
559 #define NT_QUANTA_PER_UNIX 10000000L
560 #define UNIX_TIME_ZERO_HI 0x019DB1DEUL
561 #define UNIX_TIME_ZERO_LO 0xD53E8000UL
562 /* special FILETIME values for bound-checks */
563 #define UNIX_TIME_UMAX_HI 0x0236485EUL
564 #define UNIX_TIME_UMAX_LO 0xD4A5E980UL
565 #define UNIX_TIME_SMIN_HI 0x0151669EUL
566 #define UNIX_TIME_SMIN_LO 0xD53E8000UL
567 #define UNIX_TIME_SMAX_HI 0x01E9FD1EUL
568 #define UNIX_TIME_SMAX_LO 0xD4A5E980UL
569 #define DOSTIME_MIN_FT_HI 0x01A8E79FUL
570 #define DOSTIME_MIN_FT_LO 0xE1D58000UL
571 /* time_t equivalent of DOSTIME_MINIMUM */
572 #define UTIME_1980_JAN_01_00_00 315532800L
573
574
575 #ifndef NO_W32TIMES_IZFIX
576 /*********************************/
577 /* Function utime2NtfsFileTime() */ /* convert Unix time_t format into the */
578 /*********************************/ /* form used by SetFileTime() in NT/9x */
579
utime2NtfsFileTime(time_t ut,FILETIME * pft)580 static void utime2NtfsFileTime(time_t ut, FILETIME *pft)
581 {
582 #ifdef IZ_USE_INT64
583 ULLNG64 NTtime;
584
585 /* NT_QUANTA_PER_UNIX is small enough so that "ut * NT_QUANTA_PER_UNIX"
586 * cannot overflow in 64-bit signed calculation, regardless whether "ut"
587 * is signed or unsigned. */
588 NTtime = ((LLONG64)ut * NT_QUANTA_PER_UNIX) +
589 ((ULLNG64)UNIX_TIME_ZERO_LO + ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
590 pft->dwLowDateTime = (DWORD)NTtime;
591 pft->dwHighDateTime = (DWORD)(NTtime >> 32);
592
593 #else /* !IZ_USE_INT64 (64-bit integer arithmetics may not be supported) */
594 unsigned int b1, b2, carry = 0;
595 unsigned long r0, r1, r2, r3;
596 long r4; /* signed, to catch environments with signed time_t */
597
598 b1 = ut & 0xFFFF;
599 b2 = (ut >> 16) & 0xFFFF; /* if ut is over 32 bits, too bad */
600 r1 = b1 * (NT_QUANTA_PER_UNIX & 0xFFFF);
601 r2 = b1 * (NT_QUANTA_PER_UNIX >> 16);
602 r3 = b2 * (NT_QUANTA_PER_UNIX & 0xFFFF);
603 r4 = b2 * (NT_QUANTA_PER_UNIX >> 16);
604 r0 = (r1 + (r2 << 16)) & 0xFFFFFFFFL;
605 if (r0 < r1)
606 carry++;
607 r1 = r0;
608 r0 = (r0 + (r3 << 16)) & 0xFFFFFFFFL;
609 if (r0 < r1)
610 carry++;
611 pft->dwLowDateTime = r0 + UNIX_TIME_ZERO_LO;
612 if (pft->dwLowDateTime < r0)
613 carry++;
614 pft->dwHighDateTime = r4 + (r2 >> 16) + (r3 >> 16)
615 + UNIX_TIME_ZERO_HI + carry;
616 #endif /* ?IZ_USE_INT64 */
617
618 } /* end function utime2NtfsFileTime() */
619 #endif /* !NO_W32TIMES_IZFIX */
620
621
622
623 /*********************************/
624 /* Function utime2VFatFileTime() */ /* convert Unix time_t format into the */
625 /*********************************/ /* form used by SetFileTime() in NT/9x */
626
utime2VFatFileTime(time_t ut,FILETIME * pft,int clipDosMin)627 static void utime2VFatFileTime(time_t ut, FILETIME *pft, int clipDosMin)
628 {
629 time_t utc = ut;
630 struct tm *ltm;
631 SYSTEMTIME w32tm;
632 FILETIME lft;
633
634 /* The milliseconds field gets always initialized to 0. */
635 w32tm.wMilliseconds = 0;
636
637 #ifdef __BORLANDC__ /* Borland C++ 5.x crashes when trying to reference tm */
638 if (utc < UTIME_1980_JAN_01_00_00)
639 utc = UTIME_1980_JAN_01_00_00;
640 #endif
641 ltm = localtime(&utc);
642 if (ltm == (struct tm *)NULL)
643 /* localtime() did not accept given utc time value; try to use
644 the UTC value */
645 ltm = gmtime(&utc);
646 if (ltm == (struct tm *)NULL) {
647 if (ut <= (UTIME_1980_JAN_01_00_00 + 86400)) {
648 /* use DOSTIME_MINIMUM date instead of "early" failure dates */
649 w32tm.wYear = 1980;
650 w32tm.wMonth = 1;
651 w32tm.wDay = 1;
652 w32tm.wHour = 0;
653 w32tm.wMinute = 0;
654 w32tm.wSecond = 0;
655 } else {
656 /* as a last resort, use the current system time */
657 GetLocalTime(&w32tm);
658 }
659 } else if (clipDosMin && (ltm->tm_year < 80)) {
660 w32tm.wYear = 1980;
661 w32tm.wMonth = 1;
662 w32tm.wDay = 1;
663 w32tm.wHour = 0;
664 w32tm.wMinute = 0;
665 w32tm.wSecond = 0;
666 } else {
667 w32tm.wYear = ltm->tm_year + 1900; /* year + 1900 -> year */
668 w32tm.wMonth = ltm->tm_mon + 1; /* 0..11 -> 1..12 */
669 w32tm.wDay = ltm->tm_mday; /* 1..31 */
670 w32tm.wHour = ltm->tm_hour; /* 0..23 */
671 w32tm.wMinute = ltm->tm_min; /* 0..59 */
672 w32tm.wSecond = ltm->tm_sec; /* 0..61 in ANSI C */
673 }
674
675 SystemTimeToFileTime(&w32tm, &lft);
676 LocalFileTimeToFileTime(&lft, pft);
677
678 } /* end function utime2VFatFileTime() */
679
680
681
682 /* nonzero if `y' is a leap year, else zero */
683 #define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0)
684 /* number of leap years from 1970 to `y' (not including `y' itself) */
685 #define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400)
686
687 extern ZCONST ush ydays[]; /* defined in fileio.c */
688
689 #if (defined(W32_STAT_BANDAID) && !defined(NO_W32TIMES_IZFIX))
690 /*********************************/
691 /* Function NtfsFileTime2utime() */
692 /*********************************/
693
NtfsFileTime2utime(const FILETIME * pft,time_t * ut)694 static int NtfsFileTime2utime(const FILETIME *pft, time_t *ut)
695 {
696 #ifdef IZ_USE_INT64
697 ULLNG64 NTtime;
698
699 NTtime = ((ULLNG64)pft->dwLowDateTime +
700 ((ULLNG64)pft->dwHighDateTime << 32));
701
702 #ifndef TIME_T_TYPE_DOUBLE
703 /* underflow and overflow handling */
704 #ifdef CHECK_UTIME_SIGNED_UNSIGNED
705 if ((time_t)0x80000000L < (time_t)0L)
706 {
707 if (NTtime < ((ULLNG64)UNIX_TIME_SMIN_LO +
708 ((ULLNG64)UNIX_TIME_SMIN_HI << 32))) {
709 *ut = (time_t)LONG_MIN;
710 return FALSE;
711 }
712 if (NTtime > ((ULLNG64)UNIX_TIME_SMAX_LO +
713 ((ULLNG64)UNIX_TIME_SMAX_HI << 32))) {
714 *ut = (time_t)LONG_MAX;
715 return FALSE;
716 }
717 }
718 else
719 #endif /* CHECK_UTIME_SIGNED_UNSIGNED */
720 {
721 if (NTtime < ((ULLNG64)UNIX_TIME_ZERO_LO +
722 ((ULLNG64)UNIX_TIME_ZERO_HI << 32))) {
723 *ut = (time_t)0;
724 return FALSE;
725 }
726 if (NTtime > ((ULLNG64)UNIX_TIME_UMAX_LO +
727 ((ULLNG64)UNIX_TIME_UMAX_HI << 32))) {
728 *ut = (time_t)ULONG_MAX;
729 return FALSE;
730 }
731 }
732 #endif /* !TIME_T_TYPE_DOUBLE */
733
734 NTtime -= ((ULLNG64)UNIX_TIME_ZERO_LO +
735 ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
736 *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX);
737 return TRUE;
738 #else /* !IZ_USE_INT64 (64-bit integer arithmetics may not be supported) */
739 time_t days;
740 SYSTEMTIME w32tm;
741
742 #ifndef TIME_T_TYPE_DOUBLE
743 /* underflow and overflow handling */
744 #ifdef CHECK_UTIME_SIGNED_UNSIGNED
745 if ((time_t)0x80000000L < (time_t)0L)
746 {
747 if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
748 ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
749 (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
750 *ut = (time_t)LONG_MIN;
751 return FALSE;
752 if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
753 ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
754 (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
755 *ut = (time_t)LONG_MAX;
756 return FALSE;
757 }
758 }
759 else
760 #endif /* CHECK_UTIME_SIGNED_UNSIGNED */
761 {
762 if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
763 ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
764 (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
765 *ut = (time_t)0;
766 return FALSE;
767 }
768 if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
769 ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
770 (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
771 *ut = (time_t)ULONG_MAX;
772 return FALSE;
773 }
774 }
775 #endif /* !TIME_T_TYPE_DOUBLE */
776
777 FileTimeToSystemTime(pft, &w32tm);
778
779 /* set `days' to the number of days into the year */
780 days = w32tm.wDay - 1 + ydays[w32tm.wMonth-1] +
781 (w32tm.wMonth > 2 && leap (w32tm.wYear));
782
783 /* now set `days' to the number of days since 1 Jan 1970 */
784 days += 365 * (time_t)(w32tm.wYear - 1970) +
785 (time_t)(nleap(w32tm.wYear));
786
787 *ut = (time_t)(86400L * days + 3600L * (time_t)w32tm.wHour +
788 (time_t)(60 * w32tm.wMinute + w32tm.wSecond));
789 return TRUE;
790 #endif /* ?IZ_USE_INT64 */
791 } /* end function NtfsFileTime2utime() */
792 #endif /* W32_STAT_BANDAID && !NO_W32TIMES_IZFIX */
793
794
795
796 #ifdef W32_STAT_BANDAID
797 /*********************************/
798 /* Function VFatFileTime2utime() */
799 /*********************************/
800
801 static int VFatFileTime2utime(const FILETIME *pft, time_t *ut)
802 {
803 FILETIME lft;
804 #ifndef HAVE_MKTIME
805 WORD wDOSDate, wDOSTime;
806 #else
807 SYSTEMTIME w32tm;
808 struct tm ltm;
809 #endif
810
811 if (!FileTimeToLocalFileTime(pft, &lft)) {
812 /* if pft cannot be converted to local time, set ut to current time */
813 time(ut);
814 return FALSE;
815 }
816 FTTrace((stdout, "VFatFT2utime, feed for mktime()", 1, &lft));
817 #ifndef HAVE_MKTIME
818 /* This version of the FILETIME-to-UNIXTIME conversion function
819 * uses DOS-DATE-TIME format as intermediate stage. For modification
820 * and access times, this is no problem. But, the extra fine resolution
821 * of the VFAT-stored creation time gets lost.
822 */
823 if (!FileTimeToDosDateTime(&lft, &wDOSDate, &wDOSTime)) {
824 static const FILETIME dosmin_ft =
825 {DOSTIME_MIN_FT_LO, DOSTIME_MIN_FT_HI};
826 if (CompareFileTime(&lft, &dosmin_ft) <= 0) {
827 /* underflow -> set to minimum DOS time */
828 wDOSDate = (WORD)((DWORD)DOSTIME_MINIMUM >> 16);
829 wDOSTime = (WORD)DOSTIME_MINIMUM;
830 } else {
831 /* overflow -> set to maximum DOS time */
832 wDOSDate = (WORD)0xFF9F; /* 2107-12-31 */
833 wDOSTime = (WORD)0xBF7D; /* 23:59:58 */
834 }
835 }
836 TTrace((stdout,"DosDateTime is %04u-%02u-%02u %02u:%02u:%02u\n",
837 (unsigned)((wDOSDate>>9)&0x7f)+1980,(unsigned)((wDOSDate>>5)&0x0f),
838 (unsigned)(wDOSDate&0x1f),(unsigned)((wDOSTime>>11)&0x1f),
839 (unsigned)((wDOSTime>>5)&0x3f),(unsigned)((wDOSTime<<1)&0x3e)));
840 *ut = dos_to_unix_time(((ulg)wDOSDate << 16) | (ulg)wDOSTime);
841
842 /* a cheap error check: dos_to_unix_time() only returns an odd time
843 * when clipping at maximum time_t value. DOS_DATE_TIME values have
844 * a resolution of 2 seconds and are therefore even numbers.
845 */
846 return (((*ut)&1) == (time_t)0);
847 #else /* HAVE_MKTIME */
848 FileTimeToSystemTime(&lft, &w32tm);
849 #ifndef TIME_T_TYPE_DOUBLE
850 /* underflow and overflow handling */
851 /* TODO: The range checks are not accurate, the actual limits may
852 * be off by one daylight-saving-time shift (typically 1 hour),
853 * depending on the current state of "is_dst".
854 */
855 #ifdef CHECK_UTIME_SIGNED_UNSIGNED
856 if ((time_t)0x80000000L < (time_t)0L)
857 {
858 if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
859 ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
860 (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
861 *ut = (time_t)LONG_MIN;
862 return FALSE;
863 if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
864 ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
865 (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
866 *ut = (time_t)LONG_MAX;
867 return FALSE;
868 }
869 }
870 else
871 #endif /* CHECK_UTIME_SIGNED_UNSIGNED */
872 {
873 if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
874 ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
875 (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
876 *ut = (time_t)0;
877 return FALSE;
878 }
879 if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
880 ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
881 (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
882 *ut = (time_t)ULONG_MAX;
883 return FALSE;
884 }
885 }
886 #endif /* !TIME_T_TYPE_DOUBLE */
887 ltm.tm_year = w32tm.wYear - 1900;
888 ltm.tm_mon = w32tm.wMonth - 1;
889 ltm.tm_mday = w32tm.wDay;
890 ltm.tm_hour = w32tm.wHour;
891 ltm.tm_min = w32tm.wMinute;
892 ltm.tm_sec = w32tm.wSecond;
893 ltm.tm_isdst = -1; /* let mktime determine if DST is in effect */
894 *ut = mktime(<m);
895
896 /* a cheap error check: mktime returns "(time_t)-1L" on conversion errors.
897 * Normally, we would have to apply a consistency check because "-1"
898 * could also be a valid time. But, it is quite unlikely to read back odd
899 * time numbers from file systems that store time stamps in DOS format.
900 * (The only known exception is creation time on VFAT partitions.)
901 */
902 return (*ut != (time_t)-1L);
903 #endif /* ?HAVE_MKTIME */
904
905 } /* end function VFatFileTime2utime() */
906 #endif /* W32_STAT_BANDAID */
907
908
909
910 /******************************/
911 /* Function FStampIsLocTime() */
912 /******************************/
913
914 static int FStampIsLocTime(__GPRO__ const char *path)
915 {
916 return (NTQueryVolInfo(__G__ path) ? G.lastVolLocTim : FALSE);
917 }
918
919
920
921 #ifndef NO_W32TIMES_IZFIX
922 # define UTIME_2_IZFILETIME(ut, pft) \
923 if (fs_uses_loctime) {utime2VFatFileTime(ut, pft, TRUE);} \
924 else {utime2NtfsFileTime(ut, pft);}
925 #else
926 # define UTIME_2_IZFILETIME(ut, pft) \
927 utime2VFatFileTime(ut, pft, fs_uses_loctime);
928 #endif
929
930
931
932 /****************************/ /* Get the file time in a format that */
933 /* Function getNTfiletime() */ /* can be used by SetFileTime() in NT */
934 /****************************/
935
936 static int getNTfiletime(__G__ pModFT, pAccFT, pCreFT)
937 __GDEF
938 FILETIME *pModFT;
939 FILETIME *pAccFT;
940 FILETIME *pCreFT;
941 {
942 #ifdef USE_EF_UT_TIME
943 unsigned eb_izux_flg;
944 iztimes z_utime; /* struct for Unix-style actime & modtime, + creatime */
945 #endif
946 int fs_uses_loctime = FStampIsLocTime(__G__ G.filename);
947
948 /* Copy and/or convert time and date variables, if necessary;
949 * return a flag indicating which time stamps are available. */
950 #ifdef USE_EF_UT_TIME
951 if (G.extra_field &&
952 #ifdef IZ_CHECK_TZ
953 G.tz_is_valid &&
954 #endif
955 ((eb_izux_flg = ef_scan_for_izux(G.extra_field,
956 G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
957 &z_utime, NULL)) & EB_UT_FL_MTIME))
958 {
959 TTrace((stderr, "getNTfiletime: Unix e.f. modif. time = %lu\n",
960 z_utime.mtime));
961 UTIME_2_IZFILETIME(z_utime.mtime, pModFT)
962 if (eb_izux_flg & EB_UT_FL_ATIME) {
963 UTIME_2_IZFILETIME(z_utime.atime, pAccFT)
964 }
965 if (eb_izux_flg & EB_UT_FL_CTIME) {
966 UTIME_2_IZFILETIME(z_utime.ctime, pCreFT)
967 }
968 return (int)eb_izux_flg;
969 }
970 #endif /* USE_EF_UT_TIME */
971 #ifndef NO_W32TIMES_IZFIX
972 if (!fs_uses_loctime) {
973 time_t ux_modtime;
974
975 ux_modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
976 utime2NtfsFileTime(ux_modtime, pModFT);
977 } else
978 #endif /* NO_W32TIMES_IZFIX */
979 {
980 FILETIME lft;
981
982 DosDateTimeToFileTime((WORD)(G.lrec.last_mod_dos_datetime >> 16),
983 (WORD)(G.lrec.last_mod_dos_datetime & 0xFFFFL),
984 &lft);
985 LocalFileTimeToFileTime(&lft, pModFT);
986 }
987 *pAccFT = *pModFT;
988 return (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
989
990 } /* end function getNTfiletime() */
991
992
993
994
995 /**************************/
996 /* Function SetFileSize() */
997 /**************************/
998
999 int SetFileSize(FILE *file, zusz_t filesize)
1000 {
1001 #ifdef __RSXNT__
1002 /* RSXNT environment lacks a translation function from C file pointer
1003 to Win32-API file handle. So, simply do nothing. */
1004 return 0;
1005 #else /* !__RSXNT__ */
1006 /* not yet verified, if that really creates an unfragmented file
1007 rommel@ars.de
1008 */
1009 HANDLE os_fh;
1010 #ifdef Z_UINT8_DEFINED
1011 LARGE_INTEGER fsbuf;
1012 #endif
1013
1014 /* Win9x supports FAT file system, only; presetting file size does
1015 not help to prevent fragmentation. */
1016 if (!IsWinNT()) return 0;
1017
1018 /* Win32-API calls require access to the Win32 file handle.
1019 The interface function used to retrieve the Win32 handle for
1020 a file opened by the C rtl is non-standard and may not be
1021 available for every Win32 compiler environment.
1022 (see also win32/win32.c of the Zip distribution)
1023 */
1024 os_fh = (HANDLE)_get_osfhandle(fileno(file));
1025 /* move file pointer behind the last byte of the expected file size */
1026 #ifdef Z_UINT8_DEFINED
1027 fsbuf.QuadPart = filesize;
1028 if ((SetFilePointer(os_fh, fsbuf.LowPart, &fsbuf.HighPart, FILE_BEGIN)
1029 == 0xFFFFFFFF) && GetLastError() != NO_ERROR)
1030 #else
1031 if (SetFilePointer(os_fh, (ulg)filesize, 0, FILE_BEGIN) == 0xFFFFFFFF)
1032 #endif
1033 return -1;
1034 /* extend/truncate file to the current position */
1035 if (SetEndOfFile(os_fh) == 0)
1036 return -1;
1037 /* move file position pointer back to the start of the file! */
1038 return (SetFilePointer(os_fh, 0, 0, FILE_BEGIN) == 0xFFFFFFFF) ? -1 : 0;
1039 #endif /* ?__RSXNT__ */
1040 } /* end function SetFileSize() */
1041
1042
1043
1044
1045 /****************************/
1046 /* Function close_outfile() */
1047 /****************************/
1048
1049 void close_outfile(__G)
1050 __GDEF
1051 {
1052 FILETIME Modft; /* File time type defined in NT, `last modified' time */
1053 FILETIME Accft; /* NT file time type, `last access' time */
1054 FILETIME Creft; /* NT file time type, `file creation' time */
1055 HANDLE hFile = INVALID_HANDLE_VALUE; /* File handle defined in NT */
1056 int gotTime;
1057 #ifdef NTSD_EAS
1058 uch *ebSDptr;
1059 unsigned ebSDlen;
1060 #endif
1061 #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
1062 char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
1063
1064 INTERN_TO_ISO(G.filename, ansi_name);
1065 # define Ansi_Fname ansi_name
1066 #else
1067 # define Ansi_Fname G.filename
1068 #endif
1069
1070 #ifndef __RSXNT__
1071 if (IsWinNT()) {
1072 /* Truncate the file to the current position.
1073 * This is needed to remove excess allocation in case the
1074 * extraction has failed or stopped prematurely. */
1075 SetEndOfFile((HANDLE)_get_osfhandle(fileno(G.outfile)));
1076 }
1077 #endif
1078
1079 /* Close the file and then re-open it using the Win32
1080 * CreateFile call, so that the file can be created
1081 * with GENERIC_WRITE access, otherwise the SetFileTime
1082 * call will fail. */
1083 fclose(G.outfile);
1084
1085 /* don't set the time stamp and attributes on standard output */
1086 if (uO.cflag)
1087 return;
1088
1089 /* skip restoring time stamps on user's request */
1090 if (uO.D_flag <= 1) {
1091 gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft);
1092
1093 /* open a handle to the file before processing extra fields;
1094 we do this in case new security on file prevents us from updating
1095 time stamps */
1096 hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1097 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1098 } else {
1099 gotTime = 0;
1100 }
1101
1102 /* sfield@microsoft.com: set attributes before time in case we decide to
1103 support other filetime members later. This also allows us to apply
1104 attributes before the security is changed, which may prevent this
1105 from succeeding otherwise. Also, since most files don't have
1106 any interesting attributes, only change them if something other than
1107 FILE_ATTRIBUTE_ARCHIVE appears in the attributes. This works well
1108 as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
1109 file anyway, when it's created new. */
1110 if ((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
1111 if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
1112 Info(slide, 1, ((char *)slide,
1113 "\nwarning (%d): could not set file attributes\n",
1114 (int)GetLastError()));
1115 }
1116
1117 #ifdef NTSD_EAS
1118 /* set NTFS SD extra fields */
1119 if (G.extra_field && /* zipfile extra field may have extended attribs */
1120 FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
1121 &ebSDptr, &ebSDlen))
1122 {
1123 int err = SetSD(__G__ Ansi_Fname, G.pInfo->file_attr,
1124 ebSDptr, ebSDlen);
1125
1126 if (err == IZ_EF_TRUNC) {
1127 if (uO.qflag)
1128 Info(slide, 1, ((char *)slide, "%-22s ",
1129 FnFilter1(G.filename)));
1130 Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
1131 ebSDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), uO.qflag? "\n":""));
1132 }
1133 }
1134 #endif /* NTSD_EAS */
1135
1136 /* skip restoring time stamps on user's request */
1137 if (uO.D_flag <= 1) {
1138 if ( hFile == INVALID_HANDLE_VALUE )
1139 Info(slide, 1, ((char *)slide,
1140 "\nCreateFile() error %d when trying set file time\n",
1141 (int)GetLastError()));
1142 else {
1143 if (gotTime) {
1144 FILETIME *pModft = (gotTime & EB_UT_FL_MTIME) ? &Modft : NULL;
1145 FILETIME *pAccft = (gotTime & EB_UT_FL_ATIME) ? &Accft : NULL;
1146 FILETIME *pCreft = (gotTime & EB_UT_FL_CTIME) ? &Creft : NULL;
1147
1148 if (!SetFileTime(hFile, pCreft, pAccft, pModft))
1149 Info(slide, 0, ((char *)slide,
1150 "\nSetFileTime failed: %d\n", (int)GetLastError()));
1151 }
1152 CloseHandle(hFile);
1153 }
1154 }
1155
1156 return;
1157
1158 #undef Ansi_Fname
1159
1160 } /* end function close_outfile() */
1161
1162
1163
1164
1165 #ifdef SET_DIR_ATTRIB
1166
1167 int defer_dir_attribs(__G__ pd)
1168 __GDEF
1169 direntry **pd;
1170 {
1171 NTdirattr *d_entry;
1172 #ifdef NTSD_EAS
1173 uch *ebSDptr;
1174 unsigned ebSDlen;
1175 #endif
1176
1177 /* Win9x does not support setting directory time stamps. */
1178 if (!IsWinNT()) {
1179 *pd = (direntry *)NULL;
1180 return PK_OK;
1181 }
1182
1183 #ifdef NTSD_EAS
1184 /* set extended attributes from extra fields */
1185 if (G.extra_field && /* zipfile e.f. may have extended attribs */
1186 FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
1187 &ebSDptr, &ebSDlen)) {
1188 /* ebSDlen contains the payload size of the e.f. block, but
1189 we store it including the e.b. header. */
1190 ebSDlen += EB_HEADSIZE;
1191 } else {
1192 /* no NTSD e.f. block -> no space needed to allocate */
1193 ebSDlen = 0;
1194 }
1195 #endif /* NTSD_EAS */
1196
1197 d_entry = (NTdirattr *)malloc(sizeof(NTdirattr)
1198 #ifdef NTSD_EAS
1199 + ebSDlen
1200 #endif
1201 + strlen(G.filename));
1202 *pd = (direntry *)d_entry;
1203 if (d_entry == (NTdirattr *)NULL) {
1204 return PK_MEM;
1205 }
1206 #ifdef NTSD_EAS
1207 if (ebSDlen > 0)
1208 memcpy(d_entry->buf, ebSDptr, ebSDlen);
1209 d_entry->SDlen = ebSDlen;
1210 d_entry->fn = d_entry->buf + ebSDlen;
1211 #else
1212 d_entry->fn = d_entry->buf;
1213 #endif
1214
1215 strcpy(d_entry->fn, G.filename);
1216
1217 d_entry->perms = G.pInfo->file_attr;
1218
1219 d_entry->gotTime = (uO.D_flag <= 0
1220 ? getNTfiletime(__G__ &(d_entry->Modft),
1221 &(d_entry->Accft), &(d_entry->Creft))
1222 : 0);
1223 return PK_OK;
1224 } /* end function defer_dir_attribs() */
1225
1226
1227 int set_direc_attribs(__G__ d)
1228 __GDEF
1229 direntry *d;
1230 {
1231 int errval;
1232 HANDLE hFile = INVALID_HANDLE_VALUE; /* File handle defined in NT */
1233 #ifdef __RSXNT__
1234 char *ansi_name;
1235 #endif
1236
1237 /* Win9x does not support setting directory time stamps. */
1238 if (!IsWinNT())
1239 return PK_OK;
1240
1241 errval = PK_OK;
1242 #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
1243 ansi_name = (char *)alloca(strlen(d->fn) + 1);
1244 INTERN_TO_ISO(d->fn, ansi_name);
1245 # define Ansi_Dirname ansi_name
1246 #else
1247 # define Ansi_Dirname d->fn
1248 #endif
1249
1250 /* Skip restoring directory time stamps on user' request. */
1251 if (uO.D_flag <= 0) {
1252 /* Open a handle to the directory before processing extra fields;
1253 we do this in case new security on file prevents us from updating
1254 time stamps.
1255 Although the WIN32 documentation recommends to use GENERIC_WRITE
1256 access flag to create the handle for SetFileTime(), this is too
1257 demanding for directories with the "read-only" attribute bit set.
1258 So we use the more specific flag FILE_WRITE_ATTRIBUTES here to
1259 request the minimum required access rights. (This problem is a
1260 Windows bug that has been silently fixed in Windows XP SP2.) */
1261 hFile = CreateFileA(Ansi_Dirname, FILE_WRITE_ATTRIBUTES,
1262 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1263 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1264 }
1265
1266 #ifdef NTSD_EAS
1267 if (NtAtt(d)->SDlen > 0) {
1268 int err;
1269
1270 if (QCOND2) {
1271 Info(slide, 1, ((char *)slide, " set attrib: %-22s ",
1272 FnFilter1(d->fn)));
1273 }
1274
1275 /* set NTFS SD extra fields */
1276 err = SetSD(__G__ Ansi_Dirname, NtAtt(d)->perms,
1277 NtAtt(d)->buf, NtAtt(d)->SDlen - EB_HEADSIZE);
1278 if (err == IZ_EF_TRUNC) {
1279 if (!QCOND2)
1280 Info(slide, 1, ((char *)slide, "%-22s ",
1281 FnFilter1(d->fn)));
1282 Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
1283 NtAtt(d)->SDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n"));
1284 } else if (QCOND2) {
1285 Info(slide, 0, ((char *)slide, "\n"));
1286 }
1287 if (errval < err)
1288 errval = err;
1289 }
1290 #endif /* NTSD_EAS */
1291
1292 /* Skip restoring directory time stamps on user' request. */
1293 if (uO.D_flag <= 0) {
1294 if (hFile == INVALID_HANDLE_VALUE) {
1295 Info(slide, 1, ((char *)slide,
1296 "warning: CreateFile() error %d (set file times for %s)\n",
1297 (int)GetLastError(), FnFilter1(d->fn)));
1298 if (!errval)
1299 errval = PK_WARN;
1300 } else {
1301 if (NtAtt(d)->gotTime) {
1302 FILETIME *pModft = (NtAtt(d)->gotTime & EB_UT_FL_MTIME)
1303 ? &(NtAtt(d)->Modft) : NULL;
1304 FILETIME *pAccft = (NtAtt(d)->gotTime & EB_UT_FL_ATIME)
1305 ? &(NtAtt(d)->Accft) : NULL;
1306 FILETIME *pCreft = (NtAtt(d)->gotTime & EB_UT_FL_CTIME)
1307 ? &(NtAtt(d)->Creft) : NULL;
1308
1309 if (!SetFileTime(hFile, pCreft, pAccft, pModft)) {
1310 Info(slide, 0, ((char *)slide,
1311 "warning: SetFileTime() for %s error %d\n",
1312 FnFilter1(d->fn), (int)GetLastError()));
1313 if (!errval)
1314 errval = PK_WARN;
1315 }
1316 }
1317 CloseHandle(hFile);
1318 }
1319 }
1320
1321 return errval;
1322 } /* end function set_direc_attribs() */
1323
1324 #endif /* SET_DIR_ATTRIB */
1325
1326
1327
1328
1329 #ifdef TIMESTAMP
1330
1331 /*************************/
1332 /* Function stamp_file() */
1333 /*************************/
1334
1335 int stamp_file(__GPRO__ ZCONST char *fname, time_t modtime)
1336 {
1337 FILETIME Modft; /* File time type defined in NT, `last modified' time */
1338 HANDLE hFile; /* File handle defined in NT */
1339 int errstat = 0; /* return status: 0 == "OK", -1 == "Failure" */
1340 int fs_uses_loctime = FStampIsLocTime(__G__ fname);
1341 #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
1342 char *ansi_name = (char *)alloca(strlen(fname) + 1);
1343
1344 INTERN_TO_ISO(fname, ansi_name);
1345 # define Ansi_Fname ansi_name
1346 #else
1347 # define Ansi_Fname fname
1348 #endif
1349
1350 /* open a handle to the file to prepare setting the mod-time stamp */
1351 hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1352 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1353 if ( hFile == INVALID_HANDLE_VALUE ) {
1354 errstat = -1;
1355 } else {
1356 /* convert time_t modtime into WIN32 native 64bit format */
1357 UTIME_2_IZFILETIME(modtime, &Modft)
1358 /* set Access and Modification times of the file to modtime */
1359 if (!SetFileTime(hFile, NULL, &Modft, &Modft)) {
1360 errstat = -1;
1361 }
1362 CloseHandle(hFile);
1363 }
1364
1365 return errstat;
1366
1367 #undef Ansi_Fname
1368 } /* end function stamp_file() */
1369
1370 #endif /* TIMESTAMP */
1371
1372
1373
1374
1375 /***********************/
1376 /* Function isfloppy() */ /* more precisely, is it removable? */
1377 /***********************/
1378
1379 static int isfloppy(int nDrive) /* 1 == A:, 2 == B:, etc. */
1380 {
1381 char rootPathName[4];
1382
1383 rootPathName[0] = (char)('A' + nDrive - 1); /* build the root path */
1384 rootPathName[1] = ':'; /* name, e.g. "A:/" */
1385 rootPathName[2] = '/';
1386 rootPathName[3] = '\0';
1387
1388 return (GetDriveTypeA(rootPathName) == DRIVE_REMOVABLE);
1389
1390 } /* end function isfloppy() */
1391
1392
1393
1394
1395 /*****************************/
1396 /* Function NTQueryVolInfo() */
1397 /*****************************/
1398
1399 /*
1400 * Note: 8.3 limits on filenames apply only to old-style FAT filesystems.
1401 * More recent versions of Windows (Windows NT 3.5 / Windows 4.0)
1402 * can support long filenames (LFN) on FAT filesystems. Check the
1403 * filesystem maximum component length field to detect LFN support.
1404 */
1405
1406 static int NTQueryVolInfo(__GPRO__ const char *name)
1407 {
1408 /* static char lastRootPath[4] = ""; */
1409 /* static int lastVolOldFAT; */
1410 /* static int lastVolLocTim; */
1411 char *tmp0;
1412 char tmp1[MAX_PATH], tmp2[MAX_PATH];
1413 DWORD volSerNo, maxCompLen, fileSysFlags;
1414 #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
1415 char *ansi_name = (char *)alloca(strlen(name) + 1);
1416
1417 INTERN_TO_ISO(name, ansi_name);
1418 name = ansi_name;
1419 #endif
1420
1421 if ((!strncmp(name, "//", 2) || !strncmp(name, "\\\\", 2)) &&
1422 (name[2] != '\0' && name[2] != '/' && name[2] != '\\')) {
1423 /* GetFullPathname() and GetVolumeInformation() do not work
1424 * on UNC names. For now, we return "error".
1425 * **FIXME**: check if UNC name is mapped to a drive letter
1426 * and use mapped drive for volume info query.
1427 */
1428 return FALSE;
1429 }
1430 if (isalpha((uch)name[0]) && (name[1] == ':'))
1431 tmp0 = (char *)name;
1432 else
1433 {
1434 if (!GetFullPathNameA(name, MAX_PATH, tmp1, &tmp0))
1435 return FALSE;
1436 tmp0 = &tmp1[0];
1437 }
1438 if (strncmp(G.lastRootPath, tmp0, 2) != 0) {
1439 /* For speed, we skip repeated queries for the same device */
1440 strncpy(G.lastRootPath, tmp0, 2); /* Build the root path name, */
1441 G.lastRootPath[2] = '/'; /* e.g. "A:/" */
1442 G.lastRootPath[3] = '\0';
1443
1444 if (!GetVolumeInformationA((LPCSTR)G.lastRootPath,
1445 (LPSTR)tmp1, (DWORD)MAX_PATH,
1446 &volSerNo, &maxCompLen, &fileSysFlags,
1447 (LPSTR)tmp2, (DWORD)MAX_PATH)) {
1448 G.lastRootPath[0] = '\0';
1449 return FALSE;
1450 }
1451
1452 /* LFNs are available if the component length is > 12 */
1453 G.lastVolOldFAT = (maxCompLen <= 12);
1454 /* G.lastVolOldFAT = !strncmp(strupr(tmp2), "FAT", 3); old version */
1455
1456 /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
1457 * local time!
1458 */
1459 G.lastVolLocTim = !strncmp(strupr(tmp2), "VFAT", 4) ||
1460 !strncmp(tmp2, "HPFS", 4) ||
1461 !strncmp(tmp2, "FAT", 3);
1462 }
1463
1464 return TRUE;
1465
1466 } /* end function NTQueryVolInfo() */
1467
1468
1469
1470
1471 /*****************************/
1472 /* Function IsVolumeOldFAT() */
1473 /*****************************/
1474
1475 static int IsVolumeOldFAT(__GPRO__ const char *name)
1476 {
1477 return (NTQueryVolInfo(__G__ name) ? G.lastVolOldFAT : FALSE);
1478 }
1479
1480
1481
1482
1483 #ifndef SFX
1484
1485 /************************/
1486 /* Function do_wild() */ /* identical to OS/2 version */
1487 /************************/
1488
1489 char *do_wild(__G__ wildspec)
1490 __GDEF
1491 ZCONST char *wildspec; /* only used first time on a given dir */
1492 {
1493 /* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in w32cfg.h:
1494 static zDIR *wild_dir = NULL;
1495 static ZCONST char *wildname;
1496 static char *dirname, matchname[FILNAMSIZ];
1497 static int notfirstcall=FALSE, have_dirname, dirnamelen;
1498 */
1499 char *fnamestart;
1500 struct zdirent *file;
1501
1502 /* Even when we're just returning wildspec, we *always* do so in
1503 * matchname[]--calling routine is allowed to append four characters
1504 * to the returned string, and wildspec may be a pointer to argv[].
1505 */
1506 if (!G.notfirstcall) { /* first call: must initialize everything */
1507 G.notfirstcall = TRUE;
1508
1509 if (!iswild(wildspec)) {
1510 strncpy(G.matchname, wildspec, FILNAMSIZ);
1511 G.matchname[FILNAMSIZ-1] = '\0';
1512 G.have_dirname = FALSE;
1513 G.wild_dir = NULL;
1514 return G.matchname;
1515 }
1516
1517 /* break the wildspec into a directory part and a wildcard filename */
1518 if ((G.wildname = MBSRCHR(wildspec, '/')) == (ZCONST char *)NULL &&
1519 (G.wildname = MBSRCHR(wildspec, ':')) == (ZCONST char *)NULL) {
1520 G.dirname = ".";
1521 G.dirnamelen = 1;
1522 G.have_dirname = FALSE;
1523 G.wildname = wildspec;
1524 } else {
1525 ++G.wildname; /* point at character after '/' or ':' */
1526 G.dirnamelen = G.wildname - wildspec;
1527 if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == NULL) {
1528 Info(slide, 1, ((char *)slide,
1529 "warning: cannot allocate wildcard buffers\n"));
1530 strncpy(G.matchname, wildspec, FILNAMSIZ);
1531 G.matchname[FILNAMSIZ-1] = '\0';
1532 return G.matchname; /* but maybe filespec was not a wildcard */
1533 }
1534 strncpy(G.dirname, wildspec, G.dirnamelen);
1535 G.dirname[G.dirnamelen] = '\0'; /* terminate for strcpy below */
1536 G.have_dirname = TRUE;
1537 }
1538 Trace((stderr, "do_wild: dirname = [%s]\n", FnFilter1(G.dirname)));
1539
1540 if ((G.wild_dir = (zvoid *)Opendir(G.dirname)) != NULL) {
1541 if (G.have_dirname) {
1542 strcpy(G.matchname, G.dirname);
1543 fnamestart = G.matchname + G.dirnamelen;
1544 } else
1545 fnamestart = G.matchname;
1546 while ((file = Readdir((zDIR *)G.wild_dir)) != NULL) {
1547 Trace((stderr, "do_wild: Readdir returns %s\n",
1548 FnFilter1(file->d_name)));
1549 strcpy(fnamestart, file->d_name);
1550 if (MBSRCHR(fnamestart, '.') == (char *)NULL)
1551 strcat(fnamestart, ".");
1552 if (match(fnamestart, G.wildname, TRUE WISEP) &&
1553 /* skip "." and ".." directory entries */
1554 strcmp(fnamestart, ".") && strcmp(fnamestart, "..")) {
1555 Trace((stderr, "do_wild: match() succeeds\n"));
1556 /* remove trailing dot */
1557 fnamestart = plastchar(fnamestart, strlen(fnamestart));
1558 if (*fnamestart == '.')
1559 *fnamestart = '\0';
1560 return G.matchname;
1561 }
1562 }
1563 /* if we get to here directory is exhausted, so close it */
1564 Closedir((zDIR *)G.wild_dir);
1565 G.wild_dir = NULL;
1566 }
1567 Trace((stderr, "do_wild: Opendir(%s) returns NULL\n",
1568 FnFilter1(G.dirname)));
1569
1570 /* return the raw wildspec in case that works (e.g., directory not
1571 * searchable, but filespec was not wild and file is readable) */
1572 strncpy(G.matchname, wildspec, FILNAMSIZ);
1573 G.matchname[FILNAMSIZ-1] = '\0';
1574 return G.matchname;
1575 }
1576
1577 /* last time through, might have failed opendir but returned raw wildspec */
1578 if (G.wild_dir == NULL) {
1579 G.notfirstcall = FALSE; /* reset for new wildspec */
1580 if (G.have_dirname)
1581 free(G.dirname);
1582 return (char *)NULL;
1583 }
1584
1585 /* If we've gotten this far, we've read and matched at least one entry
1586 * successfully (in a previous call), so dirname has been copied into
1587 * matchname already.
1588 */
1589 if (G.have_dirname) {
1590 /* strcpy(G.matchname, G.dirname); */
1591 fnamestart = G.matchname + G.dirnamelen;
1592 } else
1593 fnamestart = G.matchname;
1594 while ((file = Readdir((zDIR *)G.wild_dir)) != NULL) {
1595 Trace((stderr, "do_wild: readdir returns %s\n",
1596 FnFilter1(file->d_name)));
1597 strcpy(fnamestart, file->d_name);
1598 if (MBSRCHR(fnamestart, '.') == (char *)NULL)
1599 strcat(fnamestart, ".");
1600 if (match(fnamestart, G.wildname, TRUE WISEP)) {
1601 Trace((stderr, "do_wild: match() succeeds\n"));
1602 /* remove trailing dot */
1603 fnamestart = plastchar(fnamestart, strlen(fnamestart));
1604 if (*fnamestart == '.')
1605 *fnamestart = '\0';
1606 return G.matchname;
1607 }
1608 }
1609
1610 Closedir((zDIR *)G.wild_dir); /* at least one entry read; nothing left */
1611 G.wild_dir = NULL;
1612 G.notfirstcall = FALSE; /* reset for new wildspec */
1613 if (G.have_dirname)
1614 free(G.dirname);
1615 return (char *)NULL;
1616
1617 } /* end function do_wild() */
1618
1619 #endif /* !SFX */
1620
1621
1622
1623 /**********************/
1624 /* Function mapattr() */
1625 /**********************/
1626
1627 /* Identical to MS-DOS, OS/2 versions. However, NT has a lot of extra
1628 * permission stuff, so this function should probably be extended in the
1629 * future. */
1630
1631 int mapattr(__G)
1632 __GDEF
1633 {
1634 /* set archive bit for file entries (file is not backed up): */
1635 G.pInfo->file_attr = ((unsigned)G.crec.external_file_attributes |
1636 (G.crec.external_file_attributes & FILE_ATTRIBUTE_DIRECTORY ?
1637 0 : FILE_ATTRIBUTE_ARCHIVE)) & 0xff;
1638 return 0;
1639
1640 } /* end function mapattr() */
1641
1642
1643
1644
1645 /************************/
1646 /* Function mapname() */
1647 /************************/
1648
1649 int mapname(__G__ renamed)
1650 __GDEF
1651 int renamed;
1652 /*
1653 * returns:
1654 * MPN_OK - no problem detected
1655 * MPN_INF_TRUNC - caution (truncated filename)
1656 * MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
1657 * MPN_ERR_SKIP - error -> skip entry
1658 * MPN_ERR_TOOLONG - error -> path is too long
1659 * MPN_NOMEM - error (memory allocation failed) -> skip entry
1660 * [also MPN_VOL_LABEL, MPN_CREATED_DIR]
1661 */
1662 {
1663 char pathcomp[FILNAMSIZ]; /* path-component buffer */
1664 char *pp, *cp=NULL; /* character pointers */
1665 char *lastsemi = NULL; /* pointer to last semi-colon in pathcomp */
1666 #ifdef ACORN_FTYPE_NFS
1667 char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */
1668 RO_extra_block *ef_spark; /* pointer Acorn FTYPE ef block */
1669 #endif
1670 int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
1671 int error;
1672 register unsigned workch; /* hold the character being tested */
1673
1674
1675 /*---------------------------------------------------------------------------
1676 Initialize various pointers and counters and stuff.
1677 ---------------------------------------------------------------------------*/
1678
1679 /* can create path as long as not just freshening, or if user told us */
1680 G.create_dirs = (!uO.fflag || renamed);
1681
1682 G.created_dir = FALSE; /* not yet */
1683 G.renamed_fullpath = FALSE;
1684 G.fnlen = strlen(G.filename);
1685
1686 if (renamed) {
1687 cp = G.filename; /* point to beginning of renamed name... */
1688 if (*cp) do {
1689 if (*cp == '\\') /* convert backslashes to forward */
1690 *cp = '/';
1691 } while (*PREINCSTR(cp));
1692 cp = G.filename;
1693 /* use temporary rootpath if user gave full pathname */
1694 if (G.filename[0] == '/') {
1695 G.renamed_fullpath = TRUE;
1696 pathcomp[0] = '/'; /* copy the '/' and terminate */
1697 pathcomp[1] = '\0';
1698 ++cp;
1699 } else if (isalpha((uch)G.filename[0]) && G.filename[1] == ':') {
1700 G.renamed_fullpath = TRUE;
1701 pp = pathcomp;
1702 *pp++ = *cp++; /* copy the "d:" (+ '/', possibly) */
1703 *pp++ = *cp++;
1704 if (*cp == '/')
1705 *pp++ = *cp++; /* otherwise add "./"? */
1706 *pp = '\0';
1707 }
1708 }
1709
1710 /* pathcomp is ignored unless renamed_fullpath is TRUE: */
1711 if ((error = checkdir(__G__ pathcomp, INIT)) != 0) /* init path buffer */
1712 return error; /* ...unless no mem or vol label on hard disk */
1713
1714 *pathcomp = '\0'; /* initialize translation buffer */
1715 pp = pathcomp; /* point to translation buffer */
1716 if (!renamed) { /* cp already set if renamed */
1717 if (uO.jflag) /* junking directories */
1718 cp = (char *)MBSRCHR(G.filename, '/');
1719 if (cp == NULL) /* no '/' or not junking dirs */
1720 cp = G.filename; /* point to internal zipfile-member pathname */
1721 else
1722 ++cp; /* point to start of last component of path */
1723 }
1724
1725 /*---------------------------------------------------------------------------
1726 Begin main loop through characters in filename.
1727 ---------------------------------------------------------------------------*/
1728
1729 for (; (workch = (uch)*cp) != 0; INCSTR(cp)) {
1730
1731 switch (workch) {
1732 case '/': /* can assume -j flag not given */
1733 *pp = '\0';
1734 maskDOSdevice(__G__ pathcomp);
1735 if (strcmp(pathcomp, ".") == 0) {
1736 /* don't bother appending "./" to the path */
1737 *pathcomp = '\0';
1738 } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
1739 /* "../" dir traversal detected, skip over it */
1740 *pathcomp = '\0';
1741 killed_ddot = TRUE; /* set "show message" flag */
1742 }
1743 /* when path component is not empty, append it now */
1744 if (*pathcomp != '\0' &&
1745 ((error = checkdir(__G__ pathcomp, APPEND_DIR))
1746 & MPN_MASK) > MPN_INF_TRUNC)
1747 return error;
1748 pp = pathcomp; /* reset conversion buffer for next piece */
1749 lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
1750 break;
1751
1752 case ':': /* drive spec not stored, so no colon allowed */
1753 case '\\': /* '\\' may come as normal filename char (not */
1754 case '<': /* dir sep char!) from unix-like file system */
1755 case '>': /* no redirection symbols allowed either */
1756 case '|': /* no pipe signs allowed */
1757 case '"': /* no double quotes allowed */
1758 case '?': /* no wildcards allowed */
1759 case '*':
1760 *pp++ = '_'; /* these rules apply equally to FAT and NTFS */
1761 break;
1762 case ';': /* start of VMS version? */
1763 lastsemi = pp; /* remove VMS version later... */
1764 *pp++ = ';'; /* but keep semicolon for now */
1765 break;
1766
1767 #ifdef ACORN_FTYPE_NFS
1768 case ',': /* NFS filetype extension */
1769 lastcomma = pp;
1770 *pp++ = ','; /* keep for now; may need to remove */
1771 break; /* later, if requested */
1772 #endif
1773
1774 case ' ': /* keep spaces unless specifically */
1775 /* NT cannot create filenames with spaces on FAT volumes */
1776 if (uO.sflag || IsVolumeOldFAT(__G__ G.filename))
1777 *pp++ = '_';
1778 else
1779 *pp++ = ' ';
1780 break;
1781
1782 default:
1783 /* allow European characters in filenames: */
1784 if (isprint(workch) || workch >= 127)
1785 #ifdef _MBCS
1786 {
1787 memcpy(pp, cp, CLEN(cp));
1788 INCSTR(pp);
1789 }
1790 #else
1791 *pp++ = (char)workch;
1792 #endif
1793 } /* end switch */
1794
1795 } /* end while loop */
1796
1797 /* Show warning when stripping insecure "parent dir" path components */
1798 if (killed_ddot && QCOND2) {
1799 Info(slide, 0, ((char *)slide,
1800 "warning: skipped \"../\" path component(s) in %s\n",
1801 FnFilter1(G.filename)));
1802 if (!(error & ~MPN_MASK))
1803 error = (error & MPN_MASK) | PK_WARN;
1804 }
1805
1806 /*---------------------------------------------------------------------------
1807 Report if directory was created (and no file to create: filename ended
1808 in '/'), check name to be sure it exists, and combine path and name be-
1809 fore exiting.
1810 ---------------------------------------------------------------------------*/
1811
1812 if (lastchar(G.filename, G.fnlen) == '/') {
1813 #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
1814 char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
1815
1816 INTERN_TO_ISO(G.filename, ansi_name);
1817 # define Ansi_Fname ansi_name
1818 #else
1819 # define Ansi_Fname G.filename
1820 #endif
1821 checkdir(__G__ G.filename, GETPATH);
1822 if (G.created_dir) {
1823 if (QCOND2) {
1824 Info(slide, 0, ((char *)slide, " creating: %-22s\n",
1825 FnFilter1(G.filename)));
1826 }
1827
1828 /* set file attributes:
1829 The default for newly created directories is "DIR attribute
1830 flags set", so there is no need to change attributes unless
1831 one of the DOS style attribute flags is set. The readonly
1832 attribute need not be masked, since it does not prevent
1833 modifications in the new directory. */
1834 if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
1835 if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
1836 Info(slide, 1, ((char *)slide,
1837 "\nwarning (%d): could not set file attributes for %s\n",
1838 (int)GetLastError(), FnFilter1(G.filename)));
1839 }
1840
1841 /* set dir time (note trailing '/') */
1842 return (error & ~MPN_MASK) | MPN_CREATED_DIR;
1843 } else if (IS_OVERWRT_ALL) {
1844 /* overwrite attributes of existing directory on user's request */
1845
1846 /* set file attributes: */
1847 if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
1848 if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
1849 Info(slide, 1, ((char *)slide,
1850 "\nwarning (%d): could not set file attributes for %s\n",
1851 (int)GetLastError(), FnFilter1(G.filename)));
1852 }
1853 }
1854 /* dir existed already; don't look for data to extract */
1855 return (error & ~MPN_MASK) | MPN_INF_SKIP;
1856 }
1857
1858 *pp = '\0'; /* done with pathcomp: terminate it */
1859
1860 /* if not saving them, remove VMS version numbers (appended "###") */
1861 if (!uO.V_flag && lastsemi) {
1862 pp = lastsemi + 1; /* semi-colon was kept: expect #'s after */
1863 while (isdigit((uch)(*pp)))
1864 ++pp;
1865 if (*pp == '\0') /* only digits between ';' and end: nuke */
1866 *lastsemi = '\0';
1867 }
1868
1869 #ifdef ACORN_FTYPE_NFS
1870 /* translate Acorn filetype information if asked to do so */
1871 if (uO.acorn_nfs_ext &&
1872 (ef_spark = (RO_extra_block *)
1873 getRISCOSexfield(G.extra_field, G.lrec.extra_field_length))
1874 != (RO_extra_block *)NULL)
1875 {
1876 /* file *must* have a RISC OS extra field */
1877 long ft = (long)makelong(ef_spark->loadaddr);
1878 /*32-bit*/
1879 if (lastcomma) {
1880 pp = lastcomma + 1;
1881 while (isxdigit((uch)(*pp))) ++pp;
1882 if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
1883 }
1884 if ((ft & 1<<31)==0) ft=0x000FFD00;
1885 sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
1886 }
1887 #endif /* ACORN_FTYPE_NFS */
1888
1889 maskDOSdevice(__G__ pathcomp);
1890
1891 if (*pathcomp == '\0') {
1892 Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n",
1893 FnFilter1(G.filename)));
1894 return (error & ~MPN_MASK) | MPN_ERR_SKIP;
1895 }
1896
1897 checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
1898 checkdir(__G__ G.filename, GETPATH);
1899
1900 if (G.pInfo->vollabel) { /* set the volume label now */
1901 char drive[4];
1902 #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
1903 char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
1904 INTERN_TO_ISO(G.filename, ansi_name);
1905 # define Ansi_Fname ansi_name
1906 #else
1907 # define Ansi_Fname G.filename
1908 #endif
1909
1910 /* Build a drive string, e.g. "b:" */
1911 drive[0] = (char)('a' + G.nLabelDrive - 1);
1912 strcpy(drive + 1, ":\\");
1913 if (QCOND2)
1914 Info(slide, 0, ((char *)slide, "labelling %s %-22s\n", drive,
1915 FnFilter1(G.filename)));
1916 if (!SetVolumeLabelA(drive, Ansi_Fname)) {
1917 Info(slide, 1, ((char *)slide,
1918 "mapname: error setting volume label\n"));
1919 return (error & ~MPN_MASK) | MPN_ERR_SKIP;
1920 }
1921 /* success: skip the "extraction" quietly */
1922 return (error & ~MPN_MASK) | MPN_INF_SKIP;
1923 #undef Ansi_Fname
1924 }
1925
1926 Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n",
1927 FnFilter1(G.filename), error));
1928 return error;
1929
1930 } /* end function mapname() */
1931
1932
1933
1934
1935 /****************************/
1936 /* Function maskDOSdevice() */
1937 /****************************/
1938
1939 static void maskDOSdevice(__G__ pathcomp)
1940 __GDEF
1941 char *pathcomp;
1942 {
1943 /*---------------------------------------------------------------------------
1944 Put an underscore in front of the file name if the file name is a
1945 DOS/WINDOWS device name like CON.*, AUX.*, PRN.*, etc. Trying to
1946 extract such a file would fail at best and wedge us at worst.
1947 ---------------------------------------------------------------------------*/
1948 #if !defined(S_IFCHR) && defined(_S_IFCHR)
1949 # define S_IFCHR _S_IFCHR
1950 #endif
1951 #if !defined(S_ISCHR)
1952 # if defined(_S_ISCHR)
1953 # define S_ISCHR(m) _S_ISCHR(m)
1954 # elif defined(S_IFCHR)
1955 # define S_ISCHR(m) ((m) & S_IFCHR)
1956 # endif
1957 #endif
1958
1959 #ifdef DEBUG
1960 if (zstat(pathcomp, &G.statbuf) == 0) {
1961 Trace((stderr,
1962 "maskDOSdevice() stat(\"%s\", buf) st_mode result: %X, %o\n",
1963 FnFilter1(pathcomp), G.statbuf.st_mode, G.statbuf.st_mode));
1964 } else {
1965 Trace((stderr, "maskDOSdevice() stat(\"%s\", buf) failed\n",
1966 FnFilter1(pathcomp)));
1967 }
1968 #endif
1969 if (zstat(pathcomp, &G.statbuf) == 0 && S_ISCHR(G.statbuf.st_mode)) {
1970 extent i;
1971
1972 /* pathcomp contains a name of a DOS character device (builtin or
1973 * installed device driver).
1974 * Prepend a '_' to allow creation of the item in the file system.
1975 */
1976 for (i = strlen(pathcomp) + 1; i > 0; --i)
1977 pathcomp[i] = pathcomp[i - 1];
1978 pathcomp[0] = '_';
1979 }
1980 } /* end function maskDOSdevice() */
1981
1982
1983
1984
1985
1986 /**********************/
1987 /* Function map2fat() */ /* Not quite identical to OS/2 version */
1988 /**********************/
1989
1990 static void map2fat(pathcomp, pEndFAT)
1991 char *pathcomp, **pEndFAT;
1992 {
1993 char *ppc = pathcomp; /* variable pointer to pathcomp */
1994 char *pEnd = *pEndFAT; /* variable pointer to buildpathFAT */
1995 char *pBegin = *pEndFAT; /* constant pointer to start of this comp. */
1996 char *last_dot = NULL; /* last dot not converted to underscore */
1997 register unsigned workch; /* hold the character being tested */
1998
1999
2000 /* Only need check those characters which are legal in NTFS but not
2001 * in FAT: to get here, must already have passed through mapname.
2002 * Also must truncate path component to ensure 8.3 compliance.
2003 */
2004 while ((workch = (uch)*ppc++) != 0) {
2005 switch (workch) {
2006 case '[':
2007 case ']':
2008 case '+':
2009 case ',':
2010 case ';':
2011 case '=':
2012 *pEnd++ = '_'; /* convert brackets to underscores */
2013 break;
2014
2015 case '.':
2016 if (pEnd == *pEndFAT) { /* nothing appended yet... */
2017 if (*ppc == '\0') /* don't bother appending a */
2018 break; /* "./" component to the path */
2019 else if (*ppc == '.' && ppc[1] == '\0') { /* "../" */
2020 *pEnd++ = '.'; /* add first dot, */
2021 *pEnd++ = '.'; /* add second dot, and */
2022 ++ppc; /* skip over to pathcomp's end */
2023 } else { /* FAT doesn't allow null filename */
2024 *pEnd++ = '_'; /* bodies, so map .exrc -> _exrc */
2025 } /* (_.exr would keep max 3 chars) */
2026 } else { /* found dot within path component */
2027 last_dot = pEnd; /* point at last dot so far... */
2028 *pEnd++ = '_'; /* convert to underscore for now */
2029 }
2030 break;
2031
2032 default:
2033 *pEnd++ = (char)workch;
2034
2035 } /* end switch */
2036 } /* end while loop */
2037
2038 *pEnd = '\0'; /* terminate buildpathFAT */
2039
2040 /* NOTE: keep in mind that pEnd points to the end of the path
2041 * component, and *pEndFAT still points to the *beginning* of it...
2042 * Also note that the algorithm does not try to get too fancy:
2043 * if there are no dots already, the name either gets truncated
2044 * at 8 characters or the last underscore is converted to a dot
2045 * (only if more characters are saved that way). In no case is
2046 * a dot inserted between existing characters.
2047 */
2048 if (last_dot == NULL) { /* no dots: check for underscores... */
2049 char *plu = MBSRCHR(pBegin, '_'); /* pointer to last underscore */
2050
2051 if ((plu != NULL) && /* found underscore: convert to dot? */
2052 (MIN(plu - pBegin, 8) + MIN(pEnd - plu - 1, 3) > 8)) {
2053 last_dot = plu; /* be lazy: drop through to next if-blk */
2054 } else if ((pEnd - *pEndFAT) > 8) {
2055 /* no underscore; or converting underscore to dot would save less
2056 chars than leaving everything in the basename */
2057 *pEndFAT += 8; /* truncate at 8 chars */
2058 **pEndFAT = '\0';
2059 } else
2060 *pEndFAT = pEnd; /* whole thing fits into 8 chars or less */
2061 }
2062
2063 if (last_dot != NULL) { /* one dot is OK: */
2064 *last_dot = '.'; /* put it back in */
2065
2066 if ((last_dot - pBegin) > 8) {
2067 char *p, *q;
2068 int i;
2069
2070 p = last_dot;
2071 q = last_dot = pBegin + 8;
2072 for (i = 0; (i < 4) && *p; ++i) /* too many chars in basename: */
2073 *q++ = *p++; /* shift .ext left and trun- */
2074 *q = '\0'; /* cate/terminate it */
2075 *pEndFAT = q;
2076 } else if ((pEnd - last_dot) > 4) { /* too many chars in extension */
2077 *pEndFAT = last_dot + 4;
2078 **pEndFAT = '\0';
2079 } else
2080 *pEndFAT = pEnd; /* filename is fine; point at terminating zero */
2081
2082 if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ')
2083 last_dot[-1] = '_'; /* NO blank in front of '.'! */
2084 }
2085 } /* end function map2fat() */
2086
2087
2088
2089
2090 /***********************/ /* Borrowed from os2.c for UnZip 5.1. */
2091 /* Function checkdir() */ /* Difference: no EA stuff */
2092 /***********************/ /* HPFS stuff works on NTFS too */
2093
2094 int checkdir(__G__ pathcomp, flag)
2095 __GDEF
2096 char *pathcomp;
2097 int flag;
2098 /*
2099 * returns:
2100 * MPN_OK - no problem detected
2101 * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
2102 * MPN_INF_SKIP - path doesn't exist, not allowed to create
2103 * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
2104 * exists and is not a directory, but is supposed to be
2105 * MPN_ERR_TOOLONG - path is too long
2106 * MPN_NOMEM - can't allocate memory for filename buffers
2107 */
2108 {
2109 /* static int rootlen = 0; */ /* length of rootpath */
2110 /* static char *rootpath; */ /* user's "extract-to" directory */
2111 /* static char *buildpathHPFS; */ /* full path (so far) to extracted file, */
2112 /* static char *buildpathFAT; */ /* both HPFS/EA (main) and FAT versions */
2113 /* static char *endHPFS; */ /* corresponding pointers to end of */
2114 /* static char *endFAT; */ /* buildpath ('\0') */
2115
2116 # define FN_MASK 7
2117 # define FUNCTION (flag & FN_MASK)
2118
2119
2120
2121 /*---------------------------------------------------------------------------
2122 APPEND_DIR: append the path component to the path being built and check
2123 for its existence. If doesn't exist and we are creating directories, do
2124 so for this one; else signal success or error as appropriate.
2125 ---------------------------------------------------------------------------*/
2126
2127 if (FUNCTION == APPEND_DIR) {
2128 char *p = pathcomp;
2129 int too_long = FALSE;
2130
2131 Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
2132 while ((*G.endHPFS = *p++) != '\0') /* copy to HPFS filename */
2133 ++G.endHPFS;
2134 if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
2135 p = pathcomp;
2136 while ((*G.endFAT = *p++) != '\0') /* copy to FAT filename, too */
2137 ++G.endFAT;
2138 } else
2139 map2fat(pathcomp, &G.endFAT); /* map into FAT fn, update endFAT */
2140
2141 /* GRR: could do better check, see if overrunning buffer as we go:
2142 * check endHPFS-buildpathHPFS after each append, set warning variable
2143 * if within 20 of FILNAMSIZ; then if var set, do careful check when
2144 * appending. Clear variable when begin new path. */
2145
2146 /* next check: need to append '/', at least one-char name, '\0' */
2147 if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3)
2148 too_long = TRUE; /* check if extracting dir? */
2149 #ifdef FIX_STAT_BUG
2150 /* Borland C++ 5.0 does not handle a call to stat() well if the
2151 * directory does not exist (it tends to crash in strange places.)
2152 * This is apparently a problem only when compiling for GUI rather
2153 * than console. The code below attempts to work around this problem.
2154 */
2155 if (access(G.buildpathFAT, 0) != 0) {
2156 if (!G.create_dirs) { /* told not to create (freshening) */
2157 free(G.buildpathHPFS);
2158 free(G.buildpathFAT);
2159 /* path doesn't exist: nothing to do */
2160 return MPN_INF_SKIP;
2161 }
2162 if (too_long) { /* GRR: should allow FAT extraction w/o EAs */
2163 Info(slide, 1, ((char *)slide,
2164 "checkdir error: path too long: %s\n",
2165 FnFilter1(G.buildpathHPFS)));
2166 free(G.buildpathHPFS);
2167 free(G.buildpathFAT);
2168 /* no room for filenames: fatal */
2169 return MPN_ERR_TOOLONG;
2170 }
2171 if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
2172 Info(slide, 1, ((char *)slide,
2173 "checkdir error: cannot create %s\n\
2174 %s\n\
2175 unable to process %s.\n",
2176 FnFilter2(G.buildpathFAT),
2177 strerror(errno),
2178 FnFilter1(G.filename)));
2179 free(G.buildpathHPFS);
2180 free(G.buildpathFAT);
2181 /* path didn't exist, tried to create, failed */
2182 return MPN_ERR_SKIP;
2183 }
2184 G.created_dir = TRUE;
2185 }
2186 #endif /* FIX_STAT_BUG */
2187 if (SSTAT(G.buildpathFAT, &G.statbuf)) /* path doesn't exist */
2188 {
2189 if (!G.create_dirs) { /* told not to create (freshening) */
2190 free(G.buildpathHPFS);
2191 free(G.buildpathFAT);
2192 /* path doesn't exist: nothing to do */
2193 return MPN_INF_SKIP;
2194 }
2195 if (too_long) { /* GRR: should allow FAT extraction w/o EAs */
2196 Info(slide, 1, ((char *)slide,
2197 "checkdir error: path too long: %s\n",
2198 FnFilter1(G.buildpathHPFS)));
2199 free(G.buildpathHPFS);
2200 free(G.buildpathFAT);
2201 /* no room for filenames: fatal */
2202 return MPN_ERR_TOOLONG;
2203 }
2204 if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
2205 Info(slide, 1, ((char *)slide,
2206 "checkdir error: cannot create %s\n\
2207 %s\n\
2208 unable to process %s.\n",
2209 FnFilter2(G.buildpathFAT),
2210 strerror(errno),
2211 FnFilter1(G.filename)));
2212 free(G.buildpathHPFS);
2213 free(G.buildpathFAT);
2214 /* path didn't exist, tried to create, failed */
2215 return MPN_ERR_SKIP;
2216 }
2217 G.created_dir = TRUE;
2218 } else if (!S_ISDIR(G.statbuf.st_mode)) {
2219 Info(slide, 1, ((char *)slide,
2220 "checkdir error: %s exists but is not directory\n\
2221 unable to process %s.\n",
2222 FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
2223 free(G.buildpathHPFS);
2224 free(G.buildpathFAT);
2225 /* path existed but wasn't dir */
2226 return MPN_ERR_SKIP;
2227 }
2228 if (too_long) {
2229 Info(slide, 1, ((char *)slide,
2230 "checkdir error: path too long: %s\n",
2231 FnFilter1(G.buildpathHPFS)));
2232 free(G.buildpathHPFS);
2233 free(G.buildpathFAT);
2234 /* no room for filenames: fatal */
2235 return MPN_ERR_TOOLONG;
2236 }
2237 *G.endHPFS++ = '/';
2238 *G.endFAT++ = '/';
2239 *G.endHPFS = *G.endFAT = '\0';
2240 Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now = [%s]\n",
2241 FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
2242 return MPN_OK;
2243
2244 } /* end if (FUNCTION == APPEND_DIR) */
2245
2246 /*---------------------------------------------------------------------------
2247 GETPATH: copy full FAT path to the string pointed at by pathcomp (want
2248 filename to reflect name used on disk, not EAs; if full path is HPFS,
2249 buildpathFAT and buildpathHPFS will be identical). Also free both paths.
2250 ---------------------------------------------------------------------------*/
2251
2252 if (FUNCTION == GETPATH) {
2253 Trace((stderr, "getting and freeing FAT path [%s]\n",
2254 FnFilter1(G.buildpathFAT)));
2255 Trace((stderr, "freeing HPFS path [%s]\n",
2256 FnFilter1(G.buildpathHPFS)));
2257 strcpy(pathcomp, G.buildpathFAT);
2258 free(G.buildpathFAT);
2259 free(G.buildpathHPFS);
2260 G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL;
2261 return MPN_OK;
2262 }
2263
2264 /*---------------------------------------------------------------------------
2265 APPEND_NAME: assume the path component is the filename; append it and
2266 return without checking for existence.
2267 ---------------------------------------------------------------------------*/
2268
2269 if (FUNCTION == APPEND_NAME) {
2270 char *p = pathcomp;
2271 int error = MPN_OK;
2272
2273 Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
2274 /* The buildpathHPFS buffer has been allocated large enough to
2275 * hold the complete combined name, so there is no need to check
2276 * for OS filename size limit overflow within the copy loop.
2277 */
2278 while ((*G.endHPFS = *p++) != '\0') { /* copy to HPFS filename */
2279 ++G.endHPFS;
2280 }
2281 /* Now, check for OS filename size overflow. When detected, the
2282 * mapped HPFS name is truncated and a warning message is shown.
2283 */
2284 if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) {
2285 G.buildpathHPFS[FILNAMSIZ-1] = '\0';
2286 Info(slide, 1, ((char *)slide,
2287 "checkdir warning: path too long; truncating\n \
2288 %s\n -> %s\n",
2289 FnFilter1(G.filename), FnFilter2(G.buildpathHPFS)));
2290 error = MPN_INF_TRUNC; /* filename truncated */
2291 }
2292
2293 /* The buildpathFAT buffer has the same allocated size as the
2294 * buildpathHPFS buffer, so there is no need for an overflow check
2295 * within the following copy loop, either.
2296 */
2297 if (G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
2298 /* copy to FAT filename, too */
2299 p = pathcomp;
2300 while ((*G.endFAT = *p++) != '\0')
2301 ++G.endFAT;
2302 } else
2303 /* map into FAT fn, update endFAT */
2304 map2fat(pathcomp, &G.endFAT);
2305
2306 /* Check that the FAT path does not exceed the FILNAMSIZ limit, and
2307 * truncate when neccessary.
2308 * Note that truncation can only happen when the HPFS path (which is
2309 * never shorter than the FAT path) has been already truncated.
2310 * So, emission of the warning message and setting the error code
2311 * has already happened.
2312 */
2313 if ((G.endFAT-G.buildpathFAT) >= FILNAMSIZ)
2314 G.buildpathFAT[FILNAMSIZ-1] = '\0';
2315 Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT: %s\n",
2316 FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
2317
2318 return error; /* could check for existence, prompt for new name... */
2319
2320 } /* end if (FUNCTION == APPEND_NAME) */
2321
2322 /*---------------------------------------------------------------------------
2323 INIT: allocate and initialize buffer space for the file currently being
2324 extracted. If file was renamed with an absolute path, don't prepend the
2325 extract-to path.
2326 ---------------------------------------------------------------------------*/
2327
2328 if (FUNCTION == INIT) {
2329 Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
2330 #ifdef ACORN_FTYPE_NFS
2331 if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+
2332 (uO.acorn_nfs_ext ? 5 : 1)))
2333 #else
2334 if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1))
2335 #endif
2336 == NULL)
2337 return MPN_NOMEM;
2338 #ifdef ACORN_FTYPE_NFS
2339 if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+
2340 (uO.acorn_nfs_ext ? 5 : 1)))
2341 #else
2342 if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1))
2343 #endif
2344 == NULL) {
2345 free(G.buildpathHPFS);
2346 return MPN_NOMEM;
2347 }
2348 if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */
2349 /* GRR: for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
2350 if (G.renamed_fullpath && pathcomp[1] == ':')
2351 *G.buildpathHPFS = (char)ToLower(*pathcomp);
2352 else if (!G.renamed_fullpath && G.rootlen > 1 &&
2353 G.rootpath[1] == ':')
2354 *G.buildpathHPFS = (char)ToLower(*G.rootpath);
2355 else {
2356 char tmpN[MAX_PATH], *tmpP;
2357 if (GetFullPathNameA(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH)
2358 { /* by definition of MAX_PATH we should never get here */
2359 Info(slide, 1, ((char *)slide,
2360 "checkdir warning: current dir path too long\n"));
2361 return MPN_INF_TRUNC; /* can't get drive letter */
2362 }
2363 G.nLabelDrive = *tmpN - 'a' + 1;
2364 *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a');
2365 }
2366 G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */
2367 if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */
2368 || (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */
2369 free(G.buildpathHPFS);
2370 free(G.buildpathFAT);
2371 return MPN_VOL_LABEL; /* skipping with message */
2372 }
2373 *G.buildpathHPFS = '\0';
2374 } else if (G.renamed_fullpath) /* pathcomp = valid data */
2375 strcpy(G.buildpathHPFS, pathcomp);
2376 else if (G.rootlen > 0)
2377 strcpy(G.buildpathHPFS, G.rootpath);
2378 else
2379 *G.buildpathHPFS = '\0';
2380 G.endHPFS = G.buildpathHPFS;
2381 G.endFAT = G.buildpathFAT;
2382 while ((*G.endFAT = *G.endHPFS) != '\0') {
2383 ++G.endFAT;
2384 ++G.endHPFS;
2385 }
2386 Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS)));
2387 return MPN_OK;
2388 }
2389
2390 /*---------------------------------------------------------------------------
2391 ROOT: if appropriate, store the path in rootpath and create it if neces-
2392 sary; else assume it's a zipfile member and return. This path segment
2393 gets used in extracting all members from every zipfile specified on the
2394 command line. Note that under OS/2 and MS-DOS, if a candidate extract-to
2395 directory specification includes a drive letter (leading "x:"), it is
2396 treated just as if it had a trailing '/'--that is, one directory level
2397 will be created if the path doesn't exist, unless this is otherwise pro-
2398 hibited (e.g., freshening).
2399 ---------------------------------------------------------------------------*/
2400
2401 #if (!defined(SFX) || defined(SFX_EXDIR))
2402 if (FUNCTION == ROOT) {
2403 Trace((stderr, "initializing root path to [%s]\n",
2404 FnFilter1(pathcomp)));
2405 if (pathcomp == NULL) {
2406 G.rootlen = 0;
2407 return MPN_OK;
2408 }
2409 if (G.rootlen > 0) /* rootpath was already set, nothing to do */
2410 return MPN_OK;
2411 if ((G.rootlen = strlen(pathcomp)) > 0) {
2412 int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE;
2413 char *tmproot;
2414
2415 if ((tmproot = (char *)malloc(G.rootlen+3)) == (char *)NULL) {
2416 G.rootlen = 0;
2417 return MPN_NOMEM;
2418 }
2419 strcpy(tmproot, pathcomp);
2420 if (isalpha((uch)tmproot[0]) && tmproot[1] == ':')
2421 has_drive = TRUE; /* drive designator */
2422 if (tmproot[G.rootlen-1] == '/' || tmproot[G.rootlen-1] == '\\') {
2423 tmproot[--G.rootlen] = '\0';
2424 had_trailing_pathsep = TRUE;
2425 }
2426 if (has_drive && (G.rootlen == 2)) {
2427 if (!had_trailing_pathsep) /* i.e., original wasn't "x:/" */
2428 add_dot = TRUE; /* relative path: add '.' before '/' */
2429 } else if (G.rootlen > 0) { /* need not check "x:." and "x:/" */
2430 if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
2431 {
2432 /* path does not exist */
2433 if (!G.create_dirs /* || iswild(tmproot) */ ) {
2434 free(tmproot);
2435 G.rootlen = 0;
2436 /* treat as stored file */
2437 return MPN_INF_SKIP;
2438 }
2439 /* create directory (could add loop here scanning tmproot
2440 * to create more than one level, but really necessary?) */
2441 if (MKDIR(tmproot, 0777) == -1) {
2442 Info(slide, 1, ((char *)slide,
2443 "checkdir: cannot create extraction directory: %s\n",
2444 FnFilter1(tmproot)));
2445 free(tmproot);
2446 G.rootlen = 0;
2447 /* path didn't exist, tried to create, failed: */
2448 /* file exists, or need 2+ subdir levels */
2449 return MPN_ERR_SKIP;
2450 }
2451 }
2452 }
2453 if (add_dot) /* had just "x:", make "x:." */
2454 tmproot[G.rootlen++] = '.';
2455 tmproot[G.rootlen++] = '/';
2456 tmproot[G.rootlen] = '\0';
2457 if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
2458 free(tmproot);
2459 G.rootlen = 0;
2460 return MPN_NOMEM;
2461 }
2462 Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
2463 }
2464 return MPN_OK;
2465 }
2466 #endif /* !SFX || SFX_EXDIR */
2467
2468 /*---------------------------------------------------------------------------
2469 END: free rootpath, immediately prior to program exit.
2470 ---------------------------------------------------------------------------*/
2471
2472 if (FUNCTION == END) {
2473 Trace((stderr, "freeing rootpath\n"));
2474 if (G.rootlen > 0) {
2475 free(G.rootpath);
2476 G.rootlen = 0;
2477 }
2478 return MPN_OK;
2479 }
2480
2481 return MPN_INVALID; /* should never reach */
2482
2483 } /* end function checkdir() */
2484
2485
2486
2487
2488
2489 #ifndef SFX
2490
2491 /*************************/
2492 /* Function dateformat() */
2493 /*************************/
2494
2495 int dateformat()
2496 {
2497 char df[2]; /* LOCALE_IDATE has a maximum value of 2 */
2498
2499 if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDATE, df, 2) != 0) {
2500 switch (df[0])
2501 {
2502 case '0':
2503 return DF_MDY;
2504 case '1':
2505 return DF_DMY;
2506 case '2':
2507 return DF_YMD;
2508 }
2509 }
2510 return DF_MDY;
2511 }
2512
2513
2514 /****************************/
2515 /* Function dateseparator() */
2516 /****************************/
2517
2518 char dateseparator()
2519 {
2520 char df[2]; /* use only if it is one character */
2521
2522 if ((GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDATE, df, 2) != 0) &&
2523 (df[0] != '\0'))
2524 return df[0];
2525 else
2526 return '-';
2527 }
2528
2529
2530 #ifndef WINDLL
2531
2532 /************************/
2533 /* Function version() */
2534 /************************/
2535
2536 void version(__G)
2537 __GDEF
2538 {
2539 int len;
2540 #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DJGPP__))
2541 char buf[80];
2542 #if (defined(_MSC_VER) && (_MSC_VER > 900))
2543 char buf2[80];
2544 #endif
2545 #endif
2546
2547 len = sprintf((char *)slide, CompiledWith,
2548
2549 #if defined(_MSC_VER) /* MSC == VC++, but what about SDK compiler? */
2550 (sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100), buf),
2551 # if (_MSC_VER == 800)
2552 "(Visual C++ v1.1)",
2553 # elif (_MSC_VER == 850)
2554 "(Windows NT v3.5 SDK)",
2555 # elif (_MSC_VER == 900)
2556 "(Visual C++ v2.x)",
2557 # elif (_MSC_VER > 900)
2558 (sprintf(buf2, "(Visual C++ %d.%d)", _MSC_VER/100 - 6, _MSC_VER%100/10),
2559 buf2),
2560 # else
2561 "(bad version)",
2562 # endif
2563 #elif defined(__WATCOMC__)
2564 # if (__WATCOMC__ % 10 > 0)
2565 (sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
2566 __WATCOMC__ % 100), buf), "",
2567 # else
2568 (sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
2569 (__WATCOMC__ % 100) / 10), buf), "",
2570 # endif
2571 #elif defined(__BORLANDC__)
2572 "Borland C++",
2573 # if (__BORLANDC__ < 0x0200)
2574 " 1.0",
2575 # elif (__BORLANDC__ == 0x0200)
2576 " 2.0",
2577 # elif (__BORLANDC__ == 0x0400)
2578 " 3.0",
2579 # elif (__BORLANDC__ == 0x0410) /* __TURBOC__ = 0x0310 */
2580 " 3.1",
2581 # elif (__BORLANDC__ == 0x0452) /* __TURBOC__ = 0x0320 */
2582 " 4.0 or 4.02",
2583 # elif (__BORLANDC__ == 0x0460) /* __TURBOC__ = 0x0340 */
2584 " 4.5",
2585 # elif (__BORLANDC__ == 0x0500) /* __TURBOC__ = 0x0340 */
2586 " 5.0",
2587 # elif (__BORLANDC__ == 0x0520) /* __TURBOC__ = 0x0520 */
2588 " 5.2 (C++ Builder 1.0)",
2589 # elif (__BORLANDC__ == 0x0530) /* __TURBOC__ = 0x0530 */
2590 " 5.3 (C++ Builder 3.0)",
2591 # elif (__BORLANDC__ == 0x0540) /* __TURBOC__ = 0x0540 */
2592 " 5.4 (C++ Builder 4.0)",
2593 # elif (__BORLANDC__ == 0x0550) /* __TURBOC__ = 0x0550 */
2594 " 5.5 (C++ Builder 5.0)",
2595 # elif (__BORLANDC__ == 0x0551) /* __TURBOC__ = 0x0551 */
2596 " 5.5.1 (C++ Builder 5.0.1)",
2597 # elif (__BORLANDC__ == 0x0560) /* __TURBOC__ = 0x0560 */
2598 " 6.0 (C++ Builder 6.0)",
2599 # else
2600 " later than 6.0",
2601 # endif
2602 #elif defined(__LCC__)
2603 "LCC-Win32", "",
2604 #elif defined(__GNUC__)
2605 # if defined(__RSXNT__)
2606 # if (defined(__DJGPP__) && !defined(__EMX__))
2607 (sprintf(buf, "rsxnt(djgpp v%d.%02d) / gcc ",
2608 __DJGPP__, __DJGPP_MINOR__), buf),
2609 # elif defined(__DJGPP__)
2610 (sprintf(buf, "rsxnt(emx+djgpp v%d.%02d) / gcc ",
2611 __DJGPP__, __DJGPP_MINOR__), buf),
2612 # elif (defined(__GO32__) && !defined(__EMX__))
2613 "rsxnt(djgpp v1.x) / gcc ",
2614 # elif defined(__GO32__)
2615 "rsxnt(emx + djgpp v1.x) / gcc ",
2616 # elif defined(__EMX__)
2617 "rsxnt(emx)+gcc ",
2618 # else
2619 "rsxnt(unknown) / gcc ",
2620 # endif
2621 # elif defined(__CYGWIN__)
2622 "cygnus win32 / gcc ",
2623 # elif defined(__MINGW32__)
2624 "mingw32 / gcc ",
2625 # else
2626 "gcc ",
2627 # endif
2628 __VERSION__,
2629 #else /* !_MSC_VER, !__WATCOMC__, !__BORLANDC__, !__LCC__, !__GNUC__ */
2630 "unknown compiler (SDK?)", "",
2631 #endif /* ?compilers */
2632
2633 "\nWindows 9x / Windows NT/2K/XP/2K3", " (32-bit)",
2634
2635 #ifdef __DATE__
2636 " on ", __DATE__
2637 #else
2638 "", ""
2639 #endif
2640 );
2641
2642 (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
2643
2644 return;
2645
2646 } /* end function version() */
2647
2648 #endif /* !WINDLL */
2649 #endif /* !SFX */
2650
2651
2652
2653 #ifdef MORE
2654
2655 int screensize(int *tt_rows, int *tt_cols)
2656 {
2657 HANDLE hstdout;
2658 CONSOLE_SCREEN_BUFFER_INFO scr;
2659
2660 hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
2661 GetConsoleScreenBufferInfo(hstdout, &scr);
2662 if (tt_rows != NULL) *tt_rows = scr.srWindow.Bottom - scr.srWindow.Top + 1;
2663 if (tt_cols != NULL) *tt_cols = scr.srWindow.Right - scr.srWindow.Left + 1;
2664 return 0; /* signal success */
2665 }
2666
2667 #endif /* MORE */
2668
2669
2670
2671 #ifdef W32_STAT_BANDAID
2672
2673 /* All currently known variants of WIN32 operating systems (Windows 95/98,
2674 * WinNT 3.x, 4.0, 5.x) have a nasty bug in the OS kernel concerning
2675 * conversions between UTC and local time: In the time conversion functions
2676 * of the Win32 API, the timezone offset (including seasonal daylight saving
2677 * shift) between UTC and local time evaluation is erratically based on the
2678 * current system time. The correct evaluation must determine the offset
2679 * value as it {was/is/will be} for the actual time to be converted.
2680 *
2681 * Newer versions of MS C runtime lib's stat() returns utc time-stamps so
2682 * that localtime(timestamp) corresponds to the (potentially false) local
2683 * time shown by the OS' system programs (Explorer, command shell dir, etc.)
2684 * The RSXNT port follows the same strategy, but fails to recognize the
2685 * access-time attribute.
2686 *
2687 * For the NTFS file system (and other filesystems that store time-stamps
2688 * as UTC values), this results in st_mtime (, st_{c|a}time) fields which
2689 * are not stable but vary according to the seasonal change of "daylight
2690 * saving time in effect / not in effect".
2691 *
2692 * Other C runtime libs (CygWin), or the crtdll.dll supplied with Win9x/NT
2693 * return the unix-time equivalent of the UTC FILETIME values as got back
2694 * from the Win32 API call. This time, return values from NTFS are correct
2695 * whereas utimes from files on (V)FAT volumes vary according to the DST
2696 * switches.
2697 *
2698 * To achieve timestamp consistency of UTC (UT extra field) values in
2699 * Zip archives, the Info-ZIP programs require work-around code for
2700 * proper time handling in stat() (and other time handling routines).
2701 *
2702 * However, nowadays most other programs on Windows systems use the
2703 * time conversion strategy of Microsofts C runtime lib "msvcrt.dll".
2704 * To improve interoperability in environments where a "consistent" (but
2705 * false) "UTC<-->LocalTime" conversion is preferred over "stable" time
2706 * stamps, the Info-ZIP specific time conversion handling can be
2707 * deactivated by defining the preprocessor flag NO_W32TIMES_IZFIX.
2708 */
2709 /* stat() functions under Windows95 tend to fail for root directories. *
2710 * Watcom and Borland, at least, are affected by this bug. Watcom made *
2711 * a partial fix for 11.0 but still missed some cases. This substitute *
2712 * detects the case and fills in reasonable values. Otherwise we get *
2713 * effects like failure to extract to a root dir because it's not found. */
2714
2715 int zstat_win32(__W32STAT_GLOBALS__ const char *path, z_stat *buf)
2716 {
2717 if (!zstat(path, buf))
2718 {
2719 /* stat was successful, now redo the time-stamp fetches */
2720 #ifndef NO_W32TIMES_IZFIX
2721 int fs_uses_loctime = FStampIsLocTime(__G__ path);
2722 #endif
2723 HANDLE h;
2724 FILETIME Modft, Accft, Creft;
2725 #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
2726 char *ansi_path = (char *)alloca(strlen(path) + 1);
2727
2728 INTERN_TO_ISO(path, ansi_path);
2729 # define Ansi_Path ansi_path
2730 #else
2731 # define Ansi_Path path
2732 #endif
2733
2734 TTrace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime));
2735 h = CreateFileA(Ansi_Path, GENERIC_READ,
2736 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2737 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2738 if (h != INVALID_HANDLE_VALUE) {
2739 BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
2740 CloseHandle(h);
2741
2742 if (ftOK) {
2743 FTTrace((stdout, "GetFileTime returned Modft", 0, &Modft));
2744 FTTrace((stdout, "GetFileTime returned Creft", 0, &Creft));
2745 #ifndef NO_W32TIMES_IZFIX
2746 if (!fs_uses_loctime) {
2747 /* On a filesystem that stores UTC timestamps, we refill
2748 * the time fields of the struct stat buffer by directly
2749 * using the UTC values as returned by the Win32
2750 * GetFileTime() API call.
2751 */
2752 NtfsFileTime2utime(&Modft, &(buf->st_mtime));
2753 if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
2754 NtfsFileTime2utime(&Accft, &(buf->st_atime));
2755 else
2756 buf->st_atime = buf->st_mtime;
2757 if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
2758 NtfsFileTime2utime(&Creft, &(buf->st_ctime));
2759 else
2760 buf->st_ctime = buf->st_mtime;
2761 TTrace((stdout,"NTFS, recalculated modtime %08lx\n",
2762 buf->st_mtime));
2763 } else
2764 #endif /* NO_W32TIMES_IZFIX */
2765 {
2766 /* On VFAT and FAT-like filesystems, the FILETIME values
2767 * are converted back to the stable local time before
2768 * converting them to UTC unix time-stamps.
2769 */
2770 VFatFileTime2utime(&Modft, &(buf->st_mtime));
2771 if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
2772 VFatFileTime2utime(&Accft, &(buf->st_atime));
2773 else
2774 buf->st_atime = buf->st_mtime;
2775 if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
2776 VFatFileTime2utime(&Creft, &(buf->st_ctime));
2777 else
2778 buf->st_ctime = buf->st_mtime;
2779 TTrace((stdout, "VFAT, recalculated modtime %08lx\n",
2780 buf->st_mtime));
2781 }
2782 }
2783 }
2784 # undef Ansi_Path
2785 return 0;
2786 }
2787 #ifdef W32_STATROOT_FIX
2788 else
2789 {
2790 DWORD flags;
2791 #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
2792 char *ansi_path = (char *)alloca(strlen(path) + 1);
2793
2794 INTERN_TO_ISO(path, ansi_path);
2795 # define Ansi_Path ansi_path
2796 #else
2797 # define Ansi_Path path
2798 #endif
2799
2800 flags = GetFileAttributesA(Ansi_Path);
2801 if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
2802 Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
2803 FnFilter1(path)));
2804 memset(buf, 0, sizeof(z_stat));
2805 buf->st_atime = buf->st_ctime = buf->st_mtime =
2806 dos_to_unix_time(DOSTIME_MINIMUM); /* 1-1-80 */
2807 buf->st_mode = S_IFDIR | S_IREAD |
2808 ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
2809 return 0;
2810 } /* assumes: stat() won't fail on non-dirs without good reason */
2811 # undef Ansi_Path
2812 }
2813 #endif /* W32_STATROOT_FIX */
2814 return -1;
2815 }
2816
2817 #endif /* W32_STAT_BANDAID */
2818
2819
2820
2821 #ifdef W32_USE_IZ_TIMEZONE
2822 #include "timezone.h"
2823 #define SECSPERMIN 60
2824 #define MINSPERHOUR 60
2825 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
2826 static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule);
2827
2828 static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule)
2829 {
2830 if (lpw32tm->wYear != 0) {
2831 ptrule->r_type = JULIAN_DAY;
2832 ptrule->r_day = ydays[lpw32tm->wMonth - 1] + lpw32tm->wDay;
2833 } else {
2834 ptrule->r_type = MONTH_NTH_DAY_OF_WEEK;
2835 ptrule->r_mon = lpw32tm->wMonth;
2836 ptrule->r_day = lpw32tm->wDayOfWeek;
2837 ptrule->r_week = lpw32tm->wDay;
2838 }
2839 ptrule->r_time = (long)lpw32tm->wHour * SECSPERHOUR +
2840 (long)(lpw32tm->wMinute * SECSPERMIN) +
2841 (long)lpw32tm->wSecond;
2842 }
2843
2844 int GetPlatformLocalTimezone(register struct state * ZCONST sp,
2845 void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
2846 ZCONST struct rule * ZCONST start,
2847 ZCONST struct rule * ZCONST end))
2848 {
2849 TIME_ZONE_INFORMATION tzinfo;
2850 DWORD res;
2851
2852 /* read current timezone settings from registry if TZ envvar missing */
2853 res = GetTimeZoneInformation(&tzinfo);
2854 if (res != TIME_ZONE_ID_INVALID)
2855 {
2856 struct rule startrule, stoprule;
2857
2858 conv_to_rule(&(tzinfo.StandardDate), &stoprule);
2859 conv_to_rule(&(tzinfo.DaylightDate), &startrule);
2860 sp->timecnt = 0;
2861 sp->ttis[0].tt_abbrind = 0;
2862 if ((sp->charcnt =
2863 WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1,
2864 sp->chars, sizeof(sp->chars), NULL, NULL))
2865 == 0)
2866 sp->chars[sp->charcnt++] = '\0';
2867 sp->ttis[1].tt_abbrind = sp->charcnt;
2868 sp->charcnt +=
2869 WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1,
2870 sp->chars + sp->charcnt,
2871 sizeof(sp->chars) - sp->charcnt, NULL, NULL);
2872 if ((sp->charcnt - sp->ttis[1].tt_abbrind) == 0)
2873 sp->chars[sp->charcnt++] = '\0';
2874 sp->ttis[0].tt_gmtoff = - (tzinfo.Bias + tzinfo.StandardBias)
2875 * MINSPERHOUR;
2876 sp->ttis[1].tt_gmtoff = - (tzinfo.Bias + tzinfo.DaylightBias)
2877 * MINSPERHOUR;
2878 sp->ttis[0].tt_isdst = 0;
2879 sp->ttis[1].tt_isdst = 1;
2880 sp->typecnt = (startrule.r_mon == 0 && stoprule.r_mon == 0) ? 1 : 2;
2881
2882 if (sp->typecnt > 1)
2883 (*fill_tzstate_from_rules)(sp, &startrule, &stoprule);
2884 return TRUE;
2885 }
2886 return FALSE;
2887 }
2888 #endif /* W32_USE_IZ_TIMEZONE */
2889
2890 #endif /* !FUNZIP */
2891
2892
2893
2894 #ifndef WINDLL
2895 /* This replacement getch() function was originally created for Watcom C
2896 * and then additionally used with CYGWIN. Since UnZip 5.4, all other Win32
2897 * ports apply this replacement rather that their supplied getch() (or
2898 * alike) function. There are problems with unabsorbed LF characters left
2899 * over in the keyboard buffer under Win95 (and 98) when ENTER was pressed.
2900 * (Under Win95, ENTER returns two(!!) characters: CR-LF.) This problem
2901 * does not appear when run on a WinNT console prompt!
2902 */
2903
2904 /* Watcom 10.6's getch() does not handle Alt+<digit><digit><digit>. */
2905 /* Note that if PASSWD_FROM_STDIN is defined, the file containing */
2906 /* the password must have a carriage return after the word, not a */
2907 /* Unix-style newline (linefeed only). This discards linefeeds. */
2908
2909 int getch_win32(void)
2910 {
2911 HANDLE stin;
2912 DWORD rc;
2913 unsigned char buf[2];
2914 int ret = -1;
2915 DWORD odemode = ~(DWORD)0;
2916
2917 # ifdef PASSWD_FROM_STDIN
2918 stin = GetStdHandle(STD_INPUT_HANDLE);
2919 # else
2920 stin = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE,
2921 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
2922 if (stin == INVALID_HANDLE_VALUE)
2923 return -1;
2924 # endif
2925 if (GetConsoleMode(stin, &odemode))
2926 SetConsoleMode(stin, ENABLE_PROCESSED_INPUT); /* raw except ^C noticed */
2927 if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
2928 ret = buf[0];
2929 /* when the user hits return we get CR LF. We discard the LF, not the CR,
2930 * because when we call this for the first time after a previous input
2931 * such as the one for "replace foo? [y]es, ..." the LF may still be in
2932 * the input stream before whatever the user types at our prompt. */
2933 if (ret == '\n')
2934 if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
2935 ret = buf[0];
2936 if (odemode != ~(DWORD)0)
2937 SetConsoleMode(stin, odemode);
2938 # ifndef PASSWD_FROM_STDIN
2939 CloseHandle(stin);
2940 # endif
2941 return ret;
2942 }
2943 #endif /* !WINDLL */
2944
2945
2946
2947 #if (defined(UNICODE_SUPPORT) && !defined(FUNZIP))
2948 /* convert wide character string to multi-byte character string */
2949 char *wide_to_local_string(wide_string, escape_all)
2950 ZCONST zwchar *wide_string;
2951 int escape_all;
2952 {
2953 int i;
2954 wchar_t wc;
2955 int bytes_char;
2956 int default_used;
2957 int wsize = 0;
2958 int max_bytes = 9;
2959 char buf[9];
2960 char *buffer = NULL;
2961 char *local_string = NULL;
2962
2963 for (wsize = 0; wide_string[wsize]; wsize++) ;
2964
2965 if (max_bytes < MB_CUR_MAX)
2966 max_bytes = MB_CUR_MAX;
2967
2968 if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
2969 return NULL;
2970 }
2971
2972 /* convert it */
2973 buffer[0] = '\0';
2974 for (i = 0; i < wsize; i++) {
2975 if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
2976 /* wchar_t probably 2 bytes */
2977 /* could do surrogates if state_dependent and wctomb can do */
2978 wc = zwchar_to_wchar_t_default_char;
2979 } else {
2980 wc = (wchar_t)wide_string[i];
2981 }
2982 /* Unter some vendor's C-RTL, the Wide-to-MultiByte conversion functions
2983 * (like wctomb() et. al.) do not use the same codepage as the other
2984 * string arguments I/O functions (fopen, mkdir, rmdir etc.).
2985 * Therefore, we have to fall back to the underlying Win32-API call to
2986 * achieve a consistent behaviour for all supported compiler environments.
2987 * Failing RTLs are for example:
2988 * Borland (locale uses OEM-CP as default, but I/O functions expect ANSI
2989 * names)
2990 * Watcom (only "C" locale, wctomb() always uses OEM CP)
2991 * (in other words: all supported environments except the Microsoft RTLs)
2992 */
2993 bytes_char = WideCharToMultiByte(
2994 CP_ACP, WC_COMPOSITECHECK,
2995 &wc, 1,
2996 (LPSTR)buf, sizeof(buf),
2997 NULL, &default_used);
2998 if (default_used)
2999 bytes_char = -1;
3000 if (escape_all) {
3001 if (bytes_char == 1 && (uch)buf[0] <= 0x7f) {
3002 /* ASCII */
3003 strncat(buffer, buf, 1);
3004 } else {
3005 /* use escape for wide character */
3006 char *escape_string = wide_to_escape_string(wide_string[i]);
3007 strcat(buffer, escape_string);
3008 free(escape_string);
3009 }
3010 } else if (bytes_char > 0) {
3011 /* multi-byte char */
3012 strncat(buffer, buf, bytes_char);
3013 } else {
3014 /* no MB for this wide */
3015 /* use escape for wide character */
3016 char *escape_string = wide_to_escape_string(wide_string[i]);
3017 strcat(buffer, escape_string);
3018 free(escape_string);
3019 }
3020 }
3021 if ((local_string = (char *)realloc(buffer, strlen(buffer) + 1)) == NULL) {
3022 free(buffer);
3023 return NULL;
3024 }
3025
3026 return local_string;
3027 }
3028
3029
3030 #if 0
3031 wchar_t *utf8_to_wchar_string(utf8_string)
3032 char *utf8_string; /* path to get utf-8 name for */
3033 {
3034 wchar_t *qw;
3035 int ulen;
3036 int ulenw;
3037
3038 if (utf8_string == NULL)
3039 return NULL;
3040
3041 /* get length */
3042 ulenw = MultiByteToWideChar(
3043 CP_UTF8, /* UTF-8 code page */
3044 0, /* flags for character-type options */
3045 utf8_string, /* string to convert */
3046 -1, /* string length (-1 = NULL terminated) */
3047 NULL, /* buffer */
3048 0 ); /* buffer length (0 = return length) */
3049 if (ulenw == 0) {
3050 /* failed */
3051 return NULL;
3052 }
3053 ulenw++;
3054 /* get length in bytes */
3055 ulen = sizeof(wchar_t) * (ulenw + 1);
3056 if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
3057 return NULL;
3058 }
3059 /* convert multibyte to wide */
3060 ulen = MultiByteToWideChar(
3061 CP_UTF8, /* UTF-8 code page */
3062 0, /* flags for character-type options */
3063 utf8_string, /* string to convert */
3064 -1, /* string length (-1 = NULL terminated) */
3065 qw, /* buffer */
3066 ulenw); /* buffer length (0 = return length) */
3067 if (ulen == 0) {
3068 /* failed */
3069 free(qw);
3070 return NULL;
3071 }
3072
3073 return qw;
3074 }
3075
3076 wchar_t *local_to_wchar_string(local_string)
3077 char *local_string; /* path of local name */
3078 {
3079 wchar_t *qw;
3080 int ulen;
3081 int ulenw;
3082
3083 if (local_string == NULL)
3084 return NULL;
3085
3086 /* get length */
3087 ulenw = MultiByteToWideChar(
3088 CP_ACP, /* ANSI code page */
3089 0, /* flags for character-type options */
3090 local_string, /* string to convert */
3091 -1, /* string length (-1 = NULL terminated) */
3092 NULL, /* buffer */
3093 0 ); /* buffer length (0 = return length) */
3094 if (ulenw == 0) {
3095 /* failed */
3096 return NULL;
3097 }
3098 ulenw++;
3099 /* get length in bytes */
3100 ulen = sizeof(wchar_t) * (ulenw + 1);
3101 if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
3102 return NULL;
3103 }
3104 /* convert multibyte to wide */
3105 ulen = MultiByteToWideChar(
3106 CP_ACP, /* ANSI code page */
3107 0, /* flags for character-type options */
3108 local_string, /* string to convert */
3109 -1, /* string length (-1 = NULL terminated) */
3110 qw, /* buffer */
3111 ulenw); /* buffer length (0 = return length) */
3112 if (ulen == 0) {
3113 /* failed */
3114 free(qw);
3115 return NULL;
3116 }
3117
3118 return qw;
3119 }
3120 #endif /* 0 */
3121 #endif /* UNICODE_SUPPORT && !FUNZIP */
3122
3123
3124
3125 /* --------------------------------------------------- */
3126 /* Large File Support
3127 *
3128 * Initial functions by E. Gordon and R. Nausedat
3129 * 9/10/2003
3130 * Lifted from Zip 3b, win32.c and place here by Myles Bennett
3131 * 7/6/2004
3132 *
3133 * These implement 64-bit file support for Windows. The
3134 * defines and headers are in win32/w32cfg.h.
3135 *
3136 * Moved to win32i64.c by Mike White to avoid conflicts in
3137 * same name functions in WiZ using UnZip and Zip libraries.
3138 * 9/25/2003
3139 */
3140