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