diff --git a/mountinfo/mountinfo_filters.go b/mountinfo/mountinfo_filters.go index 16079c3c..037f47ba 100644 --- a/mountinfo/mountinfo_filters.go +++ b/mountinfo/mountinfo_filters.go @@ -23,7 +23,7 @@ type FilterFunc func(*Info) (skip, stop bool) // "/foo" and "/foo/bar", and discards "/foobar". func PrefixFilter(prefix string) FilterFunc { return func(m *Info) (bool, bool) { - skip := !strings.HasPrefix(m.Mountpoint+"/", prefix+"/") + skip := prefix != "/" && !strings.HasPrefix(m.Mountpoint+"/", prefix+"/") return skip, false } } @@ -40,12 +40,16 @@ func SingleEntryFilter(mp string) FilterFunc { // ParentsFilter returns all entries whose mount points // can be parents of a path specified, discarding others. +// The path must be absolute, have all symlinks resolved, +// and cleaned (i.e. no extra slashes or dots). // // For example, given /var/lib/docker/something, entries -// like /var/lib/docker, /var and / are returned. +// like /var/lib/docker, /var and / are returned, while +// /var/lib/dock is discarded. func ParentsFilter(path string) FilterFunc { return func(m *Info) (bool, bool) { - skip := !strings.HasPrefix(path, m.Mountpoint) + mp := m.Mountpoint + skip := mp != "/" && mp != path && !strings.HasPrefix(path, mp+"/") return skip, false } } diff --git a/mountinfo/mountinfo_filters_test.go b/mountinfo/mountinfo_filters_test.go index cf5b35e0..ade53ed1 100644 --- a/mountinfo/mountinfo_filters_test.go +++ b/mountinfo/mountinfo_filters_test.go @@ -12,6 +12,9 @@ func TestPrefixFilter(t *testing.T) { {prefix: "/a", mountPoint: "/a/b", shouldSkip: false}, {prefix: "/a", mountPoint: "/aa", shouldSkip: true}, {prefix: "/a", mountPoint: "/aa/b", shouldSkip: true}, + {prefix: "/", mountPoint: "/", shouldSkip: false}, + {prefix: "/", mountPoint: "/a", shouldSkip: false}, + {prefix: "/", mountPoint: "/a/b", shouldSkip: false}, // invalid prefix: prefix path must be cleaned and have no trailing slash {prefix: "/a/", mountPoint: "/a", shouldSkip: true}, @@ -29,3 +32,32 @@ func TestPrefixFilter(t *testing.T) { } } } + +func TestParentsFilter(t *testing.T) { + tests := []struct { + path string + mountPoint string + shouldSkip bool + }{ + {path: "/a/b", mountPoint: "/", shouldSkip: false}, + {path: "/a/b", mountPoint: "/a", shouldSkip: false}, + {path: "/a/b", mountPoint: "/a/b", shouldSkip: false}, + {path: "/a/b", mountPoint: "/a/b/c", shouldSkip: true}, + {path: "/a/b", mountPoint: "/b", shouldSkip: true}, + {path: "/aa", mountPoint: "/a", shouldSkip: true}, + {path: "/a/bb", mountPoint: "/a/b", shouldSkip: true}, + {path: "/", mountPoint: "/", shouldSkip: false}, + {path: "/", mountPoint: "/a", shouldSkip: true}, + } + for _, tc := range tests { + filter := ParentsFilter(tc.path) + skip, _ := filter(&Info{Mountpoint: tc.mountPoint}) + if skip != tc.shouldSkip { + if tc.shouldSkip { + t.Errorf("path %q: expected %q to be skipped", tc.path, tc.mountPoint) + } else { + t.Errorf("path %q: expected %q not to be skipped", tc.path, tc.mountPoint) + } + } + } +}