2
2
mirror of https://github.com/octoleo/restic.git synced 2024-11-26 23:06:32 +00:00

sftp: Add Layout

This commit is contained in:
Alexander Neumann 2017-04-10 22:40:24 +02:00
parent 2e53af1b75
commit ab602c9d14
2 changed files with 40 additions and 25 deletions

View File

@ -11,6 +11,7 @@ import (
// Config collects all information required to connect to an sftp server. // Config collects all information required to connect to an sftp server.
type Config struct { type Config struct {
User, Host, Dir string User, Host, Dir string
Layout string `option:"layout"`
Command string `option:"command"` Command string `option:"command"`
} }

View File

@ -2,8 +2,6 @@ package sftp
import ( import (
"bufio" "bufio"
"crypto/rand"
"encoding/hex"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -32,10 +30,14 @@ type SFTP struct {
cmd *exec.Cmd cmd *exec.Cmd
result <-chan error result <-chan error
backend.Layout
} }
var _ restic.Backend = &SFTP{} var _ restic.Backend = &SFTP{}
const defaultLayout = "default"
func startClient(program string, args ...string) (*SFTP, error) { func startClient(program string, args ...string) (*SFTP, error) {
debug.Log("start client %v %v", program, args) debug.Log("start client %v %v", program, args)
// Connect to a remote host and request the sftp subsystem via the 'ssh' // Connect to a remote host and request the sftp subsystem via the 'ssh'
@ -127,6 +129,11 @@ func open(dir string, program string, args ...string) (*SFTP, error) {
return nil, err return nil, err
} }
l, err := backend.ParseLayout(sftp, cfg.Layout, defaultLayout, cfg.Path)
if err != nil {
return nil, err
}
// test if all necessary dirs and files are there // test if all necessary dirs and files are there
for _, d := range paths(dir) { for _, d := range paths(dir) {
if _, err := sftp.c.Lstat(d); err != nil { if _, err := sftp.c.Lstat(d); err != nil {
@ -225,28 +232,6 @@ func (r *SFTP) Location() string {
return r.p return r.p
} }
// Return temp directory in correct directory for this backend.
func (r *SFTP) tempFile() (string, *sftp.File, error) {
// choose random suffix
buf := make([]byte, tempfileRandomSuffixLength)
_, err := io.ReadFull(rand.Reader, buf)
if err != nil {
return "", nil, errors.Errorf("unable to read %d random bytes for tempfile name: %v",
tempfileRandomSuffixLength, err)
}
// construct tempfile name
name := Join(r.p, backend.Paths.Temp, "temp-"+hex.EncodeToString(buf))
// create file in temp dir
f, err := r.c.Create(name)
if err != nil {
return "", nil, errors.Errorf("creating tempfile %q failed: %v", name, err)
}
return name, f, nil
}
func (r *SFTP) mkdirAll(dir string, mode os.FileMode) error { func (r *SFTP) mkdirAll(dir string, mode os.FileMode) error {
// check if directory already exists // check if directory already exists
fi, err := r.c.Lstat(dir) fi, err := r.c.Lstat(dir)
@ -349,7 +334,7 @@ func (r *SFTP) dirname(h restic.Handle) string {
// Save stores data in the backend at the handle. // Save stores data in the backend at the handle.
func (r *SFTP) Save(h restic.Handle, rd io.Reader) (err error) { func (r *SFTP) Save(h restic.Handle, rd io.Reader) (err error) {
debug.Log("save to %v", h) debug.Log("Save %v", h)
if err := r.clientError(); err != nil { if err := r.clientError(); err != nil {
return err return err
} }
@ -358,6 +343,35 @@ func (r *SFTP) Save(h restic.Handle, rd io.Reader) (err error) {
return err return err
} }
filename := r.Filename(h)
// create directories if necessary
if h.Type == restic.DataFile {
err := r.mkdirAll(path.Dir(filename), backend.Modes.Dir)
if err != nil {
return err
}
}
// test if new file exists
if _, err := r.c.Lstat(filename); err == nil {
return errors.Errorf("Close(): file %v already exists", filename)
}
err := r.c.Rename(oldname, filename)
if err != nil {
return errors.Wrap(err, "Rename")
}
// set mode to read-only
fi, err := r.c.Lstat(filename)
if err != nil {
return errors.Wrap(err, "Lstat")
}
err = r.c.Chmod(filename, fi.Mode()&os.FileMode(^uint32(0222)))
return errors.Wrap(err, "Chmod")
filename, tmpfile, err := r.tempFile() filename, tmpfile, err := r.tempFile()
if err != nil { if err != nil {
return err return err