diff --git a/backend/sftp/sftp.go b/backend/sftp/sftp.go index a3d2618e6..fceea7a3d 100644 --- a/backend/sftp/sftp.go +++ b/backend/sftp/sftp.go @@ -193,6 +193,7 @@ type Options struct { type Fs struct { name string root string + absRoot string opt Options // parsed options m configmap.Mapper // config features *fs.Features // optional features @@ -491,6 +492,7 @@ func NewFsWithConnection(ctx context.Context, name string, root string, m config f := &Fs{ name: name, root: root, + absRoot: root, opt: *opt, m: m, config: sshConfig, @@ -507,11 +509,20 @@ func NewFsWithConnection(ctx context.Context, name string, root string, m config if err != nil { return nil, errors.Wrap(err, "NewFs") } + cwd, err := c.sftpClient.Getwd() f.putSftpConnection(&c, nil) + if err != nil { + fs.Debugf(f, "Failed to read current directory - using relative paths: %v", err) + } else if !path.IsAbs(f.root) { + f.absRoot = path.Join(cwd, f.root) + fs.Debugf(f, "Using absolute root directory %q", f.absRoot) + } if root != "" { // Check to see if the root actually an existing file + oldAbsRoot := f.absRoot remote := path.Base(root) f.root = path.Dir(root) + f.absRoot = path.Dir(f.absRoot) if f.root == "." { f.root = "" } @@ -520,6 +531,7 @@ func NewFsWithConnection(ctx context.Context, name string, root string, m config if err == fs.ErrorObjectNotFound || errors.Cause(err) == fs.ErrorNotAFile { // File doesn't exist so return old f f.root = root + f.absRoot = oldAbsRoot return f, nil } return nil, err @@ -602,7 +614,7 @@ func (f *Fs) dirExists(dir string) (bool, error) { // This should return ErrDirNotFound if the directory isn't // found. func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) { - root := path.Join(f.root, dir) + root := path.Join(f.absRoot, dir) ok, err := f.dirExists(root) if err != nil { return nil, errors.Wrap(err, "List failed") @@ -683,7 +695,7 @@ func (f *Fs) PutStream(ctx context.Context, in io.Reader, src fs.ObjectInfo, opt // directories above that func (f *Fs) mkParentDir(remote string) error { parent := path.Dir(remote) - return f.mkdir(path.Join(f.root, parent)) + return f.mkdir(path.Join(f.absRoot, parent)) } // mkdir makes the directory and parents using native paths @@ -719,7 +731,7 @@ func (f *Fs) mkdir(dirPath string) error { // Mkdir makes the root directory of the Fs object func (f *Fs) Mkdir(ctx context.Context, dir string) error { - root := path.Join(f.root, dir) + root := path.Join(f.absRoot, dir) return f.mkdir(root) } @@ -735,7 +747,7 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error { return fs.ErrorDirectoryNotEmpty } // Remove the directory - root := path.Join(f.root, dir) + root := path.Join(f.absRoot, dir) c, err := f.getSftpConnection() if err != nil { return errors.Wrap(err, "Rmdir") @@ -762,7 +774,7 @@ func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, } err = c.sftpClient.Rename( srcObj.path(), - path.Join(f.root, remote), + path.Join(f.absRoot, remote), ) f.putSftpConnection(&c, err) if err != nil { @@ -789,8 +801,8 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string fs.Debugf(srcFs, "Can't move directory - not same remote type") return fs.ErrorCantDirMove } - srcPath := path.Join(srcFs.root, srcRemote) - dstPath := path.Join(f.root, dstRemote) + srcPath := path.Join(srcFs.absRoot, srcRemote) + dstPath := path.Join(f.absRoot, dstRemote) // Check if destination exists ok, err := f.dirExists(dstPath) @@ -1076,7 +1088,7 @@ func (o *Object) ModTime(ctx context.Context) time.Time { // path returns the native path of the object func (o *Object) path() string { - return path.Join(o.fs.root, o.remote) + return path.Join(o.fs.absRoot, o.remote) } // setMetadata updates the info in the object from the stat result passed in @@ -1092,7 +1104,7 @@ func (f *Fs) stat(remote string) (info os.FileInfo, err error) { if err != nil { return nil, errors.Wrap(err, "stat") } - absPath := path.Join(f.root, remote) + absPath := path.Join(f.absRoot, remote) info, err = c.sftpClient.Stat(absPath) f.putSftpConnection(&c, err) return info, err