From b9243b0ce25eb445a2cc1f15d1a4044cc8547099 Mon Sep 17 00:00:00 2001 From: Lenart Kos Date: Thu, 18 Jun 2026 22:34:30 +0200 Subject: [PATCH] fix(libsync): set read-only permissions after rename, not before setFileReadOnly() on Windows adds an ACCESS_DENIED_ACE for BUILTIN\Users to the file's DACL. Applying this to the temp file before renaming it to its final destination blocks the rename, because Windows requires Delete access on the source path to complete the operation. This caused a persistent Error 5 (Access Denied) retry loop for read-only shares and Talk attachments on Windows. Move the permission block to after uncheckedRenameReplace() succeeds, targeting the final filename instead of _tmpFile.fileName(). Fixes: #9885 Signed-off-by: Lenart Kos --- src/libsync/propagatedownload.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp index c5bd0a4043f1e..d9ed93dbb0ff5 100644 --- a/src/libsync/propagatedownload.cpp +++ b/src/libsync/propagatedownload.cpp @@ -1207,16 +1207,6 @@ void PropagateDownloadFile::downloadFinished() } } - if (_item->_locked == SyncFileItem::LockStatus::LockedItem && (_item->_lockOwnerType != SyncFileItem::LockOwnerType::UserLock || _item->_lockOwnerId != propagator()->account()->davUser())) { - qCDebug(lcPropagateDownload()) << _tmpFile.fileName() << "file is locked: making it read only"; - FileSystem::setFileReadOnly(_tmpFile.fileName(), true); - } else { - qCDebug(lcPropagateDownload()) << _tmpFile.fileName() << "file is not locked: making it" - << ((!_item->_remotePerm.isNull() && !_item->_remotePerm.hasPermission(RemotePermissions::CanWrite)) ? "read only" - : "read write"); - FileSystem::setFileReadOnlyWeak(_tmpFile.fileName(), (!_item->_remotePerm.isNull() && !_item->_remotePerm.hasPermission(RemotePermissions::CanWrite))); - } - const auto isConflict = (_item->_instruction == CSYNC_INSTRUCTION_CONFLICT && (FileSystem::isDir(filename) || !FileSystem::fileEquals(filename, _tmpFile.fileName()))) || _item->_instruction == CSYNC_INSTRUCTION_CASE_CLASH_CONFLICT; @@ -1281,6 +1271,16 @@ void PropagateDownloadFile::downloadFinished() FileSystem::setFileHidden(filename, false); + if (_item->_locked == SyncFileItem::LockStatus::LockedItem && (_item->_lockOwnerType != SyncFileItem::LockOwnerType::UserLock || _item->_lockOwnerId != propagator()->account()->davUser())) { + qCDebug(lcPropagateDownload()) << filename << "file is locked: making it read only"; + FileSystem::setFileReadOnly(filename, true); + } else { + qCDebug(lcPropagateDownload()) << filename << "file is not locked: making it" + << ((!_item->_remotePerm.isNull() && !_item->_remotePerm.hasPermission(RemotePermissions::CanWrite)) ? "read only" + : "read write"); + FileSystem::setFileReadOnlyWeak(filename, (!_item->_remotePerm.isNull() && !_item->_remotePerm.hasPermission(RemotePermissions::CanWrite))); + } + if (_needParentFolderRestorePermissions) { FileSystem::setFolderPermissions(QString::fromStdWString(_parentPath.wstring()), FileSystem::FolderPermissions::ReadOnly); emit propagator()->touchedFile(QString::fromStdWString(_parentPath.wstring()));