File indexing completed on 2024-12-22 04:35:01
0001 /* 0002 SPDX-FileCopyrightText: 2009 Nokia Corporation and /or its subsidiary(-ies). 0003 Contact: Qt Software Information (qt-info@nokia.com) 0004 0005 This file is part of the QtCore module of the Qt Toolkit. 0006 0007 $QT_BEGIN_LICENSE:LGPL$ 0008 Commercial Usage 0009 Licensees holding valid Qt Commercial licenses may use this file in 0010 accordance with the Qt Commercial License Agreement provided with the 0011 Software or, alternatively, in accordance with the terms contained in 0012 a written agreement between you and Nokia. 0013 0014 GNU Lesser General Public License Usage 0015 Alternatively, this file may be used under the terms of the GNU Lesser 0016 General Public License version 2.1 as published by the Free Software 0017 Foundation and appearing in the file LICENSE.LGPL included in the 0018 packaging of this file. Please review the following information to 0019 ensure the GNU Lesser General Public License version 2.1 requirements 0020 will be met: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 0021 0022 In addition, as a special exception, Nokia gives you certain 0023 additional rights. These rights are described in the Nokia Qt LGPL 0024 Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 0025 package. 0026 0027 GNU General Public License Usage 0028 Alternatively, this file may be used under the terms of the GNU 0029 General Public License version 3.0 as published by the Free Software 0030 Foundation and appearing in the file LICENSE.GPL included in the 0031 packaging of this file. Please review the following information to 0032 ensure the GNU General Public License version 3.0 requirements will be 0033 met: https://www.gnu.org/licenses/gpl-3.0.html. 0034 0035 If you are unsure which license is appropriate for your use, please 0036 contact the sales department at qt-sales@nokia.com. 0037 $QT_END_LICENSE$ 0038 0039 */ 0040 0041 #define _POSIX_ 0042 #include "qplatformdefs.h" 0043 #include "qabstractfileengine.h" 0044 #include "private/qfsfileengine_p.h" 0045 #include <qdebug.h> 0046 0047 #include "QtCore/QFile" 0048 #include "QtCore/QDir" 0049 #include "qtemporaryfile.h" 0050 #ifndef QT_NO_REGEXP 0051 # include "QtCore/QRegExp" 0052 #endif 0053 #include "private/qmutexpool_p.h" 0054 #include "qvarlengtharray.h" 0055 #include "qdatetime.h" 0056 #include "qt_windows.h" 0057 0058 #if !defined(Q_OS_WINCE) 0059 # include <sys/types.h> 0060 # include <direct.h> 0061 #else 0062 # include <types.h> 0063 #endif 0064 #include <objbase.h> 0065 #include <shlobj.h> 0066 #include <initguid.h> 0067 #include <accctrl.h> 0068 #include <ctype.h> 0069 #include <limits.h> 0070 #define SECURITY_WIN32 0071 #ifdef Q_CC_MINGW 0072 // A workaround for a certain version of MinGW, the define UNICODE_STRING. 0073 #include <subauth.h> 0074 #endif 0075 #include <security.h> 0076 0077 #ifndef _INTPTR_T_DEFINED 0078 #ifdef _WIN64 0079 typedef __int64 intptr_t; 0080 #else 0081 #ifdef _W64 0082 typedef _W64 int intptr_t; 0083 #else 0084 typedef INT_PTR intptr_t; 0085 #endif 0086 #endif 0087 #define _INTPTR_T_DEFINED 0088 #endif 0089 0090 #ifndef INVALID_FILE_ATTRIBUTES 0091 # define INVALID_FILE_ATTRIBUTES (DWORD (-1)) 0092 #endif 0093 0094 QT_BEGIN_NAMESPACE 0095 0096 static QString readLink(const QString &link); 0097 0098 LIBK3B_EXPORT int qt_ntfs_permission_lookup = 0; 0099 0100 #if defined(Q_OS_WINCE) 0101 static QString qfsPrivateCurrentDir = QLatin1String(""); 0102 // As none of the functions we try to resolve do exist on Windows CE 0103 // we use QT_NO_LIBRARY to shorten everything up a little bit. 0104 #define QT_NO_LIBRARY 1 0105 #endif 0106 0107 #if !defined(QT_NO_LIBRARY) 0108 QT_BEGIN_INCLUDE_NAMESPACE 0109 typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); 0110 static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0; 0111 typedef DECLSPEC_IMPORT BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE); 0112 static PtrLookupAccountSidW ptrLookupAccountSidW = 0; 0113 typedef DECLSPEC_IMPORT BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*); 0114 static PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = 0; 0115 typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID); 0116 static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0; 0117 typedef VOID (WINAPI *PtrBuildTrusteeWithNameW)(PTRUSTEE_W, unsigned short*); 0118 static PtrBuildTrusteeWithNameW ptrBuildTrusteeWithNameW = 0; 0119 typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK); 0120 static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0; 0121 typedef DECLSPEC_IMPORT PVOID (WINAPI *PtrFreeSid)(PSID); 0122 static PtrFreeSid ptrFreeSid = 0; 0123 static TRUSTEE_W currentUserTrusteeW; 0124 0125 typedef BOOL (WINAPI *PtrOpenProcessToken)(HANDLE, DWORD, PHANDLE ); 0126 static PtrOpenProcessToken ptrOpenProcessToken = 0; 0127 typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)( HANDLE, LPWSTR, LPDWORD); 0128 static PtrGetUserProfileDirectoryW ptrGetUserProfileDirectoryW = 0; 0129 typedef BOOL (WINAPI *PtrSetFilePointerEx)(HANDLE, LARGE_INTEGER, PLARGE_INTEGER, DWORD); 0130 static PtrSetFilePointerEx ptrSetFilePointerEx = 0; 0131 QT_END_INCLUDE_NAMESPACE 0132 0133 0134 void QFSFileEnginePrivate::resolveLibs() 0135 { 0136 static bool triedResolve = false; 0137 if(!triedResolve) { 0138 // need to resolve the security info functions 0139 0140 // protect initialization 0141 #ifndef QT_NO_THREAD 0142 QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); 0143 // check triedResolve again, since another thread may have already 0144 // done the initialization 0145 if(triedResolve) { 0146 // another thread did initialize the security function pointers, 0147 // so we shouldn't do it again. 0148 return; 0149 } 0150 #endif 0151 0152 triedResolve = true; 0153 #if !defined(Q_OS_WINCE) 0154 if(QSysInfo::WindowsVersion & QSysInfo::WV_NT_based) { 0155 HINSTANCE advapiHnd = LoadLibraryW(L"advapi32"); 0156 if (advapiHnd) { 0157 ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW"); 0158 ptrLookupAccountSidW = (PtrLookupAccountSidW)GetProcAddress(advapiHnd, "LookupAccountSidW"); 0159 ptrAllocateAndInitializeSid = (PtrAllocateAndInitializeSid)GetProcAddress(advapiHnd, "AllocateAndInitializeSid"); 0160 ptrBuildTrusteeWithSidW = (PtrBuildTrusteeWithSidW)GetProcAddress(advapiHnd, "BuildTrusteeWithSidW"); 0161 ptrBuildTrusteeWithNameW = (PtrBuildTrusteeWithNameW)GetProcAddress(advapiHnd, "BuildTrusteeWithNameW"); 0162 ptrGetEffectiveRightsFromAclW = (PtrGetEffectiveRightsFromAclW)GetProcAddress(advapiHnd, "GetEffectiveRightsFromAclW"); 0163 ptrFreeSid = (PtrFreeSid)GetProcAddress(advapiHnd, "FreeSid"); 0164 } 0165 if (ptrBuildTrusteeWithNameW) { 0166 HINSTANCE versionHnd = LoadLibraryW(L"version"); 0167 if (versionHnd) { 0168 typedef DWORD (WINAPI *PtrGetFileVersionInfoSizeW)(LPWSTR lptstrFilename,LPDWORD lpdwHandle); 0169 PtrGetFileVersionInfoSizeW ptrGetFileVersionInfoSizeW = (PtrGetFileVersionInfoSizeW)GetProcAddress(versionHnd, "GetFileVersionInfoSizeW"); 0170 typedef BOOL (WINAPI *PtrGetFileVersionInfoW)(LPWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); 0171 PtrGetFileVersionInfoW ptrGetFileVersionInfoW = (PtrGetFileVersionInfoW)GetProcAddress(versionHnd, "GetFileVersionInfoW"); 0172 typedef BOOL (WINAPI *PtrVerQueryValueW)(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); 0173 PtrVerQueryValueW ptrVerQueryValueW = (PtrVerQueryValueW)GetProcAddress(versionHnd, "VerQueryValueW"); 0174 if(ptrGetFileVersionInfoSizeW && ptrGetFileVersionInfoW && ptrVerQueryValueW) { 0175 DWORD fakeHandle; 0176 DWORD versionSize = ptrGetFileVersionInfoSizeW(L"secur32.dll", &fakeHandle); 0177 if(versionSize) { 0178 LPVOID versionData; 0179 versionData = malloc(versionSize); 0180 if(ptrGetFileVersionInfoW(L"secur32.dll", 0, versionSize, versionData)) { 0181 UINT puLen; 0182 VS_FIXEDFILEINFO *pLocalInfo; 0183 if(ptrVerQueryValueW(versionData, L"\\", (void**)&pLocalInfo, &puLen)) { 0184 WORD wVer1, wVer2, wVer3, wVer4; 0185 wVer1 = HIWORD(pLocalInfo->dwFileVersionMS); 0186 wVer2 = LOWORD(pLocalInfo->dwFileVersionMS); 0187 wVer3 = HIWORD(pLocalInfo->dwFileVersionLS); 0188 wVer4 = LOWORD(pLocalInfo->dwFileVersionLS); 0189 // It will not work with secur32.dll version 5.0.2195.2862 0190 if(!(wVer1 == 5 && wVer2 == 0 && wVer3 == 2195 && (wVer4 == 2862 || wVer4 == 4587))) { 0191 HINSTANCE userHnd = LoadLibraryW(L"secur32"); 0192 if (userHnd) { 0193 typedef BOOL (WINAPI *PtrGetUserNameExW)(EXTENDED_NAME_FORMAT nameFormat, ushort* lpBuffer, LPDWORD nSize); 0194 PtrGetUserNameExW ptrGetUserNameExW = (PtrGetUserNameExW)GetProcAddress(userHnd, "GetUserNameExW"); 0195 if(ptrGetUserNameExW) { 0196 static TCHAR buffer[258]; 0197 DWORD bufferSize = 257; 0198 ptrGetUserNameExW(NameSamCompatible, (ushort*)buffer, &bufferSize); 0199 ptrBuildTrusteeWithNameW(¤tUserTrusteeW, (ushort*)buffer); 0200 } 0201 FreeLibrary(userHnd); 0202 } 0203 } 0204 } 0205 } 0206 free(versionData); 0207 } 0208 } 0209 FreeLibrary(versionHnd); 0210 } 0211 } 0212 ptrOpenProcessToken = (PtrOpenProcessToken)GetProcAddress(advapiHnd, "OpenProcessToken"); 0213 HINSTANCE userenvHnd = LoadLibraryW(L"userenv"); 0214 if (userenvHnd) { 0215 ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW"); 0216 } 0217 HINSTANCE kernelHnd = LoadLibraryW(L"kernel32"); 0218 if (kernelHnd) 0219 ptrSetFilePointerEx = (PtrSetFilePointerEx)GetProcAddress(kernelHnd, "SetFilePointerEx"); 0220 } 0221 #endif 0222 } 0223 } 0224 #endif // QT_NO_LIBRARY 0225 0226 // UNC functions NT 0227 typedef DWORD (WINAPI *PtrNetShareEnum_NT)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD); 0228 static PtrNetShareEnum_NT ptrNetShareEnum_NT = 0; 0229 typedef DWORD (WINAPI *PtrNetApiBufferFree_NT)(LPVOID); 0230 static PtrNetApiBufferFree_NT ptrNetApiBufferFree_NT = 0; 0231 typedef struct _SHARE_INFO_1_NT { 0232 LPWSTR shi1_netname; 0233 DWORD shi1_type; 0234 LPWSTR shi1_remark; 0235 } SHARE_INFO_1_NT; 0236 0237 0238 bool QFSFileEnginePrivate::resolveUNCLibs_NT() 0239 { 0240 static bool triedResolve = false; 0241 if (!triedResolve) { 0242 #ifndef QT_NO_THREAD 0243 QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); 0244 if (triedResolve) { 0245 return ptrNetShareEnum_NT && ptrNetApiBufferFree_NT; 0246 } 0247 #endif 0248 triedResolve = true; 0249 #if !defined(Q_OS_WINCE) 0250 HINSTANCE hLib = LoadLibraryW(L"Netapi32"); 0251 if (hLib) { 0252 ptrNetShareEnum_NT = (PtrNetShareEnum_NT)GetProcAddress(hLib, "NetShareEnum"); 0253 if (ptrNetShareEnum_NT) 0254 ptrNetApiBufferFree_NT = (PtrNetApiBufferFree_NT)GetProcAddress(hLib, "NetApiBufferFree"); 0255 } 0256 #endif 0257 } 0258 return ptrNetShareEnum_NT && ptrNetApiBufferFree_NT; 0259 } 0260 0261 // UNC functions 9x 0262 typedef DWORD (WINAPI *PtrNetShareEnum_9x)(const char FAR *, short, char FAR *, unsigned short, unsigned short FAR *, unsigned short FAR *); 0263 static PtrNetShareEnum_9x ptrNetShareEnum_9x = 0; 0264 #ifdef LM20_NNLEN 0265 # define LM20_NNLEN_9x LM20_NNLEN 0266 #else 0267 # define LM20_NNLEN_9x 12 0268 #endif 0269 typedef struct _SHARE_INFO_1_9x { 0270 char shi1_netname[LM20_NNLEN_9x+1]; 0271 char shi1_pad1; 0272 unsigned short shi1_type; 0273 char FAR* shi1_remark; 0274 } SHARE_INFO_1_9x; 0275 0276 bool QFSFileEnginePrivate::resolveUNCLibs_9x() 0277 { 0278 static bool triedResolve = false; 0279 if (!triedResolve) { 0280 #ifndef QT_NO_THREAD 0281 QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); 0282 if (triedResolve) { 0283 return ptrNetShareEnum_9x; 0284 } 0285 #endif 0286 triedResolve = true; 0287 #if !defined(Q_OS_WINCE) 0288 HINSTANCE hLib = LoadLibraryA("Svrapi"); 0289 if (hLib) 0290 ptrNetShareEnum_9x = (PtrNetShareEnum_9x)GetProcAddress(hLib, "NetShareEnum"); 0291 #endif 0292 } 0293 return ptrNetShareEnum_9x; 0294 } 0295 0296 bool QFSFileEnginePrivate::uncListSharesOnServer(const QString &server, QStringList *list) 0297 { 0298 if (resolveUNCLibs_NT()) { 0299 SHARE_INFO_1_NT *BufPtr, *p; 0300 DWORD res; 0301 DWORD er=0,tr=0,resume=0, i; 0302 do { 0303 res = ptrNetShareEnum_NT((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume); 0304 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) { 0305 p=BufPtr; 0306 for (i = 1; i <= er; ++i) { 0307 if (list && p->shi1_type == 0) 0308 list->append(QString::fromUtf16((unsigned short *)p->shi1_netname)); 0309 p++; 0310 } 0311 } 0312 ptrNetApiBufferFree_NT(BufPtr); 0313 } while (res==ERROR_MORE_DATA); 0314 return res == ERROR_SUCCESS; 0315 0316 } else if (resolveUNCLibs_9x()) { 0317 SHARE_INFO_1_9x *pBuf = 0; 0318 short cbBuffer; 0319 unsigned short nEntriesRead = 0; 0320 unsigned short nTotalEntries = 0; 0321 short numBuffs = 20; 0322 DWORD nStatus = 0; 0323 do { 0324 cbBuffer = numBuffs * sizeof(SHARE_INFO_1_9x); 0325 pBuf = (SHARE_INFO_1_9x *)malloc(cbBuffer); 0326 if (pBuf) { 0327 nStatus = ptrNetShareEnum_9x(server.toLocal8Bit().constData(), 1, (char FAR *)pBuf, cbBuffer, &nEntriesRead, &nTotalEntries); 0328 if ((nStatus == ERROR_SUCCESS)) { 0329 for (int i = 0; i < nEntriesRead; ++i) { 0330 if (list && pBuf[i].shi1_type == 0) 0331 list->append(QString::fromLocal8Bit(pBuf[i].shi1_netname)); 0332 } 0333 free(pBuf); 0334 break; 0335 } 0336 free(pBuf); 0337 numBuffs *=2; 0338 } 0339 } while (nStatus == ERROR_MORE_DATA); 0340 return nStatus == ERROR_SUCCESS; 0341 } 0342 return false; 0343 } 0344 0345 static bool isUncRoot(const QString &server) 0346 { 0347 QString localPath = QDir::toNativeSeparators(server); 0348 QStringList parts = localPath.split(QLatin1Char('\\'), QString::SkipEmptyParts); 0349 return localPath.startsWith(QLatin1String("\\\\")) && parts.count() <= 1; 0350 } 0351 0352 static bool isUncPath(const QString &path) 0353 { 0354 // Starts with // or \\, but not \\. or //. 0355 return (path.startsWith(QLatin1String("//")) 0356 || path.startsWith(QLatin1String("\\\\"))) 0357 && (path.size() > 2 && path.at(2) != QLatin1Char('.')); 0358 } 0359 0360 static bool isRelativePath(const QString &path) 0361 { 0362 return !(path.startsWith(QLatin1Char('/')) 0363 || (path.length() >= 2 0364 && ((path.at(0).isLetter() && path.at(1) == QLatin1Char(':')) 0365 || (path.at(0) == QLatin1Char('/') && path.at(1) == QLatin1Char('/'))))); // drive, e.g. a: 0366 } 0367 0368 static QString fixIfRelativeUncPath(const QString &path) 0369 { 0370 if (isRelativePath(path)) { 0371 QString currentPath = QDir::currentPath() + QLatin1Char('/'); 0372 if (currentPath.startsWith(QLatin1String("//"))) 0373 return QString(path).prepend(currentPath); 0374 } 0375 return path; 0376 } 0377 0378 // can be //server or //server/share 0379 static bool uncShareExists(const QString &server) 0380 { 0381 QStringList parts = server.split(QLatin1Char('\\'), QString::SkipEmptyParts); 0382 if (parts.count()) { 0383 QStringList shares; 0384 if (QFSFileEnginePrivate::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(0), &shares)) { 0385 if (parts.count() >= 2) 0386 return shares.contains(parts.at(1), Qt::CaseInsensitive); 0387 else 0388 return true; 0389 } 0390 } 0391 return false; 0392 } 0393 0394 #if !defined(Q_OS_WINCE) 0395 // If you change this function, remember to also change the UNICODE version 0396 static QString nativeAbsoluteFilePathA(const QString &path) 0397 { 0398 QString ret; 0399 QVarLengthArray<char, MAX_PATH> buf(MAX_PATH); 0400 char *fileName = 0; 0401 QByteArray ba = path.toLocal8Bit(); 0402 DWORD retLen = GetFullPathNameA(ba.constData(), buf.size(), buf.data(), &fileName); 0403 if (retLen > (DWORD)buf.size()) { 0404 buf.resize(retLen); 0405 retLen = GetFullPathNameA(ba.constData(), buf.size(), buf.data(), &fileName); 0406 } 0407 if (retLen != 0) 0408 ret = QString::fromLocal8Bit(buf.data(), retLen); 0409 return ret; 0410 } 0411 #endif 0412 0413 // If you change this function, remember to also change the NON-UNICODE version 0414 static QString nativeAbsoluteFilePathW(const QString &path) 0415 { 0416 QString ret; 0417 #if !defined(Q_OS_WINCE) 0418 QVarLengthArray<wchar_t, MAX_PATH> buf(MAX_PATH); 0419 wchar_t *fileName = 0; 0420 DWORD retLen = GetFullPathNameW((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName); 0421 if (retLen > (DWORD)buf.size()) { 0422 buf.resize(retLen); 0423 retLen = GetFullPathNameW((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName); 0424 } 0425 if (retLen != 0) 0426 ret = QString::fromUtf16((unsigned short *)buf.data(), retLen); 0427 #else 0428 if (path.startsWith(QLatin1String("/")) || path.startsWith(QLatin1String("\\"))) 0429 ret = QDir::toNativeSeparators(path); 0430 else 0431 ret = QDir::toNativeSeparators(QDir::cleanPath(qfsPrivateCurrentDir + QLatin1Char('/') + path)); 0432 #endif 0433 return ret; 0434 } 0435 0436 static QString nativeAbsoluteFilePath(const QString &path) 0437 { 0438 QString absPath = QT_WA_INLINE(nativeAbsoluteFilePathW(path), nativeAbsoluteFilePathA(path)); 0439 // This is really ugly, but GetFullPathName strips off whitespace at the end. 0440 // If you for instance write ". " in the lineedit of QFileDialog, 0441 // (which is an invalid filename) this function will strip the space off and viola, 0442 // the file is later reported as existing. Therefore, we re-add the whitespace that 0443 // was at the end of path in order to keep the filename invalid. 0444 int i = path.size() - 1; 0445 while (i >= 0 && path.at(i) == QLatin1Char(' ')) --i; 0446 int extraws = path.size() - 1 - i; 0447 if (extraws >= 0) { 0448 while (extraws) { 0449 absPath.append(QLatin1Char(' ')); 0450 --extraws; 0451 } 0452 } 0453 return absPath; 0454 } 0455 0456 QByteArray QFSFileEnginePrivate::win95Name(const QString &path) 0457 { 0458 QString ret(path); 0459 if(path.length() > 1 && path[0] == QLatin1Char('/') && path[1] == QLatin1Char('/')) { 0460 // Win95 cannot handle slash-slash needs slosh-slosh. 0461 ret[0] = QLatin1Char('\\'); 0462 ret[1] = QLatin1Char('\\'); 0463 int n = ret.indexOf(QLatin1Char('/')); 0464 if(n >= 0) 0465 ret[n] = QLatin1Char('\\'); 0466 } else if(path.length() > 3 && path[2] == QLatin1Char('/') && path[3] == QLatin1Char('/')) { 0467 ret[2] = QLatin1Char('\\'); 0468 ret.remove(3, 1); 0469 int n = ret.indexOf(QLatin1Char('/')); 0470 if(n >= 0) 0471 ret[n] = QLatin1Char('\\'); 0472 } 0473 return ret.toLocal8Bit(); 0474 } 0475 0476 /*! 0477 \internal 0478 */ 0479 QString QFSFileEnginePrivate::longFileName(const QString &path) 0480 { 0481 if (path.startsWith(QLatin1String("\\\\.\\"))) 0482 return path; 0483 0484 QString absPath = nativeAbsoluteFilePath(path); 0485 #if !defined(Q_OS_WINCE) 0486 QString prefix = QLatin1String("\\\\?\\"); 0487 if (isUncPath(path)) { 0488 prefix = QLatin1String("\\\\?\\UNC\\"); 0489 absPath.remove(0, 2); 0490 } 0491 return prefix + absPath; 0492 #else 0493 return absPath; 0494 #endif 0495 } 0496 0497 /* 0498 \internal 0499 */ 0500 void QFSFileEnginePrivate::nativeInitFileName() 0501 { 0502 QT_WA({ 0503 QString path = longFileName(QDir::toNativeSeparators(fixIfRelativeUncPath(filePath))); 0504 nativeFilePath = QByteArray((const char *)path.utf16(), path.size() * 2 + 1); 0505 }, { 0506 QString path = fixIfRelativeUncPath(filePath); 0507 nativeFilePath = win95Name(path).replace('/', '\\'); 0508 }); 0509 } 0510 0511 /* 0512 \internal 0513 */ 0514 bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) 0515 { 0516 Q_Q(QFSFileEngine); 0517 0518 // All files are opened in share mode (both read and write). 0519 DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; 0520 0521 int accessRights = 0; 0522 if (openMode & QIODevice::ReadOnly) 0523 accessRights |= GENERIC_READ; 0524 if (openMode & QIODevice::WriteOnly) 0525 accessRights |= GENERIC_WRITE; 0526 0527 SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE }; 0528 0529 // WriteOnly can create files, ReadOnly cannot. 0530 DWORD creationDisp = (openMode & QIODevice::WriteOnly) 0531 ? OPEN_ALWAYS : OPEN_EXISTING; 0532 0533 // Create the file handle. 0534 QT_WA({ 0535 fileHandle = CreateFileW((TCHAR *)nativeFilePath.constData(), 0536 accessRights, 0537 shareMode, 0538 &securityAtts, 0539 creationDisp, 0540 FILE_ATTRIBUTE_NORMAL, 0541 NULL); 0542 }, { 0543 fileHandle = CreateFileA(nativeFilePath.constData(), 0544 accessRights, 0545 shareMode, 0546 &securityAtts, 0547 creationDisp, 0548 FILE_ATTRIBUTE_NORMAL, 0549 NULL); 0550 }); 0551 0552 // Bail out on error. 0553 if (fileHandle == INVALID_HANDLE_VALUE) { 0554 q->setError(QFile::OpenError, qt_error_string()); 0555 return false; 0556 } 0557 0558 // Truncate the file after successfully opening it if Truncate is passed. 0559 if (openMode & QIODevice::Truncate) 0560 q->setSize(0); 0561 0562 return true; 0563 } 0564 0565 /* 0566 \internal 0567 */ 0568 bool QFSFileEnginePrivate::nativeClose() 0569 { 0570 Q_Q(QFSFileEngine); 0571 if (fh || fd != -1) { 0572 // stdlib / stdio mode. 0573 return closeFdFh(); 0574 } 0575 0576 // Windows native mode. 0577 bool ok = true; 0578 if ((fileHandle == INVALID_HANDLE_VALUE || !CloseHandle(fileHandle)) 0579 #ifdef Q_USE_DEPRECATED_MAP_API 0580 && (fileMapHandle == INVALID_HANDLE_VALUE || !CloseHandle(fileMapHandle)) 0581 #endif 0582 ) { 0583 q->setError(QFile::UnspecifiedError, qt_error_string()); 0584 ok = false; 0585 } 0586 fileHandle = INVALID_HANDLE_VALUE; 0587 cachedFd = -1; // gets closed by CloseHandle above 0588 0589 return ok; 0590 } 0591 0592 /* 0593 \internal 0594 */ 0595 bool QFSFileEnginePrivate::nativeFlush() 0596 { 0597 if (fh) { 0598 // Buffered stdlib mode. 0599 return flushFh(); 0600 } 0601 if (fd != -1) { 0602 // Unbuffered stdio mode; always succeeds (no buffer). 0603 return true; 0604 } 0605 0606 // Windows native mode; flushing is 0607 // unnecessary. FlushFileBuffers(), the equivalent of sync() or 0608 // fsync() on Unix, does a low-level flush to the disk, and we 0609 // don't expose an API for this. 0610 return true; 0611 } 0612 0613 /* 0614 \internal 0615 */ 0616 qint64 QFSFileEnginePrivate::nativeSize() const 0617 { 0618 Q_Q(const QFSFileEngine); 0619 QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q); 0620 0621 // ### Don't flush; for buffered files, we should get away with ftell. 0622 thatQ->flush(); 0623 0624 // Buffered stdlib mode. 0625 if (fh) { 0626 QT_OFF_T oldPos = QT_FTELL(fh); 0627 QT_FSEEK(fh, 0, SEEK_END); 0628 QT_OFF_T fileSize = QT_FTELL(fh); 0629 QT_FSEEK(fh, oldPos, SEEK_SET); 0630 return qint64(fileSize); 0631 } 0632 0633 // Not-open mode, where the file name is known: We'll check the 0634 // file system directly. 0635 if (openMode == QIODevice::NotOpen && !nativeFilePath.isEmpty()) { 0636 bool ok = false; 0637 WIN32_FILE_ATTRIBUTE_DATA attribData; 0638 QT_WA({ 0639 ok = ::GetFileAttributesExW((TCHAR *)nativeFilePath.constData(), 0640 GetFileExInfoStandard, &attribData); 0641 } , { 0642 ok = ::GetFileAttributesExA(nativeFilePath.constData(), 0643 GetFileExInfoStandard, &attribData); 0644 }); 0645 if (ok) { 0646 qint64 size = attribData.nFileSizeHigh; 0647 size <<= 32; 0648 size += attribData.nFileSizeLow; 0649 return size; 0650 } 0651 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); 0652 return 0; 0653 } 0654 0655 // Unbuffed stdio mode. 0656 if(fd != -1) { 0657 #if !defined(Q_OS_WINCE) 0658 HANDLE handle = (HANDLE)_get_osfhandle(fd); 0659 if (handle != INVALID_HANDLE_VALUE) { 0660 BY_HANDLE_FILE_INFORMATION fileInfo; 0661 if (GetFileInformationByHandle(handle, &fileInfo)) { 0662 qint64 size = fileInfo.nFileSizeHigh; 0663 size <<= 32; 0664 size += fileInfo.nFileSizeLow; 0665 return size; 0666 } 0667 } 0668 #endif 0669 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); 0670 return 0; 0671 } 0672 0673 // Windows native mode. 0674 if (fileHandle == INVALID_HANDLE_VALUE) 0675 return 0; 0676 0677 BY_HANDLE_FILE_INFORMATION fileInfo; 0678 if (!GetFileInformationByHandle(fileHandle, &fileInfo)) { 0679 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); 0680 return 0; 0681 } 0682 0683 qint64 size = fileInfo.nFileSizeHigh; 0684 size <<= 32; 0685 size += fileInfo.nFileSizeLow; 0686 return size; 0687 } 0688 0689 /* 0690 \internal 0691 */ 0692 qint64 QFSFileEnginePrivate::nativePos() const 0693 { 0694 Q_Q(const QFSFileEngine); 0695 QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q); 0696 0697 if (fh || fd != -1) { 0698 // stdlib / stido mode. 0699 return posFdFh(); 0700 } 0701 0702 // Windows native mode. 0703 if (fileHandle == INVALID_HANDLE_VALUE) 0704 return 0; 0705 0706 #if !defined(QT_NO_LIBRARY) 0707 QFSFileEnginePrivate::resolveLibs(); 0708 if (!ptrSetFilePointerEx) { 0709 #endif 0710 DWORD newFilePointer = SetFilePointer(fileHandle, 0, NULL, FILE_CURRENT); 0711 if (newFilePointer == 0xFFFFFFFF) { 0712 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); 0713 return 0; 0714 } 0715 0716 // Note: returns <4GB; does not work with large files. This is the 0717 // case for MOC, UIC, qmake and other bootstrapped tools, and for 0718 // Win9x/ME. 0719 return qint64(newFilePointer); 0720 #if !defined(QT_NO_LIBRARY) 0721 } 0722 0723 // This approach supports large files. 0724 LARGE_INTEGER currentFilePos; 0725 LARGE_INTEGER offset; 0726 offset.LowPart = 0; 0727 offset.HighPart = 0; 0728 if (!ptrSetFilePointerEx(fileHandle, offset, ¤tFilePos, FILE_CURRENT)) { 0729 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); 0730 return 0; 0731 } 0732 0733 return qint64(currentFilePos.QuadPart); 0734 #endif 0735 } 0736 0737 /* 0738 \internal 0739 */ 0740 bool QFSFileEnginePrivate::nativeSeek(qint64 pos) 0741 { 0742 Q_Q(const QFSFileEngine); 0743 QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q); 0744 0745 if (fh || fd != -1) { 0746 // stdlib / stdio mode. 0747 return seekFdFh(pos); 0748 } 0749 0750 #if !defined(QT_NO_LIBRARY) 0751 QFSFileEnginePrivate::resolveLibs(); 0752 if (!ptrSetFilePointerEx) { 0753 #endif 0754 LONG seekToPos = LONG(pos); // <- lossy 0755 DWORD newFilePointer = SetFilePointer(fileHandle, seekToPos, NULL, FILE_BEGIN); 0756 if (newFilePointer == 0xFFFFFFFF) { 0757 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); 0758 return false; 0759 } 0760 0761 // Note: does not work with large files. This is the case for MOC, 0762 // UIC, qmake and other bootstrapped tools, and for Win9x/ME. 0763 return true; 0764 #if !defined(QT_NO_LIBRARY) 0765 } 0766 0767 // This approach supports large files. 0768 LARGE_INTEGER currentFilePos; 0769 LARGE_INTEGER offset; 0770 offset.LowPart = (unsigned int)(quint64(pos) & Q_UINT64_C(0xffffffff)); 0771 offset.HighPart = (unsigned int)((quint64(pos) >> 32) & Q_UINT64_C(0xffffffff)); 0772 if (ptrSetFilePointerEx(fileHandle, offset, ¤tFilePos, FILE_BEGIN) == 0) { 0773 thatQ->setError(QFile::UnspecifiedError, qt_error_string()); 0774 return false; 0775 } 0776 return true; 0777 #endif 0778 } 0779 0780 /* 0781 \internal 0782 */ 0783 qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen) 0784 { 0785 Q_Q(QFSFileEngine); 0786 0787 if (fh || fd != -1) { 0788 // stdio / stdlib mode. 0789 if (fh && nativeIsSequential() && feof(fh)) { 0790 q->setError(QFile::ReadError, qt_error_string(int(errno))); 0791 return -1; 0792 } 0793 0794 return readFdFh(data, maxlen); 0795 } 0796 0797 // Windows native mode. 0798 if (fileHandle == INVALID_HANDLE_VALUE) 0799 return -1; 0800 0801 DWORD bytesToRead = DWORD(maxlen); // <- lossy 0802 0803 // Reading on Windows fails with ERROR_NO_SYSTEM_RESOURCES when 0804 // the chunks are too large, so we limit the block size to 32MB. 0805 static const DWORD maxBlockSize = 32 * 1024 * 1024; 0806 0807 qint64 totalRead = 0; 0808 do { 0809 DWORD blockSize = qMin<DWORD>(bytesToRead, maxBlockSize); 0810 DWORD bytesRead; 0811 if (!ReadFile(fileHandle, data + totalRead, blockSize, &bytesRead, NULL)) { 0812 if (totalRead == 0) { 0813 // Note: only return failure if the first ReadFile fails. 0814 q->setError(QFile::ReadError, qt_error_string()); 0815 return -1; 0816 } 0817 break; 0818 } 0819 if (bytesRead == 0) 0820 break; 0821 totalRead += bytesRead; 0822 bytesToRead -= bytesRead; 0823 } while (totalRead < maxlen); 0824 return qint64(totalRead); 0825 } 0826 0827 /* 0828 \internal 0829 */ 0830 qint64 QFSFileEnginePrivate::nativeReadLine(char *data, qint64 maxlen) 0831 { 0832 Q_Q(QFSFileEngine); 0833 0834 if (fh || fd != -1) { 0835 // stdio / stdlib mode. 0836 return readLineFdFh(data, maxlen); 0837 } 0838 0839 // Windows native mode. 0840 if (fileHandle == INVALID_HANDLE_VALUE) 0841 return -1; 0842 0843 // ### No equivalent in Win32? 0844 return q->QAbstractFileEngine::readLine(data, maxlen); 0845 } 0846 0847 /* 0848 \internal 0849 */ 0850 qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len) 0851 { 0852 Q_Q(QFSFileEngine); 0853 0854 if (fh || fd != -1) { 0855 // stdio / stdlib mode. 0856 return writeFdFh(data, len); 0857 } 0858 0859 // Windows native mode. 0860 if (fileHandle == INVALID_HANDLE_VALUE) 0861 return -1; 0862 0863 qint64 bytesToWrite = DWORD(len); // <- lossy 0864 0865 // Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when 0866 // the chunks are too large, so we limit the block size to 32MB. 0867 static const DWORD maxBlockSize = 32 * 1024 * 1024; 0868 0869 qint64 totalWritten = 0; 0870 do { 0871 DWORD blockSize = qMin<DWORD>(bytesToWrite, maxBlockSize); 0872 DWORD bytesWritten; 0873 if (!WriteFile(fileHandle, data + totalWritten, blockSize, &bytesWritten, NULL)) { 0874 if (totalWritten == 0) { 0875 // Note: Only return error if the first WriteFile failed. 0876 q->setError(QFile::WriteError, qt_error_string()); 0877 return -1; 0878 } 0879 break; 0880 } 0881 if (bytesWritten == 0) 0882 break; 0883 totalWritten += bytesWritten; 0884 bytesToWrite -= bytesWritten; 0885 } while (totalWritten < len); 0886 return qint64(totalWritten); 0887 } 0888 0889 /* 0890 \internal 0891 */ 0892 int QFSFileEnginePrivate::nativeHandle() const 0893 { 0894 if (fh || fd != -1) 0895 return fh ? QT_FILENO(fh) : fd; 0896 #ifndef Q_OS_WINCE 0897 if (cachedFd != -1) 0898 return cachedFd; 0899 0900 int flags = 0; 0901 if (openMode & QIODevice::Append) 0902 flags |= _O_APPEND; 0903 if (!(openMode & QIODevice::WriteOnly)) 0904 flags |= _O_RDONLY; 0905 cachedFd = _open_osfhandle((intptr_t) fileHandle, flags); 0906 return cachedFd; 0907 #else 0908 return -1; 0909 #endif 0910 } 0911 0912 /* 0913 \internal 0914 */ 0915 bool QFSFileEnginePrivate::nativeIsSequential() const 0916 { 0917 #if !defined(Q_OS_WINCE) 0918 // stdlib / Windows native mode. 0919 if (fh || fileHandle != INVALID_HANDLE_VALUE) { 0920 if (fh == stdin || fh == stdout || fh == stderr) 0921 return true; 0922 0923 HANDLE handle = fileHandle; 0924 if (fileHandle == INVALID_HANDLE_VALUE) { 0925 // Rare case: using QFile::open(FILE*) to open a pipe. 0926 handle = (HANDLE)_get_osfhandle(QT_FILENO(fh)); 0927 return false; 0928 } 0929 0930 DWORD fileType = GetFileType(handle); 0931 return fileType == FILE_TYPE_PIPE; 0932 } 0933 0934 // stdio mode. 0935 if (fd != -1) 0936 return isSequentialFdFh(); 0937 #endif 0938 return false; 0939 } 0940 0941 /*! 0942 \reimp 0943 */ 0944 bool QFSFileEngine::remove() 0945 { 0946 Q_D(QFSFileEngine); 0947 QT_WA({ 0948 return ::DeleteFileW((TCHAR*)QFSFileEnginePrivate::longFileName(d->filePath).utf16()) != 0; 0949 } , { 0950 return ::DeleteFileA(QFSFileEnginePrivate::win95Name(d->filePath)) != 0; 0951 }); 0952 } 0953 0954 /*! 0955 \reimp 0956 */ 0957 bool QFSFileEngine::copy(const QString ©Name) 0958 { 0959 Q_D(QFSFileEngine); 0960 QT_WA({ 0961 return ::CopyFileW((TCHAR*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), 0962 (TCHAR*)QFSFileEnginePrivate::longFileName(copyName).utf16(), true) != 0; 0963 } , { 0964 return ::CopyFileA(QFSFileEnginePrivate::win95Name(d->filePath), 0965 QFSFileEnginePrivate::win95Name(copyName), true) != 0; 0966 }); 0967 } 0968 0969 /*! 0970 \reimp 0971 */ 0972 bool QFSFileEngine::rename(const QString &newName) 0973 { 0974 Q_D(QFSFileEngine); 0975 QT_WA({ 0976 return ::MoveFileW((TCHAR*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), 0977 (TCHAR*)QFSFileEnginePrivate::longFileName(newName).utf16()) != 0; 0978 } , { 0979 return ::MoveFileA(QFSFileEnginePrivate::win95Name(d->filePath), 0980 QFSFileEnginePrivate::win95Name(newName)) != 0; 0981 }); 0982 } 0983 0984 static inline bool mkDir(const QString &path) 0985 { 0986 #if defined(Q_OS_WINCE) 0987 // Unfortunately CreateDirectory returns true for paths longer than 0988 // 256, but does not create a directory. It starts to fail, when 0989 // path length > MAX_PATH, which is 260 usually on CE. 0990 // This only happens on a Windows Mobile device. Windows CE seems 0991 // not to be affected by this. 0992 static int platformId = 0; 0993 if (platformId == 0) { 0994 wchar_t platformString[64]; 0995 if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(platformString)/sizeof(*platformString),platformString,0)) { 0996 if (0 == wcscmp(platformString, L"PocketPC") || 0 == wcscmp(platformString, L"Smartphone")) 0997 platformId = 1; 0998 else 0999 platformId = 2; 1000 } 1001 } 1002 if (platformId == 1 && QFSFileEnginePrivate::longFileName(path).size() > 256) 1003 return false; 1004 #endif 1005 QT_WA({ 1006 return ::CreateDirectoryW((TCHAR*)QFSFileEnginePrivate::longFileName(path).utf16(), 0); 1007 } , { 1008 return ::CreateDirectoryA(QFSFileEnginePrivate::win95Name(QFileInfo(path).absoluteFilePath()), 0); 1009 }); 1010 } 1011 1012 /*! 1013 \reimp 1014 */ 1015 static inline bool rmDir(const QString &path) 1016 { 1017 QT_WA({ 1018 return ::RemoveDirectoryW((TCHAR*)QFSFileEnginePrivate::longFileName(path).utf16()); 1019 } , { 1020 return ::RemoveDirectoryA(QFSFileEnginePrivate::win95Name(QFileInfo(path).absoluteFilePath())); 1021 }); 1022 } 1023 1024 /*! 1025 \reimp 1026 */ 1027 static inline bool isDirPath(const QString &dirPath, bool *existed) 1028 { 1029 QString path = dirPath; 1030 if (path.length() == 2 &&path.at(1) == QLatin1Char(':')) 1031 path += QLatin1Char('\\'); 1032 1033 DWORD fileAttrib = INVALID_FILE_ATTRIBUTES; 1034 QT_WA({ 1035 fileAttrib = ::GetFileAttributesW((TCHAR*)QFSFileEnginePrivate::longFileName(path).utf16()); 1036 } , { 1037 fileAttrib = ::GetFileAttributesA(QFSFileEnginePrivate::win95Name(QFileInfo(path).absoluteFilePath())); 1038 }); 1039 1040 if (existed) 1041 *existed = fileAttrib != INVALID_FILE_ATTRIBUTES; 1042 1043 if (fileAttrib == INVALID_FILE_ATTRIBUTES) 1044 return false; 1045 1046 return fileAttrib & FILE_ATTRIBUTE_DIRECTORY; 1047 } 1048 1049 /*! 1050 \reimp 1051 */ 1052 bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const 1053 { 1054 QString dirName = name; 1055 if (createParentDirectories) { 1056 dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); 1057 // We specifically search for / so \ would break it.. 1058 int oldslash = -1; 1059 if (dirName.startsWith(QLatin1String("\\\\"))) { 1060 // Don't try to create the root path of a UNC path; 1061 // CreateDirectory() will just return ERROR_INVALID_NAME. 1062 for (int i = 0; i < dirName.size(); ++i) { 1063 if (dirName.at(i) != QDir::separator()) { 1064 oldslash = i; 1065 break; 1066 } 1067 } 1068 if (oldslash != -1) 1069 oldslash = dirName.indexOf(QDir::separator(), oldslash); 1070 } 1071 for (int slash=0; slash != -1; oldslash = slash) { 1072 slash = dirName.indexOf(QDir::separator(), oldslash+1); 1073 if (slash == -1) { 1074 if(oldslash == dirName.length()) 1075 break; 1076 slash = dirName.length(); 1077 } 1078 if (slash) { 1079 QString chunk = dirName.left(slash); 1080 bool existed = false; 1081 if (!isDirPath(chunk, &existed) && !existed) { 1082 if (!mkDir(chunk)) 1083 return false; 1084 } 1085 } 1086 } 1087 return true; 1088 } 1089 return mkDir(name); 1090 } 1091 1092 /*! 1093 \reimp 1094 */ 1095 bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const 1096 { 1097 QString dirName = name; 1098 if (recurseParentDirectories) { 1099 dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); 1100 for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) { 1101 QString chunk = dirName.left(slash); 1102 if (chunk.length() == 2 && chunk.at(0).isLetter() && chunk.at(1) == QLatin1Char(':')) 1103 break; 1104 if (!isDirPath(chunk, 0)) 1105 return false; 1106 if (!rmDir(chunk)) 1107 return oldslash != 0; 1108 slash = dirName.lastIndexOf(QDir::separator(), oldslash-1); 1109 } 1110 return true; 1111 } 1112 return rmDir(name); 1113 } 1114 1115 /*! 1116 \reimp 1117 */ 1118 bool QFSFileEngine::caseSensitive() const 1119 { 1120 return false; 1121 } 1122 1123 /*! 1124 Sets the current path (e.g., for QDir), to \a path. Returns true if the 1125 new path exists; otherwise this function does nothing, and returns false. 1126 1127 \sa currentPath() 1128 */ 1129 bool QFSFileEngine::setCurrentPath(const QString &path) 1130 { 1131 if (!QDir(path).exists()) 1132 return false; 1133 1134 #if !defined(Q_OS_WINCE) 1135 int r; 1136 QT_WA({ 1137 r = ::SetCurrentDirectoryW((WCHAR*)path.utf16()); 1138 } , { 1139 r = ::SetCurrentDirectoryA(QFSFileEnginePrivate::win95Name(path)); 1140 }); 1141 return r != 0; 1142 #else 1143 qfsPrivateCurrentDir = QFSFileEnginePrivate::longFileName(path); 1144 return true; 1145 #endif 1146 } 1147 1148 /*! 1149 Returns the canonicalized form of the current path used by the file 1150 engine for the drive specified by \a fileName. 1151 1152 On Windows, each drive has its own current directory, so a different 1153 path is returned for file names that include different drive names 1154 (e.g. A: or C:). 1155 1156 \sa setCurrentPath() 1157 */ 1158 QString QFSFileEngine::currentPath(const QString &fileName) 1159 { 1160 #if !defined(Q_OS_WINCE) 1161 QString ret; 1162 //if filename is a drive: then get the pwd of that drive 1163 if (fileName.length() >= 2 && 1164 fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':')) { 1165 int drv = fileName.toUpper().at(0).toLatin1() - 'A' + 1; 1166 if (_getdrive() != drv) { 1167 QT_WA({ 1168 TCHAR buf[PATH_MAX]; 1169 ::_wgetdcwd(drv, buf, PATH_MAX); 1170 ret.setUtf16((ushort*)buf, uint(::wcslen(buf))); 1171 }, { 1172 char buf[PATH_MAX]; 1173 ::_getdcwd(drv, buf, PATH_MAX); 1174 ret = QString::fromLatin1(buf); 1175 }); 1176 } 1177 } 1178 if (ret.isEmpty()) { 1179 //just the pwd 1180 QT_WA({ 1181 DWORD size = 0; 1182 WCHAR currentName[PATH_MAX]; 1183 size = ::GetCurrentDirectoryW(PATH_MAX, currentName); 1184 if (size !=0) { 1185 if (size > PATH_MAX) { 1186 WCHAR * newCurrentName = new WCHAR[size]; 1187 if (::GetCurrentDirectoryW(PATH_MAX, newCurrentName) != 0) 1188 ret = QString::fromUtf16((ushort*)newCurrentName); 1189 delete [] newCurrentName; 1190 } else { 1191 ret = QString::fromUtf16((ushort*)currentName); 1192 } 1193 } 1194 } , { 1195 DWORD size = 0; 1196 char currentName[PATH_MAX]; 1197 size = ::GetCurrentDirectoryA(PATH_MAX, currentName); 1198 if (size !=0) 1199 ret = QString::fromLocal8Bit(currentName); 1200 }); 1201 } 1202 if (ret.length() >= 2 && ret[1] == QLatin1Char(':')) 1203 ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters. 1204 return QDir::fromNativeSeparators(ret); 1205 #else 1206 Q_UNUSED(fileName); 1207 if (qfsPrivateCurrentDir.isEmpty()) 1208 qfsPrivateCurrentDir = QCoreApplication::applicationDirPath(); 1209 1210 return QDir::fromNativeSeparators(qfsPrivateCurrentDir); 1211 #endif 1212 } 1213 1214 /*! 1215 Returns the home path of the current user. 1216 1217 \sa rootPath() 1218 */ 1219 QString QFSFileEngine::homePath() 1220 { 1221 QString ret; 1222 #if !defined(QT_NO_LIBRARY) 1223 QT_WA ( 1224 { 1225 QFSFileEnginePrivate::resolveLibs(); 1226 if (ptrOpenProcessToken && ptrGetUserProfileDirectoryW) { 1227 HANDLE hnd = ::GetCurrentProcess(); 1228 HANDLE token = 0; 1229 BOOL ok = ::ptrOpenProcessToken(hnd, TOKEN_QUERY, &token); 1230 if (ok) { 1231 DWORD dwBufferSize = 0; 1232 // First call, to determine size of the strings (with '\0'). 1233 ok = ::ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize); 1234 if (!ok && dwBufferSize != 0) { // We got the required buffer size 1235 wchar_t *userDirectory = new wchar_t[dwBufferSize]; 1236 // Second call, now we can fill the allocated buffer. 1237 ok = ::ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize); 1238 if (ok) 1239 ret = QString::fromUtf16((ushort*)userDirectory); 1240 1241 delete [] userDirectory; 1242 } 1243 ::CloseHandle(token); 1244 } 1245 } 1246 } 1247 , 1248 { 1249 // GetUserProfileDirectory is only available from NT 4.0, 1250 // so fall through for Win98 and friends version. 1251 }) 1252 #endif 1253 if(ret.isEmpty() || !QFile::exists(ret)) { 1254 ret = QString::fromLocal8Bit(qgetenv("USERPROFILE").constData()); 1255 if(ret.isEmpty() || !QFile::exists(ret)) { 1256 ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE").constData()) + QString::fromLocal8Bit(qgetenv("HOMEPATH").constData()); 1257 if(ret.isEmpty() || !QFile::exists(ret)) { 1258 ret = QString::fromLocal8Bit(qgetenv("HOME").constData()); 1259 if(ret.isEmpty() || !QFile::exists(ret)) { 1260 #if defined(Q_OS_WINCE) 1261 ret = QString::fromLatin1("\\My Documents"); 1262 if (!QFile::exists(ret)) 1263 #endif 1264 ret = rootPath(); 1265 } 1266 } 1267 } 1268 } 1269 return QDir::fromNativeSeparators(ret); 1270 } 1271 1272 /*! 1273 Returns the root path. 1274 1275 \sa homePath() 1276 */ 1277 QString QFSFileEngine::rootPath() 1278 { 1279 #if defined(Q_OS_WINCE) 1280 QString ret = QString::fromLatin1("/"); 1281 #elif defined(Q_FS_FAT) 1282 QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData()); 1283 if(ret.isEmpty()) 1284 ret = QLatin1String("c:"); 1285 ret += QLatin1String("/"); 1286 #elif defined(Q_OS_OS2EMX) 1287 char dir[4]; 1288 _abspath(dir, QLatin1String("/"), _MAX_PATH); 1289 QString ret(dir); 1290 #endif 1291 return ret; 1292 } 1293 1294 /*! 1295 Returns the temporary path (i.e., a path in which it is safe to store 1296 temporary files). 1297 */ 1298 QString QFSFileEngine::tempPath() 1299 { 1300 QString ret; 1301 int success; 1302 QT_WA({ 1303 wchar_t tempPath[MAX_PATH]; 1304 success = GetTempPathW(MAX_PATH, tempPath); 1305 ret = QString::fromUtf16((ushort*)tempPath); 1306 } , { 1307 char tempPath[MAX_PATH]; 1308 success = GetTempPathA(MAX_PATH, tempPath); 1309 ret = QString::fromLocal8Bit(tempPath); 1310 }); 1311 if (ret.isEmpty() || !success) { 1312 #if !defined(Q_OS_WINCE) 1313 ret = QString::fromLatin1("c:/tmp"); 1314 #else 1315 ret = QString::fromLatin1("\\Temp"); 1316 #endif 1317 } else { 1318 ret = QDir::fromNativeSeparators(ret); 1319 while (ret.at(ret.length()-1) == QLatin1Char('/')) 1320 ret = ret.left(ret.length()-1); 1321 } 1322 return ret; 1323 } 1324 1325 /*! 1326 Returns the list of drives in the file system as a list of QFileInfo 1327 objects. On unix, Mac OS X and Windows CE, only the root path is returned. 1328 On Windows, this function returns all drives (A:\, C:\, D:\, etc.). 1329 */ 1330 QFileInfoList QFSFileEngine::drives() 1331 { 1332 QFileInfoList ret; 1333 #if !defined(Q_OS_WINCE) 1334 #if defined(Q_OS_WIN32) 1335 quint32 driveBits = (quint32) GetLogicalDrives() & 0x3ffffff; 1336 #elif defined(Q_OS_OS2EMX) 1337 quint32 driveBits, cur; 1338 if(DosQueryCurrentDisk(&cur,&driveBits) != NO_ERROR) 1339 exit(1); 1340 driveBits &= 0x3ffffff; 1341 #endif 1342 char driveName[4]; 1343 1344 qstrcpy(driveName, "A:/"); 1345 1346 while(driveBits) { 1347 if(driveBits & 1) 1348 ret.append(QString::fromLatin1(driveName).toUpper()); 1349 driveName[0]++; 1350 driveBits = driveBits >> 1; 1351 } 1352 return ret; 1353 #else 1354 ret.append(QString::fromLatin1("/").toUpper()); 1355 return ret; 1356 #endif 1357 } 1358 1359 bool QFSFileEnginePrivate::doStat() const 1360 { 1361 if (!tried_stat) { 1362 tried_stat = true; 1363 could_stat = false; 1364 1365 if (filePath.isEmpty()) 1366 return could_stat; 1367 QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; 1368 fname = fixIfRelativeUncPath(fname); 1369 1370 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); 1371 1372 if (fd != -1) { 1373 #if !defined(Q_OS_WINCE) 1374 HANDLE fh = (HANDLE)_get_osfhandle(fd); 1375 if (fh != INVALID_HANDLE_VALUE) { 1376 BY_HANDLE_FILE_INFORMATION fileInfo; 1377 if (GetFileInformationByHandle(fh, &fileInfo)) { 1378 could_stat = true; 1379 fileAttrib = fileInfo.dwFileAttributes; 1380 } 1381 } 1382 #else 1383 DWORD tmpAttributes = GetFileAttributesW((TCHAR*)QFSFileEnginePrivate::longFileName(fname).utf16()); 1384 if (tmpAttributes != -1) { 1385 fileAttrib = tmpAttributes; 1386 could_stat = true; 1387 } else { 1388 return false; 1389 } 1390 #endif 1391 } else { 1392 QT_WA({ 1393 fileAttrib = GetFileAttributesW((TCHAR*)QFSFileEnginePrivate::longFileName(fname).utf16()); 1394 } , { 1395 fileAttrib = GetFileAttributesA(QFSFileEnginePrivate::win95Name(QFileInfo(fname).absoluteFilePath())); 1396 }); 1397 could_stat = fileAttrib != INVALID_FILE_ATTRIBUTES; 1398 if (!could_stat) { 1399 #if !defined(Q_OS_WINCE) 1400 if (!fname.isEmpty() && fname.at(0).isLetter() && fname.mid(1, fname.length()) == QLatin1String(":/")) { 1401 // an empty drive ?? 1402 DWORD drivesBitmask = ::GetLogicalDrives(); 1403 int drivebit = 1 << (fname.at(0).toUpper().unicode() - QLatin1Char('A').unicode()); 1404 if (drivesBitmask & drivebit) { 1405 fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM; 1406 could_stat = true; 1407 } 1408 } else { 1409 #endif 1410 QString path = QDir::toNativeSeparators(fname); 1411 bool is_dir = false; 1412 if (path.startsWith(QLatin1String("\\\\"))) { 1413 // UNC - stat doesn't work for all cases (Windows bug) 1414 int s = path.indexOf(path.at(0),2); 1415 if (s > 0) { 1416 // "\\server\..." 1417 s = path.indexOf(path.at(0),s+1); 1418 if (s > 0) { 1419 // "\\server\share\..." 1420 if (s == path.size() - 1) { 1421 // "\\server\share\" 1422 is_dir = true; 1423 } else { 1424 // "\\server\share\notfound" 1425 } 1426 } else { 1427 // "\\server\share" 1428 is_dir = true; 1429 } 1430 } else { 1431 // "\\server" 1432 is_dir = true; 1433 } 1434 } 1435 if (is_dir && uncShareExists(path)) { 1436 // looks like a UNC dir, is a dir. 1437 fileAttrib = FILE_ATTRIBUTE_DIRECTORY; 1438 could_stat = true; 1439 } 1440 #if !defined(Q_OS_WINCE) 1441 } 1442 #endif 1443 } 1444 } 1445 SetErrorMode(oldmode); 1446 } 1447 return could_stat; 1448 } 1449 1450 1451 static QString readLink(const QString &link) 1452 { 1453 #if !defined(Q_OS_WINCE) 1454 #if !defined(QT_NO_LIBRARY) 1455 QString ret; 1456 QT_WA({ 1457 bool neededCoInit = false; 1458 IShellLink *psl; // pointer to IShellLink i/f 1459 HRESULT hres; 1460 WIN32_FIND_DATA wfd; 1461 TCHAR szGotPath[MAX_PATH]; 1462 // Get pointer to the IShellLink interface. 1463 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, 1464 IID_IShellLink, (LPVOID *)&psl); 1465 1466 if(hres == CO_E_NOTINITIALIZED) { // COM was not initialized 1467 neededCoInit = true; 1468 CoInitialize(NULL); 1469 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, 1470 IID_IShellLink, (LPVOID *)&psl); 1471 } 1472 if(SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface. 1473 IPersistFile *ppf; 1474 hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); 1475 if(SUCCEEDED(hres)) { 1476 hres = ppf->Load((LPOLESTR)link.utf16(), STGM_READ); 1477 //The original path of the link is retrieved. If the file/folder 1478 //was moved, the return value still have the old path. 1479 if(SUCCEEDED(hres)) { 1480 if (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR) 1481 ret = QString::fromUtf16((ushort*)szGotPath); 1482 } 1483 ppf->Release(); 1484 } 1485 psl->Release(); 1486 } 1487 if(neededCoInit) 1488 CoUninitialize(); 1489 } , { 1490 bool neededCoInit = false; 1491 IShellLinkA *psl; // pointer to IShellLink i/f 1492 HRESULT hres; 1493 WIN32_FIND_DATAA wfd; 1494 char szGotPath[MAX_PATH]; 1495 // Get pointer to the IShellLink interface. 1496 1497 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, 1498 IID_IShellLinkA, (LPVOID *)&psl); 1499 1500 if(hres == CO_E_NOTINITIALIZED) { // COM was not initialized 1501 neededCoInit = true; 1502 CoInitialize(NULL); 1503 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, 1504 IID_IShellLinkA, (LPVOID *)&psl); 1505 } 1506 if(SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface. 1507 IPersistFile *ppf; 1508 hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); 1509 if(SUCCEEDED(hres)) { 1510 hres = ppf->Load((LPOLESTR)QFileInfo(link).absoluteFilePath().utf16(), STGM_READ); 1511 //The original path of the link is retrieved. If the file/folder 1512 //was moved, the return value still have the old path. 1513 if(SUCCEEDED(hres)) { 1514 if (psl->GetPath((char*)szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR) 1515 ret = QString::fromLocal8Bit(szGotPath); 1516 } 1517 ppf->Release(); 1518 } 1519 psl->Release(); 1520 } 1521 if(neededCoInit) 1522 CoUninitialize(); 1523 }); 1524 return ret; 1525 #else 1526 Q_UNUSED(link); 1527 return QString(); 1528 #endif // QT_NO_LIBRARY 1529 #else 1530 wchar_t target[MAX_PATH]; 1531 QString result; 1532 if (SHGetShortcutTarget((wchar_t*)QFileInfo(link).absoluteFilePath().replace(QLatin1Char('/'),QLatin1Char('\\')).utf16(), target, MAX_PATH)) { 1533 result = QString::fromUtf16(reinterpret_cast<const ushort *> (target)); 1534 if (result.startsWith(QLatin1Char('"'))) 1535 result.remove(0,1); 1536 if (result.endsWith(QLatin1Char('"'))) 1537 result.remove(result.size()-1,1); 1538 } 1539 return result; 1540 #endif // Q_OS_WINCE 1541 } 1542 1543 /*! 1544 \internal 1545 */ 1546 QString QFSFileEnginePrivate::getLink() const 1547 { 1548 return readLink(filePath); 1549 } 1550 1551 /*! 1552 \reimp 1553 */ 1554 bool QFSFileEngine::link(const QString &newName) 1555 { 1556 #if !defined(Q_OS_WINCE) 1557 #if !defined(QT_NO_LIBRARY) 1558 bool ret = false; 1559 1560 QString linkName = newName; 1561 //### assume that they add .lnk 1562 1563 QT_WA({ 1564 HRESULT hres; 1565 IShellLink *psl; 1566 bool neededCoInit = false; 1567 1568 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); 1569 if(hres == CO_E_NOTINITIALIZED) { // COM was not initialized 1570 neededCoInit = true; 1571 CoInitialize(NULL); 1572 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); 1573 } 1574 if (SUCCEEDED(hres)) { 1575 hres = psl->SetPath((wchar_t *)fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16()); 1576 if (SUCCEEDED(hres)) { 1577 hres = psl->SetWorkingDirectory((wchar_t *)fileName(AbsolutePathName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16()); 1578 if (SUCCEEDED(hres)) { 1579 IPersistFile *ppf; 1580 hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf); 1581 if (SUCCEEDED(hres)) { 1582 hres = ppf->Save((TCHAR*)linkName.utf16(), TRUE); 1583 if (SUCCEEDED(hres)) 1584 ret = true; 1585 ppf->Release(); 1586 } 1587 } 1588 } 1589 psl->Release(); 1590 } 1591 if(neededCoInit) 1592 CoUninitialize(); 1593 } , { 1594 // the SetPath() call _sometimes_ changes the current path and when it does it sometimes 1595 // does not let us change it back unless we call currentPath() many times. 1596 QString cwd = currentPath(); 1597 HRESULT hres; 1598 IShellLinkA *psl; 1599 bool neededCoInit = false; 1600 1601 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); 1602 if(hres == CO_E_NOTINITIALIZED) { // COM was not initialized 1603 neededCoInit = true; 1604 CoInitialize(NULL); 1605 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); 1606 } 1607 if (SUCCEEDED(hres)) { 1608 currentPath(); 1609 hres = psl->SetPath((char *)QString::fromLocal8Bit(QFSFileEnginePrivate::win95Name(fileName(AbsoluteName))).utf16()); 1610 currentPath(); 1611 if (SUCCEEDED(hres)) { 1612 hres = psl->SetWorkingDirectory((char *)QString::fromLocal8Bit(QFSFileEnginePrivate::win95Name(fileName(AbsolutePathName))).utf16()); 1613 currentPath(); 1614 if (SUCCEEDED(hres)) { 1615 IPersistFile *ppf; 1616 hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf); 1617 if (SUCCEEDED(hres)) { 1618 currentPath(); 1619 hres = ppf->Save((LPCOLESTR)linkName.utf16(), TRUE); 1620 currentPath(); 1621 if (SUCCEEDED(hres)) 1622 ret = true; 1623 ppf->Release(); 1624 } 1625 } 1626 psl->Release(); 1627 } 1628 } 1629 if(neededCoInit) 1630 CoUninitialize(); 1631 setCurrentPath(cwd); 1632 }); 1633 return ret; 1634 #else 1635 Q_UNUSED(newName); 1636 return false; 1637 #endif // QT_NO_LIBRARY 1638 #else 1639 QString linkName = newName; 1640 if (!linkName.endsWith(QLatin1String(".lnk"))) 1641 linkName += QLatin1String(".lnk"); 1642 QString orgName = fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')); 1643 // Need to append on our own 1644 orgName.prepend(QLatin1Char('"')); 1645 orgName.append(QLatin1Char('"')); 1646 return SUCCEEDED(SHCreateShortcut((wchar_t*)linkName.utf16(), (wchar_t*)orgName.utf16())); 1647 #endif // Q_OS_WINCE 1648 } 1649 1650 /*! 1651 \internal 1652 */ 1653 QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions() const 1654 { 1655 QAbstractFileEngine::FileFlags ret = 0; 1656 1657 #if !defined(QT_NO_LIBRARY) 1658 if((qt_ntfs_permission_lookup > 0) && ((QSysInfo::WindowsVersion&QSysInfo::WV_NT_based) > QSysInfo::WV_NT)) { 1659 PSID pOwner = 0; 1660 PSID pGroup = 0; 1661 PACL pDacl; 1662 PSECURITY_DESCRIPTOR pSD; 1663 ACCESS_MASK access_mask; 1664 1665 enum { ReadMask = 0x00000001, WriteMask = 0x00000002, ExecMask = 0x00000020 }; 1666 resolveLibs(); 1667 if(ptrGetNamedSecurityInfoW && ptrAllocateAndInitializeSid && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW && ptrFreeSid) { 1668 1669 QString fname = filePath.endsWith(QLatin1String(".lnk")) ? readLink(filePath) : filePath; 1670 DWORD res = ptrGetNamedSecurityInfoW((wchar_t*)fname.utf16(), SE_FILE_OBJECT, 1671 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, 1672 &pOwner, &pGroup, &pDacl, 0, &pSD); 1673 1674 if(res == ERROR_SUCCESS) { 1675 TRUSTEE_W trustee; 1676 { //user 1677 if(ptrGetEffectiveRightsFromAclW(pDacl, ¤tUserTrusteeW, &access_mask) != ERROR_SUCCESS) 1678 access_mask = (ACCESS_MASK)-1; 1679 if(access_mask & ReadMask) 1680 ret |= QAbstractFileEngine::ReadUserPerm; 1681 if(access_mask & WriteMask) 1682 ret |= QAbstractFileEngine::WriteUserPerm; 1683 if(access_mask & ExecMask) 1684 ret |= QAbstractFileEngine::ExeUserPerm; 1685 } 1686 { //owner 1687 ptrBuildTrusteeWithSidW(&trustee, pOwner); 1688 if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) 1689 access_mask = (ACCESS_MASK)-1; 1690 if(access_mask & ReadMask) 1691 ret |= QAbstractFileEngine::ReadOwnerPerm; 1692 if(access_mask & WriteMask) 1693 ret |= QAbstractFileEngine::WriteOwnerPerm; 1694 if(access_mask & ExecMask) 1695 ret |= QAbstractFileEngine::ExeOwnerPerm; 1696 } 1697 { //group 1698 ptrBuildTrusteeWithSidW(&trustee, pGroup); 1699 if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) 1700 access_mask = (ACCESS_MASK)-1; 1701 if(access_mask & ReadMask) 1702 ret |= QAbstractFileEngine::ReadGroupPerm; 1703 if(access_mask & WriteMask) 1704 ret |= QAbstractFileEngine::WriteGroupPerm; 1705 if(access_mask & ExecMask) 1706 ret |= QAbstractFileEngine::ExeGroupPerm; 1707 } 1708 { //other (world) 1709 // Create SID for Everyone (World) 1710 SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY }; 1711 PSID pWorld = 0; 1712 if(ptrAllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &pWorld)) { 1713 ptrBuildTrusteeWithSidW(&trustee, pWorld); 1714 if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) 1715 access_mask = (ACCESS_MASK)-1; // ### 1716 if(access_mask & ReadMask) 1717 ret |= QAbstractFileEngine::ReadOtherPerm; 1718 if(access_mask & WriteMask) 1719 ret |= QAbstractFileEngine::WriteOtherPerm; 1720 if(access_mask & ExecMask) 1721 ret |= QAbstractFileEngine::ExeOtherPerm; 1722 } 1723 ptrFreeSid(pWorld); 1724 } 1725 LocalFree(pSD); 1726 } 1727 } 1728 } else 1729 #endif 1730 { 1731 //### what to do with permissions if we don't use ntfs or are not on a NT system 1732 // for now just add all permissions and what about exe missions ?? 1733 // also qt_ntfs_permission_lookup is now not set by default ... should it ? 1734 ret |= QAbstractFileEngine::ReadOtherPerm | QAbstractFileEngine::ReadGroupPerm 1735 | QAbstractFileEngine::ReadOwnerPerm | QAbstractFileEngine::ReadUserPerm 1736 | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::WriteOwnerPerm 1737 | QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm; 1738 } 1739 1740 if (doStat()) { 1741 if (ret & (QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | 1742 QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm)) { 1743 if (fileAttrib & FILE_ATTRIBUTE_READONLY) 1744 ret &= ~(QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | 1745 QAbstractFileEngine::WriteGroupPerm | QAbstractFileEngine::WriteOtherPerm); 1746 } 1747 1748 QString ext = filePath.right(4).toLower(); 1749 if (ext == QLatin1String(".exe") || ext == QLatin1String(".com") || ext == QLatin1String(".bat") || 1750 ext == QLatin1String(".pif") || ext == QLatin1String(".cmd") || (fileAttrib & FILE_ATTRIBUTE_DIRECTORY)) 1751 ret |= QAbstractFileEngine::ExeOwnerPerm | QAbstractFileEngine::ExeGroupPerm | 1752 QAbstractFileEngine::ExeOtherPerm | QAbstractFileEngine::ExeUserPerm; 1753 } 1754 return ret; 1755 } 1756 1757 /*! 1758 \reimp 1759 */ 1760 QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const 1761 { 1762 Q_D(const QFSFileEngine); 1763 QAbstractFileEngine::FileFlags ret = 0; 1764 // Force a stat, so that we're guaranteed to get up-to-date results 1765 if (type & QAbstractFileEngine::FileFlag(QAbstractFileEngine::Refresh)) { 1766 d->tried_stat = 0; 1767 } 1768 1769 if (type & PermsMask) { 1770 ret |= d->getPermissions(); 1771 // ### Workaround pascals ### above. Since we always set all properties to true 1772 // we need to disable read and exec access if the file does not exists 1773 if (d->doStat()) 1774 ret |= ExistsFlag; 1775 else 1776 ret &= 0x2222; 1777 } 1778 if (type & TypesMask) { 1779 if (d->filePath.endsWith(QLatin1String(".lnk"))) { 1780 ret |= LinkType; 1781 QString l = readLink(d->filePath); 1782 if (!l.isEmpty()) { 1783 if (isDirPath(l, 0)) 1784 ret |= DirectoryType; 1785 else 1786 ret |= FileType; 1787 } 1788 } else if (d->doStat()) { 1789 if (d->fileAttrib & FILE_ATTRIBUTE_DIRECTORY) { 1790 ret |= DirectoryType; 1791 } else { 1792 ret |= FileType; 1793 } 1794 } 1795 } 1796 if (type & FlagsMask) { 1797 if(d->doStat()) { 1798 ret |= QAbstractFileEngine::FileFlags(ExistsFlag | LocalDiskFlag); 1799 if (d->fileAttrib & FILE_ATTRIBUTE_HIDDEN) 1800 ret |= HiddenFlag; 1801 if (d->filePath == QLatin1String("/") || (d->filePath.at(0).isLetter() && d->filePath.mid(1,d->filePath.length()) == QLatin1String(":/")) 1802 || isUncRoot(d->filePath)) { 1803 ret |= RootFlag; 1804 ret &= ~HiddenFlag; 1805 } 1806 } 1807 } 1808 return ret; 1809 } 1810 1811 /*! 1812 \reimp 1813 */ 1814 QString QFSFileEngine::fileName(FileName file) const 1815 { 1816 Q_D(const QFSFileEngine); 1817 if(file == BaseName) { 1818 int slash = d->filePath.lastIndexOf(QLatin1Char('/')); 1819 if(slash == -1) { 1820 int colon = d->filePath.lastIndexOf(QLatin1Char(':')); 1821 if(colon != -1) 1822 return d->filePath.mid(colon + 1); 1823 return d->filePath; 1824 } 1825 return d->filePath.mid(slash + 1); 1826 } else if(file == PathName) { 1827 if(!d->filePath.size()) 1828 return d->filePath; 1829 1830 int slash = d->filePath.lastIndexOf(QLatin1Char('/')); 1831 if(slash == -1) { 1832 if(d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) 1833 return d->filePath.left(2); 1834 return QString::fromLatin1("."); 1835 } else { 1836 if(!slash) 1837 return QString::fromLatin1("/"); 1838 if(slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) 1839 slash++; 1840 return d->filePath.left(slash); 1841 } 1842 } else if(file == AbsoluteName || file == AbsolutePathName) { 1843 QString ret; 1844 1845 if (!isRelativePath()) { 1846 #if !defined(Q_OS_WINCE) 1847 if (d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') 1848 && d->filePath.at(2) != QLatin1Char('/') || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt 1849 d->filePath.startsWith(QLatin1Char('/')) // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt 1850 ) { 1851 ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(d->filePath)); 1852 } else { 1853 ret = d->filePath; 1854 } 1855 #else 1856 ret = d->filePath; 1857 #endif 1858 } else { 1859 ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->filePath); 1860 } 1861 1862 // The path should be absolute at this point. 1863 // From the docs : 1864 // Absolute paths begin with the directory separator "/" 1865 // (optionally preceded by a drive specification under Windows). 1866 if (ret.at(0) != QLatin1Char('/')) { 1867 Q_ASSERT(ret.length() >= 2); 1868 Q_ASSERT(ret.at(0).isLetter()); 1869 Q_ASSERT(ret.at(1) == QLatin1Char(':')); 1870 1871 // Force uppercase drive letters. 1872 ret[0] = ret.at(0).toUpper(); 1873 } 1874 1875 if (file == AbsolutePathName) { 1876 int slash = ret.lastIndexOf(QLatin1Char('/')); 1877 if (slash < 0) 1878 return ret; 1879 else if (ret.at(0) != QLatin1Char('/') && slash == 2) 1880 return ret.left(3); // include the slash 1881 else 1882 return ret.left(slash > 0 ? slash : 1); 1883 } 1884 return ret; 1885 } else if(file == CanonicalName || file == CanonicalPathName) { 1886 if (!(fileFlags(ExistsFlag) & ExistsFlag)) 1887 return QString(); 1888 1889 QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName)); 1890 if (!ret.isEmpty() && file == CanonicalPathName) { 1891 int slash = ret.lastIndexOf(QLatin1Char('/')); 1892 if (slash == -1) 1893 ret = QDir::currentPath(); 1894 else if (slash == 0) 1895 ret = QLatin1String("/"); 1896 ret = ret.left(slash); 1897 } 1898 return ret; 1899 } else if(file == LinkName) { 1900 return QDir::fromNativeSeparators(d->getLink()); 1901 } else if(file == BundleName) { 1902 return QString(); 1903 } 1904 return d->filePath; 1905 } 1906 1907 /*! 1908 \reimp 1909 */ 1910 bool QFSFileEngine::isRelativePath() const 1911 { 1912 Q_D(const QFSFileEngine); 1913 return !(d->filePath.startsWith(QLatin1Char('/')) 1914 || (d->filePath.length() >= 2 1915 && ((d->filePath.at(0).isLetter() && d->filePath.at(1) == QLatin1Char(':')) 1916 || (d->filePath.at(0) == QLatin1Char('/') && d->filePath.at(1) == QLatin1Char('/'))))); // drive, e.g. a: 1917 } 1918 1919 /*! 1920 \reimp 1921 */ 1922 uint QFSFileEngine::ownerId(FileOwner /*own*/) const 1923 { 1924 static const uint nobodyID = (uint) -2; 1925 return nobodyID; 1926 } 1927 1928 /*! 1929 \reimp 1930 */ 1931 QString QFSFileEngine::owner(FileOwner own) const 1932 { 1933 #if !defined(QT_NO_LIBRARY) 1934 Q_D(const QFSFileEngine); 1935 if((qt_ntfs_permission_lookup > 0) && ((QSysInfo::WindowsVersion&QSysInfo::WV_NT_based) > QSysInfo::WV_NT)) { 1936 PSID pOwner = 0; 1937 PSECURITY_DESCRIPTOR pSD; 1938 QString name; 1939 QFSFileEnginePrivate::resolveLibs(); 1940 1941 if(ptrGetNamedSecurityInfoW && ptrLookupAccountSidW) { 1942 if(ptrGetNamedSecurityInfoW((wchar_t*)d->filePath.utf16(), SE_FILE_OBJECT, 1943 own == OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION, 1944 NULL, &pOwner, NULL, NULL, &pSD) == ERROR_SUCCESS) { 1945 DWORD lowner = 0, ldomain = 0; 1946 SID_NAME_USE use; 1947 // First call, to determine size of the strings (with '\0'). 1948 ptrLookupAccountSidW(NULL, pOwner, NULL, &lowner, NULL, &ldomain, (SID_NAME_USE*)&use); 1949 wchar_t *owner = new wchar_t[lowner]; 1950 wchar_t *domain = new wchar_t[ldomain]; 1951 // Second call, size is without '\0' 1952 if(ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner, &lowner, 1953 (LPWSTR)domain, &ldomain, (SID_NAME_USE*)&use)) { 1954 name = QString::fromUtf16((ushort*)owner); 1955 } 1956 LocalFree(pSD); 1957 delete [] owner; 1958 delete [] domain; 1959 } 1960 } 1961 return name; 1962 } 1963 #else 1964 Q_UNUSED(own); 1965 #endif 1966 return QString(QLatin1String("")); 1967 } 1968 1969 /*! 1970 \reimp 1971 */ 1972 bool QFSFileEngine::setPermissions(uint perms) 1973 { 1974 Q_D(QFSFileEngine); 1975 bool ret = false; 1976 int mode = 0; 1977 1978 if (perms & QFile::ReadOwner || perms & QFile::ReadUser || perms & QFile::ReadGroup || perms & QFile::ReadOther) 1979 mode |= _S_IREAD; 1980 if (perms & QFile::WriteOwner || perms & QFile::WriteUser || perms & QFile::WriteGroup || perms & QFile::WriteOther) 1981 mode |= _S_IWRITE; 1982 1983 if (mode == 0) // not supported 1984 return false; 1985 1986 #if !defined(Q_OS_WINCE) 1987 QT_WA({ 1988 ret = ::_wchmod((TCHAR*)d->filePath.utf16(), mode) == 0; 1989 } , { 1990 ret = ::_chmod(d->filePath.toLocal8Bit(), mode) == 0; 1991 }); 1992 #else 1993 ret = ::_wchmod((TCHAR*)d->longFileName(d->filePath).utf16(), mode); 1994 #endif 1995 return ret; 1996 } 1997 1998 /*! 1999 \reimp 2000 */ 2001 bool QFSFileEngine::setSize(qint64 size) 2002 { 2003 Q_D(QFSFileEngine); 2004 2005 if (d->fileHandle != INVALID_HANDLE_VALUE || d->fd != -1) { 2006 // resize open file 2007 HANDLE fh = d->fileHandle; 2008 #if !defined(Q_OS_WINCE) 2009 if (fh == INVALID_HANDLE_VALUE) 2010 fh = (HANDLE)_get_osfhandle(d->fd); 2011 #endif 2012 if (fh == INVALID_HANDLE_VALUE) 2013 return false; 2014 qint64 currentPos = pos(); 2015 2016 if (seek(size) && SetEndOfFile(fh)) { 2017 seek(qMin(currentPos, size)); 2018 return true; 2019 } 2020 2021 seek(currentPos); 2022 return false; 2023 } 2024 2025 if (!d->nativeFilePath.isEmpty()) { 2026 // resize file on disk 2027 QFile file(d->filePath); 2028 if (file.open(QFile::ReadWrite)) { 2029 return file.resize(size); 2030 } 2031 } 2032 return false; 2033 } 2034 2035 2036 static inline QDateTime fileTimeToQDateTime(const FILETIME *time) 2037 { 2038 QDateTime ret; 2039 if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based || QSysInfo::WindowsVersion & QSysInfo::WV_CE_based) { 2040 // SystemTimeToTzSpecificLocalTime is not available on Win98/ME so we have to pull it off ourselves. 2041 SYSTEMTIME systime; 2042 FILETIME ftime; 2043 systime.wYear = 1970; 2044 systime.wMonth = 1; 2045 systime.wDay = 1; 2046 systime.wHour = 0; 2047 systime.wMinute = 0; 2048 systime.wSecond = 0; 2049 systime.wMilliseconds = 0; 2050 systime.wDayOfWeek = 4; 2051 SystemTimeToFileTime(&systime, &ftime); 2052 unsigned __int64 acttime = (unsigned __int64)time->dwHighDateTime << 32 | time->dwLowDateTime; 2053 FileTimeToSystemTime(time, &systime); 2054 unsigned __int64 time1970 = (unsigned __int64)ftime.dwHighDateTime << 32 | ftime.dwLowDateTime; 2055 unsigned __int64 difftime = acttime - time1970; 2056 difftime /= 10000000; 2057 ret.setTime_t((unsigned int)difftime); 2058 } else { 2059 #ifndef Q_OS_WINCE 2060 SYSTEMTIME sTime, lTime; 2061 FileTimeToSystemTime(time, &sTime); 2062 SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime); 2063 ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay)); 2064 ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds)); 2065 #endif 2066 } 2067 return ret; 2068 } 2069 2070 /*! 2071 \reimp 2072 */ 2073 QDateTime QFSFileEngine::fileTime(FileTime time) const 2074 { 2075 Q_D(const QFSFileEngine); 2076 QDateTime ret; 2077 if (d->fd != -1) { 2078 #if !defined(Q_OS_WINCE) 2079 HANDLE fh = (HANDLE)_get_osfhandle(d->fd); 2080 if (fh != INVALID_HANDLE_VALUE) { 2081 FILETIME creationTime, lastAccessTime, lastWriteTime; 2082 if (GetFileTime(fh, &creationTime, &lastAccessTime, &lastWriteTime)) { 2083 if(time == CreationTime) 2084 ret = fileTimeToQDateTime(&creationTime); 2085 else if(time == ModificationTime) 2086 ret = fileTimeToQDateTime(&lastWriteTime); 2087 else if(time == AccessTime) 2088 ret = fileTimeToQDateTime(&lastAccessTime); 2089 } 2090 } 2091 #endif 2092 } else { 2093 bool ok = false; 2094 WIN32_FILE_ATTRIBUTE_DATA attribData; 2095 QT_WA({ 2096 ok = ::GetFileAttributesExW((TCHAR*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), GetFileExInfoStandard, &attribData); 2097 } , { 2098 ok = ::GetFileAttributesExA(QFSFileEnginePrivate::win95Name(QFileInfo(d->filePath).absoluteFilePath()), GetFileExInfoStandard, &attribData); 2099 }); 2100 if (ok) { 2101 if(time == CreationTime) 2102 ret = fileTimeToQDateTime(&attribData.ftCreationTime); 2103 else if(time == ModificationTime) 2104 ret = fileTimeToQDateTime(&attribData.ftLastWriteTime); 2105 else if(time == AccessTime) 2106 ret = fileTimeToQDateTime(&attribData.ftLastAccessTime); 2107 } 2108 } 2109 return ret; 2110 } 2111 2112 uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, 2113 QFile::MemoryMapFlags flags) 2114 { 2115 Q_Q(QFSFileEngine); 2116 Q_UNUSED(flags); 2117 if (openMode == QFile::NotOpen) { 2118 q->setError(QFile::PermissionsError, qt_error_string()); 2119 return 0; 2120 } 2121 if (offset == 0 && size == 0) { 2122 q->setError(QFile::UnspecifiedError, qt_error_string()); 2123 return 0; 2124 } 2125 2126 2127 // get handle to the file 2128 HANDLE handle = fileHandle; 2129 #ifndef Q_OS_WINCE 2130 if (handle == INVALID_HANDLE_VALUE && fh) 2131 handle = (HANDLE)_get_osfhandle(QT_FILENO(fh)); 2132 #else 2133 #ifdef Q_USE_DEPRECATED_MAP_API 2134 nativeClose(); 2135 if (fileMapHandle == INVALID_HANDLE_VALUE) { 2136 fileMapHandle = CreateFileForMappingW((TCHAR *)nativeFilePath.constData(), 2137 GENERIC_READ | (openMode & QIODevice::WriteOnly ? GENERIC_WRITE : 0), 2138 0, 2139 NULL, 2140 OPEN_EXISTING, 2141 FILE_ATTRIBUTE_NORMAL, 2142 NULL); 2143 } 2144 handle = fileMapHandle; 2145 #endif 2146 if (handle == INVALID_HANDLE_VALUE && fh) 2147 return 0; 2148 #endif 2149 2150 // first create the file mapping handle 2151 HANDLE mapHandle = 0; 2152 DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY; 2153 QT_WA({ 2154 mapHandle = ::CreateFileMappingW(handle, 0, protection, 2155 0, 0, 0); 2156 },{ 2157 mapHandle = ::CreateFileMappingA(handle, 0, protection, 2158 0, 0, 0); 2159 }); 2160 if (mapHandle == NULL) { 2161 q->setError(QFile::PermissionsError, qt_error_string()); 2162 #ifdef Q_USE_DEPRECATED_MAP_API 2163 mapHandleClose(); 2164 #endif 2165 return 0; 2166 } 2167 2168 // setup args to map 2169 DWORD access = 0; 2170 if (openMode & QIODevice::ReadOnly) access = FILE_MAP_READ; 2171 if (openMode & QIODevice::WriteOnly) access = FILE_MAP_WRITE; 2172 2173 DWORD offsetHi = offset >> 32; 2174 DWORD offsetLo = offset & Q_UINT64_C(0xffffffff); 2175 SYSTEM_INFO sysinfo; 2176 ::GetSystemInfo(&sysinfo); 2177 int mask = sysinfo.dwAllocationGranularity - 1; 2178 int extra = offset & mask; 2179 if (extra) 2180 offsetLo &= ~mask; 2181 2182 // attempt to create the map 2183 LPVOID mapAddress = MapViewOfFile(mapHandle, access, 2184 offsetHi, offsetLo, size + extra); 2185 if (mapAddress) { 2186 uchar *address = extra + static_cast<uchar*>(mapAddress); 2187 maps[address] = QPair<int, HANDLE>(extra, mapHandle); 2188 return address; 2189 } 2190 2191 switch(GetLastError()) { 2192 case ERROR_ACCESS_DENIED: 2193 q->setError(QFile::PermissionsError, qt_error_string()); 2194 break; 2195 case ERROR_INVALID_PARAMETER: 2196 // size are out of bounds 2197 default: 2198 q->setError(QFile::UnspecifiedError, qt_error_string()); 2199 } 2200 CloseHandle(mapHandle); 2201 #ifdef Q_USE_DEPRECATED_MAP_API 2202 mapHandleClose(); 2203 #endif 2204 return 0; 2205 } 2206 2207 bool QFSFileEnginePrivate::unmap(uchar *ptr) 2208 { 2209 Q_Q(QFSFileEngine); 2210 if (!maps.contains(ptr)) { 2211 q->setError(QFile::PermissionsError, qt_error_string()); 2212 return false; 2213 } 2214 uchar *start = ptr - maps[ptr].first; 2215 if (!UnmapViewOfFile(start)) { 2216 q->setError(QFile::PermissionsError, qt_error_string()); 2217 return false; 2218 } 2219 2220 if (!CloseHandle((HANDLE)maps[ptr].second)) { 2221 q->setError(QFile::UnspecifiedError, qt_error_string()); 2222 return false; 2223 } 2224 maps.remove(ptr); 2225 2226 #ifdef Q_USE_DEPRECATED_MAP_API 2227 mapHandleClose(); 2228 #endif 2229 return true; 2230 } 2231 2232 #ifdef Q_USE_DEPRECATED_MAP_API 2233 void QFSFileEnginePrivate::mapHandleClose() 2234 { 2235 if (maps.isEmpty()) { 2236 CloseHandle(fileMapHandle); 2237 fileMapHandle = INVALID_HANDLE_VALUE; 2238 } 2239 } 2240 #endif 2241 QT_END_NAMESPACE