2
2
mirror of https://github.com/octoleo/restic.git synced 2025-01-11 02:08:44 +00:00

sftp: first step of conversion to Layout

This commit is contained in:
Alexander Neumann 2017-04-10 22:17:50 +02:00
parent a849edf19a
commit 42ea4d257b
3 changed files with 59 additions and 55 deletions

View File

@ -134,7 +134,7 @@ func Open(cfg Config) (*SFTP, error) {
return nil, err return nil, err
} }
l, err := backend.ParseLayout(sftp, cfg.Layout, defaultLayout, cfg.Path) sftp.Layout, err = backend.ParseLayout(sftp, cfg.Layout, defaultLayout, cfg.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -146,6 +146,8 @@ func Open(cfg Config) (*SFTP, error) {
} }
} }
debug.Log("layout: %v\n", sftp.Layout)
sftp.Config = cfg sftp.Config = cfg
sftp.p = cfg.Path sftp.p = cfg.Path
return sftp, nil return sftp, nil
@ -161,6 +163,16 @@ func (r *SFTP) ReadDir(dir string) ([]os.FileInfo, error) {
return r.c.ReadDir(dir) return r.c.ReadDir(dir)
} }
// IsNotExist returns true if the error is caused by a not existing file.
func (r *SFTP) IsNotExist(err error) bool {
statusError, ok := err.(*sftp.StatusError)
if !ok {
return false
}
return statusError.Error() == `sftp: "No such file" (SSH_FX_NO_SUCH_FILE)`
}
func buildSSHCommand(cfg Config) (cmd string, args []string, err error) { func buildSSHCommand(cfg Config) (cmd string, args []string, err error) {
if cfg.Command != "" { if cfg.Command != "" {
return SplitShellArgs(cfg.Command) return SplitShellArgs(cfg.Command)
@ -184,7 +196,7 @@ func buildSSHCommand(cfg Config) (cmd string, args []string, err error) {
// Create creates an sftp backend as described by the config by running // Create creates an sftp backend as described by the config by running
// "ssh" with the appropriate arguments (or cfg.Command, if set). // "ssh" with the appropriate arguments (or cfg.Command, if set).
func create(cfg Config) (*SFTP, error) { func Create(cfg Config) (*SFTP, error) {
cmd, args, err := buildSSHCommand(cfg) cmd, args, err := buildSSHCommand(cfg)
if err != nil { if err != nil {
return nil, err return nil, err
@ -196,7 +208,7 @@ func create(cfg Config) (*SFTP, error) {
return nil, err return nil, err
} }
l, err := backend.ParseLayout(sftp, cfg.Layout, defaultLayout, cfg.Path) sftp.Layout, err = backend.ParseLayout(sftp, cfg.Layout, defaultLayout, cfg.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -351,14 +363,22 @@ func (r *SFTP) Save(h restic.Handle, rd io.Reader) (err error) {
} }
} }
// test if new file exists // create new file
if _, err := r.c.Lstat(filename); err == nil { f, err := r.c.OpenFile(filename, os.O_CREATE|os.O_EXCL|os.O_WRONLY)
return errors.Errorf("Close(): file %v already exists", filename) if err != nil {
return errors.Wrap(err, "OpenFile")
} }
err := r.c.Rename(oldname, filename) // save data
_, err = io.Copy(f, rd)
if err != nil { if err != nil {
return errors.Wrap(err, "Rename") f.Close()
return errors.Wrap(err, "Write")
}
err = f.Close()
if err != nil {
return errors.Wrap(err, "Close")
} }
// set mode to read-only // set mode to read-only
@ -369,28 +389,6 @@ func (r *SFTP) Save(h restic.Handle, rd io.Reader) (err error) {
err = r.c.Chmod(filename, fi.Mode()&os.FileMode(^uint32(0222))) err = r.c.Chmod(filename, fi.Mode()&os.FileMode(^uint32(0222)))
return errors.Wrap(err, "Chmod") return errors.Wrap(err, "Chmod")
filename, tmpfile, err := r.tempFile()
if err != nil {
return err
}
n, err := io.Copy(tmpfile, rd)
if err != nil {
return errors.Wrap(err, "Write")
}
debug.Log("saved %v (%d bytes) to %v", h, n, filename)
err = tmpfile.Close()
if err != nil {
return errors.Wrap(err, "Close")
}
err = r.renameFile(filename, h)
debug.Log("save %v: rename %v: %v",
h, path.Base(filename), err)
return err
} }
// Load returns a reader that yields the contents of the file at h at the // Load returns a reader that yields the contents of the file at h at the

View File

@ -61,7 +61,7 @@ func init() {
return nil, err return nil, err
} }
cfg.Dir = tempBackendDir cfg.Path = tempBackendDir
return sftp.Create(cfg) return sftp.Create(cfg)
} }
@ -72,7 +72,7 @@ func init() {
return nil, err return nil, err
} }
cfg.Dir = tempBackendDir cfg.Path = tempBackendDir
return sftp.Open(cfg) return sftp.Open(cfg)
} }

View File

@ -1,46 +1,52 @@
package sftp package sftp
import "testing" import (
"reflect"
"testing"
)
var sshcmdTests = []struct { var sshcmdTests = []struct {
cfg Config cfg Config
s []string cmd string
args []string
}{ }{
{ {
Config{User: "user", Host: "host", Dir: "dir/subdir"}, Config{User: "user", Host: "host", Path: "dir/subdir"},
"ssh",
[]string{"host", "-l", "user", "-s", "sftp"}, []string{"host", "-l", "user", "-s", "sftp"},
}, },
{ {
Config{Host: "host", Dir: "dir/subdir"}, Config{Host: "host", Path: "dir/subdir"},
"ssh",
[]string{"host", "-s", "sftp"}, []string{"host", "-s", "sftp"},
}, },
{ {
Config{Host: "host:10022", Dir: "/dir/subdir"}, Config{Host: "host:10022", Path: "/dir/subdir"},
"ssh",
[]string{"host", "-p", "10022", "-s", "sftp"}, []string{"host", "-p", "10022", "-s", "sftp"},
}, },
{ {
Config{User: "user", Host: "host:10022", Dir: "/dir/subdir"}, Config{User: "user", Host: "host:10022", Path: "/dir/subdir"},
"ssh",
[]string{"host", "-p", "10022", "-l", "user", "-s", "sftp"}, []string{"host", "-p", "10022", "-l", "user", "-s", "sftp"},
}, },
} }
func TestBuildSSHCommand(t *testing.T) { func TestBuildSSHCommand(t *testing.T) {
for i, test := range sshcmdTests { for _, test := range sshcmdTests {
cmd := buildSSHCommand(test.cfg) t.Run("", func(t *testing.T) {
failed := false cmd, args, err := buildSSHCommand(test.cfg)
if len(cmd) != len(test.s) { if err != nil {
failed = true t.Fatal(err)
} else {
for l := range test.s {
if test.s[l] != cmd[l] {
failed = true
break
}
} }
}
if failed { if cmd != test.cmd {
t.Errorf("test %d: wrong cmd, want:\n %v\ngot:\n %v", t.Fatalf("cmd: want %v, got %v", test.cmd, cmd)
i, test.s, cmd) }
}
if !reflect.DeepEqual(test.args, args) {
t.Fatalf("wrong args, want:\n %v\ngot:\n %v", test.args, args)
}
})
} }
} }