mirror of
https://github.com/octoleo/restic.git
synced 2024-11-26 14:56:29 +00:00
sftp: Add Layout
This commit is contained in:
parent
2e53af1b75
commit
ab602c9d14
@ -11,6 +11,7 @@ import (
|
||||
// Config collects all information required to connect to an sftp server.
|
||||
type Config struct {
|
||||
User, Host, Dir string
|
||||
Layout string `option:"layout"`
|
||||
Command string `option:"command"`
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,6 @@ package sftp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@ -32,10 +30,14 @@ type SFTP struct {
|
||||
|
||||
cmd *exec.Cmd
|
||||
result <-chan error
|
||||
|
||||
backend.Layout
|
||||
}
|
||||
|
||||
var _ restic.Backend = &SFTP{}
|
||||
|
||||
const defaultLayout = "default"
|
||||
|
||||
func startClient(program string, args ...string) (*SFTP, error) {
|
||||
debug.Log("start client %v %v", program, args)
|
||||
// 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
|
||||
}
|
||||
|
||||
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
|
||||
for _, d := range paths(dir) {
|
||||
if _, err := sftp.c.Lstat(d); err != nil {
|
||||
@ -225,28 +232,6 @@ func (r *SFTP) Location() string {
|
||||
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 {
|
||||
// check if directory already exists
|
||||
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.
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -358,6 +343,35 @@ func (r *SFTP) Save(h restic.Handle, rd io.Reader) (err error) {
|
||||
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()
|
||||
if err != nil {
|
||||
return err
|
||||
|
Loading…
Reference in New Issue
Block a user