Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6725 | siemargl | 1 | /* |
2 | Copyright (c) 1990-2007 Info-ZIP. All rights reserved. |
||
3 | |||
4 | See the accompanying file LICENSE, version 2000-Apr-09 or later |
||
5 | (the contents of which are also included in zip.h) for terms of use. |
||
6 | If, for some reason, both of 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 | os2.c |
||
12 | |||
13 | OS/2-specific routines for use with Info-ZIP's UnZip 5.1 and later. |
||
14 | |||
15 | This file contains the OS/2 versions of the file name/attribute/time/etc |
||
16 | code. Most or all of the routines which make direct use of OS/2 system |
||
17 | calls (i.e., the non-lowercase routines) are Kai Uwe Rommel's. The read- |
||
18 | dir() suite was written by Michael Rendell and ported to OS/2 by Kai Uwe; |
||
19 | it is in the public domain. |
||
20 | |||
21 | Contains: GetCountryInfo() |
||
22 | SetFileSize() |
||
23 | GetFileTime() |
||
24 | SetFileTime() (TIMESTAMP only) |
||
25 | stamp_file() (TIMESTAMP only) |
||
26 | Utime2DosDateTime() |
||
27 | SetPathAttrTimes() |
||
28 | SetEAs() |
||
29 | GetLoadPath() |
||
30 | opendir() |
||
31 | closedir() |
||
32 | readdir() |
||
33 | [ seekdir() ] not used |
||
34 | [ telldir() ] not used |
||
35 | free_dircontents() |
||
36 | getdirent() |
||
37 | IsFileSystemFAT() |
||
38 | do_wild() |
||
39 | mapattr() |
||
40 | mapname() |
||
41 | checkdir() |
||
42 | isfloppy() |
||
43 | IsFileNameValid() |
||
44 | map2fat() |
||
45 | SetLongNameEA() |
||
46 | close_outfile() |
||
47 | check_for_newer() |
||
48 | dateformat() |
||
49 | version() |
||
50 | zcalloc() (16-bit, only) |
||
51 | zcfree() (16-bit, only) |
||
52 | InitNLS() |
||
53 | IsUpperNLS() |
||
54 | ToLowerNLS() |
||
55 | StringLower() |
||
56 | screensize() |
||
57 | DebugMalloc() |
||
58 | |||
59 | ---------------------------------------------------------------------------*/ |
||
60 | |||
61 | |||
62 | #define UNZIP_INTERNAL |
||
63 | #include "unzip.h" |
||
64 | |||
65 | /* fUnZip does not need anything from here except the zcalloc() & zcfree() |
||
66 | * function pair (when Deflate64 support is enabled in 16-bit environment). |
||
67 | */ |
||
68 | #ifndef FUNZIP |
||
69 | |||
70 | #include "os2acl.h" |
||
71 | |||
72 | extern ZCONST char Far TruncEAs[]; |
||
73 | |||
74 | /* local prototypes */ |
||
75 | |||
76 | #ifdef TIMESTAMP |
||
77 | static int SetFileTime(ZCONST char *name, ulg stamp); |
||
78 | #endif |
||
79 | #if defined(USE_EF_UT_TIME) || defined(TIMESTAMP) |
||
80 | static ulg Utime2DosDateTime OF((time_t uxtime)); |
||
81 | #endif |
||
82 | static int getOS2filetimes OF((__GPRO__ |
||
83 | ulg *pM_dt, ulg *pA_dt, ulg *pC_dt)); |
||
84 | static void SetPathAttrTimes OF((__GPRO__ int flags, int dir)); |
||
85 | static int SetEAs OF((__GPRO__ const char *path, |
||
86 | void *ef_block)); |
||
87 | static int SetACL OF((__GPRO__ const char *path, |
||
88 | void *ef_block)); |
||
89 | static int EvalExtraFields OF((__GPRO__ const char *path, |
||
90 | void *extra_field, unsigned ef_len)); |
||
91 | static int isfloppy OF((int nDrive)); |
||
92 | static int IsFileNameValid OF((const char *name)); |
||
93 | static void map2fat OF((char *pathcomp, char **pEndFAT)); |
||
94 | static int SetLongNameEA OF((char *name, char *longname)); |
||
95 | static void InitNLS OF((void)); |
||
96 | |||
97 | |||
98 | #ifdef ACORN_FTYPE_NFS |
||
99 | /* Acorn bits for NFS filetyping */ |
||
100 | typedef struct { |
||
101 | uch ID[2]; |
||
102 | uch size[2]; |
||
103 | uch ID_2[4]; |
||
104 | uch loadaddr[4]; |
||
105 | uch execaddr[4]; |
||
106 | uch attr[4]; |
||
107 | } RO_extra_block; |
||
108 | |||
109 | #endif /* ACORN_FTYPE_NFS */ |
||
110 | |||
111 | |||
112 | /*****************************/ |
||
113 | /* Strings used in os2.c */ |
||
114 | /*****************************/ |
||
115 | |||
116 | #ifndef SFX |
||
117 | static ZCONST char Far CantAllocateWildcard[] = |
||
118 | "warning: cannot allocate wildcard buffers\n"; |
||
119 | #endif |
||
120 | static ZCONST char Far WarnDirTraversSkip[] = |
||
121 | "warning: skipped \"../\" path component(s) in %s\n"; |
||
122 | static ZCONST char Far Creating[] = " creating: %-22s "; |
||
123 | static ZCONST char Far ConversionFailed[] = |
||
124 | "mapname: conversion of %s failed\n"; |
||
125 | static ZCONST char Far Labelling[] = "labelling %c: %-22s\n"; |
||
126 | static ZCONST char Far ErrSetVolLabel[] = |
||
127 | "mapname: error setting volume label\n"; |
||
128 | static ZCONST char Far PathTooLong[] = "checkdir error: path too long: %s\n"; |
||
129 | static ZCONST char Far CantCreateDir[] = "checkdir error: cannot create %s\n\ |
||
130 | unable to process %s.\n"; |
||
131 | static ZCONST char Far DirIsntDirectory[] = |
||
132 | "checkdir error: %s exists but is not directory\n\ |
||
133 | unable to process %s.\n"; |
||
134 | static ZCONST char Far PathTooLongTrunc[] = |
||
135 | "checkdir warning: path too long; truncating\n %s\n\ |
||
136 | -> %s\n"; |
||
137 | #if (!defined(SFX) || defined(SFX_EXDIR)) |
||
138 | static ZCONST char Far CantCreateExtractDir[] = |
||
139 | "checkdir: cannot create extraction directory: %s\n"; |
||
140 | #endif |
||
141 | |||
142 | #ifndef __GNUC__ |
||
143 | /* all supported non-gcc compilers provide MSC/DOS style mkdir() */ |
||
144 | # if (_MSC_VER >= 600) || defined(__IBMC__) |
||
145 | # include |
||
146 | # else /* own prototype because dir.h conflicts? */ |
||
147 | int mkdir(const char *path); |
||
148 | # endif |
||
149 | # define MKDIR(path,mode) mkdir(path) |
||
150 | #else |
||
151 | /* EMX and hopefully all other gcc ports support POSIX style mkdir() */ |
||
152 | # define MKDIR(path,mode) mkdir(path,mode) |
||
153 | #endif |
||
154 | |||
155 | |||
156 | #ifdef __32BIT__ |
||
157 | |||
158 | USHORT DosDevIOCtl32(PVOID pData, USHORT cbData, PVOID pParms, USHORT cbParms, |
||
159 | USHORT usFunction, USHORT usCategory, HFILE hDevice) |
||
160 | { |
||
161 | ULONG ulParmLengthInOut = cbParms, ulDataLengthInOut = cbData; |
||
162 | return (USHORT) DosDevIOCtl(hDevice, usCategory, usFunction, |
||
163 | pParms, cbParms, &ulParmLengthInOut, |
||
164 | pData, cbData, &ulDataLengthInOut); |
||
165 | } |
||
166 | |||
167 | # define DosDevIOCtl DosDevIOCtl32 |
||
168 | #else |
||
169 | # define DosDevIOCtl DosDevIOCtl2 |
||
170 | #endif |
||
171 | |||
172 | |||
173 | typedef struct |
||
174 | { |
||
175 | ush nID; |
||
176 | ush nSize; |
||
177 | ulg lSize; |
||
178 | } |
||
179 | EFHEADER, *PEFHEADER; |
||
180 | |||
181 | |||
182 | #ifdef __32BIT__ |
||
183 | |||
184 | #define DosFindFirst(p1, p2, p3, p4, p5, p6) \ |
||
185 | DosFindFirst(p1, p2, p3, p4, p5, p6, 1) |
||
186 | |||
187 | #else |
||
188 | |||
189 | typedef struct |
||
190 | { |
||
191 | ULONG oNextEntryOffset; |
||
192 | BYTE fEA; |
||
193 | BYTE cbName; |
||
194 | USHORT cbValue; |
||
195 | CHAR szName[1]; |
||
196 | } |
||
197 | FEA2, *PFEA2; |
||
198 | |||
199 | typedef struct |
||
200 | { |
||
201 | ULONG cbList; |
||
202 | FEA2 list[1]; |
||
203 | } |
||
204 | FEA2LIST, *PFEA2LIST; |
||
205 | |||
206 | #define DosQueryCurrentDisk DosQCurDisk |
||
207 | #define DosQueryFSAttach(p1, p2, p3, p4, p5) \ |
||
208 | DosQFSAttach(p1, p2, p3, p4, p5, 0) |
||
209 | #define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \ |
||
210 | DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0) |
||
211 | #define DosFindFirst(p1, p2, p3, p4, p5, p6) \ |
||
212 | DosFindFirst(p1, p2, p3, p4, p5, p6, 0) |
||
213 | #define DosMapCase DosCaseMap |
||
214 | #define DosSetPathInfo(p1, p2, p3, p4, p5) \ |
||
215 | DosSetPathInfo(p1, p2, p3, p4, p5, 0) |
||
216 | #define DosQueryPathInfo(p1, p2, p3, p4) \ |
||
217 | DosQPathInfo(p1, p2, p3, p4, 0) |
||
218 | #define DosQueryFileInfo DosQFileInfo |
||
219 | #define DosMapCase DosCaseMap |
||
220 | #define DosQueryCtryInfo DosGetCtryInfo |
||
221 | |||
222 | #endif /* !__32BIT__ */ |
||
223 | |||
224 | |||
225 | |||
226 | |||
227 | |||
228 | /* |
||
229 | * @(#) dir.h 1.4 87/11/06 Public Domain. |
||
230 | */ |
||
231 | |||
232 | #define A_RONLY 0x01 |
||
233 | #define A_HIDDEN 0x02 |
||
234 | #define A_SYSTEM 0x04 |
||
235 | #define A_LABEL 0x08 |
||
236 | #define A_DIR 0x10 |
||
237 | #define A_ARCHIVE 0x20 |
||
238 | |||
239 | |||
240 | const int attributes = A_DIR | A_HIDDEN | A_SYSTEM; |
||
241 | |||
242 | |||
243 | extern DIR *opendir(__GPRO__ ZCONST char *); |
||
244 | extern struct direct *readdir(__GPRO__ DIR *); |
||
245 | extern void seekdir(DIR *, long); |
||
246 | extern long telldir(DIR *); |
||
247 | extern void closedir(DIR *); |
||
248 | #define rewinddir(dirp) seekdir(dirp, 0L) |
||
249 | |||
250 | int IsFileSystemFAT(__GPRO__ ZCONST char *dir); |
||
251 | char *StringLower(char *szArg); |
||
252 | |||
253 | |||
254 | |||
255 | |||
256 | /* |
||
257 | * @(#)dir.c 1.4 87/11/06 Public Domain. |
||
258 | */ |
||
259 | |||
260 | |||
261 | #ifndef S_IFMT |
||
262 | # define S_IFMT 0xF000 |
||
263 | #endif |
||
264 | |||
265 | |||
266 | #ifndef SFX |
||
267 | static char *getdirent(__GPRO__ ZCONST char *); |
||
268 | static void free_dircontents(struct _dircontents *); |
||
269 | #endif /* !SFX */ |
||
270 | |||
271 | |||
272 | |||
273 | |||
274 | int GetCountryInfo(void) |
||
275 | { |
||
276 | COUNTRYINFO ctryi; |
||
277 | COUNTRYCODE ctryc; |
||
278 | #ifdef __32BIT__ |
||
279 | ULONG cbInfo; |
||
280 | #else |
||
281 | USHORT cbInfo; |
||
282 | #endif |
||
283 | |||
284 | ctryc.country = ctryc.codepage = 0; |
||
285 | |||
286 | if ( DosQueryCtryInfo(sizeof(ctryi), &ctryc, &ctryi, &cbInfo) != NO_ERROR ) |
||
287 | return 0; |
||
288 | |||
289 | return ctryi.fsDateFmt; |
||
290 | } |
||
291 | |||
292 | |||
293 | int SetFileSize(FILE *file, ulg filesize) |
||
294 | { |
||
295 | #ifdef __32BIT__ |
||
296 | return DosSetFileSize(fileno(file), (size_t)filesize) ? -1 : 0; |
||
297 | #else |
||
298 | return 0; |
||
299 | #endif |
||
300 | } |
||
301 | |||
302 | |||
303 | long GetFileTime(ZCONST char *name) |
||
304 | { |
||
305 | #ifdef __32BIT__ |
||
306 | FILESTATUS3 fs; |
||
307 | #else |
||
308 | FILESTATUS fs; |
||
309 | #endif |
||
310 | USHORT nDate, nTime; |
||
311 | |||
312 | if ( DosQueryPathInfo((PSZ) name, 1, (PBYTE) &fs, sizeof(fs)) ) |
||
313 | return -1; |
||
314 | |||
315 | nDate = * (USHORT *) &fs.fdateLastWrite; |
||
316 | nTime = * (USHORT *) &fs.ftimeLastWrite; |
||
317 | |||
318 | return ((ULONG) nDate) << 16 | nTime; |
||
319 | } |
||
320 | |||
321 | |||
322 | #ifdef TIMESTAMP |
||
323 | |||
324 | static int SetFileTime(ZCONST char *name, ulg stamp) /* swiped from Zip */ |
||
325 | { |
||
326 | FILESTATUS fs; |
||
327 | USHORT fd, ft; |
||
328 | |||
329 | if (DosQueryPathInfo((PSZ) name, FIL_STANDARD, (PBYTE) &fs, sizeof(fs))) |
||
330 | return -1; |
||
331 | |||
332 | fd = (USHORT) (stamp >> 16); |
||
333 | ft = (USHORT) stamp; |
||
334 | fs.fdateLastWrite = fs.fdateCreation = * (FDATE *) &fd; |
||
335 | fs.ftimeLastWrite = fs.ftimeCreation = * (FTIME *) &ft; |
||
336 | |||
337 | if (DosSetPathInfo((PSZ) name, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0)) |
||
338 | return -1; |
||
339 | |||
340 | return 0; |
||
341 | } |
||
342 | |||
343 | |||
344 | int stamp_file(ZCONST char *fname, time_t modtime) |
||
345 | { |
||
346 | return SetFileTime(fname, Utime2DosDateTime(modtime)); |
||
347 | } |
||
348 | |||
349 | #endif /* TIMESTAMP */ |
||
350 | |||
351 | |||
352 | /* The following DOS date/time structures are machine-dependent as they |
||
353 | * assume "little-endian" byte order. For OS/2-specific code, which |
||
354 | * is run on x86 CPUs (or emulators?), this assumption is valid; but |
||
355 | * care should be taken when using this code as template for other ports. |
||
356 | */ |
||
357 | typedef union { |
||
358 | ULONG timevalue; /* combined value, useful for comparisons */ |
||
359 | struct { |
||
360 | FTIME ft; /* system file time record: |
||
361 | * USHORT twosecs : 5 |
||
362 | * USHORT minutes : 6; |
||
363 | * USHORT hours : 5; */ |
||
364 | FDATE fd; /* system file date record: |
||
365 | * USHORT day : 5 |
||
366 | * USHORT month : 4; |
||
367 | * USHORT year : 7; */ |
||
368 | } _fdt; |
||
369 | } F_DATE_TIME, *PF_DATE_TIME; |
||
370 | |||
371 | |||
372 | #if defined(USE_EF_UT_TIME) || defined(TIMESTAMP) |
||
373 | |||
374 | static ulg Utime2DosDateTime(uxtime) |
||
375 | time_t uxtime; |
||
376 | { |
||
377 | F_DATE_TIME dosfiletime; |
||
378 | struct tm *t; |
||
379 | |||
380 | /* round up to even seconds */ |
||
381 | /* round up (down if "up" overflows) to even seconds */ |
||
382 | if (((ulg)uxtime) & 1) |
||
383 | uxtime = (uxtime + 1 > uxtime) ? uxtime + 1 : uxtime - 1; |
||
384 | |||
385 | t = localtime(&(uxtime)); |
||
386 | if (t == (struct tm *)NULL) { |
||
387 | /* time conversion error; use current time instead, hoping |
||
388 | that localtime() does not reject it as well! */ |
||
389 | time_t now = time(NULL); |
||
390 | t = localtime(&now); |
||
391 | } |
||
392 | if (t->tm_year < 80) { |
||
393 | dosfiletime._fdt.ft.twosecs = 0; |
||
394 | dosfiletime._fdt.ft.minutes = 0; |
||
395 | dosfiletime._fdt.ft.hours = 0; |
||
396 | dosfiletime._fdt.fd.day = 1; |
||
397 | dosfiletime._fdt.fd.month = 1; |
||
398 | dosfiletime._fdt.fd.year = 0; |
||
399 | } else { |
||
400 | dosfiletime._fdt.ft.twosecs = t->tm_sec >> 1; |
||
401 | dosfiletime._fdt.ft.minutes = t->tm_min; |
||
402 | dosfiletime._fdt.ft.hours = t->tm_hour; |
||
403 | dosfiletime._fdt.fd.day = t->tm_mday; |
||
404 | dosfiletime._fdt.fd.month = t->tm_mon + 1; |
||
405 | dosfiletime._fdt.fd.year = t->tm_year - 80; |
||
406 | } |
||
407 | return dosfiletime.timevalue; |
||
408 | |||
409 | } /* end function Utime2DosDateTime() */ |
||
410 | |||
411 | #endif /* USE_EF_UT_TIME || TIMESTAMP */ |
||
412 | |||
413 | |||
414 | static int getOS2filetimes(__GPRO__ ulg *pM_dt, ulg *pA_dt, ulg *pC_dt) |
||
415 | { |
||
416 | #ifdef USE_EF_UT_TIME |
||
417 | unsigned eb_izux_flg; |
||
418 | iztimes z_utime; |
||
419 | #endif |
||
420 | |||
421 | /* Copy and/or convert time and date variables, if necessary; */ |
||
422 | /* return a flag indicating which time stamps are available. */ |
||
423 | #ifdef USE_EF_UT_TIME |
||
424 | if (G.extra_field && |
||
425 | #ifdef IZ_CHECK_TZ |
||
426 | G.tz_is_valid && |
||
427 | #endif |
||
428 | ((eb_izux_flg = ef_scan_for_izux(G.extra_field, |
||
429 | G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime, |
||
430 | &z_utime, NULL)) & EB_UT_FL_MTIME)) |
||
431 | { |
||
432 | TTrace((stderr, "getOS2filetimes: UT e.f. modif. time = %lu\n", |
||
433 | z_utime.mtime)); |
||
434 | *pM_dt = Utime2DosDateTime(z_utime.mtime); |
||
435 | if (eb_izux_flg & EB_UT_FL_ATIME) { |
||
436 | TTrace((stderr, "getOS2filetimes: UT e.f. access time = %lu\n", |
||
437 | z_utime.atime)); |
||
438 | *pA_dt = Utime2DosDateTime(z_utime.atime); |
||
439 | } |
||
440 | if (eb_izux_flg & EB_UT_FL_CTIME) { |
||
441 | TTrace((stderr, "getOS2filetimes: UT e.f. creation time = %lu\n", |
||
442 | z_utime.ctime)); |
||
443 | *pC_dt = Utime2DosDateTime(z_utime.ctime); |
||
444 | } else { |
||
445 | /* no creation time value supplied, set it to modification time */ |
||
446 | *pC_dt = *pM_dt; |
||
447 | eb_izux_flg |= EB_UT_FL_CTIME; |
||
448 | } |
||
449 | return (int)eb_izux_flg; |
||
450 | } |
||
451 | #endif /* USE_EF_UT_TIME */ |
||
452 | *pC_dt = *pM_dt = G.lrec.last_mod_dos_datetime; |
||
453 | TTrace((stderr, "\ngetOS2filetimes: DOS dir modific./creation time = %lu\n", |
||
454 | *pM_dt)); |
||
455 | return (EB_UT_FL_MTIME | EB_UT_FL_CTIME); |
||
456 | } |
||
457 | |||
458 | |||
459 | static void SetPathAttrTimes(__GPRO__ int flags, int dir) |
||
460 | { |
||
461 | HFILE hFile; |
||
462 | #ifdef __32BIT__ |
||
463 | ULONG nAction; |
||
464 | #else |
||
465 | USHORT nAction; |
||
466 | #endif |
||
467 | FILESTATUS fs; |
||
468 | USHORT nLength; |
||
469 | char szName[CCHMAXPATH]; |
||
470 | ulg Mod_dt, Acc_dt, Cre_dt; |
||
471 | int gotTimes; |
||
472 | |||
473 | strcpy(szName, G.filename); |
||
474 | nLength = strlen(szName); |
||
475 | if (szName[nLength - 1] == '/') |
||
476 | szName[nLength - 1] = 0; |
||
477 | |||
478 | if (dir) |
||
479 | { |
||
480 | if ( DosQueryPathInfo(szName, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)) ) |
||
481 | return; |
||
482 | } |
||
483 | else |
||
484 | { |
||
485 | /* for regular files, open them and operate on the file handle, to |
||
486 | work around certain network operating system bugs ... */ |
||
487 | |||
488 | if ( DosOpen(szName, &hFile, &nAction, 0, 0, |
||
489 | OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW, |
||
490 | OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, 0) ) |
||
491 | return; |
||
492 | |||
493 | if ( DosQueryFileInfo(hFile, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)) ) |
||
494 | return; |
||
495 | } |
||
496 | |||
497 | if (uO.D_flag <= (dir ? 1 : 0)) { |
||
498 | /* set date/time stamps */ |
||
499 | gotTimes = getOS2filetimes(__G__ &Mod_dt, &Acc_dt, &Cre_dt); |
||
500 | if (gotTimes & EB_UT_FL_MTIME) { |
||
501 | fs.fdateLastWrite = ((F_DATE_TIME *)&Mod_dt)->_fdt.fd; |
||
502 | fs.ftimeLastWrite = ((F_DATE_TIME *)&Mod_dt)->_fdt.ft; |
||
503 | } |
||
504 | if (gotTimes & EB_UT_FL_ATIME) { |
||
505 | fs.fdateLastAccess = ((F_DATE_TIME *)&Acc_dt)->_fdt.fd; |
||
506 | fs.ftimeLastAccess = ((F_DATE_TIME *)&Acc_dt)->_fdt.ft; |
||
507 | } |
||
508 | if (gotTimes & EB_UT_FL_CTIME) { |
||
509 | fs.fdateCreation = ((F_DATE_TIME *)&Cre_dt)->_fdt.fd; |
||
510 | fs.ftimeCreation = ((F_DATE_TIME *)&Cre_dt)->_fdt.ft; |
||
511 | } |
||
512 | } |
||
513 | |||
514 | if ( flags != -1 ) |
||
515 | fs.attrFile = flags; /* hidden, system, archive, read-only */ |
||
516 | |||
517 | if (dir) |
||
518 | { |
||
519 | DosSetPathInfo(szName, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0); |
||
520 | } |
||
521 | else |
||
522 | { |
||
523 | DosSetFileInfo(hFile, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)); |
||
524 | DosClose(hFile); |
||
525 | } |
||
526 | } |
||
527 | |||
528 | |||
529 | typedef struct |
||
530 | { |
||
531 | ULONG cbList; /* length of value + 22 */ |
||
532 | #ifdef __32BIT__ |
||
533 | ULONG oNext; |
||
534 | #endif |
||
535 | BYTE fEA; /* 0 */ |
||
536 | BYTE cbName; /* length of ".LONGNAME" = 9 */ |
||
537 | USHORT cbValue; /* length of value + 4 */ |
||
538 | BYTE szName[10]; /* ".LONGNAME" */ |
||
539 | USHORT eaType; /* 0xFFFD for length-preceded ASCII */ |
||
540 | USHORT eaSize; /* length of value */ |
||
541 | BYTE szValue[CCHMAXPATH]; |
||
542 | } |
||
543 | FEALST; |
||
544 | |||
545 | |||
546 | static int SetEAs(__GPRO__ const char *path, void *ef_block) |
||
547 | { /* returns almost-PK errors */ |
||
548 | EFHEADER *pEAblock = (PEFHEADER) ef_block; |
||
549 | #ifdef __32BIT__ |
||
550 | EAOP2 eaop; |
||
551 | PFEA2LIST pFEA2list; |
||
552 | #else |
||
553 | EAOP eaop; |
||
554 | PFEALIST pFEAlist; |
||
555 | PFEA pFEA; |
||
556 | PFEA2LIST pFEA2list; |
||
557 | PFEA2 pFEA2; |
||
558 | ULONG nLength2; |
||
559 | #endif |
||
560 | USHORT nLength; |
||
561 | char szName[CCHMAXPATH]; |
||
562 | int error; |
||
563 | |||
564 | if ( ef_block == NULL || pEAblock -> nID != EF_OS2 ) |
||
565 | return PK_OK; /* not an OS/2 extra field: assume OK */ |
||
566 | |||
567 | if ( pEAblock->nSize < 4 || (pEAblock->lSize > 0L && pEAblock->nSize <= 10) ) |
||
568 | return IZ_EF_TRUNC; /* no compressed data! */ |
||
569 | |||
570 | strcpy(szName, path); |
||
571 | nLength = strlen(szName); |
||
572 | if (szName[nLength - 1] == '/') |
||
573 | szName[nLength - 1] = 0; |
||
574 | |||
575 | if ( (pFEA2list = (PFEA2LIST) malloc((size_t) pEAblock -> lSize)) == NULL ) |
||
576 | return PK_MEM4; |
||
577 | |||
578 | if ( (error = memextract(__G__ (uch *)pFEA2list, pEAblock->lSize, |
||
579 | (uch *)(pEAblock+1), (ulg)(pEAblock->nSize - 4))) != PK_OK ) |
||
580 | { |
||
581 | free(pFEA2list); |
||
582 | return error; |
||
583 | } |
||
584 | |||
585 | #ifdef __32BIT__ |
||
586 | eaop.fpGEA2List = NULL; |
||
587 | eaop.fpFEA2List = pFEA2list; |
||
588 | #else |
||
589 | pFEAlist = (PVOID) pFEA2list; |
||
590 | pFEA2 = pFEA2list -> list; |
||
591 | pFEA = pFEAlist -> list; |
||
592 | |||
593 | do |
||
594 | { |
||
595 | nLength2 = pFEA2 -> oNextEntryOffset; |
||
596 | nLength = sizeof(FEA) + pFEA2 -> cbName + 1 + pFEA2 -> cbValue; |
||
597 | |||
598 | memcpy(pFEA, (PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset), nLength); |
||
599 | |||
600 | pFEA2 = (PFEA2) ((PCH) pFEA2 + nLength2); |
||
601 | pFEA = (PFEA) ((PCH) pFEA + nLength); |
||
602 | } |
||
603 | while ( nLength2 != 0 ); |
||
604 | |||
605 | pFEAlist -> cbList = (PCH) pFEA - (PCH) pFEAlist; |
||
606 | |||
607 | eaop.fpGEAList = NULL; |
||
608 | eaop.fpFEAList = pFEAlist; |
||
609 | #endif |
||
610 | |||
611 | eaop.oError = 0; |
||
612 | DosSetPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &eaop, sizeof(eaop), 0); |
||
613 | |||
614 | if (!uO.tflag && QCOND2) |
||
615 | Info(slide, 0, ((char *)slide, " (%ld bytes EAs)", pFEA2list -> cbList)); |
||
616 | |||
617 | free(pFEA2list); |
||
618 | return PK_COOL; |
||
619 | } |
||
620 | |||
621 | |||
622 | static int SetACL(__GPRO__ const char *path, void *ef_block) |
||
623 | { /* returns almost-PK errors */ |
||
624 | EFHEADER *pACLblock = (PEFHEADER) ef_block; |
||
625 | char *szACL; |
||
626 | int error; |
||
627 | |||
628 | if ( ef_block == NULL || pACLblock -> nID != EF_ACL ) |
||
629 | return PK_OK; /* not an OS/2 extra field: assume OK */ |
||
630 | |||
631 | if (pACLblock->nSize < 4 || (pACLblock->lSize > 0L && pACLblock->nSize <= 10)) |
||
632 | return IZ_EF_TRUNC; /* no compressed data! */ |
||
633 | |||
634 | if ( (szACL = malloc((size_t) pACLblock -> lSize)) == NULL ) |
||
635 | return PK_MEM4; |
||
636 | |||
637 | if ( (error = memextract(__G__ (uch *)szACL, pACLblock->lSize, |
||
638 | (uch *)(pACLblock+1), (ulg)(pACLblock->nSize - 4))) != PK_OK ) |
||
639 | { |
||
640 | free(szACL); |
||
641 | return error; |
||
642 | } |
||
643 | |||
644 | if (acl_set(NULL, path, szACL) == 0) |
||
645 | if (!uO.tflag && QCOND2) |
||
646 | Info(slide, 0, ((char *)slide, " (%ld bytes ACL)", strlen(szACL))); |
||
647 | |||
648 | free(szACL); |
||
649 | return PK_COOL; |
||
650 | } |
||
651 | |||
652 | |||
653 | #ifdef SFX |
||
654 | |||
655 | char *GetLoadPath(__GPRO) |
||
656 | { |
||
657 | #ifdef __32BIT__ /* generic for 32-bit API */ |
||
658 | PTIB pptib; |
||
659 | PPIB pppib; |
||
660 | char *szPath; |
||
661 | |||
662 | DosGetInfoBlocks(&pptib, &pppib); |
||
663 | szPath = pppib -> pib_pchenv; |
||
664 | #else /* 16-bit, note: requires large data model */ |
||
665 | SEL selEnv; |
||
666 | USHORT offCmd; |
||
667 | char *szPath; |
||
668 | |||
669 | DosGetEnv(&selEnv, &offCmd); |
||
670 | szPath = MAKEP(selEnv, 0); |
||
671 | #endif |
||
672 | |||
673 | while (*szPath) /* find end of process environment */ |
||
674 | szPath = strchr(szPath, 0) + 1; |
||
675 | |||
676 | return szPath + 1; /* .exe file name follows environment */ |
||
677 | |||
678 | } /* end function GetLoadPath() */ |
||
679 | |||
680 | |||
681 | |||
682 | |||
683 | |||
684 | #else /* !SFX */ |
||
685 | |||
686 | DIR *opendir(__GPRO__ const char *name) |
||
687 | { |
||
688 | struct stat statb; |
||
689 | DIR *dirp; |
||
690 | char c; |
||
691 | char *s; |
||
692 | struct _dircontents *dp; |
||
693 | char nbuf[MAXPATHLEN + 1]; |
||
694 | int len; |
||
695 | |||
696 | strcpy(nbuf, name); |
||
697 | if ((len = strlen(nbuf)) == 0) |
||
698 | return NULL; |
||
699 | |||
700 | if ( ((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1) ) |
||
701 | { |
||
702 | nbuf[len - 1] = 0; |
||
703 | --len; |
||
704 | |||
705 | if ( nbuf[len - 1] == ':' ) |
||
706 | { |
||
707 | strcpy(nbuf+len, "\\."); |
||
708 | len += 2; |
||
709 | } |
||
710 | } |
||
711 | else |
||
712 | if ( nbuf[len - 1] == ':' ) |
||
713 | { |
||
714 | strcpy(nbuf+len, "."); |
||
715 | ++len; |
||
716 | } |
||
717 | |||
718 | /* GRR: Borland and Watcom C return non-zero on wildcards... < 0 ? */ |
||
719 | if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR) |
||
720 | { |
||
721 | Trace((stderr, "opendir: stat(%s) returns negative or not directory\n", |
||
722 | FnFilter1(nbuf))); |
||
723 | return NULL; |
||
724 | } |
||
725 | |||
726 | if ( (dirp = malloc(sizeof(DIR))) == NULL ) |
||
727 | return NULL; |
||
728 | |||
729 | if ( nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.') ) |
||
730 | strcpy(nbuf+len-1, "*"); |
||
731 | else |
||
732 | if ( ((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1) ) |
||
733 | strcpy(nbuf+len, "*"); |
||
734 | else |
||
735 | strcpy(nbuf+len, "\\*"); |
||
736 | |||
737 | /* len is no longer correct (but no longer needed) */ |
||
738 | Trace((stderr, "opendir: nbuf = [%s]\n", FnFilter1(nbuf))); |
||
739 | |||
740 | dirp -> dd_loc = 0; |
||
741 | dirp -> dd_contents = dirp -> dd_cp = NULL; |
||
742 | |||
743 | if ((s = getdirent(__G__ nbuf)) == NULL) |
||
744 | return dirp; |
||
745 | |||
746 | do |
||
747 | { |
||
748 | if (((dp = malloc(sizeof(struct _dircontents))) == NULL) || |
||
749 | ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL) ) |
||
750 | { |
||
751 | if (dp) |
||
752 | free(dp); |
||
753 | free_dircontents(dirp -> dd_contents); |
||
754 | |||
755 | return NULL; |
||
756 | } |
||
757 | |||
758 | if (dirp -> dd_contents) |
||
759 | { |
||
760 | dirp -> dd_cp -> _d_next = dp; |
||
761 | dirp -> dd_cp = dirp -> dd_cp -> _d_next; |
||
762 | } |
||
763 | else |
||
764 | dirp -> dd_contents = dirp -> dd_cp = dp; |
||
765 | |||
766 | strcpy(dp -> _d_entry, s); |
||
767 | dp -> _d_next = NULL; |
||
768 | |||
769 | dp -> _d_size = G.os2.find.cbFile; |
||
770 | dp -> _d_mode = G.os2.find.attrFile; |
||
771 | dp -> _d_time = *(unsigned *) &(G.os2.find.ftimeLastWrite); |
||
772 | dp -> _d_date = *(unsigned *) &(G.os2.find.fdateLastWrite); |
||
773 | } |
||
774 | while ((s = getdirent(__G__ NULL)) != NULL); |
||
775 | |||
776 | dirp -> dd_cp = dirp -> dd_contents; |
||
777 | |||
778 | return dirp; |
||
779 | } |
||
780 | |||
781 | |||
782 | void closedir(DIR * dirp) |
||
783 | { |
||
784 | free_dircontents(dirp -> dd_contents); |
||
785 | free(dirp); |
||
786 | } |
||
787 | |||
788 | |||
789 | struct direct *readdir(__GPRO__ DIR * dirp) |
||
790 | { |
||
791 | /* moved to os2data.h so it can be global */ |
||
792 | /* static struct direct dp; */ |
||
793 | |||
794 | if (dirp -> dd_cp == NULL) |
||
795 | return NULL; |
||
796 | |||
797 | G.os2.dp.d_namlen = G.os2.dp.d_reclen = |
||
798 | strlen(strcpy(G.os2.dp.d_name, dirp -> dd_cp -> _d_entry)); |
||
799 | |||
800 | G.os2.dp.d_ino = 0; |
||
801 | |||
802 | G.os2.dp.d_size = dirp -> dd_cp -> _d_size; |
||
803 | G.os2.dp.d_mode = dirp -> dd_cp -> _d_mode; |
||
804 | G.os2.dp.d_time = dirp -> dd_cp -> _d_time; |
||
805 | G.os2.dp.d_date = dirp -> dd_cp -> _d_date; |
||
806 | |||
807 | dirp -> dd_cp = dirp -> dd_cp -> _d_next; |
||
808 | dirp -> dd_loc++; |
||
809 | |||
810 | return &G.os2.dp; |
||
811 | } |
||
812 | |||
813 | |||
814 | |||
815 | #if 0 /* not used in unzip; retained for possibly future use */ |
||
816 | |||
817 | void seekdir(DIR * dirp, long off) |
||
818 | { |
||
819 | long i = off; |
||
820 | struct _dircontents *dp; |
||
821 | |||
822 | if (off >= 0) |
||
823 | { |
||
824 | for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next); |
||
825 | |||
826 | dirp -> dd_loc = off - (i + 1); |
||
827 | dirp -> dd_cp = dp; |
||
828 | } |
||
829 | } |
||
830 | |||
831 | |||
832 | long telldir(DIR * dirp) |
||
833 | { |
||
834 | return dirp -> dd_loc; |
||
835 | } |
||
836 | |||
837 | #endif /* 0 */ |
||
838 | |||
839 | |||
840 | |||
841 | static void free_dircontents(struct _dircontents * dp) |
||
842 | { |
||
843 | struct _dircontents *odp; |
||
844 | |||
845 | while (dp) |
||
846 | { |
||
847 | if (dp -> _d_entry) |
||
848 | free(dp -> _d_entry); |
||
849 | |||
850 | dp = (odp = dp) -> _d_next; |
||
851 | free(odp); |
||
852 | } |
||
853 | } |
||
854 | |||
855 | |||
856 | static char *getdirent(__GPRO__ ZCONST char *dir) |
||
857 | { |
||
858 | int done; |
||
859 | /* moved to os2data.h so it can be global */ |
||
860 | /* static int lower; */ |
||
861 | |||
862 | if (dir != NULL) |
||
863 | { /* get first entry */ |
||
864 | G.os2.hdir = HDIR_SYSTEM; |
||
865 | G.os2.count = 1; |
||
866 | done = DosFindFirst((PSZ) dir, &G.os2.hdir, attributes, |
||
867 | &G.os2.find, sizeof(G.os2.find), &G.os2.count); |
||
868 | G.os2.lower = IsFileSystemFAT(__G__ dir); |
||
869 | } |
||
870 | else /* get next entry */ |
||
871 | done = DosFindNext(G.os2.hdir, |
||
872 | &G.os2.find, sizeof(G.os2.find), &G.os2.count); |
||
873 | |||
874 | if (done == 0) |
||
875 | { |
||
876 | if ( G.os2.lower ) |
||
877 | StringLower(G.os2.find.achName); |
||
878 | return G.os2.find.achName; |
||
879 | } |
||
880 | else |
||
881 | { |
||
882 | DosFindClose(G.os2.hdir); |
||
883 | return NULL; |
||
884 | } |
||
885 | } |
||
886 | |||
887 | |||
888 | |||
889 | int IsFileSystemFAT(__GPRO__ ZCONST char *dir) /* FAT / HPFS detection */ |
||
890 | { |
||
891 | /* moved to os2data.h so they can be global */ |
||
892 | /* static USHORT nLastDrive=(USHORT)(-1), nResult; */ |
||
893 | ULONG lMap; |
||
894 | BYTE bData[64]; |
||
895 | char bName[3]; |
||
896 | #ifdef __32BIT__ |
||
897 | ULONG nDrive, cbData; |
||
898 | PFSQBUFFER2 pData = (PFSQBUFFER2) bData; |
||
899 | #else |
||
900 | USHORT nDrive, cbData; |
||
901 | PFSQBUFFER pData = (PFSQBUFFER) bData; |
||
902 | #endif |
||
903 | |||
904 | /* We separate FAT and HPFS+other file systems here. |
||
905 | at the moment I consider other systems to be similar to HPFS, |
||
906 | i.e. support long file names and case sensitive */ |
||
907 | |||
908 | if ( isalpha((uch)dir[0]) && (dir[1] == ':') ) |
||
909 | nDrive = toupper(dir[0]) - '@'; |
||
910 | else |
||
911 | DosQueryCurrentDisk(&nDrive, &lMap); |
||
912 | |||
913 | if ( nDrive == G.os2.nLastDrive ) |
||
914 | return G.os2.nResult; |
||
915 | |||
916 | bName[0] = (char) (nDrive + '@'); |
||
917 | bName[1] = ':'; |
||
918 | bName[2] = 0; |
||
919 | |||
920 | G.os2.nLastDrive = nDrive; |
||
921 | cbData = sizeof(bData); |
||
922 | |||
923 | if ( !DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData) ) |
||
924 | G.os2.nResult = !strcmp((char *) (pData -> szFSDName) + pData -> cbName, |
||
925 | "FAT"); |
||
926 | else |
||
927 | G.os2.nResult = FALSE; |
||
928 | |||
929 | /* End of this ugly code */ |
||
930 | return G.os2.nResult; |
||
931 | } /* end function IsFileSystemFAT() */ |
||
932 | |||
933 | |||
934 | |||
935 | |||
936 | |||
937 | /************************/ |
||
938 | /* Function do_wild() */ |
||
939 | /************************/ |
||
940 | |||
941 | char *do_wild(__G__ wildspec) |
||
942 | __GDEF |
||
943 | ZCONST char *wildspec; /* only used first time on a given dir */ |
||
944 | { |
||
945 | /* moved to os2data.h so they can be global */ |
||
946 | #if 0 |
||
947 | static DIR *wild_dir = NULL; |
||
948 | static ZCONST char *wildname; |
||
949 | static char *dirname, matchname[FILNAMSIZ]; |
||
950 | static int notfirstcall=FALSE, have_dirname, dirnamelen; |
||
951 | #endif |
||
952 | char *fnamestart; |
||
953 | struct direct *file; |
||
954 | |||
955 | /* Even when we're just returning wildspec, we *always* do so in |
||
956 | * matchname[]--calling routine is allowed to append four characters |
||
957 | * to the returned string, and wildspec may be a pointer to argv[]. |
||
958 | */ |
||
959 | if (!G.os2.notfirstcall) { /* first call: must initialize everything */ |
||
960 | G.os2.notfirstcall = TRUE; |
||
961 | |||
962 | if (!iswild(wildspec)) { |
||
963 | strncpy(G.os2.matchname, wildspec, FILNAMSIZ); |
||
964 | G.os2.matchname[FILNAMSIZ-1] = '\0'; |
||
965 | G.os2.have_dirname = FALSE; |
||
966 | G.os2.wild_dir = NULL; |
||
967 | return G.os2.matchname; |
||
968 | } |
||
969 | |||
970 | /* break the wildspec into a directory part and a wildcard filename */ |
||
971 | if ((G.os2.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL && |
||
972 | (G.os2.wildname = (ZCONST char *)strrchr(wildspec, ':')) == NULL) { |
||
973 | G.os2.dirname = "."; |
||
974 | G.os2.dirnamelen = 1; |
||
975 | G.os2.have_dirname = FALSE; |
||
976 | G.os2.wildname = wildspec; |
||
977 | } else { |
||
978 | ++G.os2.wildname; /* point at character after '/' or ':' */ |
||
979 | G.os2.dirnamelen = G.os2.wildname - wildspec; |
||
980 | if ((G.os2.dirname = (char *)malloc(G.os2.dirnamelen+1)) == NULL) { |
||
981 | Info(slide, 1, ((char *)slide, |
||
982 | LoadFarString(CantAllocateWildcard))); |
||
983 | strncpy(G.os2.matchname, wildspec, FILNAMSIZ); |
||
984 | G.os2.matchname[FILNAMSIZ-1] = '\0'; |
||
985 | return G.os2.matchname; /* but maybe filespec was not a wildcard */ |
||
986 | } |
||
987 | strncpy(G.os2.dirname, wildspec, G.os2.dirnamelen); |
||
988 | G.os2.dirname[G.os2.dirnamelen] = '\0'; /* terminate for strcpy below */ |
||
989 | G.os2.have_dirname = TRUE; |
||
990 | } |
||
991 | Trace((stderr, "do_wild: dirname = [%s]\n", |
||
992 | FnFilter1(G.os2.dirname))); |
||
993 | |||
994 | if ((G.os2.wild_dir = opendir(__G__ G.os2.dirname)) != NULL) { |
||
995 | if (G.os2.have_dirname) { |
||
996 | strcpy(G.os2.matchname, G.os2.dirname); |
||
997 | fnamestart = G.os2.matchname + G.os2.dirnamelen; |
||
998 | } else |
||
999 | fnamestart = G.os2.matchname; |
||
1000 | while ((file = readdir(__G__ G.os2.wild_dir)) != NULL) { |
||
1001 | Trace((stderr, "do_wild: readdir returns %s\n", |
||
1002 | FnFilter1(file->d_name))); |
||
1003 | strcpy(fnamestart, file->d_name); |
||
1004 | if (strrchr(fnamestart, '.') == (char *)NULL) |
||
1005 | strcat(fnamestart, "."); |
||
1006 | if (match(fnamestart, G.os2.wildname, 1 WISEP) && |
||
1007 | /* 1 == ignore case */ |
||
1008 | /* skip "." and ".." directory entries */ |
||
1009 | strcmp(fnamestart, ".") && strcmp(fnamestart, "..")) { |
||
1010 | Trace((stderr, "do_wild: match() succeeds\n")); |
||
1011 | /* remove trailing dot */ |
||
1012 | fnamestart += strlen(fnamestart) - 1; |
||
1013 | if (*fnamestart == '.') |
||
1014 | *fnamestart = '\0'; |
||
1015 | return G.os2.matchname; |
||
1016 | } |
||
1017 | } |
||
1018 | /* if we get to here directory is exhausted, so close it */ |
||
1019 | closedir(G.os2.wild_dir); |
||
1020 | G.os2.wild_dir = NULL; |
||
1021 | } |
||
1022 | #ifdef DEBUG |
||
1023 | else { |
||
1024 | Trace((stderr, "do_wild: opendir(%s) returns NULL\n", |
||
1025 | FnFilter1(G.os2.dirname))); |
||
1026 | } |
||
1027 | #endif /* DEBUG */ |
||
1028 | |||
1029 | /* return the raw wildspec in case that works (e.g., directory not |
||
1030 | * searchable, but filespec was not wild and file is readable) */ |
||
1031 | strncpy(G.os2.matchname, wildspec, FILNAMSIZ); |
||
1032 | G.os2.matchname[FILNAMSIZ-1] = '\0'; |
||
1033 | return G.os2.matchname; |
||
1034 | } |
||
1035 | |||
1036 | /* last time through, might have failed opendir but returned raw wildspec */ |
||
1037 | if (G.os2.wild_dir == NULL) { |
||
1038 | G.os2.notfirstcall = FALSE; /* nothing left to try--reset */ |
||
1039 | if (G.os2.have_dirname) |
||
1040 | free(G.os2.dirname); |
||
1041 | return (char *)NULL; |
||
1042 | } |
||
1043 | |||
1044 | /* If we've gotten this far, we've read and matched at least one entry |
||
1045 | * successfully (in a previous call), so dirname has been copied into |
||
1046 | * matchname already. |
||
1047 | */ |
||
1048 | if (G.os2.have_dirname) { |
||
1049 | /* strcpy(G.os2.matchname, G.os2.dirname); */ |
||
1050 | fnamestart = G.os2.matchname + G.os2.dirnamelen; |
||
1051 | } else |
||
1052 | fnamestart = G.os2.matchname; |
||
1053 | while ((file = readdir(__G__ G.os2.wild_dir)) != NULL) { |
||
1054 | Trace((stderr, "do_wild: readdir returns %s\n", |
||
1055 | FnFilter1(file->d_name))); |
||
1056 | strcpy(fnamestart, file->d_name); |
||
1057 | if (strrchr(fnamestart, '.') == (char *)NULL) |
||
1058 | strcat(fnamestart, "."); |
||
1059 | if (match(fnamestart, G.os2.wildname, 1 WISEP)) { /* 1==ignore case */ |
||
1060 | Trace((stderr, "do_wild: match() succeeds\n")); |
||
1061 | /* remove trailing dot */ |
||
1062 | fnamestart += strlen(fnamestart) - 1; |
||
1063 | if (*fnamestart == '.') |
||
1064 | *fnamestart = '\0'; |
||
1065 | return G.os2.matchname; |
||
1066 | } |
||
1067 | } |
||
1068 | |||
1069 | closedir(G.os2.wild_dir); /* have read at least one entry; nothing left */ |
||
1070 | G.os2.wild_dir = NULL; |
||
1071 | G.os2.notfirstcall = FALSE; /* reset for new wildspec */ |
||
1072 | if (G.os2.have_dirname) |
||
1073 | free(G.os2.dirname); |
||
1074 | return (char *)NULL; |
||
1075 | |||
1076 | } /* end function do_wild() */ |
||
1077 | |||
1078 | #endif /* !SFX */ |
||
1079 | |||
1080 | |||
1081 | /* scan extra fields for something we happen to know */ |
||
1082 | |||
1083 | static int EvalExtraFields(__GPRO__ const char *path, |
||
1084 | void *extra_field, unsigned ef_len) |
||
1085 | { |
||
1086 | char *ef_ptr = extra_field; |
||
1087 | PEFHEADER pEFblock; |
||
1088 | int rc = PK_OK; |
||
1089 | |||
1090 | while (ef_len >= sizeof(EFHEADER)) |
||
1091 | { |
||
1092 | pEFblock = (PEFHEADER) ef_ptr; |
||
1093 | |||
1094 | if (pEFblock -> nSize > (ef_len - EB_HEADSIZE)) |
||
1095 | return PK_ERR; /* claimed EFblock length exceeds EF size! */ |
||
1096 | |||
1097 | switch (pEFblock -> nID) |
||
1098 | { |
||
1099 | case EF_OS2: |
||
1100 | rc = SetEAs(__G__ path, ef_ptr); |
||
1101 | break; |
||
1102 | case EF_ACL: |
||
1103 | rc = (uO.X_flag) ? SetACL(__G__ path, ef_ptr) : PK_OK; |
||
1104 | break; |
||
1105 | #if 0 |
||
1106 | case EF_IZUNIX: |
||
1107 | case EF_PKUNIX: |
||
1108 | /* handled elsewhere */ |
||
1109 | break; |
||
1110 | #endif |
||
1111 | default: |
||
1112 | TTrace((stderr,"EvalExtraFields: unknown extra field block, ID=%d\n", |
||
1113 | pEFblock -> nID)); |
||
1114 | break; |
||
1115 | } |
||
1116 | |||
1117 | ef_ptr += (pEFblock -> nSize + EB_HEADSIZE); |
||
1118 | ef_len -= (pEFblock -> nSize + EB_HEADSIZE); |
||
1119 | |||
1120 | if (rc != PK_OK) |
||
1121 | break; |
||
1122 | } |
||
1123 | |||
1124 | return rc; |
||
1125 | } |
||
1126 | |||
1127 | |||
1128 | |||
1129 | /************************/ |
||
1130 | /* Function mapattr() */ |
||
1131 | /************************/ |
||
1132 | |||
1133 | int mapattr(__G) |
||
1134 | __GDEF |
||
1135 | { |
||
1136 | /* set archive bit (file is not backed up): */ |
||
1137 | G.pInfo->file_attr = (unsigned)(G.crec.external_file_attributes | 32) & 0xff; |
||
1138 | return 0; |
||
1139 | } |
||
1140 | |||
1141 | |||
1142 | |||
1143 | |||
1144 | |||
1145 | /************************/ |
||
1146 | /* Function mapname() */ |
||
1147 | /************************/ |
||
1148 | |||
1149 | /* |
||
1150 | * There are presently two possibilities in OS/2: the output filesystem is |
||
1151 | * FAT, or it is HPFS. If the former, we need to map to FAT, obviously, but |
||
1152 | * we *also* must map to HPFS and store that version of the name in extended |
||
1153 | * attributes. Either way, we need to map to HPFS, so the main mapname |
||
1154 | * routine does that. In the case that the output file system is FAT, an |
||
1155 | * extra filename-mapping routine is called in checkdir(). While it should |
||
1156 | * be possible to determine the filesystem immediately upon entry to mapname(), |
||
1157 | * it is conceivable that the DOS APPEND utility could be added to OS/2 some- |
||
1158 | * day, allowing a FAT directory to be APPENDed to an HPFS drive/path. There- |
||
1159 | * fore we simply check the filesystem at each path component. |
||
1160 | * |
||
1161 | * Note that when alternative IFSes become available/popular, everything will |
||
1162 | * become immensely more complicated. For example, a Minix filesystem would |
||
1163 | * have limited filename lengths like FAT but no extended attributes in which |
||
1164 | * to store the longer versions of the names. A BSD Unix filesystem would |
||
1165 | * support paths of length 1024 bytes or more, but it is not clear that FAT |
||
1166 | * EAs would allow such long .LONGNAME fields or that OS/2 would properly |
||
1167 | * restore such fields when moving files from FAT to the new filesystem. |
||
1168 | * |
||
1169 | * GRR: some or all of the following chars should be checked in either |
||
1170 | * mapname (HPFS) or map2fat (FAT), depending: ,=^+'"[]<>|\t& |
||
1171 | */ |
||
1172 | int mapname(__G__ renamed) |
||
1173 | __GDEF |
||
1174 | int renamed; |
||
1175 | /* |
||
1176 | * returns: |
||
1177 | * MPN_OK - no problem detected |
||
1178 | * MPN_INF_TRUNC - caution (truncated filename) |
||
1179 | * MPN_INF_SKIP - info "skip entry" (dir doesn't exist) |
||
1180 | * MPN_ERR_SKIP - error -> skip entry |
||
1181 | * MPN_ERR_TOOLONG - error -> path is too long |
||
1182 | * MPN_NOMEM - error (memory allocation failed) -> skip entry |
||
1183 | * [also MPN_VOL_LABEL, MPN_CREATED_DIR] |
||
1184 | */ |
||
1185 | { |
||
1186 | char pathcomp[FILNAMSIZ]; /* path-component buffer */ |
||
1187 | char *pp, *cp=(char *)NULL; /* character pointers */ |
||
1188 | char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */ |
||
1189 | #ifdef ACORN_FTYPE_NFS |
||
1190 | char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */ |
||
1191 | RO_extra_block *ef_spark; /* pointer Acorn FTYPE ef block */ |
||
1192 | #endif |
||
1193 | int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */ |
||
1194 | int error = MPN_OK; |
||
1195 | register unsigned workch; /* hold the character being tested */ |
||
1196 | |||
1197 | |||
1198 | /*--------------------------------------------------------------------------- |
||
1199 | Initialize various pointers and counters and stuff. |
||
1200 | ---------------------------------------------------------------------------*/ |
||
1201 | |||
1202 | /* can create path as long as not just freshening, or if user told us */ |
||
1203 | G.create_dirs = (!uO.fflag || renamed); |
||
1204 | |||
1205 | G.os2.created_dir = FALSE; /* not yet */ |
||
1206 | G.os2.renamed_fullpath = FALSE; |
||
1207 | G.os2.fnlen = strlen(G.filename); |
||
1208 | |||
1209 | /* GRR: for VMS, convert to internal format now or later? or never? */ |
||
1210 | if (renamed) { |
||
1211 | cp = G.filename - 1; /* point to beginning of renamed name... */ |
||
1212 | while (*++cp) |
||
1213 | if (*cp == '\\') /* convert backslashes to forward */ |
||
1214 | *cp = '/'; |
||
1215 | cp = G.filename; |
||
1216 | /* use temporary rootpath if user gave full pathname */ |
||
1217 | if (G.filename[0] == '/') { |
||
1218 | G.os2.renamed_fullpath = TRUE; |
||
1219 | pathcomp[0] = '/'; /* copy the '/' and terminate */ |
||
1220 | pathcomp[1] = '\0'; |
||
1221 | ++cp; |
||
1222 | } else if (isalpha((uch)G.filename[0]) && G.filename[1] == ':') { |
||
1223 | G.os2.renamed_fullpath = TRUE; |
||
1224 | pp = pathcomp; |
||
1225 | *pp++ = *cp++; /* copy the "d:" (+ '/', possibly) */ |
||
1226 | *pp++ = *cp++; |
||
1227 | if (*cp == '/') |
||
1228 | *pp++ = *cp++; /* otherwise add "./"? */ |
||
1229 | *pp = '\0'; |
||
1230 | } |
||
1231 | } |
||
1232 | |||
1233 | /* pathcomp is ignored unless renamed_fullpath is TRUE: */ |
||
1234 | if ((error = checkdir(__G__ pathcomp, INIT)) != 0) /* init path buffer */ |
||
1235 | return error; /* ...unless no mem or vol label on hard disk */ |
||
1236 | |||
1237 | *pathcomp = '\0'; /* initialize translation buffer */ |
||
1238 | pp = pathcomp; /* point to translation buffer */ |
||
1239 | if (!renamed) { /* cp already set if renamed */ |
||
1240 | if (uO.jflag) /* junking directories */ |
||
1241 | /* GRR: watch out for VMS version... */ |
||
1242 | cp = (char *)strrchr(G.filename, '/'); |
||
1243 | if (cp == (char *)NULL) /* no '/' or not junking dirs */ |
||
1244 | cp = G.filename; /* point to internal zipfile-member pathname */ |
||
1245 | else |
||
1246 | ++cp; /* point to start of last component of path */ |
||
1247 | } |
||
1248 | |||
1249 | /*--------------------------------------------------------------------------- |
||
1250 | Begin main loop through characters in filename. |
||
1251 | ---------------------------------------------------------------------------*/ |
||
1252 | |||
1253 | while ((workch = (uch)*cp++) != 0) { |
||
1254 | |||
1255 | switch (workch) { |
||
1256 | case '/': /* can assume -j flag not given */ |
||
1257 | *pp = '\0'; |
||
1258 | if (strcmp(pathcomp, ".") == 0) { |
||
1259 | /* don't bother appending "./" to the path */ |
||
1260 | *pathcomp = '\0'; |
||
1261 | } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) { |
||
1262 | /* "../" dir traversal detected, skip over it */ |
||
1263 | *pathcomp = '\0'; |
||
1264 | killed_ddot = TRUE; /* set "show message" flag */ |
||
1265 | } |
||
1266 | /* when path component is not empty, append it now */ |
||
1267 | if (*pathcomp != '\0' && |
||
1268 | ((error = checkdir(__G__ pathcomp, APPEND_DIR)) |
||
1269 | & MPN_MASK) > MPN_INF_TRUNC) |
||
1270 | return error; |
||
1271 | pp = pathcomp; /* reset conversion buffer for next piece */ |
||
1272 | lastsemi = (char *)NULL; /* leave direct. semi-colons alone */ |
||
1273 | break; |
||
1274 | |||
1275 | case ':': /* drive never stored, so no colon allowed */ |
||
1276 | case '\\': /* "non-dos" FSs may allow '\\' as normal */ |
||
1277 | *pp++ = '_'; /* character in filenames */ |
||
1278 | break; /* -> map invalid chars to underscore */ |
||
1279 | |||
1280 | case ';': /* start of VMS version? */ |
||
1281 | lastsemi = pp; /* remove VMS version later... */ |
||
1282 | *pp++ = ';'; /* but keep semicolon for now */ |
||
1283 | break; |
||
1284 | |||
1285 | #ifdef ACORN_FTYPE_NFS |
||
1286 | case ',': /* NFS filetype extension */ |
||
1287 | lastcomma = pp; |
||
1288 | *pp++ = ','; /* keep for now; may need to remove */ |
||
1289 | break; /* later, if requested */ |
||
1290 | #endif |
||
1291 | |||
1292 | case ' ': /* keep spaces unless specifically */ |
||
1293 | if (uO.sflag) /* requested to change to underscore */ |
||
1294 | *pp++ = '_'; |
||
1295 | else |
||
1296 | *pp++ = ' '; |
||
1297 | break; |
||
1298 | |||
1299 | default: |
||
1300 | /* allow ASCII 255 and European characters in filenames: */ |
||
1301 | if (isprint(workch) || workch >= 127) |
||
1302 | *pp++ = (char)workch; |
||
1303 | } /* end switch */ |
||
1304 | |||
1305 | } /* end while loop */ |
||
1306 | |||
1307 | /* Show warning when stripping insecure "parent dir" path components */ |
||
1308 | if (killed_ddot && QCOND2) { |
||
1309 | Info(slide, 0, ((char *)slide, LoadFarString(WarnDirTraversSkip), |
||
1310 | FnFilter1(G.filename))); |
||
1311 | if (!(error & ~MPN_MASK)) |
||
1312 | error = (error & MPN_MASK) | PK_WARN; |
||
1313 | } |
||
1314 | |||
1315 | /*--------------------------------------------------------------------------- |
||
1316 | Report if directory was created (and no file to create: filename ended |
||
1317 | in '/'), check name to be sure it exists, and combine path and name be- |
||
1318 | fore exiting. |
||
1319 | ---------------------------------------------------------------------------*/ |
||
1320 | |||
1321 | if (G.filename[G.os2.fnlen-1] == '/') { |
||
1322 | checkdir(__G__ G.filename, GETPATH); |
||
1323 | if (G.os2.created_dir) { |
||
1324 | if (QCOND2) |
||
1325 | Info(slide, 0, ((char *)slide, LoadFarString(Creating), |
||
1326 | FnFilter1(G.filename))); |
||
1327 | if (G.extra_field) { /* zipfile extra field has extended attribs */ |
||
1328 | int err = EvalExtraFields(__G__ G.filename, G.extra_field, |
||
1329 | G.lrec.extra_field_length); |
||
1330 | |||
1331 | if (err == IZ_EF_TRUNC) { |
||
1332 | if (uO.qflag) |
||
1333 | Info(slide, 1, ((char *)slide, "%-22s ", |
||
1334 | FnFilter1(G.filename))); |
||
1335 | Info(slide, 1, ((char *)slide, LoadFarString(TruncEAs), |
||
1336 | makeword(G.extra_field+2)-10, "\n")); |
||
1337 | } else if (!uO.qflag) |
||
1338 | (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); |
||
1339 | } else if (!uO.qflag) |
||
1340 | (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); |
||
1341 | |||
1342 | /* set date/time stamps */ |
||
1343 | SetPathAttrTimes(__G__ G.pInfo->file_attr & ~A_ARCHIVE, 1); |
||
1344 | |||
1345 | /* dir time already set */ |
||
1346 | return (error & ~MPN_MASK) | MPN_CREATED_DIR; |
||
1347 | |||
1348 | } else if (G.extra_field && IS_OVERWRT_ALL) { |
||
1349 | /* overwrite EAs of existing directory since user requested it */ |
||
1350 | int err = EvalExtraFields(__G__ G.filename, G.extra_field, |
||
1351 | G.lrec.extra_field_length); |
||
1352 | |||
1353 | if (err == IZ_EF_TRUNC) { |
||
1354 | Info(slide, 0x421, ((char *)slide, "%-22s ", |
||
1355 | FnFilter1(G.filename))); |
||
1356 | Info(slide, 0x401, ((char *)slide, LoadFarString(TruncEAs), |
||
1357 | makeword(G.extra_field+2)-10, "\n")); |
||
1358 | } |
||
1359 | |||
1360 | /* set date/time stamps (dirs only have creation times) */ |
||
1361 | SetPathAttrTimes(__G__ G.pInfo->file_attr & ~A_ARCHIVE, 1); |
||
1362 | } |
||
1363 | /* dir existed already; don't look for data to extract */ |
||
1364 | return (error & ~MPN_MASK) | MPN_INF_SKIP; |
||
1365 | } |
||
1366 | |||
1367 | *pp = '\0'; /* done with pathcomp: terminate it */ |
||
1368 | |||
1369 | /* if not saving them, remove VMS version numbers (appended "###") */ |
||
1370 | if (!uO.V_flag && lastsemi) { |
||
1371 | pp = lastsemi + 1; /* semi-colon was kept: expect #s after */ |
||
1372 | while (isdigit((uch)(*pp))) |
||
1373 | ++pp; |
||
1374 | if (*pp == '\0') /* only digits between ';' and end: nuke */ |
||
1375 | *lastsemi = '\0'; |
||
1376 | } |
||
1377 | |||
1378 | #ifdef ACORN_FTYPE_NFS |
||
1379 | /* translate Acorn filetype information if asked to do so */ |
||
1380 | if (uO.acorn_nfs_ext && |
||
1381 | (ef_spark = (RO_extra_block *) |
||
1382 | getRISCOSexfield(G.extra_field, G.lrec.extra_field_length)) |
||
1383 | != (RO_extra_block *)NULL) |
||
1384 | { |
||
1385 | /* file *must* have a RISC OS extra field */ |
||
1386 | long ft = (long)makelong(ef_spark->loadaddr); |
||
1387 | /*32-bit*/ |
||
1388 | if (lastcomma) { |
||
1389 | pp = lastcomma + 1; |
||
1390 | while (isxdigit((uch)(*pp))) ++pp; |
||
1391 | if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */ |
||
1392 | } |
||
1393 | if ((ft & 1<<31)==0) ft=0x000FFD00; |
||
1394 | sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF); |
||
1395 | } |
||
1396 | #endif /* ACORN_FTYPE_NFS */ |
||
1397 | |||
1398 | if (*pathcomp == '\0') { |
||
1399 | Info(slide, 1, ((char *)slide, LoadFarString(ConversionFailed), |
||
1400 | FnFilter1(G.filename))); |
||
1401 | return (error & ~MPN_MASK) | MPN_ERR_SKIP; |
||
1402 | } |
||
1403 | |||
1404 | checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */ |
||
1405 | checkdir(__G__ G.filename, GETPATH); |
||
1406 | Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n", |
||
1407 | FnFilter1(G.filename), error)); |
||
1408 | |||
1409 | if (G.pInfo->vollabel) { /* set the volume label now */ |
||
1410 | VOLUMELABEL FSInfoBuf; |
||
1411 | /* GRR: "VOLUMELABEL" defined for IBM C and emx, but haven't checked MSC... */ |
||
1412 | |||
1413 | strcpy(FSInfoBuf.szVolLabel, G.filename); |
||
1414 | FSInfoBuf.cch = (BYTE)strlen(FSInfoBuf.szVolLabel); |
||
1415 | |||
1416 | if (!uO.qflag) |
||
1417 | Info(slide, 0, ((char *)slide, LoadFarString(Labelling), |
||
1418 | (char)(G.os2.nLabelDrive + 'a' - 1), FnFilter1(G.filename))); |
||
1419 | if (DosSetFSInfo(G.os2.nLabelDrive, FSIL_VOLSER, (PBYTE)&FSInfoBuf, |
||
1420 | sizeof(VOLUMELABEL))) |
||
1421 | { |
||
1422 | Info(slide, 1, ((char *)slide, LoadFarString(ErrSetVolLabel))); |
||
1423 | return (error & ~MPN_MASK) | MPN_ERR_SKIP; |
||
1424 | } |
||
1425 | /* success: skip the "extraction" quietly */ |
||
1426 | return (error & ~MPN_MASK) | MPN_INF_SKIP; |
||
1427 | } |
||
1428 | |||
1429 | return error; |
||
1430 | |||
1431 | } /* end function mapname() */ |
||
1432 | |||
1433 | |||
1434 | |||
1435 | |||
1436 | |||
1437 | /***********************/ |
||
1438 | /* Function checkdir() */ |
||
1439 | /***********************/ |
||
1440 | |||
1441 | int checkdir(__G__ pathcomp, flag) |
||
1442 | __GDEF |
||
1443 | char *pathcomp; |
||
1444 | int flag; |
||
1445 | /* |
||
1446 | * returns: |
||
1447 | * MPN_OK - no problem detected |
||
1448 | * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename |
||
1449 | * MPN_INF_SKIP - path doesn't exist, not allowed to create |
||
1450 | * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path |
||
1451 | * exists and is not a directory, but is supposed to be |
||
1452 | * MPN_ERR_TOOLONG - path is too long |
||
1453 | * MPN_NOMEM - can't allocate memory for filename buffers |
||
1454 | */ |
||
1455 | { |
||
1456 | /* moved to os2data.h so they can be global */ |
||
1457 | #if 0 |
||
1458 | static int rootlen = 0; /* length of rootpath */ |
||
1459 | static char *rootpath; /* user's "extract-to" directory */ |
||
1460 | static char *buildpathHPFS; /* full path (so far) to extracted file, */ |
||
1461 | static char *buildpathFAT; /* both HPFS/EA (main) and FAT versions */ |
||
1462 | static char *endHPFS; /* corresponding pointers to end of */ |
||
1463 | static char *endFAT; /* buildpath ('\0') */ |
||
1464 | #endif |
||
1465 | |||
1466 | # define FN_MASK 7 |
||
1467 | # define FUNCTION (flag & FN_MASK) |
||
1468 | |||
1469 | |||
1470 | |||
1471 | /*--------------------------------------------------------------------------- |
||
1472 | APPEND_DIR: append the path component to the path being built and check |
||
1473 | for its existence. If doesn't exist and we are creating directories, do |
||
1474 | so for this one; else signal success or error as appropriate. |
||
1475 | ---------------------------------------------------------------------------*/ |
||
1476 | |||
1477 | if (FUNCTION == APPEND_DIR) { |
||
1478 | char *p = pathcomp; |
||
1479 | int longdirEA, too_long=FALSE; |
||
1480 | |||
1481 | Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp))); |
||
1482 | while ((*G.os2.endHPFS = *p++) != '\0') /* copy to HPFS filename */ |
||
1483 | ++G.os2.endHPFS; |
||
1484 | if (IsFileNameValid(G.os2.buildpathHPFS)) { |
||
1485 | longdirEA = FALSE; |
||
1486 | p = pathcomp; |
||
1487 | while ((*G.os2.endFAT = *p++) != '\0') /* copy to FAT filename, too */ |
||
1488 | ++G.os2.endFAT; |
||
1489 | } else { |
||
1490 | longdirEA = TRUE; |
||
1491 | /* GRR: check error return? */ |
||
1492 | map2fat(pathcomp, &G.os2.endFAT); /* map, put in FAT fn, update endFAT */ |
||
1493 | } |
||
1494 | |||
1495 | /* GRR: could do better check, see if overrunning buffer as we go: |
||
1496 | * check endHPFS-G.os2.buildpathHPFS after each append, set warning variable |
||
1497 | * if within 20 of FILNAMSIZ; then if var set, do careful check when |
||
1498 | * appending. Clear variable when begin new path. */ |
||
1499 | |||
1500 | /* next check: need to append '/', at least one-char name, '\0' */ |
||
1501 | if ((G.os2.endHPFS-G.os2.buildpathHPFS) > FILNAMSIZ-3) |
||
1502 | too_long = TRUE; /* check if extracting dir? */ |
||
1503 | #ifdef MSC /* MSC 6.00 bug: stat(non-existent-dir) == 0 [exists!] */ |
||
1504 | if (GetFileTime(G.os2.buildpathFAT) == -1 || stat(G.os2.buildpathFAT, &G.statbuf)) |
||
1505 | #else |
||
1506 | if (stat(G.os2.buildpathFAT, &G.statbuf)) /* path doesn't exist */ |
||
1507 | #endif |
||
1508 | { |
||
1509 | if (!G.create_dirs) { /* told not to create (freshening) */ |
||
1510 | free(G.os2.buildpathHPFS); |
||
1511 | free(G.os2.buildpathFAT); |
||
1512 | /* path doesn't exist: nothing to do */ |
||
1513 | return MPN_INF_SKIP; |
||
1514 | } |
||
1515 | if (too_long) { /* GRR: should allow FAT extraction w/o EAs */ |
||
1516 | Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong), |
||
1517 | FnFilter1(G.os2.buildpathHPFS))); |
||
1518 | free(G.os2.buildpathHPFS); |
||
1519 | free(G.os2.buildpathFAT); |
||
1520 | /* no room for filenames: fatal */ |
||
1521 | return MPN_ERR_TOOLONG; |
||
1522 | } |
||
1523 | if (MKDIR(G.os2.buildpathFAT, 0777) == -1) { /* create the directory */ |
||
1524 | Info(slide, 1, ((char *)slide, LoadFarString(CantCreateDir), |
||
1525 | FnFilter2(G.os2.buildpathFAT), FnFilter1(G.filename))); |
||
1526 | free(G.os2.buildpathHPFS); |
||
1527 | free(G.os2.buildpathFAT); |
||
1528 | /* path didn't exist, tried to create, failed */ |
||
1529 | return MPN_ERR_SKIP; |
||
1530 | } |
||
1531 | G.os2.created_dir = TRUE; |
||
1532 | /* only set EA if creating directory */ |
||
1533 | /* GRR: need trailing '/' before function call? */ |
||
1534 | if (longdirEA) { |
||
1535 | #ifdef DEBUG |
||
1536 | int e = |
||
1537 | #endif |
||
1538 | SetLongNameEA(G.os2.buildpathFAT, pathcomp); |
||
1539 | Trace((stderr, "APPEND_DIR: SetLongNameEA() returns %d\n", e)); |
||
1540 | } |
||
1541 | } else if (!S_ISDIR(G.statbuf.st_mode)) { |
||
1542 | Info(slide, 1, ((char *)slide, LoadFarString(DirIsntDirectory), |
||
1543 | FnFilter2(G.os2.buildpathFAT), FnFilter1(G.filename))); |
||
1544 | free(G.os2.buildpathHPFS); |
||
1545 | free(G.os2.buildpathFAT); |
||
1546 | /* path existed but wasn't dir */ |
||
1547 | return MPN_ERR_SKIP; |
||
1548 | } |
||
1549 | if (too_long) { |
||
1550 | Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong), |
||
1551 | FnFilter1(G.os2.buildpathHPFS))); |
||
1552 | free(G.os2.buildpathHPFS); |
||
1553 | free(G.os2.buildpathFAT); |
||
1554 | /* no room for filenames: fatal */ |
||
1555 | return MPN_ERR_TOOLONG; |
||
1556 | } |
||
1557 | *G.os2.endHPFS++ = '/'; |
||
1558 | *G.os2.endFAT++ = '/'; |
||
1559 | *G.os2.endHPFS = *G.os2.endFAT = '\0'; |
||
1560 | Trace((stderr, "buildpathHPFS now = [%s]\n", |
||
1561 | FnFilter1(G.os2.buildpathHPFS))); |
||
1562 | Trace((stderr, "buildpathFAT now = [%s]\n", |
||
1563 | FnFilter1(G.os2.buildpathFAT))); |
||
1564 | return MPN_OK; |
||
1565 | |||
1566 | } /* end if (FUNCTION == APPEND_DIR) */ |
||
1567 | |||
1568 | /*--------------------------------------------------------------------------- |
||
1569 | GETPATH: copy full FAT path to the string pointed at by pathcomp (want |
||
1570 | filename to reflect name used on disk, not EAs; if full path is HPFS, |
||
1571 | buildpathFAT and buildpathHPFS will be identical). Also free both paths. |
||
1572 | ---------------------------------------------------------------------------*/ |
||
1573 | |||
1574 | if (FUNCTION == GETPATH) { |
||
1575 | Trace((stderr, "getting and freeing FAT path [%s]\n", |
||
1576 | FnFilter1(G.os2.buildpathFAT))); |
||
1577 | Trace((stderr, "freeing HPFS path [%s]\n", |
||
1578 | FnFilter1(G.os2.buildpathHPFS))); |
||
1579 | strcpy(pathcomp, G.os2.buildpathFAT); |
||
1580 | free(G.os2.buildpathFAT); |
||
1581 | free(G.os2.buildpathHPFS); |
||
1582 | G.os2.buildpathHPFS = G.os2.buildpathFAT = G.os2.endHPFS = G.os2.endFAT = (char *)NULL; |
||
1583 | return MPN_OK; |
||
1584 | } |
||
1585 | |||
1586 | /*--------------------------------------------------------------------------- |
||
1587 | APPEND_NAME: assume the path component is the filename; append it and |
||
1588 | return without checking for existence. |
||
1589 | ---------------------------------------------------------------------------*/ |
||
1590 | |||
1591 | if (FUNCTION == APPEND_NAME) { |
||
1592 | char *p = pathcomp; |
||
1593 | int error = MPN_OK; |
||
1594 | |||
1595 | Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp))); |
||
1596 | /* The buildpathHPFS buffer has been allocated large enough to |
||
1597 | * hold the complete combined name, so there is no need to check |
||
1598 | * for OS filename size limit overflow within the copy loop. |
||
1599 | */ |
||
1600 | while ((*G.os2.endHPFS = *p++) != '\0') { /* copy to HPFS filename */ |
||
1601 | ++G.os2.endHPFS; |
||
1602 | } |
||
1603 | /* Now, check for OS filename size overflow. When detected, the |
||
1604 | * mapped HPFS name is truncated and a warning message is shown. |
||
1605 | */ |
||
1606 | if ((G.os2.endHPFS-G.os2.buildpathHPFS) >= FILNAMSIZ) { |
||
1607 | G.os2.buildpathHPFS[FILNAMSIZ-1] = '\0'; |
||
1608 | Info(slide, 1, ((char *)slide, LoadFarString(PathTooLongTrunc), |
||
1609 | FnFilter1(G.filename), FnFilter2(G.os2.buildpathHPFS))); |
||
1610 | error = MPN_INF_TRUNC; /* filename truncated */ |
||
1611 | } |
||
1612 | |||
1613 | /* GRR: how can longnameEA ever be set before this point??? we don't want |
||
1614 | * to save the original name to EAs if user renamed it, do we? |
||
1615 | * |
||
1616 | * if (!G.os2.longnameEA && ((G.os2.longnameEA = !IsFileNameValid(name)) != 0)) |
||
1617 | */ |
||
1618 | /* The buildpathFAT buffer has the same allocated size as the |
||
1619 | * buildpathHPFS buffer, so there is no need for an overflow check |
||
1620 | * within the following copy loop, either. |
||
1621 | */ |
||
1622 | if (G.pInfo->vollabel || IsFileNameValid(G.os2.buildpathHPFS)) { |
||
1623 | G.os2.longnameEA = FALSE; |
||
1624 | /* copy to FAT filename, too */ |
||
1625 | p = pathcomp; |
||
1626 | while ((*G.os2.endFAT = *p++) != '\0') |
||
1627 | ++G.os2.endFAT; |
||
1628 | } else { |
||
1629 | G.os2.longnameEA = TRUE; |
||
1630 | if ((G.os2.lastpathcomp = (char *)malloc(strlen(pathcomp)+1)) == |
||
1631 | (char *)NULL) |
||
1632 | { |
||
1633 | Info(slide, 1, ((char *)slide, |
||
1634 | "checkdir warning: cannot save longname EA: out of memory\n")); |
||
1635 | G.os2.longnameEA = FALSE; |
||
1636 | /* can't set .LONGNAME extended attribute */ |
||
1637 | error = MPN_INF_TRUNC; |
||
1638 | } else /* used and freed in close_outfile() */ |
||
1639 | strcpy(G.os2.lastpathcomp, pathcomp); |
||
1640 | /* map, put in FAT fn, update endFAT */ |
||
1641 | map2fat(pathcomp, &G.os2.endFAT); |
||
1642 | } |
||
1643 | |||
1644 | /* Check that the FAT path does not exceed the FILNAMSIZ limit, and |
||
1645 | * truncate when neccessary. |
||
1646 | * Note that truncation can only happen when the HPFS path (which is |
||
1647 | * never shorter than the FAT path) has been already truncated. |
||
1648 | * So, emission of the warning message and setting the error code |
||
1649 | * has already happened. |
||
1650 | */ |
||
1651 | if ((G.os2.endFAT-G.os2.buildpathFAT) >= FILNAMSIZ) |
||
1652 | G.os2.buildpathFAT[FILNAMSIZ-1] = '\0'; |
||
1653 | Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT: %s\n", |
||
1654 | FnFilter1(G.os2.buildpathHPFS), FnFilter2(G.os2.buildpathFAT))); |
||
1655 | |||
1656 | return error; /* could check for existence, prompt for new name... */ |
||
1657 | |||
1658 | } /* end if (FUNCTION == APPEND_NAME) */ |
||
1659 | |||
1660 | /*--------------------------------------------------------------------------- |
||
1661 | INIT: allocate and initialize buffer space for the file currently being |
||
1662 | extracted. If file was renamed with an absolute path, don't prepend the |
||
1663 | extract-to path. |
||
1664 | ---------------------------------------------------------------------------*/ |
||
1665 | |||
1666 | if (FUNCTION == INIT) { |
||
1667 | Trace((stderr, "initializing buildpathHPFS and buildpathFAT to ")); |
||
1668 | #ifdef ACORN_FTYPE_NFS |
||
1669 | if ((G.os2.buildpathHPFS = (char *)malloc(G.os2.fnlen+G.os2.rootlen+ |
||
1670 | (uO.acorn_nfs_ext ? 5 : 1))) |
||
1671 | #else |
||
1672 | if ((G.os2.buildpathHPFS = (char *)malloc(G.os2.fnlen+G.os2.rootlen+1)) |
||
1673 | #endif |
||
1674 | == (char *)NULL) |
||
1675 | return MPN_NOMEM; |
||
1676 | #ifdef ACORN_FTYPE_NFS |
||
1677 | if ((G.os2.buildpathFAT = (char *)malloc(G.os2.fnlen+G.os2.rootlen+ |
||
1678 | (uO.acorn_nfs_ext ? 5 : 1))) |
||
1679 | #else |
||
1680 | if ((G.os2.buildpathFAT = (char *)malloc(G.os2.fnlen+G.os2.rootlen+1)) |
||
1681 | #endif |
||
1682 | == (char *)NULL) { |
||
1683 | free(G.os2.buildpathHPFS); |
||
1684 | return MPN_NOMEM; |
||
1685 | } |
||
1686 | if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */ |
||
1687 | /* GRR: for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */ |
||
1688 | if (G.os2.renamed_fullpath && pathcomp[1] == ':') |
||
1689 | *G.os2.buildpathHPFS = (char)ToLower(*pathcomp); |
||
1690 | else if (!G.os2.renamed_fullpath && G.os2.rootlen > 1 && G.os2.rootpath[1] == ':') |
||
1691 | *G.os2.buildpathHPFS = (char)ToLower(*G.os2.rootpath); |
||
1692 | else { |
||
1693 | ULONG lMap; |
||
1694 | DosQueryCurrentDisk(&G.os2.nLabelDrive, &lMap); |
||
1695 | *G.os2.buildpathHPFS = (char)(G.os2.nLabelDrive - 1 + 'a'); |
||
1696 | } |
||
1697 | G.os2.nLabelDrive = *G.os2.buildpathHPFS - 'a' + 1; /* save for mapname() */ |
||
1698 | if (uO.volflag == 0 || *G.os2.buildpathHPFS < 'a' || /* no labels/bogus? */ |
||
1699 | (uO.volflag == 1 && !isfloppy(G.os2.nLabelDrive))) { /* -$: no fixed */ |
||
1700 | free(G.os2.buildpathHPFS); |
||
1701 | free(G.os2.buildpathFAT); |
||
1702 | return MPN_VOL_LABEL; /* skipping with message */ |
||
1703 | } |
||
1704 | *G.os2.buildpathHPFS = '\0'; |
||
1705 | } else if (G.os2.renamed_fullpath) /* pathcomp = valid data */ |
||
1706 | strcpy(G.os2.buildpathHPFS, pathcomp); |
||
1707 | else if (G.os2.rootlen > 0) |
||
1708 | strcpy(G.os2.buildpathHPFS, G.os2.rootpath); |
||
1709 | else |
||
1710 | *G.os2.buildpathHPFS = '\0'; |
||
1711 | G.os2.endHPFS = G.os2.buildpathHPFS; |
||
1712 | G.os2.endFAT = G.os2.buildpathFAT; |
||
1713 | while ((*G.os2.endFAT = *G.os2.endHPFS) != '\0') { |
||
1714 | ++G.os2.endFAT; |
||
1715 | ++G.os2.endHPFS; |
||
1716 | } |
||
1717 | Trace((stderr, "[%s]\n", FnFilter1(G.os2.buildpathHPFS))); |
||
1718 | return MPN_OK; |
||
1719 | } |
||
1720 | |||
1721 | /*--------------------------------------------------------------------------- |
||
1722 | ROOT: if appropriate, store the path in rootpath and create it if neces- |
||
1723 | sary; else assume it's a zipfile member and return. This path segment |
||
1724 | gets used in extracting all members from every zipfile specified on the |
||
1725 | command line. Note that under OS/2 and MS-DOS, if a candidate extract-to |
||
1726 | directory specification includes a drive letter (leading "x:"), it is |
||
1727 | treated just as if it had a trailing '/'--that is, one directory level |
||
1728 | will be created if the path doesn't exist, unless this is otherwise pro- |
||
1729 | hibited (e.g., freshening). |
||
1730 | ---------------------------------------------------------------------------*/ |
||
1731 | |||
1732 | #if (!defined(SFX) || defined(SFX_EXDIR)) |
||
1733 | if (FUNCTION == ROOT) { |
||
1734 | Trace((stderr, "initializing root path to [%s]\n", |
||
1735 | FnFilter1(pathcomp))); |
||
1736 | if (pathcomp == (char *)NULL) { |
||
1737 | G.os2.rootlen = 0; |
||
1738 | return MPN_OK; |
||
1739 | } |
||
1740 | if (G.os2.rootlen > 0) /* rootpath was already set, nothing to do */ |
||
1741 | return MPN_OK; |
||
1742 | if ((G.os2.rootlen = strlen(pathcomp)) > 0) { |
||
1743 | int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE; |
||
1744 | char *tmproot; |
||
1745 | |||
1746 | if ((tmproot = (char *)malloc(G.os2.rootlen+3)) == (char *)NULL) { |
||
1747 | G.os2.rootlen = 0; |
||
1748 | return MPN_NOMEM; |
||
1749 | } |
||
1750 | strcpy(tmproot, pathcomp); |
||
1751 | if (isalpha((uch)tmproot[0]) && tmproot[1] == ':') |
||
1752 | has_drive = TRUE; /* drive designator */ |
||
1753 | if (tmproot[G.os2.rootlen-1] == '/') { |
||
1754 | tmproot[--G.os2.rootlen] = '\0'; |
||
1755 | had_trailing_pathsep = TRUE; |
||
1756 | } |
||
1757 | if (has_drive && (G.os2.rootlen == 2)) { |
||
1758 | if (!had_trailing_pathsep) /* i.e., original wasn't "x:/" */ |
||
1759 | add_dot = TRUE; /* relative path: add '.' before '/' */ |
||
1760 | } else if (G.os2.rootlen > 0) { /* need not check "x:." and "x:/" */ |
||
1761 | #ifdef MSC /* MSC 6.00 bug: stat(non-existent-dir) == 0 [exists!] */ |
||
1762 | if (GetFileTime(tmproot) == -1 || |
||
1763 | SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) |
||
1764 | #else |
||
1765 | if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) |
||
1766 | #endif |
||
1767 | { /* path does not exist */ |
||
1768 | if (!G.create_dirs /* || iswild(tmproot) */ |
||
1769 | ) { |
||
1770 | free(tmproot); |
||
1771 | G.os2.rootlen = 0; |
||
1772 | return MPN_INF_SKIP; /* treat as stored file */ |
||
1773 | } |
||
1774 | /* create directory (could add loop here scanning tmproot |
||
1775 | * to create more than one level, but really necessary?) */ |
||
1776 | if (MKDIR(tmproot, 0777) == -1) { |
||
1777 | Info(slide, 1, ((char *)slide, |
||
1778 | LoadFarString(CantCreateExtractDir), |
||
1779 | FnFilter1(tmproot))); |
||
1780 | free(tmproot); |
||
1781 | G.os2.rootlen = 0; |
||
1782 | /* path didn't exist, tried to create, failed: */ |
||
1783 | /* file exists, or need 2+ directory levels */ |
||
1784 | return MPN_ERR_SKIP; |
||
1785 | } |
||
1786 | } |
||
1787 | } |
||
1788 | if (add_dot) /* had just "x:", make "x:." */ |
||
1789 | tmproot[G.os2.rootlen++] = '.'; |
||
1790 | tmproot[G.os2.rootlen++] = '/'; |
||
1791 | tmproot[G.os2.rootlen] = '\0'; |
||
1792 | if ((G.os2.rootpath = realloc(tmproot, G.os2.rootlen+1)) == NULL) { |
||
1793 | free(tmproot); |
||
1794 | G.os2.rootlen = 0; |
||
1795 | return MPN_NOMEM; |
||
1796 | } |
||
1797 | Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.os2.rootpath))); |
||
1798 | } |
||
1799 | return MPN_OK; |
||
1800 | } |
||
1801 | #endif /* !SFX || SFX_EXDIR */ |
||
1802 | |||
1803 | /*--------------------------------------------------------------------------- |
||
1804 | END: free rootpath, immediately prior to program exit. |
||
1805 | ---------------------------------------------------------------------------*/ |
||
1806 | |||
1807 | if (FUNCTION == END) { |
||
1808 | Trace((stderr, "freeing rootpath\n")); |
||
1809 | if (G.os2.rootlen > 0) { |
||
1810 | free(G.os2.rootpath); |
||
1811 | G.os2.rootlen = 0; |
||
1812 | } |
||
1813 | return MPN_OK; |
||
1814 | } |
||
1815 | |||
1816 | return MPN_INVALID; /* should never reach */ |
||
1817 | |||
1818 | } /* end function checkdir() */ |
||
1819 | |||
1820 | |||
1821 | |||
1822 | |||
1823 | |||
1824 | /***********************/ |
||
1825 | /* Function isfloppy() */ /* more precisely, is it removable? */ |
||
1826 | /***********************/ |
||
1827 | |||
1828 | static int isfloppy(nDrive) |
||
1829 | int nDrive; /* 1 == A:, 2 == B:, etc. */ |
||
1830 | { |
||
1831 | uch ParmList[1] = {0}; |
||
1832 | uch DataArea[1] = {0}; |
||
1833 | char Name[3]; |
||
1834 | HFILE handle; |
||
1835 | #ifdef __32BIT__ |
||
1836 | ULONG rc; |
||
1837 | ULONG action; |
||
1838 | #else |
||
1839 | USHORT rc; |
||
1840 | USHORT action; |
||
1841 | #endif |
||
1842 | |||
1843 | |||
1844 | Name[0] = (char) (nDrive + 'A' - 1); |
||
1845 | Name[1] = ':'; |
||
1846 | Name[2] = 0; |
||
1847 | |||
1848 | rc = DosOpen(Name, &handle, &action, 0L, FILE_NORMAL, FILE_OPEN, |
||
1849 | OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR | |
||
1850 | OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0L); |
||
1851 | |||
1852 | if (rc == ERROR_NOT_READY) /* must be removable */ |
||
1853 | return TRUE; |
||
1854 | else if (rc) { /* other error: do default a/b heuristic instead */ |
||
1855 | Trace((stderr, "error in DosOpen(DASD): guessing...\n", rc)); |
||
1856 | return (nDrive == 1 || nDrive == 2)? TRUE : FALSE; |
||
1857 | } |
||
1858 | |||
1859 | rc = DosDevIOCtl(DataArea, sizeof(DataArea), ParmList, sizeof(ParmList), |
||
1860 | DSK_BLOCKREMOVABLE, IOCTL_DISK, handle); |
||
1861 | DosClose(handle); |
||
1862 | |||
1863 | if (rc) { /* again, just check for a/b */ |
||
1864 | Trace((stderr, "error in DosDevIOCtl category IOCTL_DISK, function " |
||
1865 | "DSK_BLOCKREMOVABLE\n (rc = 0x%04x): guessing...\n", rc)); |
||
1866 | return (nDrive == 1 || nDrive == 2)? TRUE : FALSE; |
||
1867 | } else { |
||
1868 | return DataArea[0] ? FALSE : TRUE; |
||
1869 | } |
||
1870 | } /* end function isfloppy() */ |
||
1871 | |||
1872 | |||
1873 | |||
1874 | |||
1875 | |||
1876 | static int IsFileNameValid(const char *name) |
||
1877 | { |
||
1878 | HFILE hf; |
||
1879 | #ifdef __32BIT__ |
||
1880 | ULONG uAction; |
||
1881 | #else |
||
1882 | USHORT uAction; |
||
1883 | #endif |
||
1884 | |||
1885 | switch( DosOpen((PSZ) name, &hf, &uAction, 0, 0, FILE_OPEN, |
||
1886 | OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0) ) |
||
1887 | { |
||
1888 | case ERROR_INVALID_NAME: |
||
1889 | case ERROR_FILENAME_EXCED_RANGE: |
||
1890 | return FALSE; |
||
1891 | case NO_ERROR: |
||
1892 | DosClose(hf); |
||
1893 | default: |
||
1894 | return TRUE; |
||
1895 | } |
||
1896 | } |
||
1897 | |||
1898 | |||
1899 | |||
1900 | |||
1901 | |||
1902 | /**********************/ |
||
1903 | /* Function map2fat() */ |
||
1904 | /**********************/ |
||
1905 | |||
1906 | static void map2fat(pathcomp, pEndFAT) |
||
1907 | char *pathcomp, **pEndFAT; |
||
1908 | { |
||
1909 | char *ppc = pathcomp; /* variable pointer to pathcomp */ |
||
1910 | char *pEnd = *pEndFAT; /* variable pointer to buildpathFAT */ |
||
1911 | char *pBegin = *pEndFAT; /* constant pointer to start of this comp. */ |
||
1912 | char *last_dot = (char *)NULL; /* last dot not converted to underscore */ |
||
1913 | int dotname = FALSE; /* flag: path component begins with dot */ |
||
1914 | /* ("." and ".." don't count) */ |
||
1915 | register unsigned workch; /* hold the character being tested */ |
||
1916 | |||
1917 | |||
1918 | /* Only need check those characters which are legal in HPFS but not |
||
1919 | * in FAT: to get here, must already have passed through mapname. |
||
1920 | * (GRR: oops, small bug--if char was quoted, no longer have any |
||
1921 | * knowledge of that.) Also must truncate path component to ensure |
||
1922 | * 8.3 compliance... |
||
1923 | */ |
||
1924 | while ((workch = (uch)*ppc++) != 0) { |
||
1925 | switch (workch) { |
||
1926 | case '[': /* add '"' '+' ',' '=' ?? */ |
||
1927 | case ']': |
||
1928 | *pEnd++ = '_'; /* convert brackets to underscores */ |
||
1929 | break; |
||
1930 | |||
1931 | case '.': |
||
1932 | if (pEnd == *pEndFAT) { /* nothing appended yet... */ |
||
1933 | if (*ppc == '\0') /* don't bother appending a */ |
||
1934 | break; /* "./" component to the path */ |
||
1935 | else if (*ppc == '.' && ppc[1] == '\0') { /* "../" */ |
||
1936 | *pEnd++ = '.'; /* add first dot, unchanged... */ |
||
1937 | ++ppc; /* skip second dot, since it will */ |
||
1938 | } else { /* be "added" at end of if-block */ |
||
1939 | *pEnd++ = '_'; /* FAT doesn't allow null filename */ |
||
1940 | dotname = TRUE; /* bodies, so map .exrc -> _.exrc */ |
||
1941 | } /* (extra '_' now, "dot" below) */ |
||
1942 | } else if (dotname) { /* found a second dot, but still */ |
||
1943 | dotname = FALSE; /* have extra leading underscore: */ |
||
1944 | *pEnd = '\0'; /* remove it by shifting chars */ |
||
1945 | pEnd = *pEndFAT + 1; /* left one space (e.g., .p1.p2: */ |
||
1946 | while (pEnd[1]) { /* __p1 -> _p1_p2 -> _p1.p2 when */ |
||
1947 | *pEnd = pEnd[1]; /* finished) [opt.: since first */ |
||
1948 | ++pEnd; /* two chars are same, can start */ |
||
1949 | } /* shifting at second position] */ |
||
1950 | } |
||
1951 | last_dot = pEnd; /* point at last dot so far... */ |
||
1952 | *pEnd++ = '_'; /* convert dot to underscore for now */ |
||
1953 | break; |
||
1954 | |||
1955 | default: |
||
1956 | *pEnd++ = (char)workch; |
||
1957 | |||
1958 | } /* end switch */ |
||
1959 | } /* end while loop */ |
||
1960 | |||
1961 | *pEnd = '\0'; /* terminate buildpathFAT */ |
||
1962 | |||
1963 | /* NOTE: keep in mind that pEnd points to the end of the path |
||
1964 | * component, and *pEndFAT still points to the *beginning* of it... |
||
1965 | * Also note that the algorithm does not try to get too fancy: |
||
1966 | * if there are no dots already, the name either gets truncated |
||
1967 | * at 8 characters or the last underscore is converted to a dot |
||
1968 | * (only if more characters are saved that way). In no case is |
||
1969 | * a dot inserted between existing characters. |
||
1970 | */ |
||
1971 | if (last_dot == (char *)NULL) { /* no dots: check for underscores... */ |
||
1972 | char *plu = strrchr(pBegin, '_'); /* pointer to last underscore */ |
||
1973 | |||
1974 | if (plu == (char *)NULL) { /* no dots, no underscores: truncate at 8 */ |
||
1975 | *pEndFAT += 8; /* chars (could insert '.' and keep 11...) */ |
||
1976 | if (*pEndFAT > pEnd) |
||
1977 | *pEndFAT = pEnd; /* oops...didn't have 8 chars to truncate */ |
||
1978 | else |
||
1979 | **pEndFAT = '\0'; |
||
1980 | } else if (MIN(plu - pBegin, 8) + MIN(pEnd - plu - 1, 3) > 8) { |
||
1981 | last_dot = plu; /* be lazy: drop through to next if-block */ |
||
1982 | } else if ((pEnd - *pEndFAT) > 8) { |
||
1983 | *pEndFAT += 8; /* more fits into just basename than if */ |
||
1984 | **pEndFAT = '\0'; /* convert last underscore to dot */ |
||
1985 | } else |
||
1986 | *pEndFAT = pEnd; /* whole thing fits into 8 chars or less */ |
||
1987 | } |
||
1988 | |||
1989 | if (last_dot != (char *)NULL) { /* one dot (or two, in the case of */ |
||
1990 | *last_dot = '.'; /* "..") is OK: put it back in */ |
||
1991 | |||
1992 | if ((last_dot - pBegin) > 8) { |
||
1993 | char *p, *q; |
||
1994 | int i; |
||
1995 | |||
1996 | p = last_dot; |
||
1997 | q = last_dot = pBegin + 8; |
||
1998 | for (i = 0; (i < 4) && *p; ++i) /* too many chars in basename: */ |
||
1999 | *q++ = *p++; /* shift ".ext" left and */ |
||
2000 | *q = '\0'; /* truncate/terminate it */ |
||
2001 | *pEndFAT = q; |
||
2002 | } else if ((pEnd - last_dot) > 4) { /* too many chars in extension */ |
||
2003 | *pEndFAT = last_dot + 4; |
||
2004 | **pEndFAT = '\0'; |
||
2005 | } else |
||
2006 | *pEndFAT = pEnd; /* filename is fine; point at terminating zero */ |
||
2007 | |||
2008 | if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ') |
||
2009 | last_dot[-1] = '_'; /* NO blank in front of '.'! */ |
||
2010 | } |
||
2011 | } /* end function map2fat() */ |
||
2012 | |||
2013 | |||
2014 | |||
2015 | |||
2016 | |||
2017 | static int SetLongNameEA(char *name, char *longname) |
||
2018 | { |
||
2019 | EAOP eaop; |
||
2020 | FEALST fealst; |
||
2021 | |||
2022 | eaop.fpFEAList = (PFEALIST) &fealst; |
||
2023 | eaop.fpGEAList = NULL; |
||
2024 | eaop.oError = 0; |
||
2025 | |||
2026 | strcpy((char *) fealst.szName, ".LONGNAME"); |
||
2027 | strcpy((char *) fealst.szValue, longname); |
||
2028 | |||
2029 | fealst.cbList = sizeof(fealst) - CCHMAXPATH + strlen((char *) fealst.szValue); |
||
2030 | fealst.cbName = (BYTE) strlen((char *) fealst.szName); |
||
2031 | fealst.cbValue = sizeof(USHORT) * 2 + strlen((char *) fealst.szValue); |
||
2032 | |||
2033 | #ifdef __32BIT__ |
||
2034 | fealst.oNext = 0; |
||
2035 | #endif |
||
2036 | fealst.fEA = 0; |
||
2037 | fealst.eaType = 0xFFFD; |
||
2038 | fealst.eaSize = strlen((char *) fealst.szValue); |
||
2039 | |||
2040 | return DosSetPathInfo(name, FIL_QUERYEASIZE, |
||
2041 | (PBYTE) &eaop, sizeof(eaop), 0); |
||
2042 | } |
||
2043 | |||
2044 | |||
2045 | |||
2046 | |||
2047 | |||
2048 | /****************************/ |
||
2049 | /* Function close_outfile() */ |
||
2050 | /****************************/ |
||
2051 | |||
2052 | /* GRR: need to return error level!! */ |
||
2053 | |||
2054 | void close_outfile(__G) /* only for extracted files, not directories */ |
||
2055 | __GDEF |
||
2056 | { |
||
2057 | fclose(G.outfile); |
||
2058 | |||
2059 | /* set extra fields, both stored-in-zipfile and .LONGNAME flavors */ |
||
2060 | if (G.extra_field) { /* zipfile extra field may have extended attribs */ |
||
2061 | int err = EvalExtraFields(__G__ G.filename, G.extra_field, |
||
2062 | G.lrec.extra_field_length); |
||
2063 | |||
2064 | if (err == IZ_EF_TRUNC) { |
||
2065 | if (uO.qflag) |
||
2066 | Info(slide, 1, ((char *)slide, "%-22s ", |
||
2067 | FnFilter1(G.filename))); |
||
2068 | Info(slide, 1, ((char *)slide, LoadFarString(TruncEAs), |
||
2069 | makeword(G.extra_field+2)-10, uO.qflag? "\n" : "")); |
||
2070 | } |
||
2071 | } |
||
2072 | |||
2073 | if (G.os2.longnameEA) { |
||
2074 | #ifdef DEBUG |
||
2075 | int e = |
||
2076 | #endif |
||
2077 | SetLongNameEA(G.filename, G.os2.lastpathcomp); |
||
2078 | Trace((stderr, "close_outfile: SetLongNameEA() returns %d\n", e)); |
||
2079 | free(G.os2.lastpathcomp); |
||
2080 | } |
||
2081 | |||
2082 | /* set date/time and permissions */ |
||
2083 | SetPathAttrTimes(__G__ G.pInfo->file_attr, 0); |
||
2084 | |||
2085 | } /* end function close_outfile() */ |
||
2086 | |||
2087 | |||
2088 | |||
2089 | |||
2090 | |||
2091 | /******************************/ |
||
2092 | /* Function check_for_newer() */ |
||
2093 | /******************************/ |
||
2094 | |||
2095 | int check_for_newer(__G__ filename) /* return 1 if existing file newer or equal; */ |
||
2096 | __GDEF |
||
2097 | char *filename; /* 0 if older; -1 if doesn't exist yet */ |
||
2098 | { |
||
2099 | ulg existing, archive; |
||
2100 | #ifdef USE_EF_UT_TIME |
||
2101 | iztimes z_utime; |
||
2102 | #endif |
||
2103 | |||
2104 | if ((existing = (ulg)GetFileTime(filename)) == (ulg)-1) |
||
2105 | return DOES_NOT_EXIST; |
||
2106 | |||
2107 | #ifdef USE_EF_UT_TIME |
||
2108 | if (G.extra_field && |
||
2109 | #ifdef IZ_CHECK_TZ |
||
2110 | G.tz_is_valid && |
||
2111 | #endif |
||
2112 | (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0, |
||
2113 | G.lrec.last_mod_dos_datetime, &z_utime, NULL) |
||
2114 | & EB_UT_FL_MTIME)) |
||
2115 | { |
||
2116 | TTrace((stderr, "check_for_newer: using Unix extra field mtime\n")); |
||
2117 | archive = Utime2DosDateTime(z_utime.mtime); |
||
2118 | } else { |
||
2119 | archive = G.lrec.last_mod_dos_datetime; |
||
2120 | } |
||
2121 | #else /* !USE_EF_UT_TIME */ |
||
2122 | archive = G.lrec.last_mod_dos_datetime; |
||
2123 | #endif /* ?USE_EF_UT_TIME */ |
||
2124 | |||
2125 | return (existing >= archive); |
||
2126 | } /* end function check_for_newer() */ |
||
2127 | |||
2128 | |||
2129 | |||
2130 | |||
2131 | |||
2132 | #ifndef SFX |
||
2133 | |||
2134 | /*************************/ |
||
2135 | /* Function dateformat() */ |
||
2136 | /*************************/ |
||
2137 | |||
2138 | int dateformat() |
||
2139 | { |
||
2140 | /*----------------------------------------------------------------------------- |
||
2141 | For those operating systems which support it, this function returns a value |
||
2142 | which tells how national convention says that numeric dates are displayed. |
||
2143 | Return values are DF_YMD, DF_DMY and DF_MDY. |
||
2144 | -----------------------------------------------------------------------------*/ |
||
2145 | |||
2146 | switch (GetCountryInfo()) { |
||
2147 | case 0: |
||
2148 | return DF_MDY; |
||
2149 | case 1: |
||
2150 | return DF_DMY; |
||
2151 | case 2: |
||
2152 | return DF_YMD; |
||
2153 | } |
||
2154 | return DF_MDY; /* default if error */ |
||
2155 | |||
2156 | } /* end function dateformat() */ |
||
2157 | |||
2158 | |||
2159 | |||
2160 | |||
2161 | |||
2162 | /************************/ |
||
2163 | /* Function version() */ |
||
2164 | /************************/ |
||
2165 | |||
2166 | void version(__G) |
||
2167 | __GDEF |
||
2168 | { |
||
2169 | int len; |
||
2170 | #if defined(__IBMC__) || defined(__WATCOMC__) || defined(_MSC_VER) |
||
2171 | char buf[80]; |
||
2172 | #endif |
||
2173 | |||
2174 | len = sprintf((char *)slide, LoadFarString(CompiledWith), |
||
2175 | |||
2176 | #if defined(__GNUC__) |
||
2177 | # ifdef __EMX__ /* __EMX__ is defined as "1" only (sigh) */ |
||
2178 | "emx+gcc ", __VERSION__, |
||
2179 | # else |
||
2180 | "gcc ", __VERSION__, |
||
2181 | # endif |
||
2182 | #elif defined(__IBMC__) |
||
2183 | "IBM ", |
||
2184 | # if (__IBMC__ < 200) |
||
2185 | (sprintf(buf, "C Set/2 %d.%02d", __IBMC__/100,__IBMC__%100), buf), |
||
2186 | # elif (__IBMC__ < 300) |
||
2187 | (sprintf(buf, "C Set++ %d.%02d", __IBMC__/100,__IBMC__%100), buf), |
||
2188 | # else |
||
2189 | (sprintf(buf, "Visual Age C++ %d.%02d", __IBMC__/100,__IBMC__%100), buf), |
||
2190 | # endif |
||
2191 | #elif defined(__WATCOMC__) |
||
2192 | "Watcom C", (sprintf(buf, " (__WATCOMC__ = %d)", __WATCOMC__), buf), |
||
2193 | #elif defined(__TURBOC__) |
||
2194 | # ifdef __BORLANDC__ |
||
2195 | "Borland C++", |
||
2196 | # if (__BORLANDC__ < 0x0460) |
||
2197 | " 1.0", |
||
2198 | # elif (__BORLANDC__ == 0x0460) |
||
2199 | " 1.5", /* from Kai Uwe: three less than DOS */ |
||
2200 | # else |
||
2201 | " 2.0", /* (__BORLANDC__ == 0x0500)? */ |
||
2202 | # endif |
||
2203 | # else |
||
2204 | "Turbo C", /* these are probably irrelevant */ |
||
2205 | # if (__TURBOC__ >= 661) |
||
2206 | "++ 1.0 or later", |
||
2207 | # elif (__TURBOC__ == 661) |
||
2208 | " 3.0?", |
||
2209 | # elif (__TURBOC__ == 397) |
||
2210 | " 2.0", |
||
2211 | # else |
||
2212 | " 1.0 or 1.5?", |
||
2213 | # endif |
||
2214 | # endif |
||
2215 | #elif defined(MSC) |
||
2216 | "Microsoft C ", |
||
2217 | # ifdef _MSC_VER |
||
2218 | (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf), |
||
2219 | # else |
||
2220 | "5.1 or earlier", |
||
2221 | # endif |
||
2222 | #else |
||
2223 | "unknown compiler", "", |
||
2224 | #endif /* ?compilers */ |
||
2225 | |||
2226 | "OS/2", |
||
2227 | |||
2228 | /* GRR: does IBM C/2 identify itself as IBM rather than Microsoft? */ |
||
2229 | #if (defined(MSC) || (defined(__WATCOMC__) && !defined(__386__))) |
||
2230 | # if defined(M_I86HM) || defined(__HUGE__) |
||
2231 | " (16-bit, huge)", |
||
2232 | # elif defined(M_I86LM) || defined(__LARGE__) |
||
2233 | " (16-bit, large)", |
||
2234 | # elif defined(M_I86MM) || defined(__MEDIUM__) |
||
2235 | " (16-bit, medium)", |
||
2236 | # elif defined(M_I86CM) || defined(__COMPACT__) |
||
2237 | " (16-bit, compact)", |
||
2238 | # elif defined(M_I86SM) || defined(__SMALL__) |
||
2239 | " (16-bit, small)", |
||
2240 | # elif defined(M_I86TM) || defined(__TINY__) |
||
2241 | " (16-bit, tiny)", |
||
2242 | # else |
||
2243 | " (16-bit)", |
||
2244 | # endif |
||
2245 | #else |
||
2246 | " (32-bit)", |
||
2247 | #endif |
||
2248 | |||
2249 | #ifdef __DATE__ |
||
2250 | " on ", __DATE__ |
||
2251 | #else |
||
2252 | "", "" |
||
2253 | #endif |
||
2254 | ); |
||
2255 | |||
2256 | (*G.message)((zvoid *)&G, slide, (ulg)len, 0); |
||
2257 | /* MSC can't handle huge macro expansions */ |
||
2258 | |||
2259 | /* temporary debugging code for Borland compilers only */ |
||
2260 | /* __TCPLUSPLUS__, __BCPLUSPLUS__ not defined for v1.5 */ |
||
2261 | #if (defined(__TURBOC__) && defined(DEBUG)) |
||
2262 | Info(slide, 0, ((char *)slide, "\t(__TURBOC__ = 0x%04x = %d)\n", __TURBOC__, |
||
2263 | __TURBOC__)); |
||
2264 | #ifdef __BORLANDC__ |
||
2265 | Info(slide, 0, ((char *)slide, "\t(__BORLANDC__ = 0x%04x)\n",__BORLANDC__)); |
||
2266 | #else |
||
2267 | Info(slide, 0, ((char *)slide, "\tdebug(__BORLANDC__ not defined)\n")); |
||
2268 | #endif |
||
2269 | #endif /* __TURBOC__ && DEBUG */ |
||
2270 | |||
2271 | } /* end function version() */ |
||
2272 | |||
2273 | #endif /* !SFX */ |
||
2274 | |||
2275 | #endif /* !FUNZIP */ |
||
2276 | |||
2277 | |||
2278 | |||
2279 | #ifdef MY_ZCALLOC /* Special zcalloc function for MEMORY16 (MSDOS/OS2) */ |
||
2280 | |||
2281 | #if defined(MSC) || defined(__WATCOMC__) |
||
2282 | #if (!defined(_MSC_VER) || (_MSC_VER < 700)) |
||
2283 | # define _halloc halloc |
||
2284 | # define _hfree hfree |
||
2285 | #endif |
||
2286 | |||
2287 | zvoid far *zcalloc (unsigned items, unsigned size) |
||
2288 | { |
||
2289 | return (zvoid far *)_halloc((long)items, size); |
||
2290 | } |
||
2291 | |||
2292 | zvoid zcfree (zvoid far *ptr) |
||
2293 | { |
||
2294 | _hfree((void huge *)ptr); |
||
2295 | } |
||
2296 | #endif /* MSC || __WATCOMC__ */ |
||
2297 | |||
2298 | #endif /* MY_ZCALLOC */ |
||
2299 | |||
2300 | |||
2301 | |||
2302 | #ifndef FUNZIP |
||
2303 | |||
2304 | /* This table can be static because it is pseudo-constant */ |
||
2305 | static unsigned char cUpperCase[256], cLowerCase[256]; |
||
2306 | static BOOL bInitialized=FALSE; |
||
2307 | |||
2308 | /* Initialize the tables of upper- and lowercase characters, including |
||
2309 | handling of country-dependent characters. */ |
||
2310 | |||
2311 | static void InitNLS(void) |
||
2312 | { |
||
2313 | unsigned nCnt, nU; |
||
2314 | COUNTRYCODE cc; |
||
2315 | |||
2316 | if (bInitialized == FALSE) { |
||
2317 | bInitialized = TRUE; |
||
2318 | |||
2319 | for ( nCnt = 0; nCnt < 256; nCnt++ ) |
||
2320 | cUpperCase[nCnt] = cLowerCase[nCnt] = (unsigned char) nCnt; |
||
2321 | |||
2322 | cc.country = cc.codepage = 0; |
||
2323 | DosMapCase(sizeof(cUpperCase), &cc, (PCHAR) cUpperCase); |
||
2324 | |||
2325 | for ( nCnt = 0; nCnt < 256; nCnt++ ) { |
||
2326 | nU = cUpperCase[nCnt]; |
||
2327 | if (nU != nCnt && cLowerCase[nU] == (unsigned char) nU) |
||
2328 | cLowerCase[nU] = (unsigned char) nCnt; |
||
2329 | } |
||
2330 | |||
2331 | for ( nCnt = 'A'; nCnt <= 'Z'; nCnt++ ) |
||
2332 | cLowerCase[nCnt] = (unsigned char) (nCnt - 'A' + 'a'); |
||
2333 | } |
||
2334 | } |
||
2335 | |||
2336 | |||
2337 | int IsUpperNLS(int nChr) |
||
2338 | { |
||
2339 | return (cUpperCase[nChr] == (unsigned char) nChr); |
||
2340 | } |
||
2341 | |||
2342 | |||
2343 | int ToLowerNLS(int nChr) |
||
2344 | { |
||
2345 | return cLowerCase[nChr]; |
||
2346 | } |
||
2347 | |||
2348 | |||
2349 | char *StringLower(char *szArg) |
||
2350 | { |
||
2351 | unsigned char *szPtr; |
||
2352 | |||
2353 | for ( szPtr = (unsigned char *) szArg; *szPtr; szPtr++ ) |
||
2354 | *szPtr = cLowerCase[*szPtr]; |
||
2355 | return szArg; |
||
2356 | } |
||
2357 | |||
2358 | |||
2359 | #ifdef MORE |
||
2360 | int screensize(int *tt_rows, int *tt_cols) |
||
2361 | { |
||
2362 | #ifdef __EMX__ |
||
2363 | int dst[2]; |
||
2364 | _scrsize(dst); |
||
2365 | if (tt_rows != NULL) *tt_rows = dst[1]; |
||
2366 | if (tt_cols != NULL) *tt_cols = dst[0]; |
||
2367 | #else |
||
2368 | VIOMODEINFO vmi; |
||
2369 | vmi.cb = sizeof(vmi); |
||
2370 | VioGetMode(&vmi, 0); |
||
2371 | if (tt_rows != NULL) *tt_rows = vmi.row; |
||
2372 | if (tt_cols != NULL) *tt_cols = vmi.col; |
||
2373 | #endif |
||
2374 | return 0; |
||
2375 | } |
||
2376 | #endif /* MORE */ |
||
2377 | |||
2378 | |||
2379 | #if defined(__IBMC__) && defined(__DEBUG_ALLOC__) |
||
2380 | void DebugMalloc(void) |
||
2381 | { |
||
2382 | _dump_allocated(0); /* print out debug malloc memory statistics */ |
||
2383 | } |
||
2384 | #endif |
||
2385 | |||
2386 | |||
2387 | #if defined(REENTRANT) && defined(USETHREADID) |
||
2388 | ulg GetThreadId(void) |
||
2389 | { |
||
2390 | PTIB pptib; /* Address of a pointer to the |
||
2391 | Thread Information Block */ |
||
2392 | PPIB pppib; /* Address of a pointer to the |
||
2393 | Process Information Block */ |
||
2394 | |||
2395 | DosGetInfoBlocks(&pptib, &pppib); |
||
2396 | return pptib->tib_ptib2->tib2_ultid; |
||
2397 | } |
||
2398 | #endif /* defined(REENTRANT) && defined(USETHREADID) */ |
||
2399 | |||
2400 | |||
2401 | void os2GlobalsCtor(__GPRO) |
||
2402 | { |
||
2403 | G.os2.nLastDrive = (USHORT)(-1); |
||
2404 | |||
2405 | #ifdef OS2DLL |
||
2406 | G.os2.rexx_mes = "0"; |
||
2407 | #endif |
||
2408 | |||
2409 | InitNLS(); |
||
2410 | } |
||
2411 | |||
2412 | #endif /* !FUNZIP */=>>>>>>>>>31)==0)><31)==0)>>>>=>>=>>=>>><> |