Skip to content

Commit 3ab307b

Browse files
committed
fix(quota): protect local files from deletion when quota blocked upload
If a file failed to upload because the server quota was exceeded, it was never actually stored on the server — but the sync client could still delete the local copy when the remote parent folder was later moved or deleted via the web interface. checkNewDeleteConflict() now checks the error blacklist before issuing a local REMOVE. If the file carries an InsufficientRemoteStorage entry, it is kept locally and reported as a soft error instead. Setting _childIgnored also prevents the parent folder from being wiped, so the file remains reachable until the user resolves the quota situation. Signed-off-by: Camila Ayres <hello@camilasan.com>
1 parent 9ac8d75 commit 3ab307b

2 files changed

Lines changed: 28 additions & 8 deletions

File tree

src/libsync/discovery.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,18 +2505,38 @@ bool ProcessDirectoryJob::maybeRenameForWindowsCompatibility(const QString &abso
25052505
return result;
25062506
}
25072507

2508-
bool ProcessDirectoryJob::checkNewDeleteConflict(const SyncFileItemPtr &item) const
2508+
bool ProcessDirectoryJob::checkNewDeleteConflict(const SyncFileItemPtr &item)
25092509
{
2510-
if (_discoveryData->recursiveCheckForDeletedParents(item->_file)) {
2511-
qCWarning(lcDisco) << "Removing local file inside a remotely deleted folder" << item->_file;
2512-
item->_instruction = CSYNC_INSTRUCTION_REMOVE;
2513-
item->_direction = SyncFileItem::Down;
2514-
item->_wantsSpecificActions = SyncFileItem::SynchronizationOptions::MoveToClientTrashBin;
2510+
if (!_discoveryData->recursiveCheckForDeletedParents(item->_file)) {
2511+
return false;
2512+
}
2513+
2514+
// If the file was blocked from uploading by a remote storage quota error it was never on the
2515+
// server, so deleting the local copy would be permanent data loss. Protect it instead and let
2516+
// the user resolve the situation (fix quota, then sync or move the file).
2517+
if (const auto blacklistEntry = _discoveryData->_statedb->errorBlacklistEntry(item->_file);
2518+
blacklistEntry.isValid()
2519+
&& blacklistEntry._errorCategory == SyncJournalErrorBlacklistRecord::InsufficientRemoteStorage) {
2520+
qCWarning(lcDisco) << "Not removing local file inside a remotely deleted folder: "
2521+
"file was never uploaded due to storage quota —"
2522+
<< item->_file;
2523+
item->_instruction = CSYNC_INSTRUCTION_ERROR;
2524+
item->_status = SyncFileItem::SoftError;
2525+
item->_errorString = tr("\"%1\" was not deleted because its latest changes were not synced and your server quota was exceeded."
2526+
"Please manage your storage and try syncing again.")
2527+
.arg(item->_file);
2528+
// Prevent the parent directory from being deleted while a quota blocked child exists.
2529+
_childIgnored = true;
25152530
emit _discoveryData->itemDiscovered(item);
25162531
return true;
25172532
}
25182533

2519-
return false;
2534+
qCWarning(lcDisco) << "Removing local file inside a remotely deleted folder" << item->_file;
2535+
item->_instruction = CSYNC_INSTRUCTION_REMOVE;
2536+
item->_direction = SyncFileItem::Down;
2537+
item->_wantsSpecificActions = SyncFileItem::SynchronizationOptions::MoveToClientTrashBin;
2538+
emit _discoveryData->itemDiscovered(item);
2539+
return true;
25202540
}
25212541

25222542
}

src/libsync/discovery.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ class ProcessDirectoryJob : public QObject
252252
bool maybeRenameForWindowsCompatibility(const QString &absoluteFileName,
253253
CSYNC_EXCLUDE_TYPE excludeReason);
254254

255-
[[nodiscard]] bool checkNewDeleteConflict(const SyncFileItemPtr &item) const;
255+
[[nodiscard]] bool checkNewDeleteConflict(const SyncFileItemPtr &item);
256256

257257
qint64 _lastSyncTimestamp = 0;
258258

0 commit comments

Comments
 (0)