Skip to content

Commit dbd468b

Browse files
committed
mountinfo: Mounted: normalize path, return ENOENT
1. In case the argument does not exist, Mounted now returns an appropriate error. Previously, this condition was treated as "not a mount point", with no error returned, but in fact such path could be a mount point, overshadowed by another mount. Since the mount is still unreachable, it can not be unmounted anyway, so we do not fall back to mountedByMountinfo, returning an error instead. In case callers are not interested in ENOENT, they should filter it out. Amend the function doc accordingly. 2. There are some corner cases in which mountedByOpenat2 or mountedByStat do not work properly. In particular, - neither work if there's an ending slash; - neither work for a symlink to a mounted directory; - mountedByStat do not work a parent of path is a symlink residing on different filesystem. To solve these cases, we have to call normalizePath() before path is used for any of mountedBy* functions, not just before mountedByMountinfo like it was done earlier. More tests are to be added by the next commit. Signed-off-by: Kir Kolyshkin <[email protected]>
1 parent 1bcc0b1 commit dbd468b

4 files changed

Lines changed: 12 additions & 18 deletions

File tree

mountinfo/mounted_linux.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ func mountedByOpenat2(path string) (bool, error) {
1616
Flags: unix.O_PATH | unix.O_CLOEXEC,
1717
})
1818
if err != nil {
19-
if err == unix.ENOENT { // not a mount
20-
return false, nil
21-
}
2219
return false, &os.PathError{Op: "openat2", Path: dir, Err: err}
2320
}
2421
fd, err := unix.Openat2(dirfd, last, &unix.OpenHow{
@@ -32,14 +29,16 @@ func mountedByOpenat2(path string) (bool, error) {
3229
return false, nil
3330
case unix.EXDEV: // definitely a mount
3431
return true, nil
35-
case unix.ENOENT: // not a mount
36-
return false, nil
3732
}
3833
// not sure
3934
return false, &os.PathError{Op: "openat2", Path: path, Err: err}
4035
}
4136

4237
func mounted(path string) (bool, error) {
38+
path, err := normalizePath(path)
39+
if err != nil {
40+
return false, err
41+
}
4342
// Try a fast path, using openat2() with RESOLVE_NO_XDEV.
4443
mounted, err := mountedByOpenat2(path)
4544
if err == nil {

mountinfo/mounted_unix.go

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package mountinfo
55

66
import (
7-
"errors"
87
"fmt"
98
"os"
109
"path/filepath"
@@ -16,10 +15,6 @@ func mountedByStat(path string) (bool, error) {
1615
var st unix.Stat_t
1716

1817
if err := unix.Lstat(path, &st); err != nil {
19-
if err == unix.ENOENT {
20-
// Treat ENOENT as "not mounted".
21-
return false, nil
22-
}
2318
return false, &os.PathError{Op: "stat", Path: path, Err: err}
2419
}
2520
dev := st.Dev
@@ -50,14 +45,6 @@ func normalizePath(path string) (realPath string, err error) {
5045
}
5146

5247
func mountedByMountinfo(path string) (bool, error) {
53-
path, err := normalizePath(path)
54-
if err != nil {
55-
if errors.Is(err, unix.ENOENT) {
56-
// treat ENOENT as "not mounted"
57-
return false, nil
58-
}
59-
return false, err
60-
}
6148
entries, err := GetMounts(SingleEntryFilter(path))
6249
if err != nil {
6350
return false, err

mountinfo/mountinfo.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ func GetMounts(f FilterFunc) ([]*Info, error) {
1111
}
1212

1313
// Mounted determines if a specified path is a mount point.
14+
//
15+
// The non-existent path returns an error. If a caller is not interested
16+
// in this particular error, it should handle it separately using e.g.
17+
// errors.Is(err, os.ErrNotExist).
1418
func Mounted(path string) (bool, error) {
1519
// root is always mounted
1620
if path == string(os.PathSeparator) {

mountinfo/mountinfo_bsd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ func parseMountTable(filter FilterFunc) ([]*Info, error) {
5656
}
5757

5858
func mounted(path string) (bool, error) {
59+
path, err := normalizePath(path)
60+
if err != nil {
61+
return false, err
62+
}
5963
// Fast path: compare st.st_dev fields.
6064
// This should always work for FreeBSD and OpenBSD.
6165
mounted, err := mountedByStat(path)

0 commit comments

Comments
 (0)