forked from TrueCloudLab/restic
Add "-x", "--one-file-system" option
Equivalent to rsync's "-x" option. Notes to the naming: "--exclude-other-filesystems" is used by Duplicity, "--one-file-system" is used rsync and tar. This latter should be more familiar to the user.
This commit is contained in:
parent
7b3e319398
commit
53701891a1
3 changed files with 93 additions and 8 deletions
|
@ -19,13 +19,14 @@ import (
|
|||
)
|
||||
|
||||
type CmdBackup struct {
|
||||
Parent string `short:"p" long:"parent" description:"use this parent snapshot (default: last snapshot in repo that has the same target)"`
|
||||
Force bool `short:"f" long:"force" description:"Force re-reading the target. Overrides the \"parent\" flag"`
|
||||
Excludes []string `short:"e" long:"exclude" description:"Exclude a pattern (can be specified multiple times)"`
|
||||
ExcludeFile string `long:"exclude-file" description:"Read exclude-patterns from file"`
|
||||
Stdin bool `long:"stdin" description:"read backup data from stdin"`
|
||||
StdinFilename string `long:"stdin-filename" default:"stdin" description:"file name to use when reading from stdin"`
|
||||
Tags []string `long:"tag" description:"Add a tag (can be specified multiple times)"`
|
||||
Parent string `short:"p" long:"parent" description:"use this parent snapshot (default: last snapshot in repo that has the same target)"`
|
||||
Force bool `short:"f" long:"force" description:"Force re-reading the target. Overrides the \"parent\" flag"`
|
||||
Excludes []string `short:"e" long:"exclude" description:"Exclude a pattern (can be specified multiple times)"`
|
||||
ExcludeOtherFS bool `short:"x" long:"one-file-system" description:"Exclude other file systems"`
|
||||
ExcludeFile string `long:"exclude-file" description:"Read exclude-patterns from file"`
|
||||
Stdin bool `long:"stdin" description:"read backup data from stdin"`
|
||||
StdinFilename string `long:"stdin-filename" default:"stdin" description:"file name to use when reading from stdin"`
|
||||
Tags []string `long:"tag" description:"Add a tag (can be specified multiple times)"`
|
||||
|
||||
global *GlobalOptions
|
||||
}
|
||||
|
@ -239,6 +240,27 @@ func filterExisting(items []string) (result []string, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// gatherDevices returns the set of unique device ids of the files and/or
|
||||
// directory paths listed in "items".
|
||||
func gatherDevices(items []string) (deviceMap map[uint64]struct{}, err error) {
|
||||
deviceMap = make(map[uint64]struct{})
|
||||
for _, item := range items {
|
||||
fi, err := fs.Lstat(item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := fs.DeviceID(fi)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deviceMap[id] = struct{}{}
|
||||
}
|
||||
if len(deviceMap) == 0 {
|
||||
return nil, errors.New("zero allowed devices")
|
||||
}
|
||||
return deviceMap, nil
|
||||
}
|
||||
|
||||
func (cmd CmdBackup) readFromStdin(args []string) error {
|
||||
if len(args) != 0 {
|
||||
return errors.Fatalf("when reading from stdin, no additional files can be specified")
|
||||
|
@ -291,6 +313,16 @@ func (cmd CmdBackup) Execute(args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// allowed devices
|
||||
var allowedDevs map[uint64]struct{}
|
||||
if cmd.ExcludeOtherFS {
|
||||
allowedDevs, err = gatherDevices(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
debug.Log("backup.Execute", "allowed devices: %v\n", allowedDevs)
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -361,9 +393,26 @@ func (cmd CmdBackup) Execute(args []string) error {
|
|||
|
||||
if matched {
|
||||
debug.Log("backup.Execute", "path %q excluded by a filter", item)
|
||||
return false
|
||||
}
|
||||
|
||||
return !matched
|
||||
if !cmd.ExcludeOtherFS {
|
||||
return true
|
||||
}
|
||||
|
||||
id, err := fs.DeviceID(fi)
|
||||
if err != nil {
|
||||
// This should never happen because gatherDevices() would have
|
||||
// errored out earlier. If it still does that's a reason to panic.
|
||||
panic(err)
|
||||
}
|
||||
_, found := allowedDevs[id]
|
||||
if !found {
|
||||
debug.Log("backup.Execute", "path %q on disallowed device %d", item, id)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
stat, err := archiver.Scan(target, selectFilter, cmd.newScanProgress())
|
||||
|
|
21
src/restic/fs/deviceid_unix.go
Normal file
21
src/restic/fs/deviceid_unix.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
// +build !windows
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"restic/errors"
|
||||
)
|
||||
|
||||
// DeviceID extracts the device ID from an os.FileInfo object by casting it
|
||||
// to syscall.Stat_t
|
||||
func DeviceID(fi os.FileInfo) (deviceID uint64, err error) {
|
||||
if st, ok := fi.Sys().(*syscall.Stat_t); ok {
|
||||
// st.Dev is uint32 on Darwin and uint64 on Linux. Just cast
|
||||
// everything to uint64.
|
||||
return uint64(st.Dev), nil
|
||||
}
|
||||
return 0, errors.New("Could not cast to syscall.Stat_t")
|
||||
}
|
15
src/restic/fs/deviceid_windows.go
Normal file
15
src/restic/fs/deviceid_windows.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
// +build windows
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"restic/errors"
|
||||
)
|
||||
|
||||
// DeviceID extracts the device ID from an os.FileInfo object by casting it
|
||||
// to syscall.Stat_t
|
||||
func DeviceID(fi os.FileInfo) (deviceID uint64, err error) {
|
||||
return 0, errors.New("Device IDs are not supported on Windows")
|
||||
}
|
Loading…
Reference in a new issue