diff --git a/src/kio_gdrive.cpp b/src/kio_gdrive.cpp --- a/src/kio_gdrive.cpp +++ b/src/kio_gdrive.cpp @@ -34,16 +34,17 @@ #include #include #include -#include #include #include #include +#include #include -#include #include #include #include #include +#include +#include #include #include #include @@ -881,18 +882,6 @@ void KIOGDrive::del(const QUrl &url, bool isfile) { - // FIXME: Verify that a single file cannot actually have multiple parent - // references. If it can, then we need to be more careful: currently this - // implementation will simply remove the file from all it's parents but - // it actually should just remove the current parent reference - - // FIXME: Because of the above, we are not really deleting the file, but only - // moving it to trash - so if users really really really wants to delete the - // file, they have to go to GDrive web interface and delete it there. I think - // that we should do the DELETE operation here, because for trash people have - // their local trashes. This however requires fixing the first FIXME first, - // otherwise we are risking severe data loss. - qCDebug(GDRIVE) << "Deleting URL" << url << "- is it a file?" << isfile; const QUrlQuery urlQuery(url); @@ -934,13 +923,40 @@ } } - FileTrashJob trashJob(fileId, getAccount(accountId)); - runJob(trashJob, url, accountId); + // Files can have multiple parentReferences, meaning the same fileId and name + // can show up as a childReference in more than one folder. However, outright + // deleting the fileId would remove it from both folders which might result + // in an unintended loss of data. + + // Therefore, we first check if the file has more than one parent - when this + // is the case we find the parentId of the current folder and remove that + // parentId from the fileId. + + // If the fileId has exactly one parentId, we delete the entire fileId rather + // than removing the last parentId (which would cause the file to become + // invisible in your GDrive). + + ParentReferenceFetchJob parentsFetch(fileId, getAccount(accountId)); + runJob(parentsFetch, url, accountId); + const ObjectsList objects = parentsFetch.items(); + if (objects.count() > 1) { + const QString parentId = resolveFileIdFromPath(gdriveUrl.parentPath()); + qCDebug(GDRIVE) << "More than one parent - deleting parentReference" << parentId << "from URL:" << url; + ParentReferenceDeleteJob parentDeleteJob(fileId, parentId, getAccount(accountId)); + runJob(parentDeleteJob, url, accountId); + } else if (objects.count() == 1) { + qCDebug(GDRIVE) << "Exactly one parent - outright deleting the URL:" << url; + FileDeleteJob deleteJob(fileId, getAccount(accountId)); + runJob(deleteJob, url, accountId); + } else { + qCDebug(GDRIVE) << "ParentReferenceFetchJob retrieved" << objects.count() << "items, while one or more were expected."; + error(KIO::ERR_DOES_NOT_EXIST, url.path()); + return; + } m_cache.removePath(url.path()); finished(); - } void KIOGDrive::rename(const QUrl &src, const QUrl &dest, KIO::JobFlags flags)