From ff855fe1fbdea4ea36d50adff38ec00e9ecd76dd Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 13 Mar 2024 16:53:19 +0000 Subject: [PATCH] operations: Fix "optional feature not implemented" error with a crypted sftp Before this change operations.SetDirModTime could return the error "optional feature not implemented" when attempting to set modification times on crypted sftp backends. This was because crypt wraps the directories using fs.DirWrapper but these return fs.ErrorNotImplemented for the SetModTime method. The fix is to recognise that error and fall back to using the DirSetModTime method on the backend which does work. Fixes #7673 --- fs/operations/operations.go | 10 +++++++--- fs/operations/operations_test.go | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/operations/operations.go b/fs/operations/operations.go index 13c3794b3..c9a331702 100644 --- a/fs/operations/operations.go +++ b/fs/operations/operations.go @@ -2628,11 +2628,15 @@ func SetDirModTime(ctx context.Context, f fs.Fs, dst fs.Directory, dir string, m if dst != nil { if do, ok := dst.(fs.SetModTimer); ok { err := do.SetModTime(ctx, modTime) - if err != nil { + if errors.Is(err, fs.ErrorNotImplemented) { + // Fall through and run the code below if not implemented + // This can happen for fs.DirWrapper instances + } else if err != nil { return dst, err + } else { + fs.Infof(logName, "Set directory modification time (using SetModTime)") + return dst, nil } - fs.Infof(logName, "Set directory modification time (using SetModTime)") - return dst, nil } } diff --git a/fs/operations/operations_test.go b/fs/operations/operations_test.go index 9bba6ffff..d14678f13 100644 --- a/fs/operations/operations_test.go +++ b/fs/operations/operations_test.go @@ -1787,6 +1787,13 @@ func TestSetDirModTime(t *testing.T) { fstest.CheckDirModTime(ctx, t, r.Fremote, newDst, t2) } fstest.CheckDirModTime(ctx, t, r.Fremote, fstest.NewDirectory(ctx, t, r.Fremote, name), t2) + + // Now wrap the directory to make the SetModTime method return fs.ErrorNotImplemented and check that it falls back correctly + wrappedDir := fs.NewDirWrapper(existingDir.Remote(), fs.NewDir(existingDir.Remote(), existingDir.ModTime(ctx))) + newDst, err = operations.SetDirModTime(ctx, r.Fremote, wrappedDir, "SHOULD BE IGNORED", t1) + require.NoError(t, err) + require.NotNil(t, newDst) + fstest.CheckDirModTime(ctx, t, r.Fremote, fstest.NewDirectory(ctx, t, r.Fremote, name), t1) } func TestDirsEqual(t *testing.T) {