diff --git a/src/common/filesystembase.cpp b/src/common/filesystembase.cpp index b63f6c1a7e156..898fbb63bad54 100644 --- a/src/common/filesystembase.cpp +++ b/src/common/filesystembase.cpp @@ -245,54 +245,6 @@ bool FileSystem::rename(const QString &originFileName, return success; } -bool FileSystem::uncheckedRenameReplace(const QString &originFileName, - const QString &destinationFileName, - QString *errorString) -{ -#ifndef Q_OS_WIN - bool success = false; - QFile orig(originFileName); - // We want a rename that also overwrites. QFile::rename does not overwrite. - // Qt 5.1 has QSaveFile::renameOverwrite we could use. - // ### FIXME - success = true; - bool destExists = fileExists(destinationFileName); - if (destExists && !QFile::remove(destinationFileName)) { - *errorString = orig.errorString(); - qCWarning(lcFileSystem) << "Target file could not be removed."; - success = false; - } - if (success) { - success = orig.rename(destinationFileName); - } - if (!success) { - *errorString = orig.errorString(); - qCWarning(lcFileSystem) << "Renaming temp file to final failed: " << *errorString; - return false; - } - -#else //Q_OS_WIN - // You can not overwrite a read-only file on windows. - if (!isWritable(destinationFileName)) { - setFileReadOnly(destinationFileName, false); - } - - BOOL ok = 0; - QString orig = longWinPath(originFileName); - QString dest = longWinPath(destinationFileName); - - ok = MoveFileEx((wchar_t *)orig.utf16(), - (wchar_t *)dest.utf16(), - MOVEFILE_REPLACE_EXISTING + MOVEFILE_COPY_ALLOWED + MOVEFILE_WRITE_THROUGH); - if (!ok) { - *errorString = Utility::formatWinError(GetLastError()); - qCWarning(lcFileSystem) << "Renaming temp file to final failed: " << *errorString; - return false; - } -#endif - return true; -} - bool FileSystem::openAndSeekFileSharedRead(QFile *file, QString *errorOrNull, qint64 seek) { QString errorDummy; @@ -597,6 +549,7 @@ bool FileSystem::remove(const QString &fileName, QString *errorString) } return false; } + qCInfo(lcFileSystem()) << "delete" << fileName; } catch (const std::filesystem::filesystem_error &e) { diff --git a/src/common/filesystembase.h b/src/common/filesystembase.h index 8f5554000e079..e9547d2d0a7b6 100644 --- a/src/common/filesystembase.h +++ b/src/common/filesystembase.h @@ -132,14 +132,6 @@ namespace FileSystem { const QString &destinationFileName, QString *errorString = nullptr); - /** - * Rename the file \a originFileName to \a destinationFileName, and - * overwrite the destination if it already exists - without extra checks. - */ - bool OCSYNC_EXPORT uncheckedRenameReplace(const QString &originFileName, - const QString &destinationFileName, - QString *errorString); - /** * Removes a file. * diff --git a/src/libsync/filesystem.cpp b/src/libsync/filesystem.cpp index 5371ae35a02a4..55d4c3c8b6b8c 100644 --- a/src/libsync/filesystem.cpp +++ b/src/libsync/filesystem.cpp @@ -281,6 +281,7 @@ bool FileSystem::removeRecursively(const QString &path, const std::function securityDescriptor; @@ -429,6 +404,10 @@ bool FileSystem::setFolderPermissions(const QString &path, } } + if (permissions == FileSystem::FolderPermissions::ReadWrite) { + qCInfo(lcFileSystem) << path << "will be read write"; + } + for (int i = 0; i < aclSize.AceCount; ++i) { void *currentAce = nullptr; if (!GetAce(resultDacl, i, ¤tAce)) { @@ -438,9 +417,6 @@ bool FileSystem::setFolderPermissions(const QString &path, const auto currentAceHeader = reinterpret_cast(currentAce); - if (permissions == FileSystem::FolderPermissions::ReadWrite) { - qCInfo(lcFileSystem) << path << "will be read write"; - } if (permissions == FileSystem::FolderPermissions::ReadWrite && (ACCESS_DENIED_ACE_TYPE == (currentAceHeader->AceType & ACCESS_DENIED_ACE_TYPE))) { qCWarning(lcFileSystem) << "AceHeader" << path << currentAceHeader->AceFlags << currentAceHeader->AceSize << currentAceHeader->AceType; continue; @@ -478,7 +454,34 @@ bool FileSystem::setFolderPermissions(const QString &path, qCWarning(lcFileSystem) << "error when calling SetFileSecurityW" << path << GetLastError(); return false; } -#endif +#else + static constexpr auto writePerms = std::filesystem::perms::owner_write | std::filesystem::perms::group_write | std::filesystem::perms::others_write; + const auto stdStrPath = path.toStdWString(); + try + { + switch (permissions) { + case OCC::FileSystem::FolderPermissions::ReadOnly: + std::filesystem::permissions(stdStrPath, writePerms, std::filesystem::perm_options::remove); + break; + case OCC::FileSystem::FolderPermissions::ReadWrite: + break; + } + } + catch (const std::filesystem::filesystem_error &e) + { + qCWarning(lcFileSystem()) << "exception when modifying folder permissions" << e.what() << "- path1:" << e.path1().c_str() << "- path2:" << e.path2().c_str(); + return false; + } + catch (const std::system_error &e) + { + qCWarning(lcFileSystem()) << "exception when modifying folder permissions" << e.what() << "- path:" << stdStrPath; + return false; + } + catch (...) + { + qCWarning(lcFileSystem()) << "exception when modifying folder permissions - path:" << stdStrPath; + return false; + } try { @@ -506,12 +509,76 @@ bool FileSystem::setFolderPermissions(const QString &path, qCWarning(lcFileSystem()) << "exception when modifying folder permissions - path:" << stdStrPath; return false; } +#endif return true; } bool FileSystem::isFolderReadOnly(const std::filesystem::path &path) noexcept { +#ifdef Q_OS_WIN + qCInfo(lcFileSystem()) << "is it read-only folder:" << QString::fromStdWString(path.wstring()); + + SECURITY_INFORMATION info = DACL_SECURITY_INFORMATION; + std::unique_ptr securityDescriptor; + auto neededLength = 0ul; + + if (!GetFileSecurityW(path.wstring().c_str(), info, nullptr, 0, &neededLength)) { + const auto lastError = GetLastError(); + if (lastError != ERROR_INSUFFICIENT_BUFFER) { + qCWarning(lcFileSystem) << "error when calling GetFileSecurityW" << path << lastError; + return false; + } + + securityDescriptor.reset(new char[neededLength]); + + if (!GetFileSecurityW(path.wstring().c_str(), info, securityDescriptor.get(), neededLength, &neededLength)) { + qCWarning(lcFileSystem) << "error when calling GetFileSecurityW" << path << GetLastError(); + return false; + } + } + + int daclPresent = false, daclDefault = false; + PACL resultDacl = nullptr; + if (!GetSecurityDescriptorDacl(securityDescriptor.get(), &daclPresent, &resultDacl, &daclDefault)) { + qCWarning(lcFileSystem) << "error when calling GetSecurityDescriptorDacl" << path << GetLastError(); + return false; + } + if (!daclPresent || !resultDacl) { + qCWarning(lcFileSystem) << "error when calling DACL needed to set a folder read-only or read-write is missing" << path; + return false; + } + + PSID sid = nullptr; + if (!ConvertStringSidToSidW(L"S-1-5-32-545", &sid)) + { + qCWarning(lcFileSystem) << "error when calling ConvertStringSidToSidA" << path << GetLastError(); + return false; + } + + ACL_SIZE_INFORMATION aclSize; + if (!GetAclInformation(resultDacl, &aclSize, sizeof(aclSize), AclSizeInformation)) { + qCWarning(lcFileSystem) << "error when calling GetAclInformation" << path << GetLastError(); + return false; + } + + for (int i = 0; i < aclSize.AceCount; ++i) { + void *currentAce = nullptr; + if (!GetAce(resultDacl, i, ¤tAce)) { + qCWarning(lcFileSystem) << "error when calling GetAce" << path << GetLastError(); + return false; + } + + const auto currentAceHeader = reinterpret_cast(currentAce); + + if ((ACCESS_DENIED_ACE_TYPE == (currentAceHeader->AceType & ACCESS_DENIED_ACE_TYPE))) { + qCInfo(lcFileSystem()) << "detected access denied ACL: assuming read-only folder:" << QString::fromStdWString(path.wstring()); + return true; + } + } + + return false; +#else try { const auto folderStatus = std::filesystem::status(path); @@ -533,6 +600,7 @@ bool FileSystem::isFolderReadOnly(const std::filesystem::path &path) noexcept qCWarning(lcFileSystem()) << "exception when checking folder permissions - path:" << path; return false; } +#endif } FileSystem::FilePermissionsRestore::FilePermissionsRestore(const QString &path, FolderPermissions temporaryPermissions) @@ -568,4 +636,52 @@ FileSystem::FilePermissionsRestore::~FilePermissionsRestore() } } +bool FileSystem::uncheckedRenameReplace(const QString &originFileName, const QString &destinationFileName, QString *errorString) +{ +#ifndef Q_OS_WIN + bool success = false; + QFile orig(originFileName); + // We want a rename that also overwrites. QFile::rename does not overwrite. + // Qt 5.1 has QSaveFile::renameOverwrite we could use. + // ### FIXME + success = true; + bool destExists = fileExists(destinationFileName); + if (destExists && !QFile::remove(destinationFileName)) { + *errorString = orig.errorString(); + qCWarning(lcFileSystem) << "Target file could not be removed."; + success = false; + } + if (success) { + success = orig.rename(destinationFileName); + } + if (!success) { + *errorString = orig.errorString(); + qCWarning(lcFileSystem) << "Renaming temp file to final failed: " << *errorString; + return false; + } +#else //Q_OS_WIN + const auto originFileInfo = QFileInfo{originFileName}; + const auto originParentFolderPath = originFileInfo.dir().absolutePath(); + FilePermissionsRestore renameEnabler{originParentFolderPath, FileSystem::FolderPermissions::ReadWrite}; + // You can not overwrite a read-only file on windows. + if (!isWritable(destinationFileName)) { + setFileReadOnly(destinationFileName, false); + } + + BOOL ok = 0; + QString orig = longWinPath(originFileName); + QString dest = longWinPath(destinationFileName); + + ok = MoveFileEx((wchar_t *)orig.utf16(), + (wchar_t *)dest.utf16(), + MOVEFILE_REPLACE_EXISTING + MOVEFILE_COPY_ALLOWED + MOVEFILE_WRITE_THROUGH); + if (!ok) { + *errorString = Utility::formatWinError(GetLastError()); + qCWarning(lcFileSystem) << "Renaming temp file to final failed: " << *errorString; + return false; + } +#endif + return true; +} + } // namespace OCC diff --git a/src/libsync/filesystem.h b/src/libsync/filesystem.h index 26c999994394f..2682f180b84d5 100644 --- a/src/libsync/filesystem.h +++ b/src/libsync/filesystem.h @@ -130,6 +130,14 @@ namespace FileSystem { FileSystem::FolderPermissions permissions) noexcept; bool OWNCLOUDSYNC_EXPORT isFolderReadOnly(const std::filesystem::path &path) noexcept; + + /** + * Rename the file \a originFileName to \a destinationFileName, and + * overwrite the destination if it already exists - without extra checks. + */ + bool OWNCLOUDSYNC_EXPORT uncheckedRenameReplace(const QString &originFileName, + const QString &destinationFileName, + QString *errorString); } /** @} */ diff --git a/test/syncenginetestutils.cpp b/test/syncenginetestutils.cpp index e4a5d12a7c682..58fecc6e8e6cd 100644 --- a/test/syncenginetestutils.cpp +++ b/test/syncenginetestutils.cpp @@ -51,9 +51,12 @@ void DiskFileModifier::remove(const QString &relativePath) if (fi.isFile()) { QVERIFY(_rootDir.remove(relativePath)); } else { - const auto pathToDelete = fi.filePath().toStdWString(); - std::filesystem::permissions(pathToDelete, std::filesystem::perms::owner_exec, std::filesystem::perm_options::add); - QVERIFY(std::filesystem::remove_all(pathToDelete)); + const auto pathToDelete = fi.filePath(); + const auto result = OCC::FileSystem::removeRecursively(pathToDelete); + if (!result) { + qDebug() << "delete failed for:" << pathToDelete; + QVERIFY(result); + } } } @@ -70,7 +73,9 @@ void DiskFileModifier::insert(const QString &relativePath, qint64 size, char con file.close(); // Set the mtime 30 seconds in the past, for some tests that need to make sure that the mtime differs. OCC::FileSystem::setModTime(file.fileName(), OCC::Utility::qDateTimeToTime_t(QDateTime::currentDateTimeUtc().addSecs(-30))); - QCOMPARE(file.size(), size); + if (file.size() != size) { + QCOMPARE(file.size(), size); + } } void DiskFileModifier::setContents(const QString &relativePath, char contentChar) @@ -100,7 +105,11 @@ void DiskFileModifier::mkdir(const QString &relativePath) void DiskFileModifier::rename(const QString &from, const QString &to) { QVERIFY(_rootDir.exists(from)); - QVERIFY(_rootDir.rename(from, to)); + const auto result = _rootDir.rename(from, to); + if (!result) { + qDebug() << "failed to rename from:" << from << "to:" << to; + QVERIFY(result); + } } void DiskFileModifier::setModTime(const QString &relativePath, const QDateTime &modTime) diff --git a/test/testpermissions.cpp b/test/testpermissions.cpp index 93f139b5c5b4f..8721b40447471 100644 --- a/test/testpermissions.cpp +++ b/test/testpermissions.cpp @@ -48,6 +48,11 @@ static void assertCsyncJournalOk(SyncJournalDb &journal) #endif } +static bool isReadOnlyFolder(const std::wstring &path) +{ + return FileSystem::isFolderReadOnly(std::filesystem::path{path}); +} + SyncFileItemPtr findDiscoveryItem(const SyncFileItemVector &spy, const QString &path) { for (const auto &item : spy) { @@ -132,28 +137,32 @@ private slots: qInfo("Do some changes and see how they propagate"); const auto removeReadOnly = [&] (const QString &file) { - try { - const auto fileInfoToDelete = QFileInfo(fakeFolder.localPath() + file); - QFile(fakeFolder.localPath() + file).setPermissions(QFile::WriteOwner | QFile::ReadOwner); - const auto isReadOnly = !static_cast(std::filesystem::status(fileInfoToDelete.absolutePath().toStdWString()).permissions() & std::filesystem::perms::owner_write); - if (isReadOnly) { - std::filesystem::permissions(fileInfoToDelete.absolutePath().toStdWString(), std::filesystem::perms::owner_write, std::filesystem::perm_options::add); + const auto fileInfoToDelete = QFileInfo(fakeFolder.localPath() + file); + FileSystem::FilePermissionsRestore enabler{fileInfoToDelete.absolutePath(), FileSystem::FolderPermissions::ReadWrite}; + if (!fileInfoToDelete.isDir()) { + QString errorString; + const auto result = FileSystem::remove(fileInfoToDelete.absoluteFilePath(), &errorString); + if (!result) { + qDebug() << "fail to delete:" << fileInfoToDelete.absoluteFilePath() << errorString; + QVERIFY(result); } - fakeFolder.localModifier().remove(file); - if (isReadOnly) { - std::filesystem::permissions(fileInfoToDelete.absolutePath().toStdWString(), std::filesystem::perms::owner_write, std::filesystem::perm_options::remove); + } else { + const auto result = FileSystem::removeRecursively(fileInfoToDelete.absoluteFilePath()); + if (!result) { + qDebug() << "fail to delete:" << fileInfoToDelete.absoluteFilePath(); + QVERIFY(result); } } - catch (const std::exception& e) - { - qWarning() << e.what(); - } }; const auto renameReadOnly = [&] (const QString &relativePath, const QString &relativeDestinationDirectory) { try { const auto sourceFileInfo = QFileInfo(fakeFolder.localPath() + relativePath); + FileSystem::FilePermissionsRestore sourceEnabler{sourceFileInfo.absolutePath(), FileSystem::FolderPermissions::ReadWrite}; + const auto destinationFileInfo = QFileInfo(fakeFolder.localPath() + relativeDestinationDirectory); + FileSystem::FilePermissionsRestore destinationEnabler{destinationFileInfo.absolutePath(), FileSystem::FolderPermissions::ReadWrite}; + const auto isSourceReadOnly = !static_cast(std::filesystem::status(sourceFileInfo.absolutePath().toStdWString()).permissions() & std::filesystem::perms::owner_write); const auto isDestinationReadOnly = !static_cast(std::filesystem::status(destinationFileInfo.absolutePath().toStdWString()).permissions() & std::filesystem::perms::owner_write); if (isSourceReadOnly) { @@ -179,14 +188,8 @@ private slots: const auto insertReadOnly = [&] (const QString &file, const int fileSize) { try { const auto fileInfo = QFileInfo(fakeFolder.localPath() + file); - const auto isReadOnly = !static_cast(std::filesystem::status(fileInfo.absolutePath().toStdWString()).permissions() & std::filesystem::perms::owner_write); - if (isReadOnly) { - std::filesystem::permissions(fileInfo.absolutePath().toStdWString(), std::filesystem::perms::owner_write, std::filesystem::perm_options::add); - } + FileSystem::FilePermissionsRestore enabler{fileInfo.absolutePath(), FileSystem::FolderPermissions::ReadWrite}; fakeFolder.localModifier().insert(file, fileSize); - if (isReadOnly) { - std::filesystem::permissions(fileInfo.absolutePath().toStdWString(), std::filesystem::perms::owner_write, std::filesystem::perm_options::remove); - } } catch (const std::exception& e) { @@ -237,9 +240,6 @@ private slots: //2. // File should be deleted QVERIFY(!currentLocalState.find("normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_D_.data")); -#ifdef Q_OS_WINDOWS - QEXPECT_FAIL("", "", Abort); -#endif QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/canBeRemoved_PERM_D_.data")); //3. @@ -285,8 +285,6 @@ private slots: // The file should not exist on the remote, and not be there QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data")); QVERIFY(!fakeFolder.currentRemoteState().find("readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data")); - // remove it so next test succeed. - removeReadOnly("readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data"); // Both side should still be the same QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); @@ -368,8 +366,8 @@ private slots: QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data" )); // new no longer exists QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/newname_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data" )); - // but is not on server: so remove it locally for the future comparison - removeReadOnly("readonlyDirectory_PERM_M_/newname_PERM_CK_"); + // but is not on server: should have been locally removed + QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/newname_PERM_CK_")); //2. // old removed @@ -378,8 +376,8 @@ private slots: QVERIFY(fakeFolder.currentRemoteState().find("normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_")); // new no longer exists QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/moved_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data" )); - //but not on server - removeReadOnly("readonlyDirectory_PERM_M_/moved_PERM_CK_"); + // should have been cleaned up as invalid item inside read-only folder + QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/moved_PERM_CK_")); fakeFolder.remoteModifier().remove("normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_"); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); @@ -647,27 +645,21 @@ private slots: QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - auto folderStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString()); - QVERIFY(folderStatus.permissions() & std::filesystem::perms::owner_read); - QVERIFY(!static_cast(folderStatus.permissions() & std::filesystem::perms::owner_write)); + QVERIFY(isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString())); remote.find("testFolder")->permissions = RemotePermissions::fromServerString("CKWDNVRSM"); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - folderStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString()); - QVERIFY(folderStatus.permissions() & std::filesystem::perms::owner_read); - QVERIFY(folderStatus.permissions() & std::filesystem::perms::owner_write); + QVERIFY(!isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString())); remote.find("testFolder")->permissions = RemotePermissions::fromServerString("M"); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - folderStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString()); - QVERIFY(folderStatus.permissions() & std::filesystem::perms::owner_read); - QVERIFY(!static_cast(folderStatus.permissions() & std::filesystem::perms::owner_write)); + QVERIFY(isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString())); } void testChangePermissionsForFolderHierarchy() @@ -691,15 +683,9 @@ private slots: QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - auto testFolderStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString()); - QVERIFY(testFolderStatus.permissions() & std::filesystem::perms::owner_read); - QVERIFY(!static_cast(testFolderStatus.permissions() & std::filesystem::perms::owner_write)); - auto subFolderReadWriteStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder/subFolderReadWrite")).toStdWString()); - QVERIFY(subFolderReadWriteStatus.permissions() & std::filesystem::perms::owner_read); - QVERIFY(subFolderReadWriteStatus.permissions() & std::filesystem::perms::owner_write); - auto subFolderReadOnlyStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder/subFolderReadOnly")).toStdWString()); - QVERIFY(subFolderReadOnlyStatus.permissions() & std::filesystem::perms::owner_read); - QVERIFY(!static_cast(subFolderReadOnlyStatus.permissions() & std::filesystem::perms::owner_write)); + QVERIFY(isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString())); + QVERIFY(!isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder/subFolderReadWrite")).toStdWString())); + QVERIFY(isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder/subFolderReadOnly")).toStdWString())); remote.find("testFolder/subFolderReadOnly")->permissions = RemotePermissions::fromServerString("CKWDNVRSm"); remote.find("testFolder/subFolderReadWrite")->permissions = RemotePermissions::fromServerString("m"); @@ -711,12 +697,9 @@ private slots: QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - subFolderReadWriteStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder/subFolderReadWrite")).toStdWString()); - QVERIFY(subFolderReadWriteStatus.permissions() & std::filesystem::perms::owner_read); - QVERIFY(!static_cast(subFolderReadWriteStatus.permissions() & std::filesystem::perms::owner_write)); - subFolderReadOnlyStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder/subFolderReadOnly")).toStdWString()); - QVERIFY(subFolderReadOnlyStatus.permissions() & std::filesystem::perms::owner_read); - QVERIFY(subFolderReadOnlyStatus.permissions() & std::filesystem::perms::owner_write); + QVERIFY(isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString())); + QVERIFY(isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder/subFolderReadWrite")).toStdWString())); + QVERIFY(!isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder/subFolderReadOnly")).toStdWString())); remote.rename("testFolder/subFolderReadOnly", "testFolder/subFolderReadWriteNew"); remote.rename("testFolder/subFolderReadWrite", "testFolder/subFolderReadOnlyNew"); @@ -725,9 +708,7 @@ private slots: QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - testFolderStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString()); - QVERIFY(testFolderStatus.permissions() & std::filesystem::perms::owner_read); - QVERIFY(!static_cast(testFolderStatus.permissions() & std::filesystem::perms::owner_write)); + QVERIFY(isReadOnlyFolder(static_cast(fakeFolder.localPath() + QStringLiteral("/testFolder")).toStdWString())); } void testDeleteChildItemsInReadOnlyFolder()