Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | #include "stdafx.h" |
2 | #pragma hdrstop |
||
3 | #include "dz_errs.h" |
||
4 | |||
5 | #undef _DZ_FILE_ |
||
6 | #define _DZ_FILE_ DZ_UNZWIN32_CPP |
||
7 | /* This version modified by Chris Vleghert and Eric W. Engler |
||
8 | * for BCB/Delphi Zip, Jun 18, 2000. |
||
9 | |||
10 | Copyright (c) 1990-2007 Info-ZIP. All rights reserved. |
||
11 | |||
12 | See the accompanying file LICENSE, version 2007-Mar-4 or later |
||
13 | (the contents of which are also included in zip.h) for terms of use. |
||
14 | If, for some reason, all these files are missing, the Info-ZIP license |
||
15 | also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html |
||
16 | |||
17 | parts Copyright (C) 1997 Mike White, Eric W. Engler |
||
18 | ************************************************************************ |
||
19 | Copyright (C) 2009, 2010 by Russell J. Peters, Roger Aelbrecht |
||
20 | |||
21 | This file is part of TZipMaster Version 1.9. |
||
22 | |||
23 | TZipMaster is free software: you can redistribute it and/or modify |
||
24 | it under the terms of the GNU Lesser General Public License as published by |
||
25 | the Free Software Foundation, either version 3 of the License, or |
||
26 | (at your option) any later version. |
||
27 | |||
28 | TZipMaster is distributed in the hope that it will be useful, |
||
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
31 | GNU Lesser General Public License for more details. |
||
32 | |||
33 | You should have received a copy of the GNU Lesser General Public License |
||
34 | along with TZipMaster. If not, see <http://www.gnu.org/licenses/>. |
||
35 | |||
36 | contact: problems@delphizip.org (include ZipMaster in the subject). |
||
37 | updates: http://www.delphizip.org |
||
38 | DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip |
||
39 | ************************************************************************/ |
||
40 | |||
41 | /* WARNING: Don't pull any OS/2 or HPFS code without great care. Much of |
||
42 | * it is also used for NTFS, although it doesn't always have comments to |
||
43 | * that effect. */ |
||
44 | |||
45 | // MBCS update 17 Dec 2006 |
||
46 | /*--------------------------------------------------------------------------- |
||
47 | * win32.c |
||
48 | * 32-bit Windows-specific (NT/95) routines for use with Info-ZIP's UnZip 5.2 |
||
49 | * and later. (Borrowed, pilfered and plundered code from OS/2 and MS-DOS |
||
50 | * versions and from ZIP; modified as necessary.) |
||
51 | * Contains: GetLoadPath() |
||
52 | * Opendir() |
||
53 | * Readdir() |
||
54 | * Closedir() |
||
55 | * mapattr() |
||
56 | * getNTfiletime() |
||
57 | * close_outfile() |
||
58 | * isfloppy() |
||
59 | * IsVolumeOldFAT() RCV Removed. |
||
60 | * IsFileNameValid() |
||
61 | * map2fat() |
||
62 | * checkdir() |
||
63 | * do_wild() |
||
64 | * mapname() |
||
65 | * version() |
||
66 | *---------------------------------------------------------------------------*/ |
||
67 | //#include "unzip.h" |
||
68 | #include "UnzOp.h" |
||
69 | //#include <windows.h> /* must be AFTER unzip.h to avoid struct G problems */ |
||
70 | #include <shlobj.h> |
||
71 | #include <direct.h> |
||
72 | |||
73 | /* =========================================================================== |
||
74 | * Function mapattr() |
||
75 | * Identical to MS-DOS, OS/2 versions. |
||
76 | * However, NT has a lot of extra permission stuff, so this function should |
||
77 | * probably be extended in the future. |
||
78 | */ |
||
79 | int UnzOpr::mapattr(void) |
||
80 | { |
||
81 | /* Set archive bit (file is not backed up): */ |
||
82 | fpInfo->file_attr = |
||
83 | (unsigned)(fcrec.external_file_attributes | 32) & 0xff; |
||
84 | return 0; |
||
85 | } /* end function mapattr() */ |
||
86 | |||
87 | |||
88 | /* =========================================================================== |
||
89 | * Function getNTfiletime() |
||
90 | * Get the file time in a format that can be used by SetFileTime() in NT. |
||
91 | */ |
||
92 | int UnzOpr::getNTfiletime(FILETIME * ft) |
||
93 | { |
||
94 | FILETIME lft; /* 64-bit value made up of two 32 bit [low & high] */ |
||
95 | WORD wDOSDate; /* for converting from DOS date to Windows NT */ |
||
96 | WORD wDOSTime; |
||
97 | |||
98 | wDOSTime = (WORD) flrec.last_mod_file_time; |
||
99 | wDOSDate = (WORD) flrec.last_mod_file_date; |
||
100 | |||
101 | /* The DosDateTimeToFileTime() function converts a DOS date/time */ |
||
102 | /* into a 64 bit Windows NT file time */ |
||
103 | if (!DosDateTimeToFileTime(wDOSDate, wDOSTime, &lft)) |
||
104 | { |
||
105 | Notify(0, _T("DosDateTime failed: %s"), SysMsg().c_str()); |
||
106 | return false; |
||
107 | } |
||
108 | |||
109 | if (!LocalFileTimeToFileTime(&lft, ft)) |
||
110 | { |
||
111 | Notify(0, _T("LocalFileTime failed: %s"), SysMsg().c_str()); |
||
112 | *ft = lft; |
||
113 | } |
||
114 | return true; |
||
115 | } |
||
116 | |||
117 | |||
118 | /* =========================================================================== |
||
119 | * Function close_outfile() |
||
120 | */ |
||
121 | void UnzOpr::close_outfile(void) |
||
122 | { |
||
123 | FILETIME ft; /* File time type defined in NT */ |
||
124 | int gotTime; |
||
125 | |||
126 | if (!fUnzOutfile || !fUnzOutfile->IsFile) |
||
127 | return; |
||
128 | |||
129 | /* don't set the time stamp on standard output */ |
||
130 | if (fUnzOutfile) |
||
131 | { |
||
132 | ZStreamIO *tmp = fUnzOutfile; |
||
133 | fUnzOutfile = NULL; |
||
134 | delete tmp; |
||
135 | } |
||
136 | |||
137 | gotTime = getNTfiletime(&ft); |
||
138 | |||
139 | /* Close the file and then re-open it using the Win32 |
||
140 | * CreateFile call, so that the file can be created |
||
141 | * with GENERIC_WRITE access, otherwise the SetFileTime |
||
142 | * call will fail. */ |
||
143 | if (gotTime || fpInfo->ntfs_data) |
||
144 | { |
||
145 | if (Verbose < 0) |
||
146 | Notify(ITRACE, _T("setting date/time in close_outfile")); |
||
147 | |||
148 | ZFile tmpz(this, ffilename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, |
||
149 | FILE_ATTRIBUTE_NORMAL); |
||
150 | if (!tmpz.IsOpen()) |
||
151 | Notify(0, _T("CreateFile error [%s] when trying set filetime"), SysMsg().c_str()); |
||
152 | else |
||
153 | { |
||
154 | XNTFSData times; |
||
155 | memset(×, 0, sizeof(XNTFSData)); |
||
156 | times.MTime = ft; |
||
157 | if (fpInfo->ntfs_data) |
||
158 | memcpy(×, fpInfo->ntfs_data, sizeof(XNTFSData)); |
||
159 | if (!tmpz.SetTime(×.CTime, ×.ATime, ×.MTime))// &ft)) |
||
160 | Notify(0, _T("SetFileTime failed: %s"), SysMsg().c_str()); |
||
161 | } |
||
162 | |||
163 | } |
||
164 | |||
165 | /* HG: I think this could be done in the CreateFile call above - just */ |
||
166 | /* replace 'FILE_ATTRIBUTE_NORMAL' with 'fpInfo->file_attr & 0x7F' */ |
||
167 | if (!SetFileAttributes(ffilename, fpInfo->file_attr & 0x7F)) |
||
168 | Notify(IWARNING, _T("Could not set file attributes [%s]"), SysMsg().c_str()); |
||
169 | else |
||
170 | #if defined(UNICODE) && defined(ALLOW_WIN98) |
||
171 | if (IsNTorAbove) |
||
172 | SHChangeNotify(SHCNE_ATTRIBUTES, SHCNF_PATH, |
||
173 | fpInfo->spec->Base->FullPath(ffilename), NULL); |
||
174 | else |
||
175 | { |
||
176 | DZStrA atmp(fpInfo->spec->Base->FullPath(ffilename)); |
||
177 | SHChangeNotify(SHCNE_ATTRIBUTES, SHCNF_PATH, atmp, NULL); |
||
178 | } |
||
179 | #else |
||
180 | SHChangeNotify(SHCNE_ATTRIBUTES, SHCNF_PATH, |
||
181 | fpInfo->spec->Base->FullPath(ffilename), NULL); |
||
182 | #endif |
||
183 | |||
184 | return; |
||
185 | } /* end function close_outfile() */ |
||
186 | |||
187 | |||
188 | /* =========================================================================== |
||
189 | * Function isfloppy() |
||
190 | * more precisely, is it removable? |
||
191 | */ |
||
192 | static int isfloppy(int nDrive) |
||
193 | { |
||
194 | /* 1 == A:, 2 == B:, etc. */ |
||
195 | DZStrW root; |
||
196 | TCHAR c = (TCHAR)(_T('A') + nDrive - 1); /* build the root path */ |
||
197 | root += c; |
||
198 | root += _T(":\\"); |
||
199 | return(GetDriveType(root) == DRIVE_REMOVABLE); |
||
200 | } /* end function isfloppy() */ |
||
201 | |||
202 | /* =========================================================================== |
||
203 | * Function mapname() |
||
204 | * There are presently two possibilities in OS/2: the output filesystem is |
||
205 | * FAT, or it is HPFS. If the former, we need to map to FAT, obviously, but |
||
206 | * we *also* must map to HPFS and store that version of the name in extended |
||
207 | * attributes. Either way, we need to map to HPFS, so the main mapname |
||
208 | * routine does that. In the case that the output file system is FAT, an |
||
209 | * extra filename-mapping routine is called in checkdir(). While it should |
||
210 | * be possible to determine the filesystem immediately upon entry to mapname(), |
||
211 | * it is conceivable that the DOS APPEND utility could be added to OS/2 some- |
||
212 | * day, allowing a FAT directory to be APPENDed to an HPFS drive/path. There- |
||
213 | * fore we simply check the filesystem at each path component. |
||
214 | * |
||
215 | * Note that when alternative IFS's become available/popular, everything will |
||
216 | * become immensely more complicated. For example, a Minix filesystem would |
||
217 | * have limited filename lengths like FAT but no extended attributes in which |
||
218 | * to store the longer versions of the names. A BSD Unix filesystem would |
||
219 | * support paths of length 1024 bytes or more, but it is not clear that FAT |
||
220 | * EAs would allow such long .LONGNAME fields or that OS/2 would properly |
||
221 | * restore such fields when moving files from FAT to the new filesystem. |
||
222 | * |
||
223 | * GRR: some or all of the following chars should be checked in either |
||
224 | * mapname (HPFS) or map2fat (FAT), depending: ,=^+'"[]<>|\t& |
||
225 | * |
||
226 | * return 0 if no error, 1 if caution (filename trunc), |
||
227 | renamed :: 2 if warning (skip file because dir doesn't exist), |
||
228 | 3 if error (skip file), 10 if no memory (skip file), |
||
229 | IZ_VOL_LABEL if can't do vol label, IZ_CREATED_DIR |
||
230 | */ |
||
231 | int UnzOpr::mapname(int renamed) |
||
232 | { |
||
233 | DZStrW build; |
||
234 | int fposn; // possition in ffilename |
||
235 | |||
236 | /*--------------------------------------------------------------------------- |
||
237 | * Initialize various pointers and counters and stuff. |
||
238 | *---------------------------------------------------------------------------*/ |
||
239 | /* can create path as long as not just freshening, or if user told us */ |
||
240 | fcreate_dirs = (!ffflag || renamed); |
||
241 | |||
242 | fcreated_dir = false; /* not yet */ |
||
243 | bool isAbs = false; |
||
244 | fposn = 0; |
||
245 | |||
246 | if (renamed) |
||
247 | { |
||
248 | if (fpInfo->vollabel) |
||
249 | { |
||
250 | int drv; |
||
251 | /* use root or renamed path, but don't store */ |
||
252 | if (ffilename[1] == _T(':')) |
||
253 | { |
||
254 | TCHAR d = (TCHAR) _totlower(ffilename[0]); |
||
255 | drv = d - (_T('a') + 1); |
||
256 | } |
||
257 | else |
||
258 | { |
||
259 | int l = GetFullPathName(_T("."), MAX_PATH, build.GetBuffer(MAX_PATH), NULL); |
||
260 | if (l) |
||
261 | { |
||
262 | TCHAR d = (TCHAR) _totlower(ffilename[0]); |
||
263 | drv = d - (_T('a') + 1); |
||
264 | } |
||
265 | } |
||
266 | if (fvolflag == 0 || drv < 0 || drv > 25 /* no labels/bogus? */ |
||
267 | || (fvolflag == 1 && !isfloppy(drv))) |
||
268 | { |
||
269 | /* !fixed */ |
||
270 | return IZ_VOL_LABEL; /* skipping with message */ |
||
271 | } |
||
272 | fnLabelDrive = drv; |
||
273 | } |
||
274 | else |
||
275 | { |
||
276 | fposn = DriveLen(ffilename); |
||
277 | if (fposn < 0) |
||
278 | return 4; // invalid renamed stream |
||
279 | if (fposn > 0) |
||
280 | { |
||
281 | // if (ffilename[fposn] == BSLASH) |
||
282 | // fposn++; |
||
283 | // build = ffilename.Left(fposn); |
||
284 | isAbs = true; // is absolute path |
||
285 | fposn = 0; // want all of it |
||
286 | } |
||
287 | else |
||
288 | if (ffilename[0] == BSLASH) |
||
289 | { |
||
290 | ffilename = ffilename.Mid(1); |
||
291 | } |
||
292 | } |
||
293 | } |
||
294 | |||
295 | /* pathcomp is ignored unless renamed is true: */ |
||
296 | if (!renamed) |
||
297 | { |
||
298 | /* cp already set if renamed */ |
||
299 | if (fjflag) /* junking directories */ |
||
300 | { |
||
301 | fposn = ffilename.ReverseFind(BSLASH); |
||
302 | if (fposn < 0) |
||
303 | fposn = 0; |
||
304 | else |
||
305 | fposn++; |
||
306 | } |
||
307 | } |
||
308 | if (fposn > 0) |
||
309 | ffilename = ffilename.Mid(fposn); |
||
310 | DZStrW ftemp; |
||
311 | int cperr = CleanPath(ffilename, ftemp); |
||
312 | if (cperr != 0) |
||
313 | { |
||
314 | Notify(IWARNING, _T("mapname: rejecting invalid filename: %s [err:%d]"), ffilename.c_str(), cperr); |
||
315 | return DZ_ERM_INVAL_NAME; |
||
316 | } |
||
317 | // if (isAbs) |
||
318 | // ffilename = build + ftemp; |
||
319 | //// ffilename = build = ftemp; |
||
320 | // else |
||
321 | // ffilename = fpInfo->spec->Base->FullPath(ftemp); |
||
322 | if (isAbs) |
||
323 | ffilename = ftemp; |
||
324 | else |
||
325 | ffilename = fpInfo->spec->Base->FullPath(ftemp); |
||
326 | |||
327 | DZStrW dir = ExtractFilePath(ffilename); |
||
328 | // no such dir - check filename |
||
329 | if (!DirExists(dir)) |
||
330 | { |
||
331 | /* path doesn't exist // v1.6025 */ |
||
332 | if (!fcreate_dirs) |
||
333 | { |
||
334 | /* told not to create (freshening) */ |
||
335 | return IZ_SKIP_DIR; // path doesn't exist: nothing to do |
||
336 | } |
||
337 | |||
338 | if (!ForceDirectories(dir, -1)) |
||
339 | { |
||
340 | /* create the directory // v1.6025 */ |
||
341 | Notify(0, _T("can't create %s [%s], unable to process %s."), |
||
342 | dir.c_str(), SysMsg().c_str(), ffilename.c_str()); |
||
343 | return DZ_ERM_ERROR_CREATE; // path didn't exist, tried to create, failed |
||
344 | } |
||
345 | fcreated_dir = true; |
||
346 | } |
||
347 | |||
348 | if (ffilename.LastChar() == BSLASH) |
||
349 | { |
||
350 | if (fcreated_dir) |
||
351 | { |
||
352 | // Notify(0, _T(" created: %s"), ffilename); |
||
353 | /* HG: are we setting the date & time on a newly created */ |
||
354 | /* dir? Not quite sure how to do this. It does not */ |
||
355 | /* seem to be done in the MS-DOS version of mapname(). */ |
||
356 | return IZ_CREATED_DIR; /* dir time already set */ |
||
357 | } |
||
358 | return IZ_SKIP_DIR; /* dir existed already; don't look for data to extract */ |
||
359 | |||
360 | } |
||
361 | return 0; |
||
362 | } |
||
363 |