diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp index caa6922dbdb24..3b77c30150144 100644 --- a/src/libsync/propagatedownload.cpp +++ b/src/libsync/propagatedownload.cpp @@ -32,11 +32,8 @@ #include #include #include -#include -#ifdef Q_OS_UNIX -#include -#endif +#include namespace OCC { @@ -672,8 +669,21 @@ void PropagateDownloadFile::startDownload() // Can't open(Append) read-only files, make sure to make // file writable if it exists. - if (_tmpFile.exists()) + if (_tmpFile.exists()) { FileSystem::setFileReadOnly(_tmpFile.fileName(), false); + } + const auto newDirPath = std::filesystem::path{_tmpFile.fileName().toStdWString()}; + Q_ASSERT(newDirPath.has_parent_path()); + _parentFolderPath = newDirPath.parent_path(); + auto parentFolderStatus = std::filesystem::status(_parentFolderPath); + _parentPermissions = parentFolderStatus.permissions(); + if ((_parentPermissions & std::filesystem::perms::owner_write) != std::filesystem::perms::owner_write) { + std::filesystem::permissions(_parentFolderPath, _parentPermissions | std::filesystem::perms::owner_write, std::filesystem::perm_options::replace); + emit propagator()->touchedFile(QString::fromStdWString(_parentFolderPath.wstring())); + _needParentFolderRestorePermissions = true; + } + + if (!_tmpFile.open(QIODevice::Append | QIODevice::Unbuffered)) { propagator()->account()->reportClientStatus(ClientStatusReportingStatus::DownloadError_Cannot_Create_File); qCWarning(lcPropagateDownload) << "could not open temporary file" << _tmpFile.fileName(); @@ -1274,6 +1284,12 @@ void PropagateDownloadFile::downloadFinished() return; } + if (_needParentFolderRestorePermissions) { + std::filesystem::permissions(_parentFolderPath, _parentPermissions, std::filesystem::perm_options::replace); + emit propagator()->touchedFile(QString::fromStdWString(_parentFolderPath.wstring())); + _needParentFolderRestorePermissions = false; + } + FileSystem::setFileHidden(filename, false); // Maybe we downloaded a newer version of the file than we thought we would... diff --git a/src/libsync/propagatedownload.h b/src/libsync/propagatedownload.h index a56cdd4a1b0d4..4c48256259138 100644 --- a/src/libsync/propagatedownload.h +++ b/src/libsync/propagatedownload.h @@ -23,6 +23,8 @@ #include #include +#include + namespace OCC { class PropagateDownloadEncrypted; @@ -260,5 +262,9 @@ private slots: QElapsedTimer _stopwatch; PropagateDownloadEncrypted *_downloadEncryptedHelper = nullptr; + + std::filesystem::perms _parentPermissions; + std::filesystem::path _parentFolderPath; + bool _needParentFolderRestorePermissions = false; }; } diff --git a/src/libsync/propagatorjobs.cpp b/src/libsync/propagatorjobs.cpp index 9749f5a1d0b79..8e13f402ad19e 100644 --- a/src/libsync/propagatorjobs.cpp +++ b/src/libsync/propagatorjobs.cpp @@ -32,6 +32,7 @@ #include #include +#include #include @@ -181,6 +182,17 @@ void PropagateLocalMkdir::startLocalMkdir() done(SyncFileItem::FileNameClash, tr("Folder %1 cannot be created because of a local file or folder name clash!").arg(newDirStr), ErrorCategory::GenericError); return; } + + const auto newDirPath = std::filesystem::path{newDirStr.toStdWString()}; + Q_ASSERT(newDirPath.has_parent_path()); + const auto parentFolderPath = newDirPath.parent_path(); + auto parentFolderStatus = std::filesystem::status(parentFolderPath); + const auto parentPermissions = parentFolderStatus.permissions(); + if ((parentPermissions & std::filesystem::perms::owner_write) != std::filesystem::perms::owner_write) { + std::filesystem::permissions(parentFolderPath, parentPermissions | std::filesystem::perms::owner_write, std::filesystem::perm_options::replace); + emit propagator()->touchedFile(QString::fromStdWString(parentFolderPath.wstring())); + } + emit propagator()->touchedFile(newDirStr); QDir localDir(propagator()->localPath()); if (!localDir.mkpath(_item->_file)) { @@ -188,6 +200,19 @@ void PropagateLocalMkdir::startLocalMkdir() return; } + if ((parentPermissions & std::filesystem::perms::owner_write) != std::filesystem::perms::owner_write) { + std::filesystem::permissions(parentFolderPath, parentPermissions, std::filesystem::perm_options::replace); + emit propagator()->touchedFile(QString::fromStdWString(parentFolderPath.wstring())); + } + + if (!_item->_remotePerm.isNull() && + !_item->_remotePerm.hasPermission(RemotePermissions::CanAddFile) && + !_item->_remotePerm.hasPermission(RemotePermissions::CanRename) && + !_item->_remotePerm.hasPermission(RemotePermissions::CanMove) && + !_item->_remotePerm.hasPermission(RemotePermissions::CanAddSubDirectories)) { + std::filesystem::permissions(newDirStr.toStdWString(), std::filesystem::perms::owner_write | std::filesystem::perms::group_write | std::filesystem::perms::owner_write, std::filesystem::perm_options::remove); + } + // Insert the directory into the database. The correct etag will be set later, // once all contents have been propagated, because should_update_metadata is true. // Adding an entry with a dummy etag to the database still makes sense here