summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfsfileengine_win.cpp
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/corelib/io/qfsfileengine_win.cpp
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
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