author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Fri, 19 Feb 2010 23:40:16 +0200 | |
branch | RCL_3 |
changeset 4 | 3b1da2848fc7 |
parent 3 | 41300fa6a67c |
child 7 | 3f74d0d4af4c |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 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; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
458 |
if ((fileHandle == INVALID_HANDLE_VALUE || !::CloseHandle(fileHandle))) { |
0 | 459 |
q->setError(QFile::UnspecifiedError, qt_error_string()); |
460 |
ok = false; |
|
461 |
} |
|
462 |
fileHandle = INVALID_HANDLE_VALUE; |
|
463 |
cachedFd = -1; // gets closed by CloseHandle above |
|
464 |
||
465 |
return ok; |
|
466 |
} |
|
467 |
||
468 |
/* |
|
469 |
\internal |
|
470 |
*/ |
|
471 |
bool QFSFileEnginePrivate::nativeFlush() |
|
472 |
{ |
|
473 |
if (fh) { |
|
474 |
// Buffered stdlib mode. |
|
475 |
return flushFh(); |
|
476 |
} |
|
477 |
if (fd != -1) { |
|
478 |
// Unbuffered stdio mode; always succeeds (no buffer). |
|
479 |
return true; |
|
480 |
} |
|
481 |
||
482 |
// Windows native mode; flushing is |
|
483 |
// unnecessary. FlushFileBuffers(), the equivalent of sync() or |
|
484 |
// fsync() on Unix, does a low-level flush to the disk, and we |
|
485 |
// don't expose an API for this. |
|
486 |
return true; |
|
487 |
} |
|
488 |
||
489 |
/* |
|
490 |
\internal |
|
491 |
*/ |
|
492 |
qint64 QFSFileEnginePrivate::nativeSize() const |
|
493 |
{ |
|
494 |
Q_Q(const QFSFileEngine); |
|
495 |
QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q); |
|
496 |
||
497 |
// ### Don't flush; for buffered files, we should get away with ftell. |
|
498 |
thatQ->flush(); |
|
499 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
500 |
#if !defined(Q_OS_WINCE) |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
501 |
// stdlib/stdio mode. |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
502 |
if (fh || fd != -1) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
503 |
qint64 fileSize = _filelengthi64(fh ? QT_FILENO(fh) : fd); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
504 |
if (fileSize == -1) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
505 |
fileSize = 0; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
506 |
thatQ->setError(QFile::UnspecifiedError, qt_error_string(errno)); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
507 |
} |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
508 |
return fileSize; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
509 |
} |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
510 |
#else // Q_OS_WINCE |
0 | 511 |
// Buffered stdlib mode. |
512 |
if (fh) { |
|
513 |
QT_OFF_T oldPos = QT_FTELL(fh); |
|
514 |
QT_FSEEK(fh, 0, SEEK_END); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
515 |
qint64 fileSize = (qint64)QT_FTELL(fh); |
0 | 516 |
QT_FSEEK(fh, oldPos, SEEK_SET); |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
517 |
if (fileSize == -1) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
518 |
fileSize = 0; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
519 |
thatQ->setError(QFile::UnspecifiedError, qt_error_string(errno)); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
520 |
} |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
521 |
return fileSize; |
0 | 522 |
} |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
523 |
#endif |
0 | 524 |
|
525 |
// Not-open mode, where the file name is known: We'll check the |
|
526 |
// file system directly. |
|
527 |
if (openMode == QIODevice::NotOpen && !nativeFilePath.isEmpty()) { |
|
528 |
WIN32_FILE_ATTRIBUTE_DATA attribData; |
|
529 |
bool ok = ::GetFileAttributesEx((const wchar_t*)nativeFilePath.constData(), |
|
530 |
GetFileExInfoStandard, &attribData); |
|
531 |
if (!ok) { |
|
532 |
int errorCode = GetLastError(); |
|
533 |
if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { |
|
534 |
QByteArray path = nativeFilePath; |
|
535 |
// path for the FindFirstFile should not end with a trailing slash |
|
536 |
while (path.endsWith('\\')) |
|
537 |
path.chop(1); |
|
538 |
||
539 |
// FindFirstFile can not handle drives |
|
540 |
if (!path.endsWith(':')) { |
|
541 |
WIN32_FIND_DATA findData; |
|
542 |
HANDLE hFind = ::FindFirstFile((const wchar_t*)path.constData(), |
|
543 |
&findData); |
|
544 |
if (hFind != INVALID_HANDLE_VALUE) { |
|
545 |
::FindClose(hFind); |
|
546 |
ok = true; |
|
547 |
attribData.nFileSizeHigh = findData.nFileSizeHigh; |
|
548 |
attribData.nFileSizeLow = findData.nFileSizeLow; |
|
549 |
} |
|
550 |
} |
|
551 |
} |
|
552 |
} |
|
553 |
if (ok) { |
|
554 |
qint64 size = attribData.nFileSizeHigh; |
|
555 |
size <<= 32; |
|
556 |
size += attribData.nFileSizeLow; |
|
557 |
return size; |
|
558 |
} |
|
559 |
thatQ->setError(QFile::UnspecifiedError, qt_error_string()); |
|
560 |
return 0; |
|
561 |
} |
|
562 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
563 |
#if defined(Q_OS_WINCE) |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
564 |
// Unbuffed stdio mode |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
565 |
if (fd != -1) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
566 |
thatQ->setError(QFile::UnspecifiedError, QLatin1String("Not implemented!")); |
0 | 567 |
return 0; |
568 |
} |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
569 |
#endif |
0 | 570 |
|
571 |
// Windows native mode. |
|
572 |
if (fileHandle == INVALID_HANDLE_VALUE) |
|
573 |
return 0; |
|
574 |
||
575 |
BY_HANDLE_FILE_INFORMATION fileInfo; |
|
576 |
if (!GetFileInformationByHandle(fileHandle, &fileInfo)) { |
|
577 |
thatQ->setError(QFile::UnspecifiedError, qt_error_string()); |
|
578 |
return 0; |
|
579 |
} |
|
580 |
||
581 |
qint64 size = fileInfo.nFileSizeHigh; |
|
582 |
size <<= 32; |
|
583 |
size += fileInfo.nFileSizeLow; |
|
584 |
return size; |
|
585 |
} |
|
586 |
||
587 |
/* |
|
588 |
\internal |
|
589 |
*/ |
|
590 |
qint64 QFSFileEnginePrivate::nativePos() const |
|
591 |
{ |
|
592 |
Q_Q(const QFSFileEngine); |
|
593 |
QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q); |
|
594 |
||
595 |
if (fh || fd != -1) { |
|
596 |
// stdlib / stido mode. |
|
597 |
return posFdFh(); |
|
598 |
} |
|
599 |
||
600 |
// Windows native mode. |
|
601 |
if (fileHandle == INVALID_HANDLE_VALUE) |
|
602 |
return 0; |
|
603 |
||
604 |
#if !defined(Q_OS_WINCE) |
|
605 |
LARGE_INTEGER currentFilePos; |
|
606 |
LARGE_INTEGER offset; |
|
607 |
offset.QuadPart = 0; |
|
608 |
if (!::SetFilePointerEx(fileHandle, offset, ¤tFilePos, FILE_CURRENT)) { |
|
609 |
thatQ->setError(QFile::UnspecifiedError, qt_error_string()); |
|
610 |
return 0; |
|
611 |
} |
|
612 |
||
613 |
return qint64(currentFilePos.QuadPart); |
|
614 |
#else |
|
615 |
LARGE_INTEGER filepos; |
|
616 |
filepos.HighPart = 0; |
|
617 |
DWORD newFilePointer = SetFilePointer(fileHandle, 0, &filepos.HighPart, FILE_CURRENT); |
|
618 |
if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) { |
|
619 |
thatQ->setError(QFile::UnspecifiedError, qt_error_string()); |
|
620 |
return 0; |
|
621 |
} |
|
622 |
||
623 |
filepos.LowPart = newFilePointer; |
|
624 |
return filepos.QuadPart; |
|
625 |
#endif |
|
626 |
} |
|
627 |
||
628 |
/* |
|
629 |
\internal |
|
630 |
*/ |
|
631 |
bool QFSFileEnginePrivate::nativeSeek(qint64 pos) |
|
632 |
{ |
|
633 |
Q_Q(QFSFileEngine); |
|
634 |
||
635 |
if (fh || fd != -1) { |
|
636 |
// stdlib / stdio mode. |
|
637 |
return seekFdFh(pos); |
|
638 |
} |
|
639 |
||
640 |
#if !defined(Q_OS_WINCE) |
|
641 |
LARGE_INTEGER currentFilePos; |
|
642 |
LARGE_INTEGER offset; |
|
643 |
offset.QuadPart = pos; |
|
644 |
if (!::SetFilePointerEx(fileHandle, offset, ¤tFilePos, FILE_BEGIN)) { |
|
645 |
q->setError(QFile::UnspecifiedError, qt_error_string()); |
|
646 |
return false; |
|
647 |
} |
|
648 |
||
649 |
return true; |
|
650 |
#else |
|
651 |
DWORD newFilePointer; |
|
652 |
LARGE_INTEGER *li = reinterpret_cast<LARGE_INTEGER*>(&pos); |
|
653 |
newFilePointer = SetFilePointer(fileHandle, li->LowPart, &li->HighPart, FILE_BEGIN); |
|
654 |
if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) { |
|
655 |
q->setError(QFile::PositionError, qt_error_string()); |
|
656 |
return false; |
|
657 |
} |
|
658 |
||
659 |
return true; |
|
660 |
#endif |
|
661 |
} |
|
662 |
||
663 |
/* |
|
664 |
\internal |
|
665 |
*/ |
|
666 |
qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen) |
|
667 |
{ |
|
668 |
Q_Q(QFSFileEngine); |
|
669 |
||
670 |
if (fh || fd != -1) { |
|
671 |
// stdio / stdlib mode. |
|
672 |
if (fh && nativeIsSequential() && feof(fh)) { |
|
673 |
q->setError(QFile::ReadError, qt_error_string(int(errno))); |
|
674 |
return -1; |
|
675 |
} |
|
676 |
||
677 |
return readFdFh(data, maxlen); |
|
678 |
} |
|
679 |
||
680 |
// Windows native mode. |
|
681 |
if (fileHandle == INVALID_HANDLE_VALUE) |
|
682 |
return -1; |
|
683 |
||
684 |
DWORD bytesToRead = DWORD(maxlen); // <- lossy |
|
685 |
||
686 |
// Reading on Windows fails with ERROR_NO_SYSTEM_RESOURCES when |
|
687 |
// the chunks are too large, so we limit the block size to 32MB. |
|
688 |
static const DWORD maxBlockSize = 32 * 1024 * 1024; |
|
689 |
||
690 |
qint64 totalRead = 0; |
|
691 |
do { |
|
692 |
DWORD blockSize = qMin<DWORD>(bytesToRead, maxBlockSize); |
|
693 |
DWORD bytesRead; |
|
694 |
if (!ReadFile(fileHandle, data + totalRead, blockSize, &bytesRead, NULL)) { |
|
695 |
if (totalRead == 0) { |
|
696 |
// Note: only return failure if the first ReadFile fails. |
|
697 |
q->setError(QFile::ReadError, qt_error_string()); |
|
698 |
return -1; |
|
699 |
} |
|
700 |
break; |
|
701 |
} |
|
702 |
if (bytesRead == 0) |
|
703 |
break; |
|
704 |
totalRead += bytesRead; |
|
705 |
bytesToRead -= bytesRead; |
|
706 |
} while (totalRead < maxlen); |
|
707 |
return qint64(totalRead); |
|
708 |
} |
|
709 |
||
710 |
/* |
|
711 |
\internal |
|
712 |
*/ |
|
713 |
qint64 QFSFileEnginePrivate::nativeReadLine(char *data, qint64 maxlen) |
|
714 |
{ |
|
715 |
Q_Q(QFSFileEngine); |
|
716 |
||
717 |
if (fh || fd != -1) { |
|
718 |
// stdio / stdlib mode. |
|
719 |
return readLineFdFh(data, maxlen); |
|
720 |
} |
|
721 |
||
722 |
// Windows native mode. |
|
723 |
if (fileHandle == INVALID_HANDLE_VALUE) |
|
724 |
return -1; |
|
725 |
||
726 |
// ### No equivalent in Win32? |
|
727 |
return q->QAbstractFileEngine::readLine(data, maxlen); |
|
728 |
} |
|
729 |
||
730 |
/* |
|
731 |
\internal |
|
732 |
*/ |
|
733 |
qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len) |
|
734 |
{ |
|
735 |
Q_Q(QFSFileEngine); |
|
736 |
||
737 |
if (fh || fd != -1) { |
|
738 |
// stdio / stdlib mode. |
|
739 |
return writeFdFh(data, len); |
|
740 |
} |
|
741 |
||
742 |
// Windows native mode. |
|
743 |
if (fileHandle == INVALID_HANDLE_VALUE) |
|
744 |
return -1; |
|
745 |
||
746 |
qint64 bytesToWrite = DWORD(len); // <- lossy |
|
747 |
||
748 |
// Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when |
|
749 |
// the chunks are too large, so we limit the block size to 32MB. |
|
750 |
static const DWORD maxBlockSize = 32 * 1024 * 1024; |
|
751 |
||
752 |
qint64 totalWritten = 0; |
|
753 |
do { |
|
754 |
DWORD blockSize = qMin<DWORD>(bytesToWrite, maxBlockSize); |
|
755 |
DWORD bytesWritten; |
|
756 |
if (!WriteFile(fileHandle, data + totalWritten, blockSize, &bytesWritten, NULL)) { |
|
757 |
if (totalWritten == 0) { |
|
758 |
// Note: Only return error if the first WriteFile failed. |
|
759 |
q->setError(QFile::WriteError, qt_error_string()); |
|
760 |
return -1; |
|
761 |
} |
|
762 |
break; |
|
763 |
} |
|
764 |
if (bytesWritten == 0) |
|
765 |
break; |
|
766 |
totalWritten += bytesWritten; |
|
767 |
bytesToWrite -= bytesWritten; |
|
768 |
} while (totalWritten < len); |
|
769 |
return qint64(totalWritten); |
|
770 |
} |
|
771 |
||
772 |
/* |
|
773 |
\internal |
|
774 |
*/ |
|
775 |
int QFSFileEnginePrivate::nativeHandle() const |
|
776 |
{ |
|
777 |
if (fh || fd != -1) |
|
778 |
return fh ? QT_FILENO(fh) : fd; |
|
779 |
#ifndef Q_OS_WINCE |
|
780 |
if (cachedFd != -1) |
|
781 |
return cachedFd; |
|
782 |
||
783 |
int flags = 0; |
|
784 |
if (openMode & QIODevice::Append) |
|
785 |
flags |= _O_APPEND; |
|
786 |
if (!(openMode & QIODevice::WriteOnly)) |
|
787 |
flags |= _O_RDONLY; |
|
788 |
cachedFd = _open_osfhandle((intptr_t) fileHandle, flags); |
|
789 |
return cachedFd; |
|
790 |
#else |
|
791 |
return -1; |
|
792 |
#endif |
|
793 |
} |
|
794 |
||
795 |
/* |
|
796 |
\internal |
|
797 |
*/ |
|
798 |
bool QFSFileEnginePrivate::nativeIsSequential() const |
|
799 |
{ |
|
800 |
#if !defined(Q_OS_WINCE) |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
801 |
HANDLE handle = fileHandle; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
802 |
if (fh || fd != -1) |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
803 |
handle = (HANDLE)_get_osfhandle(fh ? QT_FILENO(fh) : fd); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
804 |
if (handle == INVALID_HANDLE_VALUE) |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
805 |
return false; |
0 | 806 |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
807 |
DWORD fileType = GetFileType(handle); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
808 |
return (fileType == FILE_TYPE_CHAR) |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
809 |
|| (fileType == FILE_TYPE_PIPE); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
810 |
#else |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
811 |
return false; |
0 | 812 |
#endif |
813 |
} |
|
814 |
||
815 |
bool QFSFileEngine::remove() |
|
816 |
{ |
|
817 |
Q_D(QFSFileEngine); |
|
818 |
bool ret = ::DeleteFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16()) != 0; |
|
819 |
if (!ret) |
|
820 |
setError(QFile::RemoveError, qt_error_string()); |
|
821 |
return ret; |
|
822 |
} |
|
823 |
||
824 |
bool QFSFileEngine::copy(const QString ©Name) |
|
825 |
{ |
|
826 |
Q_D(QFSFileEngine); |
|
827 |
bool ret = ::CopyFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), |
|
828 |
(wchar_t*)QFSFileEnginePrivate::longFileName(copyName).utf16(), true) != 0; |
|
829 |
if (!ret) |
|
830 |
setError(QFile::CopyError, qt_error_string()); |
|
831 |
return ret; |
|
832 |
} |
|
833 |
||
834 |
bool QFSFileEngine::rename(const QString &newName) |
|
835 |
{ |
|
836 |
Q_D(QFSFileEngine); |
|
837 |
bool ret = ::MoveFile((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), |
|
838 |
(wchar_t*)QFSFileEnginePrivate::longFileName(newName).utf16()) != 0; |
|
839 |
if (!ret) |
|
840 |
setError(QFile::RenameError, qt_error_string()); |
|
841 |
return ret; |
|
842 |
} |
|
843 |
||
844 |
static inline bool mkDir(const QString &path) |
|
845 |
{ |
|
846 |
#if defined(Q_OS_WINCE) |
|
847 |
// Unfortunately CreateDirectory returns true for paths longer than |
|
848 |
// 256, but does not create a directory. It starts to fail, when |
|
849 |
// path length > MAX_PATH, which is 260 usually on CE. |
|
850 |
// This only happens on a Windows Mobile device. Windows CE seems |
|
851 |
// not to be affected by this. |
|
852 |
static int platformId = 0; |
|
853 |
if (platformId == 0) { |
|
854 |
wchar_t platformString[64]; |
|
855 |
if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(platformString)/sizeof(*platformString),platformString,0)) { |
|
856 |
if (0 == wcscmp(platformString, L"PocketPC") || 0 == wcscmp(platformString, L"Smartphone")) |
|
857 |
platformId = 1; |
|
858 |
else |
|
859 |
platformId = 2; |
|
860 |
} |
|
861 |
} |
|
862 |
if (platformId == 1 && QFSFileEnginePrivate::longFileName(path).size() > 256) |
|
863 |
return false; |
|
864 |
#endif |
|
865 |
return ::CreateDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), 0); |
|
866 |
} |
|
867 |
||
868 |
static inline bool rmDir(const QString &path) |
|
869 |
{ |
|
870 |
return ::RemoveDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); |
|
871 |
} |
|
872 |
||
873 |
static bool isDirPath(const QString &dirPath, bool *existed) |
|
874 |
{ |
|
875 |
QString path = dirPath; |
|
876 |
if (path.length() == 2 && path.at(1) == QLatin1Char(':')) |
|
877 |
path += QLatin1Char('\\'); |
|
878 |
||
879 |
DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); |
|
880 |
if (fileAttrib == INVALID_FILE_ATTRIBUTES) { |
|
881 |
int errorCode = GetLastError(); |
|
882 |
if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { |
|
883 |
// path for the FindFirstFile should not end with a trailing slash |
|
884 |
while (path.endsWith(QLatin1Char('\\'))) |
|
885 |
path.chop(1); |
|
886 |
||
887 |
// FindFirstFile can not handle drives |
|
888 |
if (!path.endsWith(QLatin1Char(':'))) { |
|
889 |
WIN32_FIND_DATA findData; |
|
890 |
HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), |
|
891 |
&findData); |
|
892 |
if (hFind != INVALID_HANDLE_VALUE) { |
|
893 |
::FindClose(hFind); |
|
894 |
fileAttrib = findData.dwFileAttributes; |
|
895 |
} |
|
896 |
} |
|
897 |
} |
|
898 |
} |
|
899 |
||
900 |
if (existed) |
|
901 |
*existed = fileAttrib != INVALID_FILE_ATTRIBUTES; |
|
902 |
||
903 |
if (fileAttrib == INVALID_FILE_ATTRIBUTES) |
|
904 |
return false; |
|
905 |
||
906 |
return fileAttrib & FILE_ATTRIBUTE_DIRECTORY; |
|
907 |
} |
|
908 |
||
909 |
bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const |
|
910 |
{ |
|
911 |
QString dirName = name; |
|
912 |
if (createParentDirectories) { |
|
913 |
dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); |
|
914 |
// We spefically search for / so \ would break it.. |
|
915 |
int oldslash = -1; |
|
916 |
if (dirName.startsWith(QLatin1String("\\\\"))) { |
|
917 |
// Don't try to create the root path of a UNC path; |
|
918 |
// CreateDirectory() will just return ERROR_INVALID_NAME. |
|
919 |
for (int i = 0; i < dirName.size(); ++i) { |
|
920 |
if (dirName.at(i) != QDir::separator()) { |
|
921 |
oldslash = i; |
|
922 |
break; |
|
923 |
} |
|
924 |
} |
|
925 |
if (oldslash != -1) |
|
926 |
oldslash = dirName.indexOf(QDir::separator(), oldslash); |
|
927 |
} |
|
928 |
for (int slash=0; slash != -1; oldslash = slash) { |
|
929 |
slash = dirName.indexOf(QDir::separator(), oldslash+1); |
|
930 |
if (slash == -1) { |
|
931 |
if (oldslash == dirName.length()) |
|
932 |
break; |
|
933 |
slash = dirName.length(); |
|
934 |
} |
|
935 |
if (slash) { |
|
936 |
QString chunk = dirName.left(slash); |
|
937 |
bool existed = false; |
|
938 |
if (!isDirPath(chunk, &existed)) { |
|
939 |
if (!existed) { |
|
940 |
if (!mkDir(chunk)) |
|
941 |
return false; |
|
942 |
} else { |
|
943 |
return false; |
|
944 |
} |
|
945 |
} |
|
946 |
} |
|
947 |
} |
|
948 |
return true; |
|
949 |
} |
|
950 |
return mkDir(name); |
|
951 |
} |
|
952 |
||
953 |
bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const |
|
954 |
{ |
|
955 |
QString dirName = name; |
|
956 |
if (recurseParentDirectories) { |
|
957 |
dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); |
|
958 |
for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) { |
|
959 |
QString chunk = dirName.left(slash); |
|
960 |
if (chunk.length() == 2 && chunk.at(0).isLetter() && chunk.at(1) == QLatin1Char(':')) |
|
961 |
break; |
|
962 |
if (!isDirPath(chunk, 0)) |
|
963 |
return false; |
|
964 |
if (!rmDir(chunk)) |
|
965 |
return oldslash != 0; |
|
966 |
slash = dirName.lastIndexOf(QDir::separator(), oldslash-1); |
|
967 |
} |
|
968 |
return true; |
|
969 |
} |
|
970 |
return rmDir(name); |
|
971 |
} |
|
972 |
||
973 |
bool QFSFileEngine::caseSensitive() const |
|
974 |
{ |
|
975 |
return false; |
|
976 |
} |
|
977 |
||
978 |
bool QFSFileEngine::setCurrentPath(const QString &path) |
|
979 |
{ |
|
980 |
if (!QDir(path).exists()) |
|
981 |
return false; |
|
982 |
||
983 |
#if !defined(Q_OS_WINCE) |
|
984 |
return ::SetCurrentDirectory((wchar_t*)path.utf16()) != 0; |
|
985 |
#else |
|
986 |
qfsPrivateCurrentDir = QFSFileEnginePrivate::longFileName(path); |
|
987 |
return true; |
|
988 |
#endif |
|
989 |
} |
|
990 |
||
991 |
QString QFSFileEngine::currentPath(const QString &fileName) |
|
992 |
{ |
|
993 |
#if !defined(Q_OS_WINCE) |
|
994 |
QString ret; |
|
995 |
//if filename is a drive: then get the pwd of that drive |
|
996 |
if (fileName.length() >= 2 && |
|
997 |
fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':')) { |
|
998 |
int drv = fileName.toUpper().at(0).toLatin1() - 'A' + 1; |
|
999 |
if (_getdrive() != drv) { |
|
1000 |
wchar_t buf[PATH_MAX]; |
|
1001 |
::_wgetdcwd(drv, buf, PATH_MAX); |
|
1002 |
ret = QString::fromWCharArray(buf); |
|
1003 |
} |
|
1004 |
} |
|
1005 |
if (ret.isEmpty()) { |
|
1006 |
//just the pwd |
|
1007 |
DWORD size = 0; |
|
1008 |
wchar_t currentName[PATH_MAX]; |
|
1009 |
size = ::GetCurrentDirectory(PATH_MAX, currentName); |
|
1010 |
if (size != 0) { |
|
1011 |
if (size > PATH_MAX) { |
|
1012 |
wchar_t *newCurrentName = new wchar_t[size]; |
|
1013 |
if (::GetCurrentDirectory(PATH_MAX, newCurrentName) != 0) |
|
1014 |
ret = QString::fromWCharArray(newCurrentName); |
|
1015 |
delete [] newCurrentName; |
|
1016 |
} else { |
|
1017 |
ret = QString::fromWCharArray(currentName); |
|
1018 |
} |
|
1019 |
} |
|
1020 |
} |
|
1021 |
if (ret.length() >= 2 && ret[1] == QLatin1Char(':')) |
|
1022 |
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters. |
|
1023 |
return QDir::fromNativeSeparators(ret); |
|
1024 |
#else |
|
1025 |
Q_UNUSED(fileName); |
|
1026 |
if (qfsPrivateCurrentDir.isEmpty()) |
|
1027 |
qfsPrivateCurrentDir = QCoreApplication::applicationDirPath(); |
|
1028 |
||
1029 |
return QDir::fromNativeSeparators(qfsPrivateCurrentDir); |
|
1030 |
#endif |
|
1031 |
} |
|
1032 |
||
1033 |
QString QFSFileEngine::homePath() |
|
1034 |
{ |
|
1035 |
QString ret; |
|
1036 |
#if !defined(QT_NO_LIBRARY) |
|
1037 |
QFSFileEnginePrivate::resolveLibs(); |
|
1038 |
if (ptrGetUserProfileDirectoryW) { |
|
1039 |
HANDLE hnd = ::GetCurrentProcess(); |
|
1040 |
HANDLE token = 0; |
|
1041 |
BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token); |
|
1042 |
if (ok) { |
|
1043 |
DWORD dwBufferSize = 0; |
|
1044 |
// First call, to determine size of the strings (with '\0'). |
|
1045 |
ok = ::ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize); |
|
1046 |
if (!ok && dwBufferSize != 0) { // We got the required buffer size |
|
1047 |
wchar_t *userDirectory = new wchar_t[dwBufferSize]; |
|
1048 |
// Second call, now we can fill the allocated buffer. |
|
1049 |
ok = ::ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize); |
|
1050 |
if (ok) |
|
1051 |
ret = QString::fromWCharArray(userDirectory); |
|
1052 |
||
1053 |
delete [] userDirectory; |
|
1054 |
} |
|
1055 |
::CloseHandle(token); |
|
1056 |
} |
|
1057 |
} |
|
1058 |
#endif |
|
1059 |
if (ret.isEmpty() || !QFile::exists(ret)) { |
|
1060 |
ret = QString::fromLocal8Bit(qgetenv("USERPROFILE").constData()); |
|
1061 |
if (ret.isEmpty() || !QFile::exists(ret)) { |
|
1062 |
ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE").constData()) + QString::fromLocal8Bit(qgetenv("HOMEPATH").constData()); |
|
1063 |
if (ret.isEmpty() || !QFile::exists(ret)) { |
|
1064 |
ret = QString::fromLocal8Bit(qgetenv("HOME").constData()); |
|
1065 |
if (ret.isEmpty() || !QFile::exists(ret)) { |
|
1066 |
#if defined(Q_OS_WINCE) |
|
1067 |
ret = QLatin1String("\\My Documents"); |
|
1068 |
if (!QFile::exists(ret)) |
|
1069 |
#endif |
|
1070 |
ret = rootPath(); |
|
1071 |
} |
|
1072 |
} |
|
1073 |
} |
|
1074 |
} |
|
1075 |
return QDir::fromNativeSeparators(ret); |
|
1076 |
} |
|
1077 |
||
1078 |
QString QFSFileEngine::rootPath() |
|
1079 |
{ |
|
1080 |
#if defined(Q_OS_WINCE) |
|
1081 |
QString ret = QLatin1String("/"); |
|
1082 |
#elif defined(Q_FS_FAT) |
|
1083 |
QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData()); |
|
1084 |
if (ret.isEmpty()) |
|
1085 |
ret = QLatin1String("c:"); |
|
1086 |
ret.append(QLatin1Char('/')); |
|
1087 |
#elif defined(Q_OS_OS2EMX) |
|
1088 |
char dir[4]; |
|
1089 |
_abspath(dir, QLatin1String("/"), _MAX_PATH); |
|
1090 |
QString ret(dir); |
|
1091 |
#endif |
|
1092 |
return ret; |
|
1093 |
} |
|
1094 |
||
1095 |
QString QFSFileEngine::tempPath() |
|
1096 |
{ |
|
1097 |
QString ret; |
|
1098 |
{ |
|
1099 |
wchar_t tempPath[MAX_PATH]; |
|
1100 |
if (GetTempPath(MAX_PATH, tempPath)) |
|
1101 |
ret = QString::fromWCharArray(tempPath); |
|
1102 |
if (!ret.isEmpty()) { |
|
1103 |
while (ret.endsWith(QLatin1Char('\\'))) |
|
1104 |
ret.chop(1); |
|
1105 |
ret = QDir::fromNativeSeparators(ret); |
|
1106 |
} |
|
1107 |
} |
|
1108 |
if (ret.isEmpty()) { |
|
1109 |
#if !defined(Q_OS_WINCE) |
|
1110 |
ret = QLatin1String("c:/tmp"); |
|
1111 |
#else |
|
1112 |
ret = QLatin1String("/Temp"); |
|
1113 |
#endif |
|
1114 |
} |
|
1115 |
return ret; |
|
1116 |
} |
|
1117 |
||
1118 |
QFileInfoList QFSFileEngine::drives() |
|
1119 |
{ |
|
1120 |
QFileInfoList ret; |
|
1121 |
#if !defined(Q_OS_WINCE) |
|
1122 |
#if defined(Q_OS_WIN32) |
|
1123 |
quint32 driveBits = (quint32) GetLogicalDrives() & 0x3ffffff; |
|
1124 |
#elif defined(Q_OS_OS2EMX) |
|
1125 |
quint32 driveBits, cur; |
|
1126 |
if (DosQueryCurrentDisk(&cur, &driveBits) != NO_ERROR) |
|
1127 |
exit(1); |
|
1128 |
driveBits &= 0x3ffffff; |
|
1129 |
#endif |
|
1130 |
char driveName[] = "A:/"; |
|
1131 |
||
1132 |
while (driveBits) { |
|
1133 |
if (driveBits & 1) |
|
1134 |
ret.append(QFileInfo(QLatin1String(driveName))); |
|
1135 |
driveName[0]++; |
|
1136 |
driveBits = driveBits >> 1; |
|
1137 |
} |
|
1138 |
return ret; |
|
1139 |
#else |
|
1140 |
ret.append(QFileInfo(QLatin1String("/"))); |
|
1141 |
return ret; |
|
1142 |
#endif |
|
1143 |
} |
|
1144 |
||
1145 |
bool QFSFileEnginePrivate::doStat() const |
|
1146 |
{ |
|
1147 |
if (!tried_stat) { |
|
1148 |
tried_stat = true; |
|
1149 |
could_stat = false; |
|
1150 |
||
1151 |
if (filePath.isEmpty()) |
|
1152 |
return could_stat; |
|
1153 |
||
1154 |
QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; |
|
1155 |
fname = fixIfRelativeUncPath(fname); |
|
1156 |
||
1157 |
UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); |
|
1158 |
||
1159 |
if (fd != -1) { |
|
1160 |
#if !defined(Q_OS_WINCE) |
|
1161 |
HANDLE fh = (HANDLE)_get_osfhandle(fd); |
|
1162 |
if (fh != INVALID_HANDLE_VALUE) { |
|
1163 |
BY_HANDLE_FILE_INFORMATION fileInfo; |
|
1164 |
if (GetFileInformationByHandle(fh, &fileInfo)) { |
|
1165 |
could_stat = true; |
|
1166 |
fileAttrib = fileInfo.dwFileAttributes; |
|
1167 |
} |
|
1168 |
} |
|
1169 |
#else |
|
1170 |
DWORD tmpAttributes = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16()); |
|
1171 |
if (tmpAttributes != -1) { |
|
1172 |
fileAttrib = tmpAttributes; |
|
1173 |
could_stat = true; |
|
1174 |
} |
|
1175 |
#endif |
|
1176 |
} else { |
|
1177 |
fileAttrib = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16()); |
|
1178 |
if (fileAttrib == INVALID_FILE_ATTRIBUTES) { |
|
1179 |
int errorCode = GetLastError(); |
|
1180 |
if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { |
|
1181 |
QString path = QDir::toNativeSeparators(fname); |
|
1182 |
// path for the FindFirstFile should not end with a trailing slash |
|
1183 |
while (path.endsWith(QLatin1Char('\\'))) |
|
1184 |
path.chop(1); |
|
1185 |
||
1186 |
// FindFirstFile can not handle drives |
|
1187 |
if (!path.endsWith(QLatin1Char(':'))) { |
|
1188 |
WIN32_FIND_DATA findData; |
|
1189 |
HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), |
|
1190 |
&findData); |
|
1191 |
if (hFind != INVALID_HANDLE_VALUE) { |
|
1192 |
::FindClose(hFind); |
|
1193 |
fileAttrib = findData.dwFileAttributes; |
|
1194 |
} |
|
1195 |
} |
|
1196 |
} |
|
1197 |
} |
|
1198 |
could_stat = fileAttrib != INVALID_FILE_ATTRIBUTES; |
|
1199 |
if (!could_stat) { |
|
1200 |
#if !defined(Q_OS_WINCE) |
|
1201 |
if (isDriveRoot(fname)) { |
|
1202 |
// a valid drive ?? |
|
1203 |
DWORD drivesBitmask = ::GetLogicalDrives(); |
|
1204 |
int drivebit = 1 << (fname.at(0).toUpper().unicode() - QLatin1Char('A').unicode()); |
|
1205 |
if (drivesBitmask & drivebit) { |
|
1206 |
fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM; |
|
1207 |
could_stat = true; |
|
1208 |
} |
|
1209 |
} else { |
|
1210 |
#endif |
|
1211 |
QString path = QDir::toNativeSeparators(fname); |
|
1212 |
bool is_dir = false; |
|
1213 |
if (path.startsWith(QLatin1String("\\\\"))) { |
|
1214 |
// UNC - stat doesn't work for all cases (Windows bug) |
|
1215 |
int s = path.indexOf(path.at(0),2); |
|
1216 |
if (s > 0) { |
|
1217 |
// "\\server\..." |
|
1218 |
s = path.indexOf(path.at(0),s+1); |
|
1219 |
if (s > 0) { |
|
1220 |
// "\\server\share\..." |
|
1221 |
if (s == path.size() - 1) { |
|
1222 |
// "\\server\share\" |
|
1223 |
is_dir = true; |
|
1224 |
} else { |
|
1225 |
// "\\server\share\notfound" |
|
1226 |
} |
|
1227 |
} else { |
|
1228 |
// "\\server\share" |
|
1229 |
is_dir = true; |
|
1230 |
} |
|
1231 |
} else { |
|
1232 |
// "\\server" |
|
1233 |
is_dir = true; |
|
1234 |
} |
|
1235 |
} |
|
1236 |
if (is_dir && uncShareExists(path)) { |
|
1237 |
// looks like a UNC dir, is a dir. |
|
1238 |
fileAttrib = FILE_ATTRIBUTE_DIRECTORY; |
|
1239 |
could_stat = true; |
|
1240 |
} |
|
1241 |
#if !defined(Q_OS_WINCE) |
|
1242 |
} |
|
1243 |
#endif |
|
1244 |
} |
|
1245 |
} |
|
1246 |
||
1247 |
SetErrorMode(oldmode); |
|
1248 |
} |
|
1249 |
return could_stat; |
|
1250 |
} |
|
1251 |
||
1252 |
||
1253 |
static QString readSymLink(const QString &link) |
|
1254 |
{ |
|
1255 |
QString result; |
|
1256 |
#if !defined(Q_OS_WINCE) |
|
1257 |
HANDLE handle = CreateFile((wchar_t*)QFSFileEnginePrivate::longFileName(link).utf16(), |
|
1258 |
FILE_READ_EA, |
|
1259 |
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
|
1260 |
0, |
|
1261 |
OPEN_EXISTING, |
|
1262 |
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, |
|
1263 |
0); |
|
1264 |
if (handle != INVALID_HANDLE_VALUE) { |
|
1265 |
DWORD bufsize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; |
|
1266 |
REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)qMalloc(bufsize); |
|
1267 |
DWORD retsize = 0; |
|
1268 |
if (::DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, 0, 0, rdb, bufsize, &retsize, 0)) { |
|
1269 |
if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { |
|
1270 |
int length = rdb->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t); |
|
1271 |
int offset = rdb->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); |
|
1272 |
const wchar_t* PathBuffer = &rdb->MountPointReparseBuffer.PathBuffer[offset]; |
|
1273 |
result = QString::fromWCharArray(PathBuffer, length); |
|
1274 |
} else { |
|
1275 |
int length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); |
|
1276 |
int offset = rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); |
|
1277 |
const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset]; |
|
1278 |
result = QString::fromWCharArray(PathBuffer, length); |
|
1279 |
} |
|
1280 |
// cut-off "//?/" and "/??/" |
|
1281 |
if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\')) |
|
1282 |
result = result.mid(4); |
|
1283 |
} |
|
1284 |
qFree(rdb); |
|
1285 |
CloseHandle(handle); |
|
1286 |
} |
|
1287 |
#else |
|
1288 |
Q_UNUSED(link); |
|
1289 |
#endif // Q_OS_WINCE |
|
1290 |
return result; |
|
1291 |
} |
|
1292 |
||
1293 |
static QString readLink(const QString &link) |
|
1294 |
{ |
|
1295 |
#if !defined(Q_OS_WINCE) |
|
1296 |
#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS) |
|
1297 |
QString ret; |
|
1298 |
||
1299 |
bool neededCoInit = false; |
|
1300 |
IShellLink *psl; // pointer to IShellLink i/f |
|
1301 |
WIN32_FIND_DATA wfd; |
|
1302 |
wchar_t szGotPath[MAX_PATH]; |
|
1303 |
||
1304 |
// Get pointer to the IShellLink interface. |
|
1305 |
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl); |
|
1306 |
||
1307 |
if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized |
|
1308 |
neededCoInit = true; |
|
1309 |
CoInitialize(NULL); |
|
1310 |
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, |
|
1311 |
IID_IShellLink, (LPVOID *)&psl); |
|
1312 |
} |
|
1313 |
if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface. |
|
1314 |
IPersistFile *ppf; |
|
1315 |
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); |
|
1316 |
if (SUCCEEDED(hres)) { |
|
1317 |
hres = ppf->Load((LPOLESTR)link.utf16(), STGM_READ); |
|
1318 |
//The original path of the link is retrieved. If the file/folder |
|
1319 |
//was moved, the return value still have the old path. |
|
1320 |
if (SUCCEEDED(hres)) { |
|
1321 |
if (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR) |
|
1322 |
ret = QString::fromWCharArray(szGotPath); |
|
1323 |
} |
|
1324 |
ppf->Release(); |
|
1325 |
} |
|
1326 |
psl->Release(); |
|
1327 |
} |
|
1328 |
if (neededCoInit) |
|
1329 |
CoUninitialize(); |
|
1330 |
||
1331 |
return ret; |
|
1332 |
#else |
|
1333 |
Q_UNUSED(link); |
|
1334 |
return QString(); |
|
1335 |
#endif // QT_NO_LIBRARY |
|
1336 |
#else |
|
1337 |
wchar_t target[MAX_PATH]; |
|
1338 |
QString result; |
|
1339 |
if (SHGetShortcutTarget((wchar_t*)QFileInfo(link).absoluteFilePath().replace(QLatin1Char('/'),QLatin1Char('\\')).utf16(), target, MAX_PATH)) { |
|
1340 |
result = QString::fromWCharArray(target); |
|
1341 |
if (result.startsWith(QLatin1Char('"'))) |
|
1342 |
result.remove(0,1); |
|
1343 |
if (result.endsWith(QLatin1Char('"'))) |
|
1344 |
result.remove(result.size()-1,1); |
|
1345 |
} |
|
1346 |
return result; |
|
1347 |
#endif // Q_OS_WINCE |
|
1348 |
} |
|
1349 |
||
1350 |
bool QFSFileEngine::link(const QString &newName) |
|
1351 |
{ |
|
1352 |
#if !defined(Q_OS_WINCE) |
|
1353 |
#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS) |
|
1354 |
bool ret = false; |
|
1355 |
||
1356 |
QString linkName = newName; |
|
1357 |
//### assume that they add .lnk |
|
1358 |
||
1359 |
IShellLink *psl; |
|
1360 |
bool neededCoInit = false; |
|
1361 |
||
1362 |
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); |
|
1363 |
||
1364 |
if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized |
|
1365 |
neededCoInit = true; |
|
1366 |
CoInitialize(NULL); |
|
1367 |
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); |
|
1368 |
} |
|
1369 |
||
1370 |
if (SUCCEEDED(hres)) { |
|
1371 |
hres = psl->SetPath((wchar_t *)fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16()); |
|
1372 |
if (SUCCEEDED(hres)) { |
|
1373 |
hres = psl->SetWorkingDirectory((wchar_t *)fileName(AbsolutePathName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16()); |
|
1374 |
if (SUCCEEDED(hres)) { |
|
1375 |
IPersistFile *ppf; |
|
1376 |
hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf); |
|
1377 |
if (SUCCEEDED(hres)) { |
|
1378 |
hres = ppf->Save((wchar_t*)linkName.utf16(), TRUE); |
|
1379 |
if (SUCCEEDED(hres)) |
|
1380 |
ret = true; |
|
1381 |
ppf->Release(); |
|
1382 |
} |
|
1383 |
} |
|
1384 |
} |
|
1385 |
psl->Release(); |
|
1386 |
} |
|
1387 |
if (!ret) |
|
1388 |
setError(QFile::RenameError, qt_error_string()); |
|
1389 |
||
1390 |
if (neededCoInit) |
|
1391 |
CoUninitialize(); |
|
1392 |
||
1393 |
return ret; |
|
1394 |
#else |
|
1395 |
Q_UNUSED(newName); |
|
1396 |
return false; |
|
1397 |
#endif // QT_NO_LIBRARY |
|
1398 |
#else |
|
1399 |
QString linkName = newName; |
|
1400 |
if (!linkName.endsWith(QLatin1String(".lnk"))) |
|
1401 |
linkName += QLatin1String(".lnk"); |
|
1402 |
QString orgName = fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')); |
|
1403 |
// Need to append on our own |
|
1404 |
orgName.prepend(QLatin1Char('"')); |
|
1405 |
orgName.append(QLatin1Char('"')); |
|
1406 |
bool ret = SUCCEEDED(SHCreateShortcut((wchar_t*)linkName.utf16(), (wchar_t*)orgName.utf16())); |
|
1407 |
if (!ret) |
|
1408 |
setError(QFile::RenameError, qt_error_string()); |
|
1409 |
return ret; |
|
1410 |
#endif // Q_OS_WINCE |
|
1411 |
} |
|
1412 |
||
1413 |
/*! |
|
1414 |
\internal |
|
1415 |
*/ |
|
1416 |
QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions() const |
|
1417 |
{ |
|
1418 |
QAbstractFileEngine::FileFlags ret = 0; |
|
1419 |
||
1420 |
#if !defined(QT_NO_LIBRARY) |
|
1421 |
if((qt_ntfs_permission_lookup > 0) && ((QSysInfo::WindowsVersion&QSysInfo::WV_NT_based) > QSysInfo::WV_NT)) { |
|
1422 |
resolveLibs(); |
|
1423 |
if(ptrGetNamedSecurityInfoW && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW) { |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1424 |
enum { ReadMask = 0x00000001, WriteMask = 0x00000002, ExecMask = 0x00000020 }; |
0 | 1425 |
|
1426 |
QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1427 |
PSID pOwner = 0; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1428 |
PSID pGroup = 0; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1429 |
PACL pDacl; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1430 |
PSECURITY_DESCRIPTOR pSD; |
0 | 1431 |
DWORD res = ptrGetNamedSecurityInfoW((wchar_t*)fname.utf16(), SE_FILE_OBJECT, |
1432 |
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, |
|
1433 |
&pOwner, &pGroup, &pDacl, 0, &pSD); |
|
1434 |
if(res == ERROR_SUCCESS) { |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1435 |
ACCESS_MASK access_mask; |
0 | 1436 |
TRUSTEE_W trustee; |
1437 |
{ //user |
|
1438 |
if(ptrGetEffectiveRightsFromAclW(pDacl, ¤tUserTrusteeW, &access_mask) != ERROR_SUCCESS) |
|
1439 |
access_mask = (ACCESS_MASK)-1; |
|
1440 |
if(access_mask & ReadMask) |
|
1441 |
ret |= QAbstractFileEngine::ReadUserPerm; |
|
1442 |
if(access_mask & WriteMask) |
|
1443 |
ret |= QAbstractFileEngine::WriteUserPerm; |
|
1444 |
if(access_mask & ExecMask) |
|
1445 |
ret |= QAbstractFileEngine::ExeUserPerm; |
|
1446 |
} |
|
1447 |
{ //owner |
|
1448 |
ptrBuildTrusteeWithSidW(&trustee, pOwner); |
|
1449 |
if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) |
|
1450 |
access_mask = (ACCESS_MASK)-1; |
|
1451 |
if(access_mask & ReadMask) |
|
1452 |
ret |= QAbstractFileEngine::ReadOwnerPerm; |
|
1453 |
if(access_mask & WriteMask) |
|
1454 |
ret |= QAbstractFileEngine::WriteOwnerPerm; |
|
1455 |
if(access_mask & ExecMask) |
|
1456 |
ret |= QAbstractFileEngine::ExeOwnerPerm; |
|
1457 |
} |
|
1458 |
{ //group |
|
1459 |
ptrBuildTrusteeWithSidW(&trustee, pGroup); |
|
1460 |
if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) |
|
1461 |
access_mask = (ACCESS_MASK)-1; |
|
1462 |
if(access_mask & ReadMask) |
|
1463 |
ret |= QAbstractFileEngine::ReadGroupPerm; |
|
1464 |
if(access_mask & WriteMask) |
|
1465 |
ret |= QAbstractFileEngine::WriteGroupPerm; |
|
1466 |
if(access_mask & ExecMask) |
|
1467 |
ret |= QAbstractFileEngine::ExeGroupPerm; |
|
1468 |
} |
|
1469 |
{ //other (world) |
|
1470 |
if(ptrGetEffectiveRightsFromAclW(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS) |
|
1471 |
access_mask = (ACCESS_MASK)-1; // ### |
|
1472 |
if(access_mask & ReadMask) |
|
1473 |
ret |= QAbstractFileEngine::ReadOtherPerm; |
|
1474 |
if(access_mask & WriteMask) |
|
1475 |
ret |= QAbstractFileEngine::WriteOtherPerm; |
|
1476 |
if(access_mask & ExecMask) |
|
1477 |
ret |= QAbstractFileEngine::ExeOtherPerm; |
|
1478 |
} |
|
1479 |
LocalFree(pSD); |
|
1480 |
} |
|
1481 |
} |
|
1482 |
} else |
|
1483 |
#endif |
|
1484 |
{ |
|
1485 |
//### what to do with permissions if we don't use NTFS |
|
1486 |
// for now just add all permissions and what about exe missions ?? |
|
1487 |
// also qt_ntfs_permission_lookup is now not set by defualt ... should it ? |
|
1488 |
ret |= QAbstractFileEngine::ReadOtherPerm | QAbstractFileEngine::ReadGroupPerm |
|
1489 |
| QAbstractFileEngine::ReadOwnerPerm | QAbstractFileEngine::ReadUserPerm |
|
1490 |
| QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::WriteOwnerPerm |
|
1491 |
| QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm; |
|
1492 |
||
1493 |
if (doStat()) { |
|
1494 |
if (ret & (QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | |
|
1495 |
QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm)) { |
|
1496 |
if (fileAttrib & FILE_ATTRIBUTE_READONLY) |
|
1497 |
ret &= ~(QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | |
|
1498 |
QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm); |
|
1499 |
} |
|
1500 |
||
1501 |
QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; |
|
1502 |
QString ext = fname.right(4).toLower(); |
|
1503 |
if (ext == QLatin1String(".exe") || ext == QLatin1String(".com") || ext == QLatin1String(".bat") || |
|
1504 |
ext == QLatin1String(".pif") || ext == QLatin1String(".cmd") || (fileAttrib & FILE_ATTRIBUTE_DIRECTORY)) |
|
1505 |
ret |= QAbstractFileEngine::ExeOwnerPerm | QAbstractFileEngine::ExeGroupPerm | |
|
1506 |
QAbstractFileEngine::ExeOtherPerm | QAbstractFileEngine::ExeUserPerm; |
|
1507 |
} |
|
1508 |
} |
|
1509 |
return ret; |
|
1510 |
} |
|
1511 |
||
1512 |
/*! |
|
1513 |
\internal |
|
1514 |
*/ |
|
1515 |
bool QFSFileEnginePrivate::isSymlink() const |
|
1516 |
{ |
|
1517 |
#if !defined(Q_OS_WINCE) |
|
1518 |
if (need_lstat) { |
|
1519 |
need_lstat = false; |
|
1520 |
is_link = false; |
|
1521 |
||
1522 |
if (fileAttrib & FILE_ATTRIBUTE_REPARSE_POINT) { |
|
1523 |
QString path = QDir::toNativeSeparators(filePath); |
|
1524 |
// path for the FindFirstFile should not end with a trailing slash |
|
1525 |
while (path.endsWith(QLatin1Char('\\'))) |
|
1526 |
path.chop(1); |
|
1527 |
||
1528 |
WIN32_FIND_DATA findData; |
|
1529 |
HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), |
|
1530 |
&findData); |
|
1531 |
if (hFind != INVALID_HANDLE_VALUE) { |
|
1532 |
::FindClose(hFind); |
|
1533 |
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) |
|
1534 |
&& (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT |
|
1535 |
|| findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { |
|
1536 |
is_link = true; |
|
1537 |
} |
|
1538 |
} |
|
1539 |
} |
|
1540 |
} |
|
1541 |
return is_link; |
|
1542 |
#else |
|
1543 |
return false; |
|
1544 |
#endif // Q_OS_WINCE |
|
1545 |
} |
|
1546 |
||
1547 |
/*! |
|
1548 |
\reimp |
|
1549 |
*/ |
|
1550 |
QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const |
|
1551 |
{ |
|
1552 |
Q_D(const QFSFileEngine); |
|
1553 |
QAbstractFileEngine::FileFlags ret = 0; |
|
1554 |
// Force a stat, so that we're guaranteed to get up-to-date results |
|
1555 |
if (type & Refresh) { |
|
1556 |
d->tried_stat = 0; |
|
1557 |
#if !defined(Q_OS_WINCE) |
|
1558 |
d->need_lstat = 1; |
|
1559 |
#endif |
|
1560 |
} |
|
1561 |
||
1562 |
if (type & PermsMask) { |
|
1563 |
ret |= d->getPermissions(); |
|
1564 |
// ### Workaround pascals ### above. Since we always set all properties to true |
|
1565 |
// we need to disable read and exec access if the file does not exists |
|
1566 |
if (d->doStat()) |
|
1567 |
ret |= ExistsFlag; |
|
1568 |
else |
|
1569 |
ret &= 0x2222; |
|
1570 |
} |
|
1571 |
if (type & TypesMask) { |
|
1572 |
if (d->filePath.endsWith(QLatin1String(".lnk"))) { |
|
1573 |
ret |= LinkType; |
|
1574 |
QString l = readLink(d->filePath); |
|
1575 |
if (!l.isEmpty()) { |
|
1576 |
bool existed = false; |
|
1577 |
if (isDirPath(l, &existed) && existed) |
|
1578 |
ret |= DirectoryType; |
|
1579 |
else if (existed) |
|
1580 |
ret |= FileType; |
|
1581 |
} |
|
1582 |
} else if (d->doStat()) { |
|
1583 |
if ((type & LinkType) && d->isSymlink()) |
|
1584 |
ret |= LinkType; |
|
1585 |
if (d->fileAttrib & FILE_ATTRIBUTE_DIRECTORY) { |
|
1586 |
ret |= DirectoryType; |
|
1587 |
} else { |
|
1588 |
ret |= FileType; |
|
1589 |
} |
|
1590 |
} |
|
1591 |
} |
|
1592 |
if (type & FlagsMask) { |
|
1593 |
ret |= LocalDiskFlag; |
|
1594 |
if (d->doStat()) { |
|
1595 |
ret |= ExistsFlag; |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1596 |
if (d->filePath == QLatin1String("/") || isDriveRoot(d->filePath) || isUncRoot(d->filePath)) |
0 | 1597 |
ret |= RootFlag; |
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1598 |
else if (d->fileAttrib & FILE_ATTRIBUTE_HIDDEN) |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1599 |
ret |= HiddenFlag; |
0 | 1600 |
} |
1601 |
} |
|
1602 |
return ret; |
|
1603 |
} |
|
1604 |
||
1605 |
QString QFSFileEngine::fileName(FileName file) const |
|
1606 |
{ |
|
1607 |
Q_D(const QFSFileEngine); |
|
1608 |
if (file == BaseName) { |
|
1609 |
int slash = d->filePath.lastIndexOf(QLatin1Char('/')); |
|
1610 |
if (slash == -1) { |
|
1611 |
int colon = d->filePath.lastIndexOf(QLatin1Char(':')); |
|
1612 |
if (colon != -1) |
|
1613 |
return d->filePath.mid(colon + 1); |
|
1614 |
return d->filePath; |
|
1615 |
} |
|
1616 |
return d->filePath.mid(slash + 1); |
|
1617 |
} else if (file == PathName) { |
|
1618 |
if (!d->filePath.size()) |
|
1619 |
return d->filePath; |
|
1620 |
||
1621 |
int slash = d->filePath.lastIndexOf(QLatin1Char('/')); |
|
1622 |
if (slash == -1) { |
|
1623 |
if (d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) |
|
1624 |
return d->filePath.left(2); |
|
1625 |
return QString(QLatin1Char('.')); |
|
1626 |
} else { |
|
1627 |
if (!slash) |
|
1628 |
return QString(QLatin1Char('/')); |
|
1629 |
if (slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) |
|
1630 |
slash++; |
|
1631 |
return d->filePath.left(slash); |
|
1632 |
} |
|
1633 |
} else if (file == AbsoluteName || file == AbsolutePathName) { |
|
1634 |
QString ret; |
|
1635 |
||
1636 |
if (!isRelativePath()) { |
|
1637 |
#if !defined(Q_OS_WINCE) |
|
1638 |
if ((d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') |
|
1639 |
&& d->filePath.at(2) != QLatin1Char('/')) || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt |
|
1640 |
d->filePath.startsWith(QLatin1Char('/')) // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt |
|
1641 |
) { |
|
1642 |
ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(d->filePath)); |
|
1643 |
} else { |
|
1644 |
ret = d->filePath; |
|
1645 |
} |
|
1646 |
#else |
|
1647 |
ret = d->filePath; |
|
1648 |
#endif |
|
1649 |
} else { |
|
1650 |
ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->filePath); |
|
1651 |
} |
|
1652 |
||
1653 |
// The path should be absolute at this point. |
|
1654 |
// From the docs : |
|
1655 |
// Absolute paths begin with the directory separator "/" |
|
1656 |
// (optionally preceded by a drive specification under Windows). |
|
1657 |
if (ret.at(0) != QLatin1Char('/')) { |
|
1658 |
Q_ASSERT(ret.length() >= 2); |
|
1659 |
Q_ASSERT(ret.at(0).isLetter()); |
|
1660 |
Q_ASSERT(ret.at(1) == QLatin1Char(':')); |
|
1661 |
||
1662 |
// Force uppercase drive letters. |
|
1663 |
ret[0] = ret.at(0).toUpper(); |
|
1664 |
} |
|
1665 |
||
1666 |
if (file == AbsolutePathName) { |
|
1667 |
int slash = ret.lastIndexOf(QLatin1Char('/')); |
|
1668 |
if (slash < 0) |
|
1669 |
return ret; |
|
1670 |
else if (ret.at(0) != QLatin1Char('/') && slash == 2) |
|
1671 |
return ret.left(3); // include the slash |
|
1672 |
else |
|
1673 |
return ret.left(slash > 0 ? slash : 1); |
|
1674 |
} |
|
1675 |
return ret; |
|
1676 |
} else if (file == CanonicalName || file == CanonicalPathName) { |
|
1677 |
if (!(fileFlags(ExistsFlag) & ExistsFlag)) |
|
1678 |
return QString(); |
|
1679 |
||
1680 |
QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName)); |
|
1681 |
if (!ret.isEmpty() && file == CanonicalPathName) { |
|
1682 |
int slash = ret.lastIndexOf(QLatin1Char('/')); |
|
1683 |
if (slash == -1) |
|
1684 |
ret = QDir::currentPath(); |
|
1685 |
else if (slash == 0) |
|
1686 |
ret = QString(QLatin1Char('/')); |
|
1687 |
ret = ret.left(slash); |
|
1688 |
} |
|
1689 |
return ret; |
|
1690 |
} else if (file == LinkName) { |
|
1691 |
QString ret; |
|
1692 |
if (d->filePath.endsWith(QLatin1String(".lnk"))) |
|
1693 |
ret = readLink(d->filePath); |
|
1694 |
else if (d->doStat() && d->isSymlink()) |
|
1695 |
ret = readSymLink(d->filePath); |
|
1696 |
return QDir::fromNativeSeparators(ret); |
|
1697 |
} else if (file == BundleName) { |
|
1698 |
return QString(); |
|
1699 |
} |
|
1700 |
return d->filePath; |
|
1701 |
} |
|
1702 |
||
1703 |
bool QFSFileEngine::isRelativePath() const |
|
1704 |
{ |
|
1705 |
Q_D(const QFSFileEngine); |
|
1706 |
// drive, e.g. "a:", or UNC root, e.q. "//" |
|
1707 |
return !(d->filePath.startsWith(QLatin1Char('/')) |
|
1708 |
|| (d->filePath.length() >= 2 |
|
1709 |
&& ((d->filePath.at(0).isLetter() && d->filePath.at(1) == QLatin1Char(':')) |
|
1710 |
|| (d->filePath.at(0) == QLatin1Char('/') && d->filePath.at(1) == QLatin1Char('/'))))); |
|
1711 |
} |
|
1712 |
||
1713 |
uint QFSFileEngine::ownerId(FileOwner /*own*/) const |
|
1714 |
{ |
|
1715 |
static const uint nobodyID = (uint) -2; |
|
1716 |
return nobodyID; |
|
1717 |
} |
|
1718 |
||
1719 |
QString QFSFileEngine::owner(FileOwner own) const |
|
1720 |
{ |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1721 |
QString name; |
0 | 1722 |
#if !defined(QT_NO_LIBRARY) |
1723 |
Q_D(const QFSFileEngine); |
|
1724 |
||
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1725 |
if ((qt_ntfs_permission_lookup > 0) && ((QSysInfo::WindowsVersion&QSysInfo::WV_NT_based) > QSysInfo::WV_NT)) { |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1726 |
QFSFileEnginePrivate::resolveLibs(); |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1727 |
if (ptrGetNamedSecurityInfoW && ptrLookupAccountSidW) { |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1728 |
PSID pOwner = 0; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1729 |
PSECURITY_DESCRIPTOR pSD; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1730 |
if (ptrGetNamedSecurityInfoW((wchar_t*)d->filePath.utf16(), SE_FILE_OBJECT, |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1731 |
own == OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION, |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1732 |
own == OwnerUser ? &pOwner : 0, own == OwnerGroup ? &pOwner : 0, |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1733 |
0, 0, &pSD) == ERROR_SUCCESS) { |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1734 |
DWORD lowner = 64; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1735 |
DWORD ldomain = 64; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1736 |
QVarLengthArray<wchar_t, 64> owner(lowner); |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1737 |
QVarLengthArray<wchar_t, 64> domain(ldomain); |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1738 |
SID_NAME_USE use = SidTypeUnknown; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1739 |
// First call, to determine size of the strings (with '\0'). |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1740 |
if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner, |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1741 |
(LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) { |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1742 |
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1743 |
if (lowner > (DWORD)owner.size()) |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1744 |
owner.resize(lowner); |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1745 |
if (ldomain > (DWORD)domain.size()) |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1746 |
domain.resize(ldomain); |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1747 |
// Second call, try on resized buf-s |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1748 |
if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner, |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1749 |
(LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) { |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1750 |
lowner = 0; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1751 |
} |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1752 |
} else { |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1753 |
lowner = 0; |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1754 |
} |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1755 |
} |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1756 |
if (lowner != 0) |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1757 |
name = QString::fromWCharArray(owner.data()); |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1758 |
LocalFree(pSD); |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1759 |
} |
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1760 |
} |
0 | 1761 |
} |
1762 |
#else |
|
1763 |
Q_UNUSED(own); |
|
1764 |
#endif |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1765 |
return name; |
0 | 1766 |
} |
1767 |
||
1768 |
bool QFSFileEngine::setPermissions(uint perms) |
|
1769 |
{ |
|
1770 |
Q_D(QFSFileEngine); |
|
1771 |
bool ret = false; |
|
1772 |
int mode = 0; |
|
1773 |
||
1774 |
if (perms & QFile::ReadOwner || perms & QFile::ReadUser || perms & QFile::ReadGroup || perms & QFile::ReadOther) |
|
1775 |
mode |= _S_IREAD; |
|
1776 |
if (perms & QFile::WriteOwner || perms & QFile::WriteUser || perms & QFile::WriteGroup || perms & QFile::WriteOther) |
|
1777 |
mode |= _S_IWRITE; |
|
1778 |
||
1779 |
if (mode == 0) // not supported |
|
1780 |
return false; |
|
1781 |
||
1782 |
ret = ::_wchmod((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), mode) == 0; |
|
1783 |
if (!ret) |
|
1784 |
setError(QFile::PermissionsError, qt_error_string(errno)); |
|
1785 |
return ret; |
|
1786 |
} |
|
1787 |
||
1788 |
bool QFSFileEngine::setSize(qint64 size) |
|
1789 |
{ |
|
1790 |
Q_D(QFSFileEngine); |
|
1791 |
||
1792 |
if (d->fileHandle != INVALID_HANDLE_VALUE || d->fd != -1) { |
|
1793 |
// resize open file |
|
1794 |
HANDLE fh = d->fileHandle; |
|
1795 |
#if !defined(Q_OS_WINCE) |
|
1796 |
if (fh == INVALID_HANDLE_VALUE) |
|
1797 |
fh = (HANDLE)_get_osfhandle(d->fd); |
|
1798 |
#endif |
|
1799 |
if (fh == INVALID_HANDLE_VALUE) |
|
1800 |
return false; |
|
1801 |
qint64 currentPos = pos(); |
|
1802 |
||
1803 |
if (seek(size) && SetEndOfFile(fh)) { |
|
1804 |
seek(qMin(currentPos, size)); |
|
1805 |
return true; |
|
1806 |
} |
|
1807 |
||
1808 |
seek(currentPos); |
|
1809 |
return false; |
|
1810 |
} |
|
1811 |
||
1812 |
if (!d->nativeFilePath.isEmpty()) { |
|
1813 |
// resize file on disk |
|
1814 |
QFile file(d->filePath); |
|
1815 |
if (file.open(QFile::ReadWrite)) { |
|
1816 |
bool ret = file.resize(size); |
|
1817 |
if (!ret) |
|
1818 |
setError(QFile::ResizeError, file.errorString()); |
|
1819 |
return ret; |
|
1820 |
} |
|
1821 |
} |
|
1822 |
return false; |
|
1823 |
} |
|
1824 |
||
1825 |
||
1826 |
static inline QDateTime fileTimeToQDateTime(const FILETIME *time) |
|
1827 |
{ |
|
1828 |
QDateTime ret; |
|
1829 |
||
1830 |
#if defined(Q_OS_WINCE) |
|
1831 |
SYSTEMTIME systime; |
|
1832 |
FILETIME ftime; |
|
1833 |
systime.wYear = 1970; |
|
1834 |
systime.wMonth = 1; |
|
1835 |
systime.wDay = 1; |
|
1836 |
systime.wHour = 0; |
|
1837 |
systime.wMinute = 0; |
|
1838 |
systime.wSecond = 0; |
|
1839 |
systime.wMilliseconds = 0; |
|
1840 |
systime.wDayOfWeek = 4; |
|
1841 |
SystemTimeToFileTime(&systime, &ftime); |
|
1842 |
unsigned __int64 acttime = (unsigned __int64)time->dwHighDateTime << 32 | time->dwLowDateTime; |
|
1843 |
FileTimeToSystemTime(time, &systime); |
|
1844 |
unsigned __int64 time1970 = (unsigned __int64)ftime.dwHighDateTime << 32 | ftime.dwLowDateTime; |
|
1845 |
unsigned __int64 difftime = acttime - time1970; |
|
1846 |
difftime /= 10000000; |
|
1847 |
ret.setTime_t((unsigned int)difftime); |
|
1848 |
#else |
|
1849 |
SYSTEMTIME sTime, lTime; |
|
1850 |
FileTimeToSystemTime(time, &sTime); |
|
1851 |
SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime); |
|
1852 |
ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay)); |
|
1853 |
ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds)); |
|
1854 |
#endif |
|
1855 |
||
1856 |
return ret; |
|
1857 |
} |
|
1858 |
||
1859 |
QDateTime QFSFileEngine::fileTime(FileTime time) const |
|
1860 |
{ |
|
1861 |
Q_D(const QFSFileEngine); |
|
1862 |
QDateTime ret; |
|
1863 |
if (d->fd != -1) { |
|
1864 |
#if !defined(Q_OS_WINCE) |
|
1865 |
HANDLE fh = (HANDLE)_get_osfhandle(d->fd); |
|
1866 |
if (fh != INVALID_HANDLE_VALUE) { |
|
1867 |
FILETIME creationTime, lastAccessTime, lastWriteTime; |
|
1868 |
if (GetFileTime(fh, &creationTime, &lastAccessTime, &lastWriteTime)) { |
|
1869 |
if(time == CreationTime) |
|
1870 |
ret = fileTimeToQDateTime(&creationTime); |
|
1871 |
else if(time == ModificationTime) |
|
1872 |
ret = fileTimeToQDateTime(&lastWriteTime); |
|
1873 |
else if(time == AccessTime) |
|
1874 |
ret = fileTimeToQDateTime(&lastAccessTime); |
|
1875 |
} |
|
1876 |
} |
|
1877 |
#endif |
|
1878 |
} else { |
|
1879 |
WIN32_FILE_ATTRIBUTE_DATA attribData; |
|
1880 |
bool ok = ::GetFileAttributesEx((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), GetFileExInfoStandard, &attribData); |
|
1881 |
if (!ok) { |
|
1882 |
int errorCode = GetLastError(); |
|
1883 |
if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { |
|
1884 |
QString path = QDir::toNativeSeparators(d->filePath); |
|
1885 |
// path for the FindFirstFile should not end with a trailing slash |
|
1886 |
while (path.endsWith(QLatin1Char('\\'))) |
|
1887 |
path.chop(1); |
|
1888 |
||
1889 |
// FindFirstFile can not handle drives |
|
1890 |
if (!path.endsWith(QLatin1Char(':'))) { |
|
1891 |
WIN32_FIND_DATA findData; |
|
1892 |
HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), |
|
1893 |
&findData); |
|
1894 |
if (hFind != INVALID_HANDLE_VALUE) { |
|
1895 |
::FindClose(hFind); |
|
1896 |
ok = true; |
|
1897 |
attribData.ftCreationTime = findData.ftCreationTime; |
|
1898 |
attribData.ftLastWriteTime = findData.ftLastWriteTime; |
|
1899 |
attribData.ftLastAccessTime = findData.ftLastAccessTime; |
|
1900 |
} |
|
1901 |
} |
|
1902 |
} |
|
1903 |
} |
|
1904 |
if (ok) { |
|
1905 |
if(time == CreationTime) |
|
1906 |
ret = fileTimeToQDateTime(&attribData.ftCreationTime); |
|
1907 |
else if(time == ModificationTime) |
|
1908 |
ret = fileTimeToQDateTime(&attribData.ftLastWriteTime); |
|
1909 |
else if(time == AccessTime) |
|
1910 |
ret = fileTimeToQDateTime(&attribData.ftLastAccessTime); |
|
1911 |
} |
|
1912 |
} |
|
1913 |
return ret; |
|
1914 |
} |
|
1915 |
||
1916 |
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, |
|
1917 |
QFile::MemoryMapFlags flags) |
|
1918 |
{ |
|
1919 |
Q_Q(QFSFileEngine); |
|
1920 |
Q_UNUSED(flags); |
|
1921 |
if (openMode == QFile::NotOpen) { |
|
1922 |
q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); |
|
1923 |
return 0; |
|
1924 |
} |
|
1925 |
if (offset == 0 && size == 0) { |
|
1926 |
q->setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER)); |
|
1927 |
return 0; |
|
1928 |
} |
|
1929 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1930 |
if (mapHandle == INVALID_HANDLE_VALUE) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1931 |
// get handle to the file |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1932 |
HANDLE handle = fileHandle; |
0 | 1933 |
|
1934 |
#ifndef Q_OS_WINCE |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1935 |
if (handle == INVALID_HANDLE_VALUE && fh) |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1936 |
handle = (HANDLE)::_get_osfhandle(QT_FILENO(fh)); |
0 | 1937 |
#endif |
1938 |
||
1939 |
#ifdef Q_USE_DEPRECATED_MAP_API |
|
1940 |
nativeClose(); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1941 |
// handle automatically closed by kernel with mapHandle (below). |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1942 |
handle = ::CreateFileForMapping((const wchar_t*)nativeFilePath.constData(), |
0 | 1943 |
GENERIC_READ | (openMode & QIODevice::WriteOnly ? GENERIC_WRITE : 0), |
1944 |
0, |
|
1945 |
NULL, |
|
1946 |
OPEN_EXISTING, |
|
1947 |
FILE_ATTRIBUTE_NORMAL, |
|
1948 |
NULL); |
|
1949 |
#endif |
|
1950 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1951 |
if (handle == INVALID_HANDLE_VALUE) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1952 |
q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1953 |
return 0; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1954 |
} |
0 | 1955 |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1956 |
// first create the file mapping handle |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1957 |
DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1958 |
mapHandle = ::CreateFileMapping(handle, 0, protection, 0, 0, 0); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1959 |
if (mapHandle == INVALID_HANDLE_VALUE) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1960 |
q->setError(QFile::PermissionsError, qt_error_string()); |
0 | 1961 |
#ifdef Q_USE_DEPRECATED_MAP_API |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1962 |
::CloseHandle(handle); |
0 | 1963 |
#endif |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1964 |
return 0; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1965 |
} |
0 | 1966 |
} |
1967 |
||
1968 |
// setup args to map |
|
1969 |
DWORD access = 0; |
|
1970 |
if (openMode & QIODevice::ReadOnly) access = FILE_MAP_READ; |
|
1971 |
if (openMode & QIODevice::WriteOnly) access = FILE_MAP_WRITE; |
|
1972 |
||
1973 |
DWORD offsetHi = offset >> 32; |
|
1974 |
DWORD offsetLo = offset & Q_UINT64_C(0xffffffff); |
|
1975 |
SYSTEM_INFO sysinfo; |
|
1976 |
::GetSystemInfo(&sysinfo); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1977 |
DWORD mask = sysinfo.dwAllocationGranularity - 1; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1978 |
DWORD extra = offset & mask; |
0 | 1979 |
if (extra) |
1980 |
offsetLo &= ~mask; |
|
1981 |
||
1982 |
// attempt to create the map |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1983 |
LPVOID mapAddress = ::MapViewOfFile(mapHandle, access, |
0 | 1984 |
offsetHi, offsetLo, size + extra); |
1985 |
if (mapAddress) { |
|
1986 |
uchar *address = extra + static_cast<uchar*>(mapAddress); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1987 |
maps[address] = extra; |
0 | 1988 |
return address; |
1989 |
} |
|
1990 |
||
1991 |
switch(GetLastError()) { |
|
1992 |
case ERROR_ACCESS_DENIED: |
|
1993 |
q->setError(QFile::PermissionsError, qt_error_string()); |
|
1994 |
break; |
|
1995 |
case ERROR_INVALID_PARAMETER: |
|
1996 |
// size are out of bounds |
|
1997 |
default: |
|
1998 |
q->setError(QFile::UnspecifiedError, qt_error_string()); |
|
1999 |
} |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2000 |
|
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2001 |
::CloseHandle(mapHandle); |
0 | 2002 |
return 0; |
2003 |
} |
|
2004 |
||
2005 |
bool QFSFileEnginePrivate::unmap(uchar *ptr) |
|
2006 |
{ |
|
2007 |
Q_Q(QFSFileEngine); |
|
2008 |
if (!maps.contains(ptr)) { |
|
2009 |
q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); |
|
2010 |
return false; |
|
2011 |
} |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2012 |
uchar *start = ptr - maps[ptr]; |
0 | 2013 |
if (!UnmapViewOfFile(start)) { |
2014 |
q->setError(QFile::PermissionsError, qt_error_string()); |
|
2015 |
return false; |
|
2016 |
} |
|
2017 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2018 |
maps.remove(ptr); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2019 |
if (maps.isEmpty()) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2020 |
::CloseHandle(mapHandle); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2021 |
mapHandle = INVALID_HANDLE_VALUE; |
0 | 2022 |
} |
2023 |
||
2024 |
return true; |
|
2025 |
} |
|
2026 |
||
2027 |
QT_END_NAMESPACE |