Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6725 | siemargl | 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 |
||
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 |
||
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 | |||
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 | |||
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 | |||
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 | |||
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. */ |
||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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+ |
||
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 | |||
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 | |||
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 | */=>>>>-->>>>31)==0)><31)==0)>':>=>=>>=>=>=>=>>>>>>><>1)&0x3e))); |