From 05fc734440414d0e2b21aeea6ebf9b0c7bb87045 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Wed, 2 Sep 2020 06:23:41 +1000 Subject: [PATCH] Handle removing child items on OneDrive when parent item responds with access denied (Issue #1041) (#1045) * Handle removing child items on OneDrive when parent item responds with access denied due to parent folder permissions issue. --- src/onedrive.d | 2 +- src/sync.d | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/onedrive.d b/src/onedrive.d index 3cb3bed4..48983845 100644 --- a/src/onedrive.d +++ b/src/onedrive.d @@ -971,8 +971,8 @@ final class OneDriveApi } } catch (CurlException e) { // Parse and display error message received from OneDrive + log.vdebug("onedrive.perform() Generated a OneDrive CurlException"); log.error("ERROR: OneDrive returned an error with the following message:"); - auto errorArray = splitLines(e.msg); string errorMessage = errorArray[0]; diff --git a/src/sync.d b/src/sync.d index 6fcfa815..aefa60e4 100644 --- a/src/sync.d +++ b/src/sync.d @@ -4694,6 +4694,7 @@ final class SyncEngine // query the database - how many objects will this remove? auto children = getChildren(item.driveId, item.id); long itemsToDelete = count(children); + log.vdebug("Number of items to delete: ", itemsToDelete); // Are we running in monitor mode? A local delete of a file will issue a inotify event, which will trigger the local & remote data immediately if (!cfg.getValueBool("monitor")) { @@ -4725,33 +4726,73 @@ final class SyncEngine // do the delete try { + // what item are we trying to delete? + log.vdebug("Attempting to delete item from drive: ", item.driveId); + log.vdebug("Attempting to delete this item id: ", item.id); + // perform the delete via the API onedrive.deleteById(item.driveId, item.id, item.eTag); } catch (OneDriveException e) { if (e.httpStatusCode == 404) { // item.id, item.eTag could not be found on driveId log.vlog("OneDrive reported: The resource could not be found."); } else { + // Not a 404 response .. is this a 401 response due to some sort of OneDrive Business security policy? + if ((e.httpStatusCode == 401) && (accountType != "personal")) { + log.vdebug("onedrive.deleteById generated a 401 error response when attempting to delete object by item id"); + auto errorArray = splitLines(e.msg); + JSONValue errorMessage = parseJSON(replace(e.msg, errorArray[0], "")); + if (errorMessage["error"]["message"].str == "Access denied. You do not have permission to perform this action or access this resource.") { + // Issue #1041 - Unable to delete OneDrive content when permissions prevent deletion + try { + log.vdebug("Attemtping a reverse delete of all child objects from OneDrive"); + foreach_reverse (Item child; children) { + log.vdebug("Delete child item from drive: ", child.driveId); + log.vdebug("Delete this child item id: ", child.id); + onedrive.deleteById(child.driveId, child.id, child.eTag); + // delete the child reference in the local database + itemdb.deleteById(child.driveId, child.id); + } + log.vdebug("Delete parent item from drive: ", item.driveId); + log.vdebug("Delete this parent item id: ", item.id); + onedrive.deleteById(item.driveId, item.id, item.eTag); + } catch (OneDriveException e) { + // display what the error is + log.vdebug("A further error was generated when attempting a reverse delete of objects from OneDrive"); + displayOneDriveErrorMessage(e.msg); + return; + } + } + } + // Not a 404 response .. is this a 403 response due to OneDrive Business Retention Policy being enabled? if ((e.httpStatusCode == 403) && (accountType != "personal")) { + log.vdebug("onedrive.deleteById generated a 403 error response when attempting to delete object by item id"); auto errorArray = splitLines(e.msg); JSONValue errorMessage = parseJSON(replace(e.msg, errorArray[0], "")); if (errorMessage["error"]["message"].str == "Request was cancelled by event received. If attempting to delete a non-empty folder, it's possible that it's on hold") { // Issue #338 - Unable to delete OneDrive content when OneDrive Business Retention Policy is enabled try { + log.vdebug("Attemtping a reverse delete of all child objects from OneDrive"); foreach_reverse (Item child; children) { + log.vdebug("Delete child item from drive: ", child.driveId); + log.vdebug("Delete this child item id: ", child.id); onedrive.deleteById(child.driveId, child.id, child.eTag); // delete the child reference in the local database itemdb.deleteById(child.driveId, child.id); } + log.vdebug("Delete parent item from drive: ", item.driveId); + log.vdebug("Delete this parent item id: ", item.id); onedrive.deleteById(item.driveId, item.id, item.eTag); } catch (OneDriveException e) { // display what the error is + log.vdebug("A further error was generated when attempting a reverse delete of objects from OneDrive"); displayOneDriveErrorMessage(e.msg); return; } } } else { // Not a 403 response & OneDrive Business Account / O365 Shared Folder / Library + log.vdebug("onedrive.deleteById generated an error response when attempting to delete object by item id"); // display what the error is displayOneDriveErrorMessage(e.msg); return;