From 9ee3ad70e9001afb8e9bfbed12ca8c1d9a1501ff Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 18 Mar 2021 08:00:08 +0000 Subject: [PATCH] sftp: fix SetModTime stat failed: object not found with --sftp-set-modtime=false Some sftp servers don't allow the user to access the file after upload. In this case the error message indicates that using --sftp-set-modtime=false would fix the problem. However it doesn't because SetModTime does a stat call which can't be disabled. Update SetModTime failed: SetModTime stat failed: object not found After upload this patch checks for an `object not found` error if set_modtime == false and ignores it, returning the expected size of the object instead. It also makes SetModTime do nothing if set_modtime = false https://forum.rclone.org/t/sftp-update-setmodtime-failed/22873 --- backend/sftp/sftp.go | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/backend/sftp/sftp.go b/backend/sftp/sftp.go index 8bbd50fe2..2c9e24322 100644 --- a/backend/sftp/sftp.go +++ b/backend/sftp/sftp.go @@ -1354,18 +1354,19 @@ func (o *Object) stat(ctx context.Context) error { // // it also updates the info field func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error { - if o.fs.opt.SetModTime { - c, err := o.fs.getSftpConnection(ctx) - if err != nil { - return errors.Wrap(err, "SetModTime") - } - err = c.sftpClient.Chtimes(o.path(), modTime, modTime) - o.fs.putSftpConnection(&c, err) - if err != nil { - return errors.Wrap(err, "SetModTime failed") - } + if !o.fs.opt.SetModTime { + return nil } - err := o.stat(ctx) + c, err := o.fs.getSftpConnection(ctx) + if err != nil { + return errors.Wrap(err, "SetModTime") + } + err = c.sftpClient.Chtimes(o.path(), modTime, modTime) + o.fs.putSftpConnection(&c, err) + if err != nil { + return errors.Wrap(err, "SetModTime failed") + } + err = o.stat(ctx) if err != nil { return errors.Wrap(err, "SetModTime stat failed") } @@ -1496,10 +1497,28 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op remove() return errors.Wrap(err, "Update Close failed") } + + // Set the mod time - this stats the object if o.fs.opt.SetModTime == true err = o.SetModTime(ctx, src.ModTime(ctx)) if err != nil { return errors.Wrap(err, "Update SetModTime failed") } + + // Stat the file after the upload to read its stats back if o.fs.opt.SetModTime == false + if !o.fs.opt.SetModTime { + err = o.stat(ctx) + if err == fs.ErrorObjectNotFound { + // In the specific case of o.fs.opt.SetModTime == false + // if the object wasn't found then don't return an error + fs.Debugf(o, "Not found after upload with set_modtime=false so returning best guess") + o.modTime = src.ModTime(ctx) + o.size = src.Size() + o.mode = os.FileMode(0666) // regular file + } else if err != nil { + return errors.Wrap(err, "Update stat failed") + } + } + return nil }