Refactor device ID checking
This commit is contained in:
parent
9a97095a4c
commit
037f0a4c91
1 changed files with 53 additions and 28 deletions
|
@ -199,12 +199,17 @@ func isDirExcludedByFile(dir, tagFilename, header string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// gatherDevices returns the set of unique device ids of the files and/or
|
||||
// directory paths listed in "items".
|
||||
func gatherDevices(items []string) (deviceMap map[string]uint64, err error) {
|
||||
deviceMap = make(map[string]uint64)
|
||||
for _, item := range items {
|
||||
item, err = filepath.Abs(filepath.Clean(item))
|
||||
// DeviceMap is used to track allowed source devices for backup. This is used to
|
||||
// check for crossing mount points during backup (for --one-file-system). It
|
||||
// maps the name of a source path to its device ID.
|
||||
type DeviceMap map[string]uint64
|
||||
|
||||
// NewDeviceMap creates a new device map from the list of source paths.
|
||||
func NewDeviceMap(allowedSourcePaths []string) (DeviceMap, error) {
|
||||
deviceMap := make(map[string]uint64)
|
||||
|
||||
for _, item := range allowedSourcePaths {
|
||||
item, err := filepath.Abs(filepath.Clean(item))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -213,30 +218,63 @@ func gatherDevices(items []string) (deviceMap map[string]uint64, err error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, err := fs.DeviceID(fi)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deviceMap[item] = id
|
||||
}
|
||||
|
||||
if len(deviceMap) == 0 {
|
||||
return nil, errors.New("zero allowed devices")
|
||||
}
|
||||
|
||||
return deviceMap, nil
|
||||
}
|
||||
|
||||
// IsAllowed returns true if the path is located on an allowed device.
|
||||
func (m DeviceMap) IsAllowed(item string, deviceID uint64) (bool, error) {
|
||||
for dir := item; ; dir = filepath.Dir(dir) {
|
||||
debug.Log("item %v, test dir %v", item, dir)
|
||||
|
||||
// find a parent directory that is on an allowed device (otherwise
|
||||
// we would not traverse the directory at all)
|
||||
allowedID, ok := m[dir]
|
||||
if !ok {
|
||||
if dir == filepath.Dir(dir) {
|
||||
// arrived at root, no allowed device found. this should not happen.
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// if the item has a different device ID than the parent directory,
|
||||
// we crossed a file system boundary
|
||||
if allowedID != deviceID {
|
||||
debug.Log("item %v (dir %v) on disallowed device %d", item, dir, deviceID)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// item is on allowed device, accept it
|
||||
debug.Log("item %v allowed", item)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("item %v (device ID %v) not found, deviceMap: %v", item, deviceID, m)
|
||||
}
|
||||
|
||||
// rejectByDevice returns a RejectFunc that rejects files which are on a
|
||||
// different file systems than the files/dirs in samples.
|
||||
func rejectByDevice(samples []string) (RejectFunc, error) {
|
||||
allowed, err := gatherDevices(samples)
|
||||
deviceMap, err := NewDeviceMap(samples)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
debug.Log("allowed devices: %v\n", allowed)
|
||||
debug.Log("allowed devices: %v\n", deviceMap)
|
||||
|
||||
return func(item string, fi os.FileInfo) bool {
|
||||
item = filepath.Clean(item)
|
||||
|
||||
id, err := fs.DeviceID(fi)
|
||||
if err != nil {
|
||||
// This should never happen because gatherDevices() would have
|
||||
|
@ -244,26 +282,13 @@ func rejectByDevice(samples []string) (RejectFunc, error) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
for dir := item; ; dir = filepath.Dir(dir) {
|
||||
debug.Log("item %v, test dir %v", item, dir)
|
||||
|
||||
allowedID, ok := allowed[dir]
|
||||
if !ok {
|
||||
if dir == filepath.Dir(dir) {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if allowedID != id {
|
||||
debug.Log("path %q on disallowed device %d", item, id)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
allowed, err := deviceMap.IsAllowed(filepath.Clean(item), id)
|
||||
if err != nil {
|
||||
// this should not happen
|
||||
panic(fmt.Sprintf("error checking device ID of %v: %v", item, err))
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("item %v, device id %v not found, allowedDevs: %v", item, id, allowed))
|
||||
return !allowed
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue