diff options
author | Gabriel de Dietrich <gabriel.dedietrich@qt.io> | 2017-07-13 16:34:32 -0700 |
---|---|---|
committer | Gabriel de Dietrich <gabriel.dedietrich@qt.io> | 2017-07-13 16:36:10 -0700 |
commit | d38fe875c7850ca2c6ca28f91e94ae276735fac8 (patch) | |
tree | e5c92cef74e0853490d77cf0139b23f00d548a6e /src/corelib/io | |
parent | ac4e848c9802377b7c4ff673180f28b9ca76b746 (diff) | |
parent | 627f0a7f7d775ecd263b95dd07fca44bfcb0c5cf (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.pri | 5 | ||||
-rw-r--r-- | src/corelib/io/qfile.cpp | 8 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemengine_p.h | 2 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemengine_unix.cpp | 43 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemengine_win.cpp | 6 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemwatcher_win.cpp | 47 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_unix.cpp | 7 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_win.cpp | 52 |
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); } |