|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtCore module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #define _POSIX_ |
|
43 #include "qplatformdefs.h" |
|
44 #include "qabstractfileengine.h" |
|
45 #include "private/qfsfileengine_p.h" |
|
46 #include <qdebug.h> |
|
47 |
|
48 #include "qfile.h" |
|
49 #include "qdir.h" |
|
50 #include "private/qmutexpool_p.h" |
|
51 #include "qvarlengtharray.h" |
|
52 #include "qdatetime.h" |
|
53 #include "qt_windows.h" |
|
54 |
|
55 #if !defined(Q_OS_WINCE) |
|
56 # include <sys/types.h> |
|
57 # include <direct.h> |
|
58 # include <winioctl.h> |
|
59 #else |
|
60 # include <types.h> |
|
61 #endif |
|
62 #include <objbase.h> |
|
63 #include <shlobj.h> |
|
64 #include <initguid.h> |
|
65 #include <accctrl.h> |
|
66 #include <ctype.h> |
|
67 #include <limits.h> |
|
68 #define SECURITY_WIN32 |
|
69 #ifdef Q_CC_MINGW |
|
70 // A workaround for a certain version of MinGW, the define UNICODE_STRING. |
|
71 #include <subauth.h> |
|
72 #endif |
|
73 #include <security.h> |
|
74 |
|
75 #ifndef _INTPTR_T_DEFINED |
|
76 #ifdef _WIN64 |
|
77 typedef __int64 intptr_t; |
|
78 #else |
|
79 #ifdef _W64 |
|
80 typedef _W64 int intptr_t; |
|
81 #else |
|
82 typedef INT_PTR intptr_t; |
|
83 #endif |
|
84 #endif |
|
85 #define _INTPTR_T_DEFINED |
|
86 #endif |
|
87 |
|
88 #ifndef INVALID_FILE_ATTRIBUTES |
|
89 # define INVALID_FILE_ATTRIBUTES (DWORD (-1)) |
|
90 #endif |
|
91 |
|
92 #if !defined(Q_OS_WINCE) |
|
93 # if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) |
|
94 typedef struct _REPARSE_DATA_BUFFER { |
|
95 ULONG ReparseTag; |
|
96 USHORT ReparseDataLength; |
|
97 USHORT Reserved; |
|
98 union { |
|
99 struct { |
|
100 USHORT SubstituteNameOffset; |
|
101 USHORT SubstituteNameLength; |
|
102 USHORT PrintNameOffset; |
|
103 USHORT PrintNameLength; |
|
104 ULONG Flags; |
|
105 WCHAR PathBuffer[1]; |
|
106 } SymbolicLinkReparseBuffer; |
|
107 struct { |
|
108 USHORT SubstituteNameOffset; |
|
109 USHORT SubstituteNameLength; |
|
110 USHORT PrintNameOffset; |
|
111 USHORT PrintNameLength; |
|
112 WCHAR PathBuffer[1]; |
|
113 } MountPointReparseBuffer; |
|
114 struct { |
|
115 UCHAR DataBuffer[1]; |
|
116 } GenericReparseBuffer; |
|
117 }; |
|
118 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; |
|
119 # define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) |
|
120 # endif // !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) |
|
121 |
|
122 # ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE |
|
123 # define MAXIMUM_REPARSE_DATA_BUFFER_SIZE 16384 |
|
124 # endif |
|
125 # ifndef IO_REPARSE_TAG_SYMLINK |
|
126 # define IO_REPARSE_TAG_SYMLINK (0xA000000CL) |
|
127 # endif |
|
128 # ifndef FSCTL_GET_REPARSE_POINT |
|
129 # define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) |
|
130 # endif |
|
131 #endif // !defined(Q_OS_WINCE) |
|
132 |
|
133 QT_BEGIN_NAMESPACE |
|
134 |
|
135 static QString readLink(const QString &link); |
|
136 |
|
137 Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0; |
|
138 |
|
139 #if defined(Q_OS_WINCE) |
|
140 static QString qfsPrivateCurrentDir = QLatin1String(""); |
|
141 // As none of the functions we try to resolve do exist on Windows CE |
|
142 // we use QT_NO_LIBRARY to shorten everything up a little bit. |
|
143 #define QT_NO_LIBRARY 1 |
|
144 #endif |
|
145 |
|
146 #if !defined(QT_NO_LIBRARY) |
|
147 QT_BEGIN_INCLUDE_NAMESPACE |
|
148 typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); |
|
149 static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0; |
|
150 typedef BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE); |
|
151 static PtrLookupAccountSidW ptrLookupAccountSidW = 0; |
|
152 typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID); |
|
153 static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0; |
|
154 typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK); |
|
155 static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0; |
|
156 static TRUSTEE_W currentUserTrusteeW; |
|
157 static TRUSTEE_W worldTrusteeW; |
|
158 |
|
159 typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD); |
|
160 static PtrGetUserProfileDirectoryW ptrGetUserProfileDirectoryW = 0; |
|
161 QT_END_INCLUDE_NAMESPACE |
|
162 |
|
163 |
|
164 void QFSFileEnginePrivate::resolveLibs() |
|
165 { |
|
166 static bool triedResolve = false; |
|
167 if (!triedResolve) { |
|
168 // need to resolve the security info functions |
|
169 |
|
170 // protect initialization |
|
171 #ifndef QT_NO_THREAD |
|
172 QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); |
|
173 // check triedResolve again, since another thread may have already |
|
174 // done the initialization |
|
175 if (triedResolve) { |
|
176 // another thread did initialize the security function pointers, |
|
177 // so we shouldn't do it again. |
|
178 return; |
|
179 } |
|
180 #endif |
|
181 |
|
182 triedResolve = true; |
|
183 #if !defined(Q_OS_WINCE) |
|
184 HINSTANCE advapiHnd = LoadLibraryW(L"advapi32"); |
|
185 if (advapiHnd) { |
|
186 ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW"); |
|
187 ptrLookupAccountSidW = (PtrLookupAccountSidW)GetProcAddress(advapiHnd, "LookupAccountSidW"); |
|
188 ptrBuildTrusteeWithSidW = (PtrBuildTrusteeWithSidW)GetProcAddress(advapiHnd, "BuildTrusteeWithSidW"); |
|
189 ptrGetEffectiveRightsFromAclW = (PtrGetEffectiveRightsFromAclW)GetProcAddress(advapiHnd, "GetEffectiveRightsFromAclW"); |
|
190 } |
|
191 if (ptrBuildTrusteeWithSidW) { |
|
192 // Create TRUSTEE for current user |
|
193 HANDLE hnd = ::GetCurrentProcess(); |
|
194 HANDLE token = 0; |
|
195 if (::OpenProcessToken(hnd, TOKEN_QUERY, &token)) { |
|
196 TOKEN_USER tu; |
|
197 DWORD retsize; |
|
198 if (::GetTokenInformation(token, TokenUser, &tu, sizeof(tu), &retsize)) |
|
199 ptrBuildTrusteeWithSidW(¤tUserTrusteeW, tu.User.Sid); |
|
200 ::CloseHandle(token); |
|
201 } |
|
202 |
|
203 typedef BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*); |
|
204 PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = (PtrAllocateAndInitializeSid)GetProcAddress(advapiHnd, "AllocateAndInitializeSid"); |
|
205 typedef PVOID (WINAPI *PtrFreeSid)(PSID); |
|
206 PtrFreeSid ptrFreeSid = (PtrFreeSid)GetProcAddress(advapiHnd, "FreeSid"); |
|
207 if (ptrAllocateAndInitializeSid && ptrFreeSid) { |
|
208 // Create TRUSTEE for Everyone (World) |
|
209 SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY }; |
|
210 PSID pWorld = 0; |
|
211 if (ptrAllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pWorld)) |
|
212 ptrBuildTrusteeWithSidW(&worldTrusteeW, pWorld); |
|
213 ptrFreeSid(pWorld); |
|
214 } |
|
215 } |
|
216 HINSTANCE userenvHnd = LoadLibraryW(L"userenv"); |
|
217 if (userenvHnd) |
|
218 ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW"); |
|
219 #endif |
|
220 } |
|
221 } |
|
222 #endif // QT_NO_LIBRARY |
|
223 |
|
224 // UNC functions NT |
|
225 typedef DWORD (WINAPI *PtrNetShareEnum)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD); |
|
226 static PtrNetShareEnum ptrNetShareEnum = 0; |
|
227 typedef DWORD (WINAPI *PtrNetApiBufferFree)(LPVOID); |
|
228 static PtrNetApiBufferFree ptrNetApiBufferFree = 0; |
|
229 typedef struct _SHARE_INFO_1 { |
|
230 LPWSTR shi1_netname; |
|
231 DWORD shi1_type; |
|
232 LPWSTR shi1_remark; |
|
233 } SHARE_INFO_1; |
|
234 |
|
235 |
|
236 bool QFSFileEnginePrivate::resolveUNCLibs() |
|
237 { |
|
238 static bool triedResolve = false; |
|
239 if (!triedResolve) { |
|
240 #ifndef QT_NO_THREAD |
|
241 QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); |
|
242 if (triedResolve) { |
|
243 return ptrNetShareEnum && ptrNetApiBufferFree; |
|
244 } |
|
245 #endif |
|
246 triedResolve = true; |
|
247 #if !defined(Q_OS_WINCE) |
|
248 HINSTANCE hLib = LoadLibraryW(L"Netapi32"); |
|
249 if (hLib) { |
|
250 ptrNetShareEnum = (PtrNetShareEnum)GetProcAddress(hLib, "NetShareEnum"); |
|
251 if (ptrNetShareEnum) |
|
252 ptrNetApiBufferFree = (PtrNetApiBufferFree)GetProcAddress(hLib, "NetApiBufferFree"); |
|
253 } |
|
254 #endif |
|
255 } |
|
256 return ptrNetShareEnum && ptrNetApiBufferFree; |
|
257 } |
|
258 |
|
259 bool QFSFileEnginePrivate::uncListSharesOnServer(const QString &server, QStringList *list) |
|
260 { |
|
261 if (resolveUNCLibs()) { |
|
262 SHARE_INFO_1 *BufPtr, *p; |
|
263 DWORD res; |
|
264 DWORD er = 0, tr = 0, resume = 0, i; |
|
265 do { |
|
266 res = ptrNetShareEnum((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume); |
|
267 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) { |
|
268 p = BufPtr; |
|
269 for (i = 1; i <= er; ++i) { |
|
270 if (list && p->shi1_type == 0) |
|
271 list->append(QString::fromWCharArray(p->shi1_netname)); |
|
272 p++; |
|
273 } |
|
274 } |
|
275 ptrNetApiBufferFree(BufPtr); |
|
276 } while (res == ERROR_MORE_DATA); |
|
277 return res == ERROR_SUCCESS; |
|
278 } |
|
279 return false; |
|
280 } |
|
281 |
|
282 static bool isUncRoot(const QString &server) |
|
283 { |
|
284 QString localPath = QDir::toNativeSeparators(server); |
|
285 if (!localPath.startsWith(QLatin1String("\\\\"))) |
|
286 return false; |
|
287 |
|
288 int idx = localPath.indexOf(QLatin1Char('\\'), 2); |
|
289 if (idx == -1 || idx + 1 == localPath.length()) |
|
290 return true; |
|
291 |
|
292 localPath = localPath.right(localPath.length() - idx - 1).trimmed(); |
|
293 return localPath.isEmpty(); |
|
294 } |
|
295 |
|
296 #if !defined(Q_OS_WINCE) |
|
297 static inline bool isUncPath(const QString &path) |
|
298 { |
|
299 // Starts with \\, but not \\. |
|
300 return (path.startsWith(QLatin1String("\\\\")) |
|
301 && path.size() > 2 && path.at(2) != QLatin1Char('.')); |
|
302 } |
|
303 #endif |
|
304 |
|
305 static inline bool isRelativePath(const QString &path) |
|
306 { |
|
307 // drive, e.g. "a:", or UNC root, e.q. "//" |
|
308 return !(path.startsWith(QLatin1Char('/')) |
|
309 || (path.length() >= 2 |
|
310 && ((path.at(0).isLetter() && path.at(1) == QLatin1Char(':')) |
|
311 || (path.at(0) == QLatin1Char('/') && path.at(1) == QLatin1Char('/'))))); |
|
312 } |
|
313 |
|
314 static QString fixIfRelativeUncPath(const QString &path) |
|
315 { |
|
316 if (isRelativePath(path)) { |
|
317 QString currentPath = QDir::currentPath() + QLatin1Char('/'); |
|
318 if (currentPath.startsWith(QLatin1String("//"))) |
|
319 return QString(path).prepend(currentPath); |
|
320 } |
|
321 return path; |
|
322 } |
|
323 |
|
324 // can be //server or //server/share |
|
325 static bool uncShareExists(const QString &server) |
|
326 { |
|
327 QStringList parts = server.split(QLatin1Char('\\'), QString::SkipEmptyParts); |
|
328 if (parts.count()) { |
|
329 QStringList shares; |
|
330 if (QFSFileEnginePrivate::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(0), &shares)) |
|
331 return parts.count() >= 2 ? shares.contains(parts.at(1), Qt::CaseInsensitive) : true; |
|
332 } |
|
333 return false; |
|
334 } |
|
335 |
|
336 static inline bool isDriveRoot(const QString &path) |
|
337 { |
|
338 return (path.length() == 3 |
|
339 && path.at(0).isLetter() && path.at(1) == QLatin1Char(':') |
|
340 && path.at(2) == QLatin1Char('/')); |
|
341 } |
|
342 |
|
343 static QString nativeAbsoluteFilePath(const QString &path) |
|
344 { |
|
345 QString absPath; |
|
346 #if !defined(Q_OS_WINCE) |
|
347 QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1)); |
|
348 wchar_t *fileName = 0; |
|
349 DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName); |
|
350 if (retLen > (DWORD)buf.size()) { |
|
351 buf.resize(retLen); |
|
352 retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName); |
|
353 } |
|
354 if (retLen != 0) |
|
355 absPath = QString::fromWCharArray(buf.data(), retLen); |
|
356 #else |
|
357 if (path.startsWith(QLatin1Char('/')) || path.startsWith(QLatin1Char('\\'))) |
|
358 absPath = QDir::toNativeSeparators(path); |
|
359 else |
|
360 absPath = QDir::toNativeSeparators(QDir::cleanPath(qfsPrivateCurrentDir + QLatin1Char('/') + path)); |
|
361 #endif |
|
362 // This is really ugly, but GetFullPathName strips off whitespace at the end. |
|
363 // If you for instance write ". " in the lineedit of QFileDialog, |
|
364 // (which is an invalid filename) this function will strip the space off and viola, |
|
365 // the file is later reported as existing. Therefore, we re-add the whitespace that |
|
366 // was at the end of path in order to keep the filename invalid. |
|
367 if (!path.isEmpty() && path.at(path.size() - 1) == QLatin1Char(' ')) |
|
368 absPath.append(QLatin1Char(' ')); |
|
369 return absPath; |
|
370 } |
|
371 |
|
372 /*! |
|
373 \internal |
|
374 */ |
|
375 QString QFSFileEnginePrivate::longFileName(const QString &path) |
|
376 { |
|
377 if (path.startsWith(QLatin1String("\\\\.\\"))) |
|
378 return path; |
|
379 |
|
380 QString absPath = nativeAbsoluteFilePath(path); |
|
381 #if !defined(Q_OS_WINCE) |
|
382 QString prefix = QLatin1String("\\\\?\\"); |
|
383 if (isUncPath(absPath)) { |
|
384 prefix.append(QLatin1String("UNC\\")); // "\\\\?\\UNC\\" |
|
385 absPath.remove(0, 2); |
|
386 } |
|
387 return prefix + absPath; |
|
388 #else |
|
389 return absPath; |
|
390 #endif |
|
391 } |
|
392 |
|
393 /* |
|
394 \internal |
|
395 */ |
|
396 void QFSFileEnginePrivate::nativeInitFileName() |
|
397 { |
|
398 QString path = longFileName(QDir::toNativeSeparators(fixIfRelativeUncPath(filePath))); |
|
399 nativeFilePath = QByteArray((const char *)path.utf16(), path.size() * 2 + 1); |
|
400 } |
|
401 |
|
402 /* |
|
403 \internal |
|
404 */ |
|
405 bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) |
|
406 { |
|
407 Q_Q(QFSFileEngine); |
|
408 |
|
409 // All files are opened in share mode (both read and write). |
|
410 DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; |
|
411 |
|
412 int accessRights = 0; |
|
413 if (openMode & QIODevice::ReadOnly) |
|
414 accessRights |= GENERIC_READ; |
|
415 if (openMode & QIODevice::WriteOnly) |
|
416 accessRights |= GENERIC_WRITE; |
|
417 |
|
418 SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE }; |
|
419 |
|
420 // WriteOnly can create files, ReadOnly cannot. |
|
421 DWORD creationDisp = (openMode & QIODevice::WriteOnly) ? OPEN_ALWAYS : OPEN_EXISTING; |
|
422 |
|
423 // Create the file handle. |
|
424 fileHandle = CreateFile((const wchar_t*)nativeFilePath.constData(), |
|
425 accessRights, |
|
426 shareMode, |
|
427 &securityAtts, |
|
428 creationDisp, |
|
429 FILE_ATTRIBUTE_NORMAL, |
|
430 NULL); |
|
431 |
|
432 // Bail out on error. |
|
433 if (fileHandle == INVALID_HANDLE_VALUE) { |
|
434 q->setError(QFile::OpenError, qt_error_string()); |
|
435 return false; |
|
436 } |
|
437 |
|
438 // Truncate the file after successfully opening it if Truncate is passed. |
|
439 if (openMode & QIODevice::Truncate) |
|
440 q->setSize(0); |
|
441 |
|
442 return true; |
|
443 } |
|
444 |
|
445 /* |
|
446 \internal |
|
447 */ |
|
448 bool QFSFileEnginePrivate::nativeClose() |
|
449 { |
|
450 Q_Q(QFSFileEngine); |
|
451 if (fh || fd != -1) { |
|
452 // stdlib / stdio mode. |
|
453 return closeFdFh(); |
|
454 } |
|
455 |
|
456 // Windows native mode. |
|
457 bool ok = true; |
|
458 if ((fileHandle == INVALID_HANDLE_VALUE || !CloseHandle(fileHandle)) |
|
459 #ifdef Q_USE_DEPRECATED_MAP_API |
|
460 && (fileMapHandle == INVALID_HANDLE_VALUE || !CloseHandle(fileMapHandle)) |
|
461 #endif |
|
462 ) { |
|
463 q->setError(QFile::UnspecifiedError, qt_error_string()); |
|
464 ok = false; |
|
465 } |
|
466 #ifdef Q_USE_DEPRECATED_MAP_API |
|
467 fileMapHandle = INVALID_HANDLE_VALUE; |
|
468 #endif |
|
469 fileHandle = INVALID_HANDLE_VALUE; |
|
470 cachedFd = -1; // gets closed by CloseHandle above |
|
471 |
|
472 return ok; |
|
473 } |
|
474 |
|
475 /* |
|
476 \internal |
|
477 */ |
|
478 bool QFSFileEnginePrivate::nativeFlush() |
|
479 { |
|
480 if (fh) { |
|
481 // Buffered stdlib mode. |
|
482 return flushFh(); |
|
483 } |
|
484 if (fd != -1) { |
|
485 // Unbuffered stdio mode; always succeeds (no buffer). |
|
486 return true; |
|
487 } |
|
488 |
|
489 // Windows native mode; flushing is |
|
490 // unnecessary. FlushFileBuffers(), the equivalent of sync() or |
|
491 // fsync() on Unix, does a low-level flush to the disk, and we |
|
492 // don't expose an API for this. |
|
493 return true; |
|
494 } |
|
495 |
|
496 /* |
|
497 \internal |
|
498 */ |
|
499 qint64 QFSFileEnginePrivate::nativeSize() const |
|
500 { |
|
501 Q_Q(const QFSFileEngine); |
|
502 QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q); |
|
503 |
|
504 // ### Don't flush; for buffered files, we should get away with ftell. |
|
505 thatQ->flush(); |
|
506 |
|
507 // Buffered stdlib mode. |
|
508 if (fh) { |
|
509 QT_OFF_T oldPos = QT_FTELL(fh); |
|
510 QT_FSEEK(fh, 0, SEEK_END); |
|
511 QT_OFF_T fileSize = QT_FTELL(fh); |
|
512 QT_FSEEK(fh, oldPos, SEEK_SET); |
|
513 return qint64(fileSize); |
|
514 } |
|
515 |
|
516 // Not-open mode, where the file name is known: We'll check the |
|
517 // file system directly. |
|
518 if (openMode == QIODevice::NotOpen && !nativeFilePath.isEmpty()) { |
|
519 WIN32_FILE_ATTRIBUTE_DATA attribData; |
|
520 bool ok = ::GetFileAttributesEx((const wchar_t*)nativeFilePath.constData(), |
|
521 GetFileExInfoStandard, &attribData); |
|
522 if (!ok) { |
|
523 int errorCode = GetLastError(); |
|
524 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { |
|
525 QByteArray path = nativeFilePath; |
|
526 // path for the FindFirstFile should not end with a trailing slash |
|
527 while (path.endsWith('\\')) |
|
528 path.chop(1); |
|
529 |
|
530 // FindFirstFile can not handle drives |
|
531 if (!path.endsWith(':')) { |
|
532 WIN32_FIND_DATA findData; |
|
533 HANDLE hFind = ::FindFirstFile((const wchar_t*)path.constData(), |
|
534 &findData); |
|
535 if (hFind != INVALID_HANDLE_VALUE) { |
|
536 ::FindClose(hFind); |
|
537 ok = true; |
|
538 attribData.nFileSizeHigh = findData.nFileSizeHigh; |
|
539 attribData.nFileSizeLow = findData.nFileSizeLow; |
|
540 } |
|
541 } |
|
542 } |
|
543 } |
|
544 if (ok) { |
|
545 qint64 size = attribData.nFileSizeHigh; |
|
546 size <<= 32; |
|
547 size += attribData.nFileSizeLow; |
|
548 return size; |
|
549 } |
|
550 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); |
|
551 return 0; |
|
552 } |
|
553 |
|
554 // Unbuffed stdio mode. |
|
555 if(fd != -1) { |
|
556 #if !defined(Q_OS_WINCE) |
|
557 HANDLE handle = (HANDLE)_get_osfhandle(fd); |
|
558 if (handle != INVALID_HANDLE_VALUE) { |
|
559 BY_HANDLE_FILE_INFORMATION fileInfo; |
|
560 if (GetFileInformationByHandle(handle, &fileInfo)) { |
|
561 qint64 size = fileInfo.nFileSizeHigh; |
|
562 size <<= 32; |
|
563 size += fileInfo.nFileSizeLow; |
|
564 return size; |
|
565 } |
|
566 } |
|
567 #endif |
|
568 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); |
|
569 return 0; |
|
570 } |
|
571 |
|
572 // Windows native mode. |
|
573 if (fileHandle == INVALID_HANDLE_VALUE) |
|
574 return 0; |
|
575 |
|
576 BY_HANDLE_FILE_INFORMATION fileInfo; |
|
577 if (!GetFileInformationByHandle(fileHandle, &fileInfo)) { |
|
578 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); |
|
579 return 0; |
|
580 } |
|
581 |
|
582 qint64 size = fileInfo.nFileSizeHigh; |
|
583 size <<= 32; |
|
584 size += fileInfo.nFileSizeLow; |
|
585 return size; |
|
586 } |
|
587 |
|
588 /* |
|
589 \internal |
|
590 */ |
|
591 qint64 QFSFileEnginePrivate::nativePos() const |
|
592 { |
|
593 Q_Q(const QFSFileEngine); |
|
594 QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q); |
|
595 |
|
596 if (fh || fd != -1) { |
|
597 // stdlib / stido mode. |
|
598 return posFdFh(); |
|
599 } |
|
600 |
|
601 // Windows native mode. |
|
602 if (fileHandle == INVALID_HANDLE_VALUE) |
|
603 return 0; |
|
604 |
|
605 #if !defined(Q_OS_WINCE) |
|
606 LARGE_INTEGER currentFilePos; |
|
607 LARGE_INTEGER offset; |
|
608 offset.QuadPart = 0; |
|
609 if (!::SetFilePointerEx(fileHandle, offset, ¤tFilePos, FILE_CURRENT)) { |
|
610 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); |
|
611 return 0; |
|
612 } |
|
613 |
|
614 return qint64(currentFilePos.QuadPart); |
|
615 #else |
|
616 LARGE_INTEGER filepos; |
|
617 filepos.HighPart = 0; |
|
618 DWORD newFilePointer = SetFilePointer(fileHandle, 0, &filepos.HighPart, FILE_CURRENT); |
|
619 if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) { |
|
620 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); |
|
621 return 0; |
|
622 } |
|
623 |
|
624 filepos.LowPart = newFilePointer; |
|
625 return filepos.QuadPart; |
|
626 #endif |
|
627 } |
|
628 |
|
629 /* |
|
630 \internal |
|
631 */ |
|
632 bool QFSFileEnginePrivate::nativeSeek(qint64 pos) |
|
633 { |
|
634 Q_Q(QFSFileEngine); |
|
635 |
|
636 if (fh || fd != -1) { |
|
637 // stdlib / stdio mode. |
|
638 return seekFdFh(pos); |
|
639 } |
|
640 |
|
641 #if !defined(Q_OS_WINCE) |
|
642 LARGE_INTEGER currentFilePos; |
|
643 LARGE_INTEGER offset; |
|
644 offset.QuadPart = pos; |
|
645 if (!::SetFilePointerEx(fileHandle, offset, ¤tFilePos, FILE_BEGIN)) { |
|
646 q->setError(QFile::UnspecifiedError, qt_error_string()); |
|
647 return false; |
|
648 } |
|
649 |
|
650 return true; |
|
651 #else |
|
652 DWORD newFilePointer; |
|
653 LARGE_INTEGER *li = reinterpret_cast<LARGE_INTEGER*>(&pos); |
|
654 newFilePointer = SetFilePointer(fileHandle, li->LowPart, &li->HighPart, FILE_BEGIN); |
|
655 if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) { |
|
656 q->setError(QFile::PositionError, qt_error_string()); |
|
657 return false; |
|
658 } |
|
659 |
|
660 return true; |
|
661 #endif |
|
662 } |
|
663 |
|
664 /* |
|
665 \internal |
|
666 */ |
|
667 qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen) |
|
668 { |
|
669 Q_Q(QFSFileEngine); |
|
670 |
|
671 if (fh || fd != -1) { |
|
672 // stdio / stdlib mode. |
|
673 if (fh && nativeIsSequential() && feof(fh)) { |
|
674 q->setError(QFile::ReadError, qt_error_string(int(errno))); |
|
675 return -1; |
|
676 } |
|
677 |
|
678 return readFdFh(data, maxlen); |
|
679 } |
|
680 |
|
681 // Windows native mode. |
|
682 if (fileHandle == INVALID_HANDLE_VALUE) |
|
683 return -1; |
|
684 |
|
685 DWORD bytesToRead = DWORD(maxlen); // <- lossy |
|
686 |
|
687 // Reading on Windows fails with ERROR_NO_SYSTEM_RESOURCES when |
|
688 // the chunks are too large, so we limit the block size to 32MB. |
|
689 static const DWORD maxBlockSize = 32 * 1024 * 1024; |
|
690 |
|
691 qint64 totalRead = 0; |
|
692 do { |
|
693 DWORD blockSize = qMin<DWORD>(bytesToRead, maxBlockSize); |
|
694 DWORD bytesRead; |
|
695 if (!ReadFile(fileHandle, data + totalRead, blockSize, &bytesRead, NULL)) { |
|
696 if (totalRead == 0) { |
|
697 // Note: only return failure if the first ReadFile fails. |
|
698 q->setError(QFile::ReadError, qt_error_string()); |
|
699 return -1; |
|
700 } |
|
701 break; |
|
702 } |
|
703 if (bytesRead == 0) |
|
704 break; |
|
705 totalRead += bytesRead; |
|
706 bytesToRead -= bytesRead; |
|
707 } while (totalRead < maxlen); |
|
708 return qint64(totalRead); |
|
709 } |
|
710 |
|
711 /* |
|
712 \internal |
|
713 */ |
|
714 qint64 QFSFileEnginePrivate::nativeReadLine(char *data, qint64 maxlen) |
|
715 { |
|
716 Q_Q(QFSFileEngine); |
|
717 |
|
718 if (fh || fd != -1) { |
|
719 // stdio / stdlib mode. |
|
720 return readLineFdFh(data, maxlen); |
|
721 } |
|
722 |
|
723 // Windows native mode. |
|
724 if (fileHandle == INVALID_HANDLE_VALUE) |
|
725 return -1; |
|
726 |
|
727 // ### No equivalent in Win32? |
|
728 return q->QAbstractFileEngine::readLine(data, maxlen); |
|
729 } |
|
730 |
|
731 /* |
|
732 \internal |
|
733 */ |
|
734 qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len) |
|
735 { |
|
736 Q_Q(QFSFileEngine); |
|
737 |
|
738 if (fh || fd != -1) { |
|
739 // stdio / stdlib mode. |
|
740 return writeFdFh(data, len); |
|
741 } |
|
742 |
|
743 // Windows native mode. |
|
744 if (fileHandle == INVALID_HANDLE_VALUE) |
|
745 return -1; |
|
746 |
|
747 qint64 bytesToWrite = DWORD(len); // <- lossy |
|
748 |
|
749 // Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when |
|
750 // the chunks are too large, so we limit the block size to 32MB. |
|
751 static const DWORD maxBlockSize = 32 * 1024 * 1024; |
|
752 |
|
753 qint64 totalWritten = 0; |
|
754 do { |
|
755 DWORD blockSize = qMin<DWORD>(bytesToWrite, maxBlockSize); |
|
756 DWORD bytesWritten; |
|
757 if (!WriteFile(fileHandle, data + totalWritten, blockSize, &bytesWritten, NULL)) { |
|
758 if (totalWritten == 0) { |
|
759 // Note: Only return error if the first WriteFile failed. |
|
760 q->setError(QFile::WriteError, qt_error_string()); |
|
761 return -1; |
|
762 } |
|
763 break; |
|
764 } |
|
765 if (bytesWritten == 0) |
|
766 break; |
|
767 totalWritten += bytesWritten; |
|
768 bytesToWrite -= bytesWritten; |
|
769 } while (totalWritten < len); |
|
770 return qint64(totalWritten); |
|
771 } |
|
772 |
|
773 /* |
|
774 \internal |
|
775 */ |
|
776 int QFSFileEnginePrivate::nativeHandle() const |
|
777 { |
|
778 if (fh || fd != -1) |
|
779 return fh ? QT_FILENO(fh) : fd; |
|
780 #ifndef Q_OS_WINCE |
|
781 if (cachedFd != -1) |
|
782 return cachedFd; |
|
783 |
|
784 int flags = 0; |
|
785 if (openMode & QIODevice::Append) |
|
786 flags |= _O_APPEND; |
|
787 if (!(openMode & QIODevice::WriteOnly)) |
|
788 flags |= _O_RDONLY; |
|
789 cachedFd = _open_osfhandle((intptr_t) fileHandle, flags); |
|
790 return cachedFd; |
|
791 #else |
|
792 return -1; |
|
793 #endif |
|
794 } |
|
795 |
|
796 /* |
|
797 \internal |
|
798 */ |
|
799 bool QFSFileEnginePrivate::nativeIsSequential() const |
|
800 { |
|
801 #if !defined(Q_OS_WINCE) |
|
802 // stdlib / Windows native mode. |
|
803 if (fh || fileHandle != INVALID_HANDLE_VALUE) { |
|
804 if (fh == stdin || fh == stdout || fh == stderr) |
|
805 return true; |
|
806 |
|
807 HANDLE handle = fileHandle; |
|
808 if (fileHandle == INVALID_HANDLE_VALUE) { |
|
809 // Rare case: using QFile::open(FILE*) to open a pipe. |
|
810 handle = (HANDLE)_get_osfhandle(QT_FILENO(fh)); |
|
811 return false; |
|
812 } |
|
813 |
|
814 DWORD fileType = GetFileType(handle); |
|
815 return fileType == FILE_TYPE_PIPE; |
|
816 } |
|
817 |
|
818 // stdio mode. |
|
819 if (fd != -1) |
|
820 return isSequentialFdFh(); |
|
821 #endif |
|
822 return false; |
|
823 } |
|
824 |
|
825 bool QFSFileEngine::remove() |
|
826 { |
|
827 Q_D(QFSFileEngine); |
|
828 bool ret = ::DeleteFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16()) != 0; |
|
829 if (!ret) |
|
830 setError(QFile::RemoveError, qt_error_string()); |
|
831 return ret; |
|
832 } |
|
833 |
|
834 bool QFSFileEngine::copy(const QString ©Name) |
|
835 { |
|
836 Q_D(QFSFileEngine); |
|
837 bool ret = ::CopyFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), |
|
838 (wchar_t*)QFSFileEnginePrivate::longFileName(copyName).utf16(), true) != 0; |
|
839 if (!ret) |
|
840 setError(QFile::CopyError, qt_error_string()); |
|
841 return ret; |
|
842 } |
|
843 |
|
844 bool QFSFileEngine::rename(const QString &newName) |
|
845 { |
|
846 Q_D(QFSFileEngine); |
|
847 bool ret = ::MoveFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), |
|
848 (wchar_t*)QFSFileEnginePrivate::longFileName(newName).utf16()) != 0; |
|
849 if (!ret) |
|
850 setError(QFile::RenameError, qt_error_string()); |
|
851 return ret; |
|
852 } |
|
853 |
|
854 static inline bool mkDir(const QString &path) |
|
855 { |
|
856 #if defined(Q_OS_WINCE) |
|
857 // Unfortunately CreateDirectory returns true for paths longer than |
|
858 // 256, but does not create a directory. It starts to fail, when |
|
859 // path length > MAX_PATH, which is 260 usually on CE. |
|
860 // This only happens on a Windows Mobile device. Windows CE seems |
|
861 // not to be affected by this. |
|
862 static int platformId = 0; |
|
863 if (platformId == 0) { |
|
864 wchar_t platformString[64]; |
|
865 if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(platformString)/sizeof(*platformString),platformString,0)) { |
|
866 if (0 == wcscmp(platformString, L"PocketPC") || 0 == wcscmp(platformString, L"Smartphone")) |
|
867 platformId = 1; |
|
868 else |
|
869 platformId = 2; |
|
870 } |
|
871 } |
|
872 if (platformId == 1 && QFSFileEnginePrivate::longFileName(path).size() > 256) |
|
873 return false; |
|
874 #endif |
|
875 return ::CreateDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), 0); |
|
876 } |
|
877 |
|
878 static inline bool rmDir(const QString &path) |
|
879 { |
|
880 return ::RemoveDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); |
|
881 } |
|
882 |
|
883 static bool isDirPath(const QString &dirPath, bool *existed) |
|
884 { |
|
885 QString path = dirPath; |
|
886 if (path.length() == 2 && path.at(1) == QLatin1Char(':')) |
|
887 path += QLatin1Char('\\'); |
|
888 |
|
889 DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); |
|
890 if (fileAttrib == INVALID_FILE_ATTRIBUTES) { |
|
891 int errorCode = GetLastError(); |
|
892 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { |
|
893 // path for the FindFirstFile should not end with a trailing slash |
|
894 while (path.endsWith(QLatin1Char('\\'))) |
|
895 path.chop(1); |
|
896 |
|
897 // FindFirstFile can not handle drives |
|
898 if (!path.endsWith(QLatin1Char(':'))) { |
|
899 WIN32_FIND_DATA findData; |
|
900 HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), |
|
901 &findData); |
|
902 if (hFind != INVALID_HANDLE_VALUE) { |
|
903 ::FindClose(hFind); |
|
904 fileAttrib = findData.dwFileAttributes; |
|
905 } |
|
906 } |
|
907 } |
|
908 } |
|
909 |
|
910 if (existed) |
|
911 *existed = fileAttrib != INVALID_FILE_ATTRIBUTES; |
|
912 |
|
913 if (fileAttrib == INVALID_FILE_ATTRIBUTES) |
|
914 return false; |
|
915 |
|
916 return fileAttrib & FILE_ATTRIBUTE_DIRECTORY; |
|
917 } |
|
918 |
|
919 bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const |
|
920 { |
|
921 QString dirName = name; |
|
922 if (createParentDirectories) { |
|
923 dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); |
|
924 // We spefically search for / so \ would break it.. |
|
925 int oldslash = -1; |
|
926 if (dirName.startsWith(QLatin1String("\\\\"))) { |
|
927 // Don't try to create the root path of a UNC path; |
|
928 // CreateDirectory() will just return ERROR_INVALID_NAME. |
|
929 for (int i = 0; i < dirName.size(); ++i) { |
|
930 if (dirName.at(i) != QDir::separator()) { |
|
931 oldslash = i; |
|
932 break; |
|
933 } |
|
934 } |
|
935 if (oldslash != -1) |
|
936 oldslash = dirName.indexOf(QDir::separator(), oldslash); |
|
937 } |
|
938 for (int slash=0; slash != -1; oldslash = slash) { |
|
939 slash = dirName.indexOf(QDir::separator(), oldslash+1); |
|
940 if (slash == -1) { |
|
941 if (oldslash == dirName.length()) |
|
942 break; |
|
943 slash = dirName.length(); |
|
944 } |
|
945 if (slash) { |
|
946 QString chunk = dirName.left(slash); |
|
947 bool existed = false; |
|
948 if (!isDirPath(chunk, &existed)) { |
|
949 if (!existed) { |
|
950 if (!mkDir(chunk)) |
|
951 return false; |
|
952 } else { |
|
953 return false; |
|
954 } |
|
955 } |
|
956 } |
|
957 } |
|
958 return true; |
|
959 } |
|
960 return mkDir(name); |
|
961 } |
|
962 |
|
963 bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const |
|
964 { |
|
965 QString dirName = name; |
|
966 if (recurseParentDirectories) { |
|
967 dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); |
|
968 for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) { |
|
969 QString chunk = dirName.left(slash); |
|
970 if (chunk.length() == 2 && chunk.at(0).isLetter() && chunk.at(1) == QLatin1Char(':')) |
|
971 break; |
|
972 if (!isDirPath(chunk, 0)) |
|
973 return false; |
|
974 if (!rmDir(chunk)) |
|
975 return oldslash != 0; |
|
976 slash = dirName.lastIndexOf(QDir::separator(), oldslash-1); |
|
977 } |
|
978 return true; |
|
979 } |
|
980 return rmDir(name); |
|
981 } |
|
982 |
|
983 bool QFSFileEngine::caseSensitive() const |
|
984 { |
|
985 return false; |
|
986 } |
|
987 |
|
988 bool QFSFileEngine::setCurrentPath(const QString &path) |
|
989 { |
|
990 if (!QDir(path).exists()) |
|
991 return false; |
|
992 |
|
993 #if !defined(Q_OS_WINCE) |
|
994 return ::SetCurrentDirectory((wchar_t*)path.utf16()) != 0; |
|
995 #else |
|
996 qfsPrivateCurrentDir = QFSFileEnginePrivate::longFileName(path); |
|
997 return true; |
|
998 #endif |
|
999 } |
|
1000 |
|
1001 QString QFSFileEngine::currentPath(const QString &fileName) |
|
1002 { |
|
1003 #if !defined(Q_OS_WINCE) |
|
1004 QString ret; |
|
1005 //if filename is a drive: then get the pwd of that drive |
|
1006 if (fileName.length() >= 2 && |
|
1007 fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':')) { |
|
1008 int drv = fileName.toUpper().at(0).toLatin1() - 'A' + 1; |
|
1009 if (_getdrive() != drv) { |
|
1010 wchar_t buf[PATH_MAX]; |
|
1011 ::_wgetdcwd(drv, buf, PATH_MAX); |
|
1012 ret = QString::fromWCharArray(buf); |
|
1013 } |
|
1014 } |
|
1015 if (ret.isEmpty()) { |
|
1016 //just the pwd |
|
1017 DWORD size = 0; |
|
1018 wchar_t currentName[PATH_MAX]; |
|
1019 size = ::GetCurrentDirectory(PATH_MAX, currentName); |
|
1020 if (size != 0) { |
|
1021 if (size > PATH_MAX) { |
|
1022 wchar_t *newCurrentName = new wchar_t[size]; |
|
1023 if (::GetCurrentDirectory(PATH_MAX, newCurrentName) != 0) |
|
1024 ret = QString::fromWCharArray(newCurrentName); |
|
1025 delete [] newCurrentName; |
|
1026 } else { |
|
1027 ret = QString::fromWCharArray(currentName); |
|
1028 } |
|
1029 } |
|
1030 } |
|
1031 if (ret.length() >= 2 && ret[1] == QLatin1Char(':')) |
|
1032 ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters. |
|
1033 return QDir::fromNativeSeparators(ret); |
|
1034 #else |
|
1035 Q_UNUSED(fileName); |
|
1036 if (qfsPrivateCurrentDir.isEmpty()) |
|
1037 qfsPrivateCurrentDir = QCoreApplication::applicationDirPath(); |
|
1038 |
|
1039 return QDir::fromNativeSeparators(qfsPrivateCurrentDir); |
|
1040 #endif |
|
1041 } |
|
1042 |
|
1043 QString QFSFileEngine::homePath() |
|
1044 { |
|
1045 QString ret; |
|
1046 #if !defined(QT_NO_LIBRARY) |
|
1047 QFSFileEnginePrivate::resolveLibs(); |
|
1048 if (ptrGetUserProfileDirectoryW) { |
|
1049 HANDLE hnd = ::GetCurrentProcess(); |
|
1050 HANDLE token = 0; |
|
1051 BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token); |
|
1052 if (ok) { |
|
1053 DWORD dwBufferSize = 0; |
|
1054 // First call, to determine size of the strings (with '\0'). |
|
1055 ok = ::ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize); |
|
1056 if (!ok && dwBufferSize != 0) { // We got the required buffer size |
|
1057 wchar_t *userDirectory = new wchar_t[dwBufferSize]; |
|
1058 // Second call, now we can fill the allocated buffer. |
|
1059 ok = ::ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize); |
|
1060 if (ok) |
|
1061 ret = QString::fromWCharArray(userDirectory); |
|
1062 |
|
1063 delete [] userDirectory; |
|
1064 } |
|
1065 ::CloseHandle(token); |
|
1066 } |
|
1067 } |
|
1068 #endif |
|
1069 if (ret.isEmpty() || !QFile::exists(ret)) { |
|
1070 ret = QString::fromLocal8Bit(qgetenv("USERPROFILE").constData()); |
|
1071 if (ret.isEmpty() || !QFile::exists(ret)) { |
|
1072 ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE").constData()) + QString::fromLocal8Bit(qgetenv("HOMEPATH").constData()); |
|
1073 if (ret.isEmpty() || !QFile::exists(ret)) { |
|
1074 ret = QString::fromLocal8Bit(qgetenv("HOME").constData()); |
|
1075 if (ret.isEmpty() || !QFile::exists(ret)) { |
|
1076 #if defined(Q_OS_WINCE) |
|
1077 ret = QLatin1String("\\My Documents"); |
|
1078 if (!QFile::exists(ret)) |
|
1079 #endif |
|
1080 ret = rootPath(); |
|
1081 } |
|
1082 } |
|
1083 } |
|
1084 } |
|
1085 return QDir::fromNativeSeparators(ret); |
|
1086 } |
|
1087 |
|
1088 QString QFSFileEngine::rootPath() |
|
1089 { |
|
1090 #if defined(Q_OS_WINCE) |
|
1091 QString ret = QLatin1String("/"); |
|
1092 #elif defined(Q_FS_FAT) |
|
1093 QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData()); |
|
1094 if (ret.isEmpty()) |
|
1095 ret = QLatin1String("c:"); |
|
1096 ret.append(QLatin1Char('/')); |
|
1097 #elif defined(Q_OS_OS2EMX) |
|
1098 char dir[4]; |
|
1099 _abspath(dir, QLatin1String("/"), _MAX_PATH); |
|
1100 QString ret(dir); |
|
1101 #endif |
|
1102 return ret; |
|
1103 } |
|
1104 |
|
1105 QString QFSFileEngine::tempPath() |
|
1106 { |
|
1107 QString ret; |
|
1108 { |
|
1109 wchar_t tempPath[MAX_PATH]; |
|
1110 if (GetTempPath(MAX_PATH, tempPath)) |
|
1111 ret = QString::fromWCharArray(tempPath); |
|
1112 if (!ret.isEmpty()) { |
|
1113 while (ret.endsWith(QLatin1Char('\\'))) |
|
1114 ret.chop(1); |
|
1115 ret = QDir::fromNativeSeparators(ret); |
|
1116 } |
|
1117 } |
|
1118 if (ret.isEmpty()) { |
|
1119 #if !defined(Q_OS_WINCE) |
|
1120 ret = QLatin1String("c:/tmp"); |
|
1121 #else |
|
1122 ret = QLatin1String("/Temp"); |
|
1123 #endif |
|
1124 } |
|
1125 return ret; |
|
1126 } |
|
1127 |
|
1128 QFileInfoList QFSFileEngine::drives() |
|
1129 { |
|
1130 QFileInfoList ret; |
|
1131 #if !defined(Q_OS_WINCE) |
|
1132 #if defined(Q_OS_WIN32) |
|
1133 quint32 driveBits = (quint32) GetLogicalDrives() & 0x3ffffff; |
|
1134 #elif defined(Q_OS_OS2EMX) |
|
1135 quint32 driveBits, cur; |
|
1136 if (DosQueryCurrentDisk(&cur, &driveBits) != NO_ERROR) |
|
1137 exit(1); |
|
1138 driveBits &= 0x3ffffff; |
|
1139 #endif |
|
1140 char driveName[] = "A:/"; |
|
1141 |
|
1142 while (driveBits) { |
|
1143 if (driveBits & 1) |
|
1144 ret.append(QFileInfo(QLatin1String(driveName))); |
|
1145 driveName[0]++; |
|
1146 driveBits = driveBits >> 1; |
|
1147 } |
|
1148 return ret; |
|
1149 #else |
|
1150 ret.append(QFileInfo(QLatin1String("/"))); |
|
1151 return ret; |
|
1152 #endif |
|
1153 } |
|
1154 |
|
1155 bool QFSFileEnginePrivate::doStat() const |
|
1156 { |
|
1157 if (!tried_stat) { |
|
1158 tried_stat = true; |
|
1159 could_stat = false; |
|
1160 |
|
1161 if (filePath.isEmpty()) |
|
1162 return could_stat; |
|
1163 |
|
1164 QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; |
|
1165 fname = fixIfRelativeUncPath(fname); |
|
1166 |
|
1167 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); |
|
1168 |
|
1169 if (fd != -1) { |
|
1170 #if !defined(Q_OS_WINCE) |
|
1171 HANDLE fh = (HANDLE)_get_osfhandle(fd); |
|
1172 if (fh != INVALID_HANDLE_VALUE) { |
|
1173 BY_HANDLE_FILE_INFORMATION fileInfo; |
|
1174 if (GetFileInformationByHandle(fh, &fileInfo)) { |
|
1175 could_stat = true; |
|
1176 fileAttrib = fileInfo.dwFileAttributes; |
|
1177 } |
|
1178 } |
|
1179 #else |
|
1180 DWORD tmpAttributes = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16()); |
|
1181 if (tmpAttributes != -1) { |
|
1182 fileAttrib = tmpAttributes; |
|
1183 could_stat = true; |
|
1184 } |
|
1185 #endif |
|
1186 } else { |
|
1187 fileAttrib = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16()); |
|
1188 if (fileAttrib == INVALID_FILE_ATTRIBUTES) { |
|
1189 int errorCode = GetLastError(); |
|
1190 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { |
|
1191 QString path = QDir::toNativeSeparators(fname); |
|
1192 // path for the FindFirstFile should not end with a trailing slash |
|
1193 while (path.endsWith(QLatin1Char('\\'))) |
|
1194 path.chop(1); |
|
1195 |
|
1196 // FindFirstFile can not handle drives |
|
1197 if (!path.endsWith(QLatin1Char(':'))) { |
|
1198 WIN32_FIND_DATA findData; |
|
1199 HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), |
|
1200 &findData); |
|
1201 if (hFind != INVALID_HANDLE_VALUE) { |
|
1202 ::FindClose(hFind); |
|
1203 fileAttrib = findData.dwFileAttributes; |
|
1204 } |
|
1205 } |
|
1206 } |
|
1207 } |
|
1208 could_stat = fileAttrib != INVALID_FILE_ATTRIBUTES; |
|
1209 if (!could_stat) { |
|
1210 #if !defined(Q_OS_WINCE) |
|
1211 if (isDriveRoot(fname)) { |
|
1212 // a valid drive ?? |
|
1213 DWORD drivesBitmask = ::GetLogicalDrives(); |
|
1214 int drivebit = 1 << (fname.at(0).toUpper().unicode() - QLatin1Char('A').unicode()); |
|
1215 if (drivesBitmask & drivebit) { |
|
1216 fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM; |
|
1217 could_stat = true; |
|
1218 } |
|
1219 } else { |
|
1220 #endif |
|
1221 QString path = QDir::toNativeSeparators(fname); |
|
1222 bool is_dir = false; |
|
1223 if (path.startsWith(QLatin1String("\\\\"))) { |
|
1224 // UNC - stat doesn't work for all cases (Windows bug) |
|
1225 int s = path.indexOf(path.at(0),2); |
|
1226 if (s > 0) { |
|
1227 // "\\server\..." |
|
1228 s = path.indexOf(path.at(0),s+1); |
|
1229 if (s > 0) { |
|
1230 // "\\server\share\..." |
|
1231 if (s == path.size() - 1) { |
|
1232 // "\\server\share\" |
|
1233 is_dir = true; |
|
1234 } else { |
|
1235 // "\\server\share\notfound" |
|
1236 } |
|
1237 } else { |
|
1238 // "\\server\share" |
|
1239 is_dir = true; |
|
1240 } |
|
1241 } else { |
|
1242 // "\\server" |
|
1243 is_dir = true; |
|
1244 } |
|
1245 } |
|
1246 if (is_dir && uncShareExists(path)) { |
|
1247 // looks like a UNC dir, is a dir. |
|
1248 fileAttrib = FILE_ATTRIBUTE_DIRECTORY; |
|
1249 could_stat = true; |
|
1250 } |
|
1251 #if !defined(Q_OS_WINCE) |
|
1252 } |
|
1253 #endif |
|
1254 } |
|
1255 } |
|
1256 |
|
1257 SetErrorMode(oldmode); |
|
1258 } |
|
1259 return could_stat; |
|
1260 } |
|
1261 |
|
1262 |
|
1263 static QString readSymLink(const QString &link) |
|
1264 { |
|
1265 QString result; |
|
1266 #if !defined(Q_OS_WINCE) |
|
1267 HANDLE handle = CreateFile((wchar_t*)QFSFileEnginePrivate::longFileName(link).utf16(), |
|
1268 FILE_READ_EA, |
|
1269 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
|
1270 0, |
|
1271 OPEN_EXISTING, |
|
1272 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, |
|
1273 0); |
|
1274 if (handle != INVALID_HANDLE_VALUE) { |
|
1275 DWORD bufsize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; |
|
1276 REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)qMalloc(bufsize); |
|
1277 DWORD retsize = 0; |
|
1278 if (::DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, 0, 0, rdb, bufsize, &retsize, 0)) { |
|
1279 if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { |
|
1280 int length = rdb->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t); |
|
1281 int offset = rdb->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); |
|
1282 const wchar_t* PathBuffer = &rdb->MountPointReparseBuffer.PathBuffer[offset]; |
|
1283 result = QString::fromWCharArray(PathBuffer, length); |
|
1284 } else { |
|
1285 int length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); |
|
1286 int offset = rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); |
|
1287 const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset]; |
|
1288 result = QString::fromWCharArray(PathBuffer, length); |
|
1289 } |
|
1290 // cut-off "//?/" and "/??/" |
|
1291 if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\')) |
|
1292 result = result.mid(4); |
|
1293 } |
|
1294 qFree(rdb); |
|
1295 CloseHandle(handle); |
|
1296 } |
|
1297 #else |
|
1298 Q_UNUSED(link); |
|
1299 #endif // Q_OS_WINCE |
|
1300 return result; |
|
1301 } |
|
1302 |
|
1303 static QString readLink(const QString &link) |
|
1304 { |
|
1305 #if !defined(Q_OS_WINCE) |
|
1306 #if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS) |
|
1307 QString ret; |
|
1308 |
|
1309 bool neededCoInit = false; |
|
1310 IShellLink *psl; // pointer to IShellLink i/f |
|
1311 WIN32_FIND_DATA wfd; |
|
1312 wchar_t szGotPath[MAX_PATH]; |
|
1313 |
|
1314 // Get pointer to the IShellLink interface. |
|
1315 HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl); |
|
1316 |
|
1317 if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized |
|
1318 neededCoInit = true; |
|
1319 CoInitialize(NULL); |
|
1320 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, |
|
1321 IID_IShellLink, (LPVOID *)&psl); |
|
1322 } |
|
1323 if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface. |
|
1324 IPersistFile *ppf; |
|
1325 hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); |
|
1326 if (SUCCEEDED(hres)) { |
|
1327 hres = ppf->Load((LPOLESTR)link.utf16(), STGM_READ); |
|
1328 //The original path of the link is retrieved. If the file/folder |
|
1329 //was moved, the return value still have the old path. |
|
1330 if (SUCCEEDED(hres)) { |
|
1331 if (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR) |
|
1332 ret = QString::fromWCharArray(szGotPath); |
|
1333 } |
|
1334 ppf->Release(); |
|
1335 } |
|
1336 psl->Release(); |
|
1337 } |
|
1338 if (neededCoInit) |
|
1339 CoUninitialize(); |
|
1340 |
|
1341 return ret; |
|
1342 #else |
|
1343 Q_UNUSED(link); |
|
1344 return QString(); |
|
1345 #endif // QT_NO_LIBRARY |
|
1346 #else |
|
1347 wchar_t target[MAX_PATH]; |
|
1348 QString result; |
|
1349 if (SHGetShortcutTarget((wchar_t*)QFileInfo(link).absoluteFilePath().replace(QLatin1Char('/'),QLatin1Char('\\')).utf16(), target, MAX_PATH)) { |
|
1350 result = QString::fromWCharArray(target); |
|
1351 if (result.startsWith(QLatin1Char('"'))) |
|
1352 result.remove(0,1); |
|
1353 if (result.endsWith(QLatin1Char('"'))) |
|
1354 result.remove(result.size()-1,1); |
|
1355 } |
|
1356 return result; |
|
1357 #endif // Q_OS_WINCE |
|
1358 } |
|
1359 |
|
1360 bool QFSFileEngine::link(const QString &newName) |
|
1361 { |
|
1362 #if !defined(Q_OS_WINCE) |
|
1363 #if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS) |
|
1364 bool ret = false; |
|
1365 |
|
1366 QString linkName = newName; |
|
1367 //### assume that they add .lnk |
|
1368 |
|
1369 IShellLink *psl; |
|
1370 bool neededCoInit = false; |
|
1371 |
|
1372 HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); |
|
1373 |
|
1374 if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized |
|
1375 neededCoInit = true; |
|
1376 CoInitialize(NULL); |
|
1377 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); |
|
1378 } |
|
1379 |
|
1380 if (SUCCEEDED(hres)) { |
|
1381 hres = psl->SetPath((wchar_t *)fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16()); |
|
1382 if (SUCCEEDED(hres)) { |
|
1383 hres = psl->SetWorkingDirectory((wchar_t *)fileName(AbsolutePathName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16()); |
|
1384 if (SUCCEEDED(hres)) { |
|
1385 IPersistFile *ppf; |
|
1386 hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf); |
|
1387 if (SUCCEEDED(hres)) { |
|
1388 hres = ppf->Save((wchar_t*)linkName.utf16(), TRUE); |
|
1389 if (SUCCEEDED(hres)) |
|
1390 ret = true; |
|
1391 ppf->Release(); |
|
1392 } |
|
1393 } |
|
1394 } |
|
1395 psl->Release(); |
|
1396 } |
|
1397 if (!ret) |
|
1398 setError(QFile::RenameError, qt_error_string()); |
|
1399 |
|
1400 if (neededCoInit) |
|
1401 CoUninitialize(); |
|
1402 |
|
1403 return ret; |
|
1404 #else |
|
1405 Q_UNUSED(newName); |
|
1406 return false; |
|
1407 #endif // QT_NO_LIBRARY |
|
1408 #else |
|
1409 QString linkName = newName; |
|
1410 if (!linkName.endsWith(QLatin1String(".lnk"))) |
|
1411 linkName += QLatin1String(".lnk"); |
|
1412 QString orgName = fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')); |
|
1413 // Need to append on our own |
|
1414 orgName.prepend(QLatin1Char('"')); |
|
1415 orgName.append(QLatin1Char('"')); |
|
1416 bool ret = SUCCEEDED(SHCreateShortcut((wchar_t*)linkName.utf16(), (wchar_t*)orgName.utf16())); |
|
1417 if (!ret) |
|
1418 setError(QFile::RenameError, qt_error_string()); |
|
1419 return ret; |
|
1420 #endif // Q_OS_WINCE |
|
1421 } |
|
1422 |
|
1423 /*! |
|
1424 \internal |
|
1425 */ |
|
1426 QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions() const |
|
1427 { |
|
1428 QAbstractFileEngine::FileFlags ret = 0; |
|
1429 |
|
1430 #if !defined(QT_NO_LIBRARY) |
|
1431 if((qt_ntfs_permission_lookup > 0) && ((QSysInfo::WindowsVersion&QSysInfo::WV_NT_based) > QSysInfo::WV_NT)) { |
|
1432 PSID pOwner = 0; |
|
1433 PSID pGroup = 0; |
|
1434 PACL pDacl; |
|
1435 PSECURITY_DESCRIPTOR pSD; |
|
1436 ACCESS_MASK access_mask; |
|
1437 |
|
1438 enum { ReadMask = 0x00000001, WriteMask = 0x00000002, ExecMask = 0x00000020 }; |
|
1439 resolveLibs(); |
|
1440 if(ptrGetNamedSecurityInfoW && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW) { |
|
1441 |
|
1442 QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; |
|
1443 DWORD res = ptrGetNamedSecurityInfoW((wchar_t*)fname.utf16(), SE_FILE_OBJECT, |
|
1444 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, |
|
1445 &pOwner, &pGroup, &pDacl, 0, &pSD); |
|
1446 |
|
1447 if(res == ERROR_SUCCESS) { |
|
1448 TRUSTEE_W trustee; |
|
1449 { //user |
|
1450 if(ptrGetEffectiveRightsFromAclW(pDacl, ¤tUserTrusteeW, &access_mask) != ERROR_SUCCESS) |
|
1451 access_mask = (ACCESS_MASK)-1; |
|
1452 if(access_mask & ReadMask) |
|
1453 ret |= QAbstractFileEngine::ReadUserPerm; |
|
1454 if(access_mask & WriteMask) |
|
1455 ret |= QAbstractFileEngine::WriteUserPerm; |
|
1456 if(access_mask & ExecMask) |
|
1457 ret |= QAbstractFileEngine::ExeUserPerm; |
|
1458 } |
|
1459 { //owner |
|
1460 ptrBuildTrusteeWithSidW(&trustee, pOwner); |
|
1461 if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) |
|
1462 access_mask = (ACCESS_MASK)-1; |
|
1463 if(access_mask & ReadMask) |
|
1464 ret |= QAbstractFileEngine::ReadOwnerPerm; |
|
1465 if(access_mask & WriteMask) |
|
1466 ret |= QAbstractFileEngine::WriteOwnerPerm; |
|
1467 if(access_mask & ExecMask) |
|
1468 ret |= QAbstractFileEngine::ExeOwnerPerm; |
|
1469 } |
|
1470 { //group |
|
1471 ptrBuildTrusteeWithSidW(&trustee, pGroup); |
|
1472 if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) |
|
1473 access_mask = (ACCESS_MASK)-1; |
|
1474 if(access_mask & ReadMask) |
|
1475 ret |= QAbstractFileEngine::ReadGroupPerm; |
|
1476 if(access_mask & WriteMask) |
|
1477 ret |= QAbstractFileEngine::WriteGroupPerm; |
|
1478 if(access_mask & ExecMask) |
|
1479 ret |= QAbstractFileEngine::ExeGroupPerm; |
|
1480 } |
|
1481 { //other (world) |
|
1482 if(ptrGetEffectiveRightsFromAclW(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS) |
|
1483 access_mask = (ACCESS_MASK)-1; // ### |
|
1484 if(access_mask & ReadMask) |
|
1485 ret |= QAbstractFileEngine::ReadOtherPerm; |
|
1486 if(access_mask & WriteMask) |
|
1487 ret |= QAbstractFileEngine::WriteOtherPerm; |
|
1488 if(access_mask & ExecMask) |
|
1489 ret |= QAbstractFileEngine::ExeOtherPerm; |
|
1490 } |
|
1491 LocalFree(pSD); |
|
1492 } |
|
1493 } |
|
1494 } else |
|
1495 #endif |
|
1496 { |
|
1497 //### what to do with permissions if we don't use NTFS |
|
1498 // for now just add all permissions and what about exe missions ?? |
|
1499 // also qt_ntfs_permission_lookup is now not set by defualt ... should it ? |
|
1500 ret |= QAbstractFileEngine::ReadOtherPerm | QAbstractFileEngine::ReadGroupPerm |
|
1501 | QAbstractFileEngine::ReadOwnerPerm | QAbstractFileEngine::ReadUserPerm |
|
1502 | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::WriteOwnerPerm |
|
1503 | QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm; |
|
1504 |
|
1505 if (doStat()) { |
|
1506 if (ret & (QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | |
|
1507 QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm)) { |
|
1508 if (fileAttrib & FILE_ATTRIBUTE_READONLY) |
|
1509 ret &= ~(QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | |
|
1510 QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm); |
|
1511 } |
|
1512 |
|
1513 QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; |
|
1514 QString ext = fname.right(4).toLower(); |
|
1515 if (ext == QLatin1String(".exe") || ext == QLatin1String(".com") || ext == QLatin1String(".bat") || |
|
1516 ext == QLatin1String(".pif") || ext == QLatin1String(".cmd") || (fileAttrib & FILE_ATTRIBUTE_DIRECTORY)) |
|
1517 ret |= QAbstractFileEngine::ExeOwnerPerm | QAbstractFileEngine::ExeGroupPerm | |
|
1518 QAbstractFileEngine::ExeOtherPerm | QAbstractFileEngine::ExeUserPerm; |
|
1519 } |
|
1520 } |
|
1521 return ret; |
|
1522 } |
|
1523 |
|
1524 /*! |
|
1525 \internal |
|
1526 */ |
|
1527 bool QFSFileEnginePrivate::isSymlink() const |
|
1528 { |
|
1529 #if !defined(Q_OS_WINCE) |
|
1530 if (need_lstat) { |
|
1531 need_lstat = false; |
|
1532 is_link = false; |
|
1533 |
|
1534 if (fileAttrib & FILE_ATTRIBUTE_REPARSE_POINT) { |
|
1535 QString path = QDir::toNativeSeparators(filePath); |
|
1536 // path for the FindFirstFile should not end with a trailing slash |
|
1537 while (path.endsWith(QLatin1Char('\\'))) |
|
1538 path.chop(1); |
|
1539 |
|
1540 WIN32_FIND_DATA findData; |
|
1541 HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), |
|
1542 &findData); |
|
1543 if (hFind != INVALID_HANDLE_VALUE) { |
|
1544 ::FindClose(hFind); |
|
1545 if ((findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) |
|
1546 && (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT |
|
1547 || findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { |
|
1548 is_link = true; |
|
1549 } |
|
1550 } |
|
1551 } |
|
1552 } |
|
1553 return is_link; |
|
1554 #else |
|
1555 return false; |
|
1556 #endif // Q_OS_WINCE |
|
1557 } |
|
1558 |
|
1559 /*! |
|
1560 \reimp |
|
1561 */ |
|
1562 QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const |
|
1563 { |
|
1564 Q_D(const QFSFileEngine); |
|
1565 QAbstractFileEngine::FileFlags ret = 0; |
|
1566 // Force a stat, so that we're guaranteed to get up-to-date results |
|
1567 if (type & Refresh) { |
|
1568 d->tried_stat = 0; |
|
1569 #if !defined(Q_OS_WINCE) |
|
1570 d->need_lstat = 1; |
|
1571 #endif |
|
1572 } |
|
1573 |
|
1574 if (type & PermsMask) { |
|
1575 ret |= d->getPermissions(); |
|
1576 // ### Workaround pascals ### above. Since we always set all properties to true |
|
1577 // we need to disable read and exec access if the file does not exists |
|
1578 if (d->doStat()) |
|
1579 ret |= ExistsFlag; |
|
1580 else |
|
1581 ret &= 0x2222; |
|
1582 } |
|
1583 if (type & TypesMask) { |
|
1584 if (d->filePath.endsWith(QLatin1String(".lnk"))) { |
|
1585 ret |= LinkType; |
|
1586 QString l = readLink(d->filePath); |
|
1587 if (!l.isEmpty()) { |
|
1588 bool existed = false; |
|
1589 if (isDirPath(l, &existed) && existed) |
|
1590 ret |= DirectoryType; |
|
1591 else if (existed) |
|
1592 ret |= FileType; |
|
1593 } |
|
1594 } else if (d->doStat()) { |
|
1595 if ((type & LinkType) && d->isSymlink()) |
|
1596 ret |= LinkType; |
|
1597 if (d->fileAttrib & FILE_ATTRIBUTE_DIRECTORY) { |
|
1598 ret |= DirectoryType; |
|
1599 } else { |
|
1600 ret |= FileType; |
|
1601 } |
|
1602 } |
|
1603 } |
|
1604 if (type & FlagsMask) { |
|
1605 ret |= LocalDiskFlag; |
|
1606 if (d->doStat()) { |
|
1607 ret |= ExistsFlag; |
|
1608 if (d->filePath == QLatin1String("/") || isDriveRoot(d->filePath) || isUncRoot(d->filePath)) { |
|
1609 ret |= RootFlag; |
|
1610 } else if (d->fileAttrib & FILE_ATTRIBUTE_HIDDEN) { |
|
1611 QString baseName = fileName(BaseName); |
|
1612 if (baseName != QLatin1String(".") && baseName != QLatin1String("..")) |
|
1613 ret |= HiddenFlag; |
|
1614 } |
|
1615 } |
|
1616 } |
|
1617 return ret; |
|
1618 } |
|
1619 |
|
1620 QString QFSFileEngine::fileName(FileName file) const |
|
1621 { |
|
1622 Q_D(const QFSFileEngine); |
|
1623 if (file == BaseName) { |
|
1624 int slash = d->filePath.lastIndexOf(QLatin1Char('/')); |
|
1625 if (slash == -1) { |
|
1626 int colon = d->filePath.lastIndexOf(QLatin1Char(':')); |
|
1627 if (colon != -1) |
|
1628 return d->filePath.mid(colon + 1); |
|
1629 return d->filePath; |
|
1630 } |
|
1631 return d->filePath.mid(slash + 1); |
|
1632 } else if (file == PathName) { |
|
1633 if (!d->filePath.size()) |
|
1634 return d->filePath; |
|
1635 |
|
1636 int slash = d->filePath.lastIndexOf(QLatin1Char('/')); |
|
1637 if (slash == -1) { |
|
1638 if (d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) |
|
1639 return d->filePath.left(2); |
|
1640 return QString(QLatin1Char('.')); |
|
1641 } else { |
|
1642 if (!slash) |
|
1643 return QString(QLatin1Char('/')); |
|
1644 if (slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) |
|
1645 slash++; |
|
1646 return d->filePath.left(slash); |
|
1647 } |
|
1648 } else if (file == AbsoluteName || file == AbsolutePathName) { |
|
1649 QString ret; |
|
1650 |
|
1651 if (!isRelativePath()) { |
|
1652 #if !defined(Q_OS_WINCE) |
|
1653 if ((d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') |
|
1654 && d->filePath.at(2) != QLatin1Char('/')) || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt |
|
1655 d->filePath.startsWith(QLatin1Char('/')) // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt |
|
1656 ) { |
|
1657 ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(d->filePath)); |
|
1658 } else { |
|
1659 ret = d->filePath; |
|
1660 } |
|
1661 #else |
|
1662 ret = d->filePath; |
|
1663 #endif |
|
1664 } else { |
|
1665 ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->filePath); |
|
1666 } |
|
1667 |
|
1668 // The path should be absolute at this point. |
|
1669 // From the docs : |
|
1670 // Absolute paths begin with the directory separator "/" |
|
1671 // (optionally preceded by a drive specification under Windows). |
|
1672 if (ret.at(0) != QLatin1Char('/')) { |
|
1673 Q_ASSERT(ret.length() >= 2); |
|
1674 Q_ASSERT(ret.at(0).isLetter()); |
|
1675 Q_ASSERT(ret.at(1) == QLatin1Char(':')); |
|
1676 |
|
1677 // Force uppercase drive letters. |
|
1678 ret[0] = ret.at(0).toUpper(); |
|
1679 } |
|
1680 |
|
1681 if (file == AbsolutePathName) { |
|
1682 int slash = ret.lastIndexOf(QLatin1Char('/')); |
|
1683 if (slash < 0) |
|
1684 return ret; |
|
1685 else if (ret.at(0) != QLatin1Char('/') && slash == 2) |
|
1686 return ret.left(3); // include the slash |
|
1687 else |
|
1688 return ret.left(slash > 0 ? slash : 1); |
|
1689 } |
|
1690 return ret; |
|
1691 } else if (file == CanonicalName || file == CanonicalPathName) { |
|
1692 if (!(fileFlags(ExistsFlag) & ExistsFlag)) |
|
1693 return QString(); |
|
1694 |
|
1695 QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName)); |
|
1696 if (!ret.isEmpty() && file == CanonicalPathName) { |
|
1697 int slash = ret.lastIndexOf(QLatin1Char('/')); |
|
1698 if (slash == -1) |
|
1699 ret = QDir::currentPath(); |
|
1700 else if (slash == 0) |
|
1701 ret = QString(QLatin1Char('/')); |
|
1702 ret = ret.left(slash); |
|
1703 } |
|
1704 return ret; |
|
1705 } else if (file == LinkName) { |
|
1706 QString ret; |
|
1707 if (d->filePath.endsWith(QLatin1String(".lnk"))) |
|
1708 ret = readLink(d->filePath); |
|
1709 else if (d->doStat() && d->isSymlink()) |
|
1710 ret = readSymLink(d->filePath); |
|
1711 return QDir::fromNativeSeparators(ret); |
|
1712 } else if (file == BundleName) { |
|
1713 return QString(); |
|
1714 } |
|
1715 return d->filePath; |
|
1716 } |
|
1717 |
|
1718 bool QFSFileEngine::isRelativePath() const |
|
1719 { |
|
1720 Q_D(const QFSFileEngine); |
|
1721 // drive, e.g. "a:", or UNC root, e.q. "//" |
|
1722 return !(d->filePath.startsWith(QLatin1Char('/')) |
|
1723 || (d->filePath.length() >= 2 |
|
1724 && ((d->filePath.at(0).isLetter() && d->filePath.at(1) == QLatin1Char(':')) |
|
1725 || (d->filePath.at(0) == QLatin1Char('/') && d->filePath.at(1) == QLatin1Char('/'))))); |
|
1726 } |
|
1727 |
|
1728 uint QFSFileEngine::ownerId(FileOwner /*own*/) const |
|
1729 { |
|
1730 static const uint nobodyID = (uint) -2; |
|
1731 return nobodyID; |
|
1732 } |
|
1733 |
|
1734 QString QFSFileEngine::owner(FileOwner own) const |
|
1735 { |
|
1736 #if !defined(QT_NO_LIBRARY) |
|
1737 Q_D(const QFSFileEngine); |
|
1738 if((qt_ntfs_permission_lookup > 0) && ((QSysInfo::WindowsVersion&QSysInfo::WV_NT_based) > QSysInfo::WV_NT)) { |
|
1739 PSID pOwner = 0; |
|
1740 PSECURITY_DESCRIPTOR pSD; |
|
1741 QString name; |
|
1742 QFSFileEnginePrivate::resolveLibs(); |
|
1743 |
|
1744 if(ptrGetNamedSecurityInfoW && ptrLookupAccountSidW) { |
|
1745 if(ptrGetNamedSecurityInfoW((wchar_t*)d->filePath.utf16(), SE_FILE_OBJECT, |
|
1746 own == OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION, |
|
1747 NULL, &pOwner, NULL, NULL, &pSD) == ERROR_SUCCESS) { |
|
1748 DWORD lowner = 0, ldomain = 0; |
|
1749 SID_NAME_USE use; |
|
1750 // First call, to determine size of the strings (with '\0'). |
|
1751 ptrLookupAccountSidW(NULL, pOwner, NULL, &lowner, NULL, &ldomain, (SID_NAME_USE*)&use); |
|
1752 wchar_t *owner = new wchar_t[lowner]; |
|
1753 wchar_t *domain = new wchar_t[ldomain]; |
|
1754 // Second call, size is without '\0' |
|
1755 if(ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner, &lowner, |
|
1756 (LPWSTR)domain, &ldomain, (SID_NAME_USE*)&use)) { |
|
1757 name = QString::fromUtf16((ushort*)owner); |
|
1758 } |
|
1759 LocalFree(pSD); |
|
1760 delete [] owner; |
|
1761 delete [] domain; |
|
1762 } |
|
1763 } |
|
1764 return name; |
|
1765 } |
|
1766 #else |
|
1767 Q_UNUSED(own); |
|
1768 #endif |
|
1769 return QString(); |
|
1770 } |
|
1771 |
|
1772 bool QFSFileEngine::setPermissions(uint perms) |
|
1773 { |
|
1774 Q_D(QFSFileEngine); |
|
1775 bool ret = false; |
|
1776 int mode = 0; |
|
1777 |
|
1778 if (perms & QFile::ReadOwner || perms & QFile::ReadUser || perms & QFile::ReadGroup || perms & QFile::ReadOther) |
|
1779 mode |= _S_IREAD; |
|
1780 if (perms & QFile::WriteOwner || perms & QFile::WriteUser || perms & QFile::WriteGroup || perms & QFile::WriteOther) |
|
1781 mode |= _S_IWRITE; |
|
1782 |
|
1783 if (mode == 0) // not supported |
|
1784 return false; |
|
1785 |
|
1786 ret = ::_wchmod((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), mode) == 0; |
|
1787 if (!ret) |
|
1788 setError(QFile::PermissionsError, qt_error_string(errno)); |
|
1789 return ret; |
|
1790 } |
|
1791 |
|
1792 bool QFSFileEngine::setSize(qint64 size) |
|
1793 { |
|
1794 Q_D(QFSFileEngine); |
|
1795 |
|
1796 if (d->fileHandle != INVALID_HANDLE_VALUE || d->fd != -1) { |
|
1797 // resize open file |
|
1798 HANDLE fh = d->fileHandle; |
|
1799 #if !defined(Q_OS_WINCE) |
|
1800 if (fh == INVALID_HANDLE_VALUE) |
|
1801 fh = (HANDLE)_get_osfhandle(d->fd); |
|
1802 #endif |
|
1803 if (fh == INVALID_HANDLE_VALUE) |
|
1804 return false; |
|
1805 qint64 currentPos = pos(); |
|
1806 |
|
1807 if (seek(size) && SetEndOfFile(fh)) { |
|
1808 seek(qMin(currentPos, size)); |
|
1809 return true; |
|
1810 } |
|
1811 |
|
1812 seek(currentPos); |
|
1813 return false; |
|
1814 } |
|
1815 |
|
1816 if (!d->nativeFilePath.isEmpty()) { |
|
1817 // resize file on disk |
|
1818 QFile file(d->filePath); |
|
1819 if (file.open(QFile::ReadWrite)) { |
|
1820 bool ret = file.resize(size); |
|
1821 if (!ret) |
|
1822 setError(QFile::ResizeError, file.errorString()); |
|
1823 return ret; |
|
1824 } |
|
1825 } |
|
1826 return false; |
|
1827 } |
|
1828 |
|
1829 |
|
1830 static inline QDateTime fileTimeToQDateTime(const FILETIME *time) |
|
1831 { |
|
1832 QDateTime ret; |
|
1833 |
|
1834 #if defined(Q_OS_WINCE) |
|
1835 SYSTEMTIME systime; |
|
1836 FILETIME ftime; |
|
1837 systime.wYear = 1970; |
|
1838 systime.wMonth = 1; |
|
1839 systime.wDay = 1; |
|
1840 systime.wHour = 0; |
|
1841 systime.wMinute = 0; |
|
1842 systime.wSecond = 0; |
|
1843 systime.wMilliseconds = 0; |
|
1844 systime.wDayOfWeek = 4; |
|
1845 SystemTimeToFileTime(&systime, &ftime); |
|
1846 unsigned __int64 acttime = (unsigned __int64)time->dwHighDateTime << 32 | time->dwLowDateTime; |
|
1847 FileTimeToSystemTime(time, &systime); |
|
1848 unsigned __int64 time1970 = (unsigned __int64)ftime.dwHighDateTime << 32 | ftime.dwLowDateTime; |
|
1849 unsigned __int64 difftime = acttime - time1970; |
|
1850 difftime /= 10000000; |
|
1851 ret.setTime_t((unsigned int)difftime); |
|
1852 #else |
|
1853 SYSTEMTIME sTime, lTime; |
|
1854 FileTimeToSystemTime(time, &sTime); |
|
1855 SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime); |
|
1856 ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay)); |
|
1857 ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds)); |
|
1858 #endif |
|
1859 |
|
1860 return ret; |
|
1861 } |
|
1862 |
|
1863 QDateTime QFSFileEngine::fileTime(FileTime time) const |
|
1864 { |
|
1865 Q_D(const QFSFileEngine); |
|
1866 QDateTime ret; |
|
1867 if (d->fd != -1) { |
|
1868 #if !defined(Q_OS_WINCE) |
|
1869 HANDLE fh = (HANDLE)_get_osfhandle(d->fd); |
|
1870 if (fh != INVALID_HANDLE_VALUE) { |
|
1871 FILETIME creationTime, lastAccessTime, lastWriteTime; |
|
1872 if (GetFileTime(fh, &creationTime, &lastAccessTime, &lastWriteTime)) { |
|
1873 if(time == CreationTime) |
|
1874 ret = fileTimeToQDateTime(&creationTime); |
|
1875 else if(time == ModificationTime) |
|
1876 ret = fileTimeToQDateTime(&lastWriteTime); |
|
1877 else if(time == AccessTime) |
|
1878 ret = fileTimeToQDateTime(&lastAccessTime); |
|
1879 } |
|
1880 } |
|
1881 #endif |
|
1882 } else { |
|
1883 WIN32_FILE_ATTRIBUTE_DATA attribData; |
|
1884 bool ok = ::GetFileAttributesEx((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), GetFileExInfoStandard, &attribData); |
|
1885 if (!ok) { |
|
1886 int errorCode = GetLastError(); |
|
1887 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { |
|
1888 QString path = QDir::toNativeSeparators(d->filePath); |
|
1889 // path for the FindFirstFile should not end with a trailing slash |
|
1890 while (path.endsWith(QLatin1Char('\\'))) |
|
1891 path.chop(1); |
|
1892 |
|
1893 // FindFirstFile can not handle drives |
|
1894 if (!path.endsWith(QLatin1Char(':'))) { |
|
1895 WIN32_FIND_DATA findData; |
|
1896 HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), |
|
1897 &findData); |
|
1898 if (hFind != INVALID_HANDLE_VALUE) { |
|
1899 ::FindClose(hFind); |
|
1900 ok = true; |
|
1901 attribData.ftCreationTime = findData.ftCreationTime; |
|
1902 attribData.ftLastWriteTime = findData.ftLastWriteTime; |
|
1903 attribData.ftLastAccessTime = findData.ftLastAccessTime; |
|
1904 } |
|
1905 } |
|
1906 } |
|
1907 } |
|
1908 if (ok) { |
|
1909 if(time == CreationTime) |
|
1910 ret = fileTimeToQDateTime(&attribData.ftCreationTime); |
|
1911 else if(time == ModificationTime) |
|
1912 ret = fileTimeToQDateTime(&attribData.ftLastWriteTime); |
|
1913 else if(time == AccessTime) |
|
1914 ret = fileTimeToQDateTime(&attribData.ftLastAccessTime); |
|
1915 } |
|
1916 } |
|
1917 return ret; |
|
1918 } |
|
1919 |
|
1920 uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, |
|
1921 QFile::MemoryMapFlags flags) |
|
1922 { |
|
1923 Q_Q(QFSFileEngine); |
|
1924 Q_UNUSED(flags); |
|
1925 if (openMode == QFile::NotOpen) { |
|
1926 q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); |
|
1927 return 0; |
|
1928 } |
|
1929 if (offset == 0 && size == 0) { |
|
1930 q->setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER)); |
|
1931 return 0; |
|
1932 } |
|
1933 |
|
1934 |
|
1935 // get handle to the file |
|
1936 HANDLE handle = fileHandle; |
|
1937 #ifndef Q_OS_WINCE |
|
1938 if (handle == INVALID_HANDLE_VALUE && fh) |
|
1939 handle = (HANDLE)_get_osfhandle(QT_FILENO(fh)); |
|
1940 #endif |
|
1941 |
|
1942 #ifdef Q_USE_DEPRECATED_MAP_API |
|
1943 if (fileMapHandle == INVALID_HANDLE_VALUE) { |
|
1944 nativeClose(); |
|
1945 fileMapHandle = CreateFileForMapping((const wchar_t*)nativeFilePath.constData(), |
|
1946 GENERIC_READ | (openMode & QIODevice::WriteOnly ? GENERIC_WRITE : 0), |
|
1947 0, |
|
1948 NULL, |
|
1949 OPEN_EXISTING, |
|
1950 FILE_ATTRIBUTE_NORMAL, |
|
1951 NULL); |
|
1952 } |
|
1953 handle = fileMapHandle; |
|
1954 #endif |
|
1955 |
|
1956 if (handle == INVALID_HANDLE_VALUE) { |
|
1957 q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); |
|
1958 return 0; |
|
1959 } |
|
1960 |
|
1961 // first create the file mapping handle |
|
1962 DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY; |
|
1963 HANDLE mapHandle = ::CreateFileMapping(handle, 0, protection, 0, 0, 0); |
|
1964 if (mapHandle == NULL) { |
|
1965 q->setError(QFile::PermissionsError, qt_error_string()); |
|
1966 #ifdef Q_USE_DEPRECATED_MAP_API |
|
1967 mapHandleClose(); |
|
1968 #endif |
|
1969 return 0; |
|
1970 } |
|
1971 |
|
1972 // setup args to map |
|
1973 DWORD access = 0; |
|
1974 if (openMode & QIODevice::ReadOnly) access = FILE_MAP_READ; |
|
1975 if (openMode & QIODevice::WriteOnly) access = FILE_MAP_WRITE; |
|
1976 |
|
1977 DWORD offsetHi = offset >> 32; |
|
1978 DWORD offsetLo = offset & Q_UINT64_C(0xffffffff); |
|
1979 SYSTEM_INFO sysinfo; |
|
1980 ::GetSystemInfo(&sysinfo); |
|
1981 int mask = sysinfo.dwAllocationGranularity - 1; |
|
1982 int extra = offset & mask; |
|
1983 if (extra) |
|
1984 offsetLo &= ~mask; |
|
1985 |
|
1986 // attempt to create the map |
|
1987 LPVOID mapAddress = MapViewOfFile(mapHandle, access, |
|
1988 offsetHi, offsetLo, size + extra); |
|
1989 if (mapAddress) { |
|
1990 uchar *address = extra + static_cast<uchar*>(mapAddress); |
|
1991 maps[address] = QPair<int, HANDLE>(extra, mapHandle); |
|
1992 return address; |
|
1993 } |
|
1994 |
|
1995 switch(GetLastError()) { |
|
1996 case ERROR_ACCESS_DENIED: |
|
1997 q->setError(QFile::PermissionsError, qt_error_string()); |
|
1998 break; |
|
1999 case ERROR_INVALID_PARAMETER: |
|
2000 // size are out of bounds |
|
2001 default: |
|
2002 q->setError(QFile::UnspecifiedError, qt_error_string()); |
|
2003 } |
|
2004 CloseHandle(mapHandle); |
|
2005 #ifdef Q_USE_DEPRECATED_MAP_API |
|
2006 mapHandleClose(); |
|
2007 #endif |
|
2008 return 0; |
|
2009 } |
|
2010 |
|
2011 bool QFSFileEnginePrivate::unmap(uchar *ptr) |
|
2012 { |
|
2013 Q_Q(QFSFileEngine); |
|
2014 if (!maps.contains(ptr)) { |
|
2015 q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); |
|
2016 return false; |
|
2017 } |
|
2018 uchar *start = ptr - maps[ptr].first; |
|
2019 if (!UnmapViewOfFile(start)) { |
|
2020 q->setError(QFile::PermissionsError, qt_error_string()); |
|
2021 return false; |
|
2022 } |
|
2023 |
|
2024 if (!CloseHandle((HANDLE)maps[ptr].second)) { |
|
2025 q->setError(QFile::UnspecifiedError, qt_error_string()); |
|
2026 return false; |
|
2027 } |
|
2028 maps.remove(ptr); |
|
2029 |
|
2030 #ifdef Q_USE_DEPRECATED_MAP_API |
|
2031 mapHandleClose(); |
|
2032 #endif |
|
2033 return true; |
|
2034 } |
|
2035 |
|
2036 #ifdef Q_USE_DEPRECATED_MAP_API |
|
2037 void QFSFileEnginePrivate::mapHandleClose() |
|
2038 { |
|
2039 if (maps.isEmpty()) { |
|
2040 CloseHandle(fileMapHandle); |
|
2041 fileMapHandle = INVALID_HANDLE_VALUE; |
|
2042 } |
|
2043 } |
|
2044 #endif |
|
2045 |
|
2046 QT_END_NAMESPACE |