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

Merge pull request #626 from rfjakob/master

Add "-x", "--one-file-system" option
This commit is contained in:
Alexander Neumann 2016-09-18 20:03:58 +02:00
commit 0a9cbd47c7
3 changed files with 93 additions and 8 deletions

View File

@ -22,6 +22,7 @@ type CmdBackup struct {
Parent string `short:"p" long:"parent" description:"use this parent snapshot (default: last snapshot in repo that has the same target)"` 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"` 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)"` 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"` ExcludeFile string `long:"exclude-file" description:"Read exclude-patterns from file"`
Stdin bool `long:"stdin" description:"read backup data from stdin"` 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"` StdinFilename string `long:"stdin-filename" default:"stdin" description:"file name to use when reading from stdin"`
@ -239,6 +240,27 @@ func filterExisting(items []string) (result []string, err error) {
return 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 { func (cmd CmdBackup) readFromStdin(args []string) error {
if len(args) != 0 { if len(args) != 0 {
return errors.Fatalf("when reading from stdin, no additional files can be specified") 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 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() repo, err := cmd.global.OpenRepository()
if err != nil { if err != nil {
return err return err
@ -361,9 +393,26 @@ func (cmd CmdBackup) Execute(args []string) error {
if matched { if matched {
debug.Log("backup.Execute", "path %q excluded by a filter", item) 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()) stat, err := archiver.Scan(target, selectFilter, cmd.newScanProgress())

View 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")
}

View 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")
}