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(&currentUserTrusteeW, (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, &currentFilePos, 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, &currentFilePos, 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 &copyName)
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, &currentUserTrusteeW, &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