From 076ff96f6b31bfd44a2f9474d4311c19d83ce19c Mon Sep 17 00:00:00 2001 From: Ivan Andreev <ivandeex@gmail.com> Date: Mon, 22 Feb 2021 18:29:00 +0000 Subject: [PATCH] webdav: check that purged directory really exists (#2921) Sharepoint 2016 returns status 204 to the purge request even if the directory to purge does not really exist. This change adds an extra check to detect this condition and returns a proper error code. --- backend/webdav/webdav.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go index ea25fa276..dfc490947 100644 --- a/backend/webdav/webdav.go +++ b/backend/webdav/webdav.go @@ -142,6 +142,7 @@ type Fs struct { canStream bool // set if can stream useOCMtime bool // set if can use X-OC-Mtime retryWithZeroDepth bool // some vendors (sharepoint) won't list files when Depth is 1 (our default) + checkBeforePurge bool // enables extra check that directory to purge really exists hasMD5 bool // set if can use owncloud style checksums for MD5 hasSHA1 bool // set if can use owncloud style checksums for SHA1 ntlmAuthMu sync.Mutex // mutex to serialize NTLM auth roundtrips @@ -540,6 +541,12 @@ func (f *Fs) setQuirks(ctx context.Context, vendor string) error { // Sharepoint with NTLM authentication // See comment above f.retryWithZeroDepth = true + + // Sharepoint 2016 returns status 204 to the purge request + // even if the directory to purge does not really exist + // so we must perform an extra check to detect this + // condition and return a proper error code. + f.checkBeforePurge = true case "other": default: fs.Debugf(f, "Unknown vendor %q", vendor) @@ -879,6 +886,21 @@ func (f *Fs) purgeCheck(ctx context.Context, dir string, check bool) error { if notEmpty { return fs.ErrorDirectoryNotEmpty } + } else if f.checkBeforePurge { + // We are doing purge as the `check` argument is unset. + // The quirk says that we are working with Sharepoint 2016. + // This provider returns status 204 even if the purged directory + // does not really exist so we perform an extra check here. + // Only the existence is checked, all other errors must be + // ignored here to make the rclone test suite pass. + depth := defaultDepth + if f.retryWithZeroDepth { + depth = "0" + } + _, err := f.readMetaDataForPath(ctx, dir, depth) + if err == fs.ErrorObjectNotFound { + return fs.ErrorDirNotFound + } } opts := rest.Opts{ Method: "DELETE",