From 62d3388e3230c82aaac46a9cb5ecfff609fddb0a Mon Sep 17 00:00:00 2001 From: Matthieu Gallien Date: Fri, 9 Feb 2024 15:22:49 +0100 Subject: [PATCH] test and ensure folders can change between read/write and read-only Signed-off-by: Matthieu Gallien --- src/libsync/owncloudpropagator.cpp | 31 +++++++++++ test/testpermissions.cpp | 89 ++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/src/libsync/owncloudpropagator.cpp b/src/libsync/owncloudpropagator.cpp index 6664be246616b..84c17d0e2f328 100644 --- a/src/libsync/owncloudpropagator.cpp +++ b/src/libsync/owncloudpropagator.cpp @@ -1453,6 +1453,37 @@ void PropagateDirectory::slotSubJobsFinished(SyncFileItem::Status status) if (_item->_instruction == CSYNC_INSTRUCTION_RENAME || _item->_instruction == CSYNC_INSTRUCTION_NEW || _item->_instruction == CSYNC_INSTRUCTION_UPDATE_METADATA) { + + if (!_item->_remotePerm.isNull() && + !_item->_remotePerm.hasPermission(RemotePermissions::CanAddFile) && + !_item->_remotePerm.hasPermission(RemotePermissions::CanRename) && + !_item->_remotePerm.hasPermission(RemotePermissions::CanMove) && + !_item->_remotePerm.hasPermission(RemotePermissions::CanAddSubDirectories)) { + try { + std::filesystem::permissions(propagator()->fullLocalPath(_item->_file).toStdWString(), std::filesystem::perms::owner_write | std::filesystem::perms::group_write | std::filesystem::perms::others_write, std::filesystem::perm_options::remove); + } + catch (const std::filesystem::filesystem_error &e) + { + qCWarning(lcDirectory) << "exception when checking parent folder access rights" << e.what() << e.path1().c_str() << e.path2().c_str(); + _item->_status = SyncFileItem::NormalError; + _item->_errorString = tr("The folder %1 cannot be made read-only: %2").arg(_item->_file, e.what()); + } + } else if (!_item->_remotePerm.isNull() && + (_item->_remotePerm.hasPermission(RemotePermissions::CanAddFile) || + !_item->_remotePerm.hasPermission(RemotePermissions::CanRename) || + !_item->_remotePerm.hasPermission(RemotePermissions::CanMove) || + !_item->_remotePerm.hasPermission(RemotePermissions::CanAddSubDirectories))) { + try { + std::filesystem::permissions(propagator()->fullLocalPath(_item->_file).toStdWString(), std::filesystem::perms::owner_write, std::filesystem::perm_options::add); + } + catch (const std::filesystem::filesystem_error &e) + { + qCWarning(lcDirectory) << "exception when checking parent folder access rights" << e.what() << e.path1().c_str() << e.path2().c_str(); + _item->_status = SyncFileItem::NormalError; + _item->_errorString = tr("The folder %1 cannot be made read-only: %2").arg(_item->_file, e.what()); + } + } + const auto result = propagator()->updateMetadata(*_item); if (!result) { status = _item->_status = SyncFileItem::FatalError; diff --git a/test/testpermissions.cpp b/test/testpermissions.cpp index cdcf9049a6bc1..18cbac772f703 100644 --- a/test/testpermissions.cpp +++ b/test/testpermissions.cpp @@ -12,6 +12,7 @@ #include #include +#include using namespace OCC; @@ -590,6 +591,94 @@ private slots: QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); } + + static void demo_perms(std::filesystem::perms p) + { + using std::filesystem::perms; + auto show = [=](char op, perms perm) + { + std::cout << (perms::none == (perm & p) ? '-' : op); + }; + show('r', perms::owner_read); + show('w', perms::owner_write); + show('x', perms::owner_exec); + show('r', perms::group_read); + show('w', perms::group_write); + show('x', perms::group_exec); + show('r', perms::others_read); + show('w', perms::others_write); + show('x', perms::others_exec); + std::cout << std::endl; + } + + void testReadOnlyFolderIsReallyReadOnly() + { + FakeFolder fakeFolder{FileInfo{}}; + + auto &remote = fakeFolder.remoteModifier(); + + remote.mkdir("readOnlyFolder"); + + remote.find("readOnlyFolder")->permissions = RemotePermissions::fromServerString("M"); + + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + const auto folderStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/readOnlyFolder")).toStdWString()); + QVERIFY(folderStatus.permissions() & std::filesystem::perms::owner_read); + } + + void testReadWriteFolderIsReallyReadWrite() + { + FakeFolder fakeFolder{FileInfo{}}; + + auto &remote = fakeFolder.remoteModifier(); + + remote.mkdir("readWriteFolder"); + + remote.find("readWriteFolder")->permissions = RemotePermissions::fromServerString("WDNVRSM"); + + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + const auto folderStatus = std::filesystem::status(static_cast(fakeFolder.localPath() + QStringLiteral("/readWriteFolder")).toStdWString()); + QVERIFY(folderStatus.permissions() & std::filesystem::perms::owner_read); + QVERIFY(folderStatus.permissions() & std::filesystem::perms::owner_write); + } + + void testChangePermissionsFolder() + { + FakeFolder fakeFolder{FileInfo{}}; + + auto &remote = fakeFolder.remoteModifier(); + + remote.mkdir("testFolder"); + + remote.find("testFolder")->permissions = RemotePermissions::fromServerString("M"); + + 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); + + remote.find("testFolder")->permissions = RemotePermissions::fromServerString("WDNVRSM"); + + 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); + + 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); + } }; QTEST_GUILESS_MAIN(TestPermissions)