summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfsfileengine_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qfsfileengine_win.cpp')
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp1008
1 files changed, 1008 insertions, 0 deletions
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
new file mode 100644
index 0000000000..9c858c2e1d
--- /dev/null
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -0,0 +1,1008 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define _POSIX_
+#include "qplatformdefs.h"
+#include "qabstractfileengine.h"
+#include "private/qfsfileengine_p.h"
+#include "qfilesystemengine_p.h"
+#include <qdebug.h>
+
+#include "qfile.h"
+#include "qdir.h"
+#include "private/qmutexpool_p.h"
+#include "qvarlengtharray.h"
+#include "qdatetime.h"
+#include "qt_windows.h"
+
+#if !defined(Q_OS_WINCE)
+# include <sys/types.h>
+# include <direct.h>
+# include <winioctl.h>
+#else
+# include <types.h>
+#endif
+#include <objbase.h>
+#include <shlobj.h>
+#include <initguid.h>
+#include <accctrl.h>
+#include <ctype.h>
+#include <limits.h>
+#define SECURITY_WIN32
+#include <security.h>
+
+#ifndef PATH_MAX
+#define PATH_MAX FILENAME_MAX
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(Q_OS_WINCE)
+static inline bool isUncPath(const QString &path)
+{
+ // Starts with \\, but not \\.
+ return (path.startsWith(QLatin1String("\\\\"))
+ && path.size() > 2 && path.at(2) != QLatin1Char('.'));
+}
+#endif
+
+/*!
+ \internal
+*/
+QString QFSFileEnginePrivate::longFileName(const QString &path)
+{
+ if (path.startsWith(QLatin1String("\\\\.\\")))
+ return path;
+
+ QString absPath = QFileSystemEngine::nativeAbsoluteFilePath(path);
+#if !defined(Q_OS_WINCE)
+ QString prefix = QLatin1String("\\\\?\\");
+ if (isUncPath(absPath)) {
+ prefix.append(QLatin1String("UNC\\")); // "\\\\?\\UNC\\"
+ absPath.remove(0, 2);
+ }
+ return prefix + absPath;
+#else
+ return absPath;
+#endif
+}
+
+/*
+ \internal
+*/
+bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
+{
+ Q_Q(QFSFileEngine);
+
+ // All files are opened in share mode (both read and write).
+ DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+ int accessRights = 0;
+ if (openMode & QIODevice::ReadOnly)
+ accessRights |= GENERIC_READ;
+ if (openMode & QIODevice::WriteOnly)
+ accessRights |= GENERIC_WRITE;
+
+ SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
+
+ // WriteOnly can create files, ReadOnly cannot.
+ DWORD creationDisp = (openMode & QIODevice::WriteOnly) ? OPEN_ALWAYS : OPEN_EXISTING;
+ // Create the file handle.
+ fileHandle = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(),
+ accessRights,
+ shareMode,
+ &securityAtts,
+ creationDisp,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ // Bail out on error.
+ if (fileHandle == INVALID_HANDLE_VALUE) {
+ q->setError(QFile::OpenError, qt_error_string());
+ return false;
+ }
+
+ // Truncate the file after successfully opening it if Truncate is passed.
+ if (openMode & QIODevice::Truncate)
+ q->setSize(0);
+
+ return true;
+}
+
+/*
+ \internal
+*/
+bool QFSFileEnginePrivate::nativeClose()
+{
+ Q_Q(QFSFileEngine);
+ if (fh || fd != -1) {
+ // stdlib / stdio mode.
+ return closeFdFh();
+ }
+
+ // Windows native mode.
+ bool ok = true;
+
+#ifndef Q_OS_WINCE
+ if (cachedFd != -1) {
+ if (::_close(cachedFd) && !::CloseHandle(fileHandle)) {
+ q->setError(QFile::UnspecifiedError, qt_error_string());
+ ok = false;
+ }
+
+ // System handle is closed with associated file descriptor.
+ fileHandle = INVALID_HANDLE_VALUE;
+ cachedFd = -1;
+
+ return ok;
+ }
+#endif
+
+ if ((fileHandle == INVALID_HANDLE_VALUE || !::CloseHandle(fileHandle))) {
+ q->setError(QFile::UnspecifiedError, qt_error_string());
+ ok = false;
+ }
+ fileHandle = INVALID_HANDLE_VALUE;
+ return ok;
+}
+
+/*
+ \internal
+*/
+bool QFSFileEnginePrivate::nativeFlush()
+{
+ if (fh) {
+ // Buffered stdlib mode.
+ return flushFh();
+ }
+ if (fd != -1) {
+ // Unbuffered stdio mode; always succeeds (no buffer).
+ return true;
+ }
+
+ // Windows native mode; flushing is
+ // unnecessary. FlushFileBuffers(), the equivalent of sync() or
+ // fsync() on Unix, does a low-level flush to the disk, and we
+ // don't expose an API for this.
+ return true;
+}
+
+/*
+ \internal
+*/
+qint64 QFSFileEnginePrivate::nativeSize() const
+{
+ Q_Q(const QFSFileEngine);
+ QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q);
+
+ // ### Don't flush; for buffered files, we should get away with ftell.
+ thatQ->flush();
+
+ // Always retrive the current information
+ metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
+#if defined(Q_OS_WINCE)
+ // Buffered stdlib mode.
+ if (fh) {
+ QT_OFF_T oldPos = QT_FTELL(fh);
+ QT_FSEEK(fh, 0, SEEK_END);
+ qint64 fileSize = (qint64)QT_FTELL(fh);
+ QT_FSEEK(fh, oldPos, SEEK_SET);
+ if (fileSize == -1) {
+ fileSize = 0;
+ thatQ->setError(QFile::UnspecifiedError, qt_error_string(errno));
+ }
+ return fileSize;
+ }
+ if (fd != -1) {
+ thatQ->setError(QFile::UnspecifiedError, QLatin1String("Not implemented!"));
+ return 0;
+ }
+#endif
+ bool filled = false;
+ if (fileHandle != INVALID_HANDLE_VALUE && openMode != QIODevice::NotOpen )
+ filled = QFileSystemEngine::fillMetaData(fileHandle, metaData,
+ QFileSystemMetaData::SizeAttribute);
+ else
+ filled = doStat(QFileSystemMetaData::SizeAttribute);
+
+ if (!filled) {
+ thatQ->setError(QFile::UnspecifiedError, qt_error_string(errno));
+ }
+ return metaData.size();
+}
+
+/*
+ \internal
+*/
+qint64 QFSFileEnginePrivate::nativePos() const
+{
+ Q_Q(const QFSFileEngine);
+ QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q);
+
+ if (fh || fd != -1) {
+ // stdlib / stido mode.
+ return posFdFh();
+ }
+
+ // Windows native mode.
+ if (fileHandle == INVALID_HANDLE_VALUE)
+ return 0;
+
+#if !defined(Q_OS_WINCE)
+ LARGE_INTEGER currentFilePos;
+ LARGE_INTEGER offset;
+ offset.QuadPart = 0;
+ if (!::SetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_CURRENT)) {
+ thatQ->setError(QFile::UnspecifiedError, qt_error_string());
+ return 0;
+ }
+
+ return qint64(currentFilePos.QuadPart);
+#else
+ LARGE_INTEGER filepos;
+ filepos.HighPart = 0;
+ DWORD newFilePointer = SetFilePointer(fileHandle, 0, &filepos.HighPart, FILE_CURRENT);
+ if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
+ thatQ->setError(QFile::UnspecifiedError, qt_error_string());
+ return 0;
+ }
+
+ filepos.LowPart = newFilePointer;
+ return filepos.QuadPart;
+#endif
+}
+
+/*
+ \internal
+*/
+bool QFSFileEnginePrivate::nativeSeek(qint64 pos)
+{
+ Q_Q(QFSFileEngine);
+
+ if (fh || fd != -1) {
+ // stdlib / stdio mode.
+ return seekFdFh(pos);
+ }
+
+#if !defined(Q_OS_WINCE)
+ LARGE_INTEGER currentFilePos;
+ LARGE_INTEGER offset;
+ offset.QuadPart = pos;
+ if (!::SetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_BEGIN)) {
+ q->setError(QFile::UnspecifiedError, qt_error_string());
+ return false;
+ }
+
+ return true;
+#else
+ DWORD newFilePointer;
+ LARGE_INTEGER *li = reinterpret_cast<LARGE_INTEGER*>(&pos);
+ newFilePointer = SetFilePointer(fileHandle, li->LowPart, &li->HighPart, FILE_BEGIN);
+ if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
+ q->setError(QFile::PositionError, qt_error_string());
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+/*
+ \internal
+*/
+qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen)
+{
+ Q_Q(QFSFileEngine);
+
+ if (fh || fd != -1) {
+ // stdio / stdlib mode.
+ if (fh && nativeIsSequential() && feof(fh)) {
+ q->setError(QFile::ReadError, qt_error_string(int(errno)));
+ return -1;
+ }
+
+ return readFdFh(data, maxlen);
+ }
+
+ // Windows native mode.
+ if (fileHandle == INVALID_HANDLE_VALUE)
+ return -1;
+
+ DWORD bytesToRead = DWORD(maxlen); // <- lossy
+
+ // Reading on Windows fails with ERROR_NO_SYSTEM_RESOURCES when
+ // the chunks are too large, so we limit the block size to 32MB.
+ static const DWORD maxBlockSize = 32 * 1024 * 1024;
+
+ qint64 totalRead = 0;
+ do {
+ DWORD blockSize = qMin<DWORD>(bytesToRead, maxBlockSize);
+ DWORD bytesRead;
+ if (!ReadFile(fileHandle, data + totalRead, blockSize, &bytesRead, NULL)) {
+ if (totalRead == 0) {
+ // Note: only return failure if the first ReadFile fails.
+ q->setError(QFile::ReadError, qt_error_string());
+ return -1;
+ }
+ break;
+ }
+ if (bytesRead == 0)
+ break;
+ totalRead += bytesRead;
+ bytesToRead -= bytesRead;
+ } while (totalRead < maxlen);
+ return qint64(totalRead);
+}
+
+/*
+ \internal
+*/
+qint64 QFSFileEnginePrivate::nativeReadLine(char *data, qint64 maxlen)
+{
+ Q_Q(QFSFileEngine);
+
+ if (fh || fd != -1) {
+ // stdio / stdlib mode.
+ return readLineFdFh(data, maxlen);
+ }
+
+ // Windows native mode.
+ if (fileHandle == INVALID_HANDLE_VALUE)
+ return -1;
+
+ // ### No equivalent in Win32?
+ return q->QAbstractFileEngine::readLine(data, maxlen);
+}
+
+/*
+ \internal
+*/
+qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len)
+{
+ Q_Q(QFSFileEngine);
+
+ if (fh || fd != -1) {
+ // stdio / stdlib mode.
+ return writeFdFh(data, len);
+ }
+
+ // Windows native mode.
+ if (fileHandle == INVALID_HANDLE_VALUE)
+ return -1;
+
+ qint64 bytesToWrite = DWORD(len); // <- lossy
+
+ // Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when
+ // the chunks are too large, so we limit the block size to 32MB.
+ static const DWORD maxBlockSize = 32 * 1024 * 1024;
+
+ qint64 totalWritten = 0;
+ do {
+ DWORD blockSize = qMin<DWORD>(bytesToWrite, maxBlockSize);
+ DWORD bytesWritten;
+ if (!WriteFile(fileHandle, data + totalWritten, blockSize, &bytesWritten, NULL)) {
+ if (totalWritten == 0) {
+ // Note: Only return error if the first WriteFile failed.
+ q->setError(QFile::WriteError, qt_error_string());
+ return -1;
+ }
+ break;
+ }
+ if (bytesWritten == 0)
+ break;
+ totalWritten += bytesWritten;
+ bytesToWrite -= bytesWritten;
+ } while (totalWritten < len);
+ return qint64(totalWritten);
+}
+
+/*
+ \internal
+*/
+int QFSFileEnginePrivate::nativeHandle() const
+{
+ if (fh || fd != -1)
+ return fh ? QT_FILENO(fh) : fd;
+#ifndef Q_OS_WINCE
+ if (cachedFd != -1)
+ return cachedFd;
+
+ int flags = 0;
+ if (openMode & QIODevice::Append)
+ flags |= _O_APPEND;
+ if (!(openMode & QIODevice::WriteOnly))
+ flags |= _O_RDONLY;
+ cachedFd = _open_osfhandle((intptr_t) fileHandle, flags);
+ return cachedFd;
+#else
+ return -1;
+#endif
+}
+
+/*
+ \internal
+*/
+bool QFSFileEnginePrivate::nativeIsSequential() const
+{
+#if !defined(Q_OS_WINCE)
+ HANDLE handle = fileHandle;
+ if (fh || fd != -1)
+ handle = (HANDLE)_get_osfhandle(fh ? QT_FILENO(fh) : fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ return false;
+
+ DWORD fileType = GetFileType(handle);
+ return (fileType == FILE_TYPE_CHAR)
+ || (fileType == FILE_TYPE_PIPE);
+#else
+ return false;
+#endif
+}
+
+bool QFSFileEngine::remove()
+{
+ Q_D(QFSFileEngine);
+ QSystemError error;
+ bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
+ if (!ret)
+ setError(QFile::RemoveError, error.toString());
+ return ret;
+}
+
+bool QFSFileEngine::copy(const QString &copyName)
+{
+ Q_D(QFSFileEngine);
+ QSystemError error;
+ bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(copyName), error);
+ if (!ret)
+ setError(QFile::CopyError, error.toString());
+ return ret;
+}
+
+bool QFSFileEngine::rename(const QString &newName)
+{
+ Q_D(QFSFileEngine);
+ QSystemError error;
+ bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
+ if (!ret)
+ setError(QFile::RenameError, error.toString());
+ return ret;
+}
+
+bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
+{
+ return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories);
+}
+
+bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
+{
+ return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
+}
+
+bool QFSFileEngine::caseSensitive() const
+{
+ return false;
+}
+
+bool QFSFileEngine::setCurrentPath(const QString &path)
+{
+ return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
+}
+
+QString QFSFileEngine::currentPath(const QString &fileName)
+{
+#if !defined(Q_OS_WINCE)
+ QString ret;
+ //if filename is a drive: then get the pwd of that drive
+ if (fileName.length() >= 2 &&
+ fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':')) {
+ int drv = fileName.toUpper().at(0).toLatin1() - 'A' + 1;
+ if (_getdrive() != drv) {
+ wchar_t buf[PATH_MAX];
+ ::_wgetdcwd(drv, buf, PATH_MAX);
+ ret = QString::fromWCharArray(buf);
+ }
+ }
+ if (ret.isEmpty()) {
+ //just the pwd
+ ret = QFileSystemEngine::currentPath().filePath();
+ }
+ if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
+ ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
+ return ret;
+#else
+ Q_UNUSED(fileName);
+ return QFileSystemEngine::currentPath();
+#endif
+}
+
+QString QFSFileEngine::homePath()
+{
+ return QFileSystemEngine::homePath();
+}
+
+QString QFSFileEngine::rootPath()
+{
+ return QFileSystemEngine::rootPath();
+}
+
+QString QFSFileEngine::tempPath()
+{
+ return QFileSystemEngine::tempPath();
+}
+
+QFileInfoList QFSFileEngine::drives()
+{
+ QFileInfoList ret;
+#if !defined(Q_OS_WINCE)
+#if defined(Q_OS_WIN32)
+ quint32 driveBits = (quint32) GetLogicalDrives() & 0x3ffffff;
+#elif defined(Q_OS_OS2EMX)
+ quint32 driveBits, cur;
+ if (DosQueryCurrentDisk(&cur, &driveBits) != NO_ERROR)
+ exit(1);
+ driveBits &= 0x3ffffff;
+#endif
+ char driveName[] = "A:/";
+
+ while (driveBits) {
+ if (driveBits & 1)
+ ret.append(QFileInfo(QLatin1String(driveName)));
+ driveName[0]++;
+ driveBits = driveBits >> 1;
+ }
+ return ret;
+#else
+ ret.append(QFileInfo(QLatin1String("/")));
+ return ret;
+#endif
+}
+
+bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const
+{
+ if (!tried_stat || !metaData.hasFlags(flags)) {
+ tried_stat = true;
+
+#if !defined(Q_OS_WINCE)
+ int localFd = fd;
+ if (fh && fileEntry.isEmpty())
+ localFd = QT_FILENO(fh);
+ if (localFd != -1)
+ QFileSystemEngine::fillMetaData(localFd, metaData, flags);
+#endif
+ if (metaData.missingFlags(flags) && !fileEntry.isEmpty())
+ QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags));
+ }
+
+ return metaData.exists();
+}
+
+
+bool QFSFileEngine::link(const QString &newName)
+{
+#if !defined(Q_OS_WINCE)
+#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS)
+ bool ret = false;
+
+ QString linkName = newName;
+ //### assume that they add .lnk
+
+ IShellLink *psl;
+ bool neededCoInit = false;
+
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
+
+ if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
+ neededCoInit = true;
+ CoInitialize(NULL);
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
+ }
+
+ if (SUCCEEDED(hres)) {
+ hres = psl->SetPath((wchar_t *)fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16());
+ if (SUCCEEDED(hres)) {
+ hres = psl->SetWorkingDirectory((wchar_t *)fileName(AbsolutePathName).replace(QLatin1Char('/'), QLatin1Char('\\')).utf16());
+ if (SUCCEEDED(hres)) {
+ IPersistFile *ppf;
+ hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
+ if (SUCCEEDED(hres)) {
+ hres = ppf->Save((wchar_t*)linkName.utf16(), TRUE);
+ if (SUCCEEDED(hres))
+ ret = true;
+ ppf->Release();
+ }
+ }
+ }
+ psl->Release();
+ }
+ if (!ret)
+ setError(QFile::RenameError, qt_error_string());
+
+ if (neededCoInit)
+ CoUninitialize();
+
+ return ret;
+#else
+ Q_UNUSED(newName);
+ return false;
+#endif // QT_NO_LIBRARY
+#else
+ QString linkName = newName;
+ if (!linkName.endsWith(QLatin1String(".lnk")))
+ linkName += QLatin1String(".lnk");
+ QString orgName = fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\'));
+ // Need to append on our own
+ orgName.prepend(QLatin1Char('"'));
+ orgName.append(QLatin1Char('"'));
+ bool ret = SUCCEEDED(SHCreateShortcut((wchar_t*)linkName.utf16(), (wchar_t*)orgName.utf16()));
+ if (!ret)
+ setError(QFile::RenameError, qt_error_string());
+ return ret;
+#endif // Q_OS_WINCE
+}
+
+/*!
+ \reimp
+*/
+QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const
+{
+ Q_D(const QFSFileEngine);
+
+ if (type & Refresh)
+ d->metaData.clear();
+
+ QAbstractFileEngine::FileFlags ret = 0;
+
+ if (type & FlagsMask)
+ ret |= LocalDiskFlag;
+
+ bool exists;
+ {
+ QFileSystemMetaData::MetaDataFlags queryFlags = 0;
+
+ queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type))
+ & QFileSystemMetaData::Permissions;
+
+ // AliasType and BundleType are 0x0
+ if (type & TypesMask)
+ queryFlags |= QFileSystemMetaData::AliasType
+ | QFileSystemMetaData::LinkType
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::BundleType;
+
+ if (type & FlagsMask)
+ queryFlags |= QFileSystemMetaData::HiddenAttribute
+ | QFileSystemMetaData::ExistsAttribute;
+
+ queryFlags |= QFileSystemMetaData::LinkType;
+
+ exists = d->doStat(queryFlags);
+ }
+
+ if (exists && (type & PermsMask))
+ ret |= FileFlags(uint(d->metaData.permissions()));
+
+ if (type & TypesMask) {
+ if ((type & LinkType) && d->metaData.isLegacyLink())
+ ret |= LinkType;
+ if (d->metaData.isDirectory()) {
+ ret |= DirectoryType;
+ } else {
+ ret |= FileType;
+ }
+ }
+ if (type & FlagsMask) {
+ if (d->metaData.exists()) {
+ ret |= ExistsFlag;
+ if (d->fileEntry.isRoot())
+ ret |= RootFlag;
+ else if (d->metaData.isHidden())
+ ret |= HiddenFlag;
+ }
+ }
+ return ret;
+}
+
+QString QFSFileEngine::fileName(FileName file) const
+{
+ Q_D(const QFSFileEngine);
+ if (file == BaseName) {
+ return d->fileEntry.fileName();
+ } else if (file == PathName) {
+ return d->fileEntry.path();
+ } else if (file == AbsoluteName || file == AbsolutePathName) {
+ QString ret;
+
+ if (!isRelativePath()) {
+#if !defined(Q_OS_WINCE)
+ if (d->fileEntry.filePath().startsWith(QLatin1Char('/')) || // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt
+ d->fileEntry.filePath().size() == 2 || // It's a drive letter that needs to get a working dir appended
+ (d->fileEntry.filePath().size() > 2 && d->fileEntry.filePath().at(2) != QLatin1Char('/')) || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt
+ d->fileEntry.filePath().contains(QLatin1String("/../")) || d->fileEntry.filePath().contains(QLatin1String("/./")) ||
+ d->fileEntry.filePath().endsWith(QLatin1String("/..")) || d->fileEntry.filePath().endsWith(QLatin1String("/.")))
+ {
+ ret = QDir::fromNativeSeparators(QFileSystemEngine::nativeAbsoluteFilePath(d->fileEntry.filePath()));
+ } else
+#endif
+ {
+ ret = d->fileEntry.filePath();
+ }
+ } else {
+ ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->fileEntry.filePath());
+ }
+
+ // The path should be absolute at this point.
+ // From the docs :
+ // Absolute paths begin with the directory separator "/"
+ // (optionally preceded by a drive specification under Windows).
+ if (ret.at(0) != QLatin1Char('/')) {
+ Q_ASSERT(ret.length() >= 2);
+ Q_ASSERT(ret.at(0).isLetter());
+ Q_ASSERT(ret.at(1) == QLatin1Char(':'));
+
+ // Force uppercase drive letters.
+ ret[0] = ret.at(0).toUpper();
+ }
+
+ if (file == AbsolutePathName) {
+ int slash = ret.lastIndexOf(QLatin1Char('/'));
+ if (slash < 0)
+ return ret;
+ else if (ret.at(0) != QLatin1Char('/') && slash == 2)
+ return ret.left(3); // include the slash
+ else
+ return ret.left(slash > 0 ? slash : 1);
+ }
+ return ret;
+ } else if (file == CanonicalName || file == CanonicalPathName) {
+ if (!(fileFlags(ExistsFlag) & ExistsFlag))
+ return QString();
+ QFileSystemEntry entry(QFileSystemEngine::canonicalName(QFileSystemEntry(fileName(AbsoluteName)), d->metaData));
+
+ if (file == CanonicalPathName)
+ return entry.path();
+ return entry.filePath();
+ } else if (file == LinkName) {
+ return QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData).filePath();
+ } else if (file == BundleName) {
+ return QString();
+ }
+ return d->fileEntry.filePath();
+}
+
+bool QFSFileEngine::isRelativePath() const
+{
+ Q_D(const QFSFileEngine);
+ // drive, e.g. "a:", or UNC root, e.q. "//"
+ return d->fileEntry.isRelative();
+}
+
+uint QFSFileEngine::ownerId(FileOwner /*own*/) const
+{
+ static const uint nobodyID = (uint) -2;
+ return nobodyID;
+}
+
+QString QFSFileEngine::owner(FileOwner own) const
+{
+ Q_D(const QFSFileEngine);
+ return QFileSystemEngine::owner(d->fileEntry, own);
+}
+
+bool QFSFileEngine::setPermissions(uint perms)
+{
+ Q_D(QFSFileEngine);
+ QSystemError error;
+ bool ret = QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error);
+ if (!ret)
+ setError(QFile::PermissionsError, error.toString());
+ return ret;
+}
+
+bool QFSFileEngine::setSize(qint64 size)
+{
+ Q_D(QFSFileEngine);
+
+ if (d->fileHandle != INVALID_HANDLE_VALUE || d->fd != -1 || d->fh) {
+ // resize open file
+ HANDLE fh = d->fileHandle;
+#if !defined(Q_OS_WINCE)
+ if (fh == INVALID_HANDLE_VALUE) {
+ if (d->fh)
+ fh = (HANDLE)_get_osfhandle(QT_FILENO(d->fh));
+ else
+ fh = (HANDLE)_get_osfhandle(d->fd);
+ }
+#endif
+ if (fh == INVALID_HANDLE_VALUE)
+ return false;
+ qint64 currentPos = pos();
+
+ if (seek(size) && SetEndOfFile(fh)) {
+ seek(qMin(currentPos, size));
+ return true;
+ }
+
+ seek(currentPos);
+ return false;
+ }
+
+ if (!d->fileEntry.isEmpty()) {
+ // resize file on disk
+ QFile file(d->fileEntry.filePath());
+ if (file.open(QFile::ReadWrite)) {
+ bool ret = file.resize(size);
+ if (!ret)
+ setError(QFile::ResizeError, file.errorString());
+ return ret;
+ }
+ }
+ return false;
+}
+
+
+QDateTime QFSFileEngine::fileTime(FileTime time) const
+{
+ Q_D(const QFSFileEngine);
+
+ if (d->doStat(QFileSystemMetaData::Times))
+ return d->metaData.fileTime(time);
+
+ return QDateTime();
+}
+
+uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
+ QFile::MemoryMapFlags flags)
+{
+ Q_Q(QFSFileEngine);
+ Q_UNUSED(flags);
+ if (openMode == QFile::NotOpen) {
+ q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
+ return 0;
+ }
+ if (offset == 0 && size == 0) {
+ q->setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
+ return 0;
+ }
+
+ if (mapHandle == INVALID_HANDLE_VALUE) {
+ // get handle to the file
+ HANDLE handle = fileHandle;
+
+#ifndef Q_OS_WINCE
+ if (handle == INVALID_HANDLE_VALUE && fh)
+ handle = (HANDLE)::_get_osfhandle(QT_FILENO(fh));
+#endif
+
+#ifdef Q_USE_DEPRECATED_MAP_API
+ nativeClose();
+ // handle automatically closed by kernel with mapHandle (below).
+ handle = ::CreateFileForMapping((const wchar_t*)fileEntry.nativeFilePath().utf16(),
+ GENERIC_READ | (openMode & QIODevice::WriteOnly ? GENERIC_WRITE : 0),
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ // Since this is a special case, we check if the return value was NULL and if so
+ // we change it to INVALID_HANDLE_VALUE to follow the logic inside this function.
+ if(0 == handle)
+ handle = INVALID_HANDLE_VALUE;
+#endif
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
+ return 0;
+ }
+
+ // first create the file mapping handle
+ DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY;
+ mapHandle = ::CreateFileMapping(handle, 0, protection, 0, 0, 0);
+ if (mapHandle == INVALID_HANDLE_VALUE) {
+ q->setError(QFile::PermissionsError, qt_error_string());
+#ifdef Q_USE_DEPRECATED_MAP_API
+ ::CloseHandle(handle);
+#endif
+ return 0;
+ }
+ }
+
+ // setup args to map
+ DWORD access = 0;
+ if (openMode & QIODevice::ReadOnly) access = FILE_MAP_READ;
+ if (openMode & QIODevice::WriteOnly) access = FILE_MAP_WRITE;
+
+ DWORD offsetHi = offset >> 32;
+ DWORD offsetLo = offset & Q_UINT64_C(0xffffffff);
+ SYSTEM_INFO sysinfo;
+ ::GetSystemInfo(&sysinfo);
+ DWORD mask = sysinfo.dwAllocationGranularity - 1;
+ DWORD extra = offset & mask;
+ if (extra)
+ offsetLo &= ~mask;
+
+ // attempt to create the map
+ LPVOID mapAddress = ::MapViewOfFile(mapHandle, access,
+ offsetHi, offsetLo, size + extra);
+ if (mapAddress) {
+ uchar *address = extra + static_cast<uchar*>(mapAddress);
+ maps[address] = extra;
+ return address;
+ }
+
+ switch(GetLastError()) {
+ case ERROR_ACCESS_DENIED:
+ q->setError(QFile::PermissionsError, qt_error_string());
+ break;
+ case ERROR_INVALID_PARAMETER:
+ // size are out of bounds
+ default:
+ q->setError(QFile::UnspecifiedError, qt_error_string());
+ }
+
+ ::CloseHandle(mapHandle);
+ return 0;
+}
+
+bool QFSFileEnginePrivate::unmap(uchar *ptr)
+{
+ Q_Q(QFSFileEngine);
+ if (!maps.contains(ptr)) {
+ q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
+ return false;
+ }
+ uchar *start = ptr - maps[ptr];
+ if (!UnmapViewOfFile(start)) {
+ q->setError(QFile::PermissionsError, qt_error_string());
+ return false;
+ }
+
+ maps.remove(ptr);
+ if (maps.isEmpty()) {
+ ::CloseHandle(mapHandle);
+ mapHandle = INVALID_HANDLE_VALUE;
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE