summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorGabriel de Dietrich <gabriel.dedietrich@qt.io>2017-07-13 16:34:32 -0700
committerGabriel de Dietrich <gabriel.dedietrich@qt.io>2017-07-13 16:36:10 -0700
commitd38fe875c7850ca2c6ca28f91e94ae276735fac8 (patch)
treee5c92cef74e0853490d77cf0139b23f00d548a6e /src/corelib/io
parentac4e848c9802377b7c4ff673180f28b9ca76b746 (diff)
parent627f0a7f7d775ecd263b95dd07fca44bfcb0c5cf (diff)
Merge remote-tracking branch 'origin/5.9' into dev
Conflicts: src/widgets/widgets/qmainwindowlayout.cpp Change-Id: I306b4f5ad11bceb336c9091241b468d455fe6bb6
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/io.pri5
-rw-r--r--src/corelib/io/qfile.cpp8
-rw-r--r--src/corelib/io/qfilesystemengine_p.h2
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp43
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp6
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp47
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp7
-rw-r--r--src/corelib/io/qstorageinfo_win.cpp52
8 files changed, 121 insertions, 49 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index 38e5c23c05..cc43608d8c 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -113,7 +113,10 @@ win32 {
SOURCES += io/qfilesystemwatcher_win.cpp
HEADERS += io/qfilesystemwatcher_win_p.h
SOURCES += io/qfilesystemengine_win.cpp
- SOURCES += io/qfilesystemiterator_win.cpp
+
+ qtConfig(filesystemiterator) {
+ SOURCES += io/qfilesystemiterator_win.cpp
+ }
!winrt {
HEADERS += \
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index ddd343b515..c7a06e49d5 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -568,9 +568,11 @@ QFile::rename(const QString &newName)
}
// If the file exists and it is a case-changing rename ("foo" -> "Foo"),
// compare Ids to make sure it really is a different file.
- if (QFile::exists(newName)) {
- if (d->fileName.compare(newName, Qt::CaseInsensitive)
- || QFileSystemEngine::id(QFileSystemEntry(d->fileName)) != QFileSystemEngine::id(QFileSystemEntry(newName))) {
+ // Note: this does not take file engines into account.
+ QByteArray targetId = QFileSystemEngine::id(QFileSystemEntry(newName));
+ if (!targetId.isNull()) {
+ QByteArray fileId = QFileSystemEngine::id(QFileSystemEntry(d->fileName));
+ if (fileId != targetId || d->fileName.compare(newName, Qt::CaseInsensitive)) {
// ### Race condition. If a file is moved in after this, it /will/ be
// overwritten. On Unix, the proper solution is to use hardlinks:
// return ::link(old, new) && ::remove(old);
diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h
index de18c997df..196ed8df69 100644
--- a/src/corelib/io/qfilesystemengine_p.h
+++ b/src/corelib/io/qfilesystemengine_p.h
@@ -92,6 +92,8 @@ public:
QFileSystemMetaData::MetaDataFlags what);
#if defined(Q_OS_UNIX)
static bool fillMetaData(int fd, QFileSystemMetaData &data); // what = PosixStatFlags
+ static bool setPermissions(int fd, QFile::Permissions permissions, QSystemError &error,
+ QFileSystemMetaData *data = nullptr);
#endif
#if defined(Q_OS_WIN)
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 2c8c4e8f9e..940a0a2122 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -315,9 +315,10 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
//static
QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
{
- struct stat statResult;
- if (stat(entry.nativeFilePath().constData(), &statResult)) {
- qErrnoWarning("stat() failed for '%s'", entry.nativeFilePath().constData());
+ QT_STATBUF statResult;
+ if (QT_STAT(entry.nativeFilePath().constData(), &statResult)) {
+ if (errno != ENOENT)
+ qErrnoWarning("stat() failed for '%s'", entry.nativeFilePath().constData());
return QByteArray();
}
QByteArray result = QByteArray::number(quint64(statResult.st_dev), 16);
@@ -428,15 +429,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
data.entryFlags &= ~what;
- const char * nativeFilePath;
- int nativeFilePathLength;
- {
- const QByteArray &path = entry.nativeFilePath();
- nativeFilePath = path.constData();
- nativeFilePathLength = path.size();
- Q_UNUSED(nativeFilePathLength);
- }
-
+ const QByteArray nativeFilePath = entry.nativeFilePath();
bool entryExists = true; // innocent until proven otherwise
QT_STATBUF statBuffer;
@@ -660,8 +653,7 @@ bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &
}
-//static
-bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data)
+static mode_t toMode_t(QFile::Permissions permissions)
{
mode_t mode = 0;
if (permissions & (QFile::ReadOwner | QFile::ReadUser))
@@ -682,6 +674,13 @@ bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Per
mode |= S_IWOTH;
if (permissions & QFile::ExeOther)
mode |= S_IXOTH;
+ return mode;
+}
+
+//static
+bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data)
+{
+ mode_t mode = toMode_t(permissions);
bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0;
if (success && data) {
@@ -694,6 +693,22 @@ bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Per
return success;
}
+//static
+bool QFileSystemEngine::setPermissions(int fd, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data)
+{
+ mode_t mode = toMode_t(permissions);
+
+ bool success = ::fchmod(fd, mode) == 0;
+ if (success && data) {
+ data->entryFlags &= ~QFileSystemMetaData::Permissions;
+ data->entryFlags |= QFileSystemMetaData::MetaDataFlag(uint(permissions));
+ data->knownFlagsMask |= QFileSystemMetaData::Permissions;
+ }
+ if (!success)
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return success;
+}
+
QString QFileSystemEngine::homePath()
{
QString home = QFile::decodeName(qgetenv("HOME"));
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index d95a6de777..889fbfea7b 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -602,13 +602,13 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
QByteArray result;
const HANDLE handle =
#ifndef Q_OS_WINRT
- CreateFile((wchar_t*)entry.nativeFilePath().utf16(), GENERIC_READ,
+ CreateFile((wchar_t*)entry.nativeFilePath().utf16(), 0,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else // !Q_OS_WINRT
- CreateFile2((const wchar_t*)entry.nativeFilePath().utf16(), GENERIC_READ,
+ CreateFile2((const wchar_t*)entry.nativeFilePath().utf16(), 0,
FILE_SHARE_READ, OPEN_EXISTING, NULL);
#endif // Q_OS_WINRT
- if (handle) {
+ if (handle != INVALID_HANDLE_VALUE) {
result = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ?
fileIdWin8(handle) : fileId(handle);
CloseHandle(handle);
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index c385a82fc5..ff0d45935c 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -71,6 +71,19 @@ QT_BEGIN_NAMESPACE
# define DEBUG if (false) qDebug
#endif
+static Qt::HANDLE createChangeNotification(const QString &path, uint flags)
+{
+ // Volume and folder paths need a trailing slash for proper notification
+ // (e.g. "c:" -> "c:/").
+ QString nativePath = QDir::toNativeSeparators(path);
+ if ((flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) == 0 && !nativePath.endsWith(QLatin1Char('\\')))
+ nativePath.append(QLatin1Char('\\'));
+ const HANDLE result = FindFirstChangeNotification(reinterpret_cast<const wchar_t *>(nativePath.utf16()),
+ FALSE, flags);
+ DEBUG() << __FUNCTION__ << nativePath << hex <<showbase << flags << "returns" << result;
+ return result;
+}
+
#ifndef Q_OS_WINRT
///////////
// QWindowsRemovableDriveListener
@@ -404,8 +417,29 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
thread = *jt;
QMutexLocker locker(&(thread->mutex));
- handle = thread->handleForDir.value(QFileSystemWatcherPathKey(absolutePath));
- if (handle.handle != INVALID_HANDLE_VALUE && handle.flags == flags) {
+ const auto hit = thread->handleForDir.find(QFileSystemWatcherPathKey(absolutePath));
+ if (hit != thread->handleForDir.end() && hit.value().flags < flags) {
+ // Requesting to add a file whose directory has been added previously.
+ // Recreate the notification handle to add the missing notification attributes
+ // for files (FILE_NOTIFY_CHANGE_ATTRIBUTES...)
+ DEBUG() << "recreating" << absolutePath << hex << showbase << hit.value().flags
+ << "->" << flags;
+ const Qt::HANDLE fileHandle = createChangeNotification(absolutePath, flags);
+ if (fileHandle != INVALID_HANDLE_VALUE) {
+ const int index = thread->handles.indexOf(hit.value().handle);
+ const auto pit = thread->pathInfoForHandle.find(hit.value().handle);
+ Q_ASSERT(index != -1);
+ Q_ASSERT(pit != thread->pathInfoForHandle.end());
+ FindCloseChangeNotification(hit.value().handle);
+ thread->handles[index] = hit.value().handle = fileHandle;
+ hit.value().flags = flags;
+ thread->pathInfoForHandle.insert(fileHandle, pit.value());
+ thread->pathInfoForHandle.erase(pit);
+ }
+ }
+ // In addition, check on flags for sufficient notification attributes
+ if (hit != thread->handleForDir.end() && hit.value().flags >= flags) {
+ handle = hit.value();
// found a thread now insert...
DEBUG() << "Found a thread" << thread;
@@ -426,14 +460,9 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
}
// no thread found, first create a handle
- if (handle.handle == INVALID_HANDLE_VALUE || handle.flags != flags) {
+ if (handle.handle == INVALID_HANDLE_VALUE) {
DEBUG() << "No thread found";
- // Volume and folder paths need a trailing slash for proper notification
- // (e.g. "c:" -> "c:/").
- const QString effectiveAbsolutePath =
- isDir ? (absolutePath + QLatin1Char('/')) : absolutePath;
-
- handle.handle = FindFirstChangeNotification((wchar_t*) QDir::toNativeSeparators(effectiveAbsolutePath).utf16(), false, flags);
+ handle.handle = createChangeNotification(absolutePath, flags);
handle.flags = flags;
if (handle.handle == INVALID_HANDLE_VALUE)
continue;
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index 62e613ed14..69961ff76a 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -600,7 +600,12 @@ bool QFSFileEngine::setPermissions(uint perms)
{
Q_D(QFSFileEngine);
QSystemError error;
- if (!QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error, 0)) {
+ bool ok;
+ if (d->fd != -1)
+ ok = QFileSystemEngine::setPermissions(d->fd, QFile::Permissions(perms), error, 0);
+ else
+ ok = QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error, 0);
+ if (!ok) {
setError(QFile::PermissionsError, error.toString());
return false;
}
diff --git a/src/corelib/io/qstorageinfo_win.cpp b/src/corelib/io/qstorageinfo_win.cpp
index f02e46f095..3830c5480c 100644
--- a/src/corelib/io/qstorageinfo_win.cpp
+++ b/src/corelib/io/qstorageinfo_win.cpp
@@ -43,36 +43,52 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qvarlengtharray.h>
+#include "qfilesystementry_p.h"
+
#include <qt_windows.h>
QT_BEGIN_NAMESPACE
static const int defaultBufferSize = MAX_PATH + 1;
-void QStorageInfoPrivate::initRootPath()
+static QString canonicalPath(const QString &rootPath)
{
- rootPath = QFileInfo(rootPath).canonicalFilePath();
-
- if (rootPath.isEmpty())
- return;
-
- QString path = QDir::toNativeSeparators(rootPath);
- rootPath.clear();
+ QString path = QDir::toNativeSeparators(QFileInfo(rootPath).canonicalFilePath());
+ if (path.isEmpty())
+ return path;
if (path.startsWith(QLatin1String("\\\\?\\")))
path.remove(0, 4);
if (path.length() < 2 || path.at(1) != QLatin1Char(':'))
- return;
+ return QString();
+
path[0] = path[0].toUpper();
if (!(path.at(0).unicode() >= 'A' && path.at(0).unicode() <= 'Z'))
- return;
+ return QString();
if (!path.endsWith(QLatin1Char('\\')))
path.append(QLatin1Char('\\'));
+ return path;
+}
+
+void QStorageInfoPrivate::initRootPath()
+{
+ // Do not unnecessarily call QFileInfo::canonicalFilePath() if the path is
+ // already a drive root since it may hang on network drives.
+ const QString path = QFileSystemEntry::isDriveRootPath(rootPath)
+ ? QDir::toNativeSeparators(rootPath)
+ : canonicalPath(rootPath);
+
+ if (path.isEmpty()) {
+ valid = ready = false;
+ return;
+ }
// ### test if disk mounted to folder on other disk
wchar_t buffer[defaultBufferSize];
if (::GetVolumePathName(reinterpret_cast<const wchar_t *>(path.utf16()), buffer, defaultBufferSize))
rootPath = QDir::fromNativeSeparators(QString::fromWCharArray(buffer));
+ else
+ valid = ready = false;
}
static inline QByteArray getDevice(const QString &rootPath)
@@ -108,11 +124,14 @@ static inline QByteArray getDevice(const QString &rootPath)
void QStorageInfoPrivate::doStat()
{
+ valid = ready = true;
initRootPath();
- if (rootPath.isEmpty())
+ if (!valid || !ready)
return;
retrieveVolumeInfo();
+ if (!valid || !ready)
+ return;
device = getDevice(rootPath);
retrieveDiskFreeSpace();
}
@@ -137,9 +156,6 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
ready = false;
valid = ::GetLastError() == ERROR_NOT_READY;
} else {
- ready = true;
- valid = true;
-
fileSystemType = QString::fromWCharArray(fileSystemTypeBuffer).toLatin1();
name = QString::fromWCharArray(nameBuffer);
@@ -154,10 +170,10 @@ void QStorageInfoPrivate::retrieveDiskFreeSpace()
const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
const QString path = QDir::toNativeSeparators(rootPath);
- ::GetDiskFreeSpaceEx(reinterpret_cast<const wchar_t *>(path.utf16()),
- PULARGE_INTEGER(&bytesAvailable),
- PULARGE_INTEGER(&bytesTotal),
- PULARGE_INTEGER(&bytesFree));
+ ready = ::GetDiskFreeSpaceEx(reinterpret_cast<const wchar_t *>(path.utf16()),
+ PULARGE_INTEGER(&bytesAvailable),
+ PULARGE_INTEGER(&bytesTotal),
+ PULARGE_INTEGER(&bytesFree));
::SetErrorMode(oldmode);
}