From 32b8cf375d25cdfea611b9c2da381d6d785dd856 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 18 Sep 2020 21:03:12 +0200 Subject: [PATCH 1/2] Some refactor and improved GoDoc about Windows support Signed-off-by: Sebastiaan van Stijn --- mount/mount.go | 53 ++++++------------------------------ mount/unmount_unix.go | 50 +++++++++++++++++++++++++++++++--- mount/unmount_unsupported.go | 2 +- 3 files changed, 55 insertions(+), 50 deletions(-) diff --git a/mount/mount.go b/mount/mount.go index 4a7bb27b..ac8808cc 100644 --- a/mount/mount.go +++ b/mount/mount.go @@ -2,23 +2,20 @@ package mount -import ( - "fmt" - "sort" - - "github.com/moby/sys/mountinfo" -) - // Mount will mount filesystem according to the specified configuration. // Options must be specified like the mount or fstab unix commands: // "opt1=val1,opt2=val2". See flags.go for supported option flags. +// +// Mount is not implemented on Windows. func Mount(device, target, mType, options string) error { flag, data := parseOptions(options) return mount(device, target, mType, uintptr(flag), data) } // Unmount lazily unmounts a filesystem on supported platforms, otherwise does -// a normal unmount. If target is not a mount point, no error is returned. +// a normal unmount. If target is not a mount point, no error is returned. +// +// Unmount is not implemented on Windows. func Unmount(target string) error { return unmount(target, mntDetach) } @@ -26,42 +23,8 @@ func Unmount(target string) error { // RecursiveUnmount unmounts the target and all mounts underneath, starting // with the deepest mount first. The argument does not have to be a mount // point itself. +// +// RecursiveUnmount is not implemented on Windows. func RecursiveUnmount(target string) error { - // Fast path, works if target is a mount point that can be unmounted. - // On Linux, mntDetach flag ensures a recursive unmount. For other - // platforms, if there are submounts, we'll get EBUSY (and fall back - // to the slow path). NOTE we do not ignore EINVAL here as target might - // not be a mount point itself (but there can be mounts underneath). - if err := unmountBare(target, mntDetach); err == nil { - return nil - } - - // Slow path: get all submounts, sort, unmount one by one. - mounts, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target)) - if err != nil { - return err - } - - // Make the deepest mount be first - sort.Slice(mounts, func(i, j int) bool { - return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint) - }) - - var suberr error - for i, m := range mounts { - err = unmount(m.Mountpoint, mntDetach) - if err != nil { - if i == len(mounts)-1 { // last mount - return fmt.Errorf("%w (possible cause: %s)", err, suberr) - } - // This is a submount, we can ignore the error for now, - // the final unmount will fail if this is a real problem. - // With that in mind, the _first_ failed unmount error - // might be the real error cause, so let's keep it. - if suberr == nil { - suberr = err - } - } - } - return nil + return recursiveUnmount(target) } diff --git a/mount/unmount_unix.go b/mount/unmount_unix.go index 924d059a..1616cf4a 100644 --- a/mount/unmount_unix.go +++ b/mount/unmount_unix.go @@ -2,14 +2,56 @@ package mount -import "golang.org/x/sys/unix" +import ( + "fmt" + "sort" -func unmountBare(target string, flags int) error { - return unix.Unmount(target, flags) + "github.com/moby/sys/mountinfo" + "golang.org/x/sys/unix" +) + +func recursiveUnmount(target string) error { + // Fast path, works if target is a mount point that can be unmounted. + // On Linux, mntDetach flag ensures a recursive unmount. For other + // platforms, if there are submounts, we'll get EBUSY (and fall back + // to the slow path). NOTE we do not ignore EINVAL here as target might + // not be a mount point itself (but there can be mounts underneath). + if err := unix.Unmount(target, mntDetach); err == nil { + return nil + } + + // Slow path: get all submounts, sort, unmount one by one. + mounts, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target)) + if err != nil { + return err + } + + // Make the deepest mount be first + sort.Slice(mounts, func(i, j int) bool { + return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint) + }) + + var suberr error + for i, m := range mounts { + err = unmount(m.Mountpoint, mntDetach) + if err != nil { + if i == len(mounts)-1 { // last mount + return fmt.Errorf("%w (possible cause: %s)", err, suberr) + } + // This is a submount, we can ignore the error for now, + // the final unmount will fail if this is a real problem. + // With that in mind, the _first_ failed unmount error + // might be the real error cause, so let's keep it. + if suberr == nil { + suberr = err + } + } + } + return nil } func unmount(target string, flags int) error { - err := unmountBare(target, flags) + err := unix.Unmount(target, flags) if err == nil || err == unix.EINVAL { // Ignore "not mounted" error here. Note the same error // can be returned if flags are invalid, so this code diff --git a/mount/unmount_unsupported.go b/mount/unmount_unsupported.go index 4d6073ec..94cfb9d5 100644 --- a/mount/unmount_unsupported.go +++ b/mount/unmount_unsupported.go @@ -2,7 +2,7 @@ package mount -func unmountBare(_ string, _ int) error { +func recursiveUnmount(_ string) error { panic("Not implemented") } From 7a521626bc899dcb685cdebdfcaa88cd535d2e5e Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 1 Oct 2020 18:00:03 +0200 Subject: [PATCH 2/2] mount: remove Windows stubs Signed-off-by: Sebastiaan van Stijn --- mount/doc.go | 5 +++ mount/{flags.go => flags_unix.go} | 2 + mount/flags_unsupported.go | 30 -------------- mount/mount.go | 30 -------------- mount/{unmount_unix.go => mount_unix.go} | 53 +++++++++++++++--------- mount/mounter_freebsd.go | 2 + mount/mounter_unsupported.go | 4 +- mount/sharedsubtree_linux_test.go | 2 +- mount/unmount_unsupported.go | 11 ----- 9 files changed, 45 insertions(+), 94 deletions(-) create mode 100644 mount/doc.go rename mount/{flags.go => flags_unix.go} (99%) delete mode 100644 mount/flags_unsupported.go delete mode 100644 mount/mount.go rename mount/{unmount_unix.go => mount_unix.go} (64%) delete mode 100644 mount/unmount_unsupported.go diff --git a/mount/doc.go b/mount/doc.go new file mode 100644 index 00000000..b8108d85 --- /dev/null +++ b/mount/doc.go @@ -0,0 +1,5 @@ +// Package mount provides a set of functions to mount and unmount mounts. +// +// Currently it supports Linux. For historical reasons, there is also some support for FreeBSD. + +package mount diff --git a/mount/flags.go b/mount/flags_unix.go similarity index 99% rename from mount/flags.go rename to mount/flags_unix.go index d514a9d8..995d7280 100644 --- a/mount/flags.go +++ b/mount/flags_unix.go @@ -1,3 +1,5 @@ +// +build !darwin,!windows + package mount import ( diff --git a/mount/flags_unsupported.go b/mount/flags_unsupported.go deleted file mode 100644 index 3ec4a11e..00000000 --- a/mount/flags_unsupported.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build !linux,!freebsd - -package mount - -// These flags are unsupported. -const ( - BIND = 0 - DIRSYNC = 0 - MANDLOCK = 0 - NOATIME = 0 - NODEV = 0 - NODIRATIME = 0 - NOEXEC = 0 - NOSUID = 0 - UNBINDABLE = 0 - RUNBINDABLE = 0 - PRIVATE = 0 - RPRIVATE = 0 - SHARED = 0 - RSHARED = 0 - SLAVE = 0 - RSLAVE = 0 - RBIND = 0 - RELATIME = 0 - REMOUNT = 0 - STRICTATIME = 0 - SYNCHRONOUS = 0 - RDONLY = 0 - mntDetach = 0 -) diff --git a/mount/mount.go b/mount/mount.go deleted file mode 100644 index ac8808cc..00000000 --- a/mount/mount.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build go1.13 - -package mount - -// Mount will mount filesystem according to the specified configuration. -// Options must be specified like the mount or fstab unix commands: -// "opt1=val1,opt2=val2". See flags.go for supported option flags. -// -// Mount is not implemented on Windows. -func Mount(device, target, mType, options string) error { - flag, data := parseOptions(options) - return mount(device, target, mType, uintptr(flag), data) -} - -// Unmount lazily unmounts a filesystem on supported platforms, otherwise does -// a normal unmount. If target is not a mount point, no error is returned. -// -// Unmount is not implemented on Windows. -func Unmount(target string) error { - return unmount(target, mntDetach) -} - -// RecursiveUnmount unmounts the target and all mounts underneath, starting -// with the deepest mount first. The argument does not have to be a mount -// point itself. -// -// RecursiveUnmount is not implemented on Windows. -func RecursiveUnmount(target string) error { - return recursiveUnmount(target) -} diff --git a/mount/unmount_unix.go b/mount/mount_unix.go similarity index 64% rename from mount/unmount_unix.go rename to mount/mount_unix.go index 1616cf4a..b47ab875 100644 --- a/mount/unmount_unix.go +++ b/mount/mount_unix.go @@ -1,4 +1,4 @@ -// +build !windows +// +build !darwin,!windows package mount @@ -10,7 +10,37 @@ import ( "golang.org/x/sys/unix" ) -func recursiveUnmount(target string) error { +// Mount will mount filesystem according to the specified configuration. +// Options must be specified like the mount or fstab unix commands: +// "opt1=val1,opt2=val2". See flags.go for supported option flags. +func Mount(device, target, mType, options string) error { + flag, data := parseOptions(options) + return mount(device, target, mType, uintptr(flag), data) +} + +// Unmount lazily unmounts a filesystem on supported platforms, otherwise does +// a normal unmount. If target is not a mount point, no error is returned. +func Unmount(target string) error { + err := unix.Unmount(target, mntDetach) + if err == nil || err == unix.EINVAL { + // Ignore "not mounted" error here. Note the same error + // can be returned if flags are invalid, so this code + // assumes that the flags value is always correct. + return nil + } + + return &mountError{ + op: "umount", + target: target, + flags: uintptr(mntDetach), + err: err, + } +} + +// RecursiveUnmount unmounts the target and all mounts underneath, starting +// with the deepest mount first. The argument does not have to be a mount +// point itself. +func RecursiveUnmount(target string) error { // Fast path, works if target is a mount point that can be unmounted. // On Linux, mntDetach flag ensures a recursive unmount. For other // platforms, if there are submounts, we'll get EBUSY (and fall back @@ -33,7 +63,7 @@ func recursiveUnmount(target string) error { var suberr error for i, m := range mounts { - err = unmount(m.Mountpoint, mntDetach) + err = Unmount(m.Mountpoint) if err != nil { if i == len(mounts)-1 { // last mount return fmt.Errorf("%w (possible cause: %s)", err, suberr) @@ -49,20 +79,3 @@ func recursiveUnmount(target string) error { } return nil } - -func unmount(target string, flags int) error { - err := unix.Unmount(target, flags) - if err == nil || err == unix.EINVAL { - // Ignore "not mounted" error here. Note the same error - // can be returned if flags are invalid, so this code - // assumes that the flags value is always correct. - return nil - } - - return &mountError{ - op: "umount", - target: target, - flags: uintptr(flags), - err: err, - } -} diff --git a/mount/mounter_freebsd.go b/mount/mounter_freebsd.go index 3964af4f..f4e2e0bb 100644 --- a/mount/mounter_freebsd.go +++ b/mount/mounter_freebsd.go @@ -1,3 +1,5 @@ +// +build freebsd cgo + package mount /* diff --git a/mount/mounter_unsupported.go b/mount/mounter_unsupported.go index 15380671..41ac018a 100644 --- a/mount/mounter_unsupported.go +++ b/mount/mounter_unsupported.go @@ -1,7 +1,7 @@ -// +build !linux,!freebsd freebsd,!cgo +// +build freebsd,!cgo package mount func mount(device, target, mType string, flag uintptr, data string) error { - panic("Not implemented") + panic("cgo required on freebsd") } diff --git a/mount/sharedsubtree_linux_test.go b/mount/sharedsubtree_linux_test.go index e950230a..1e2a053e 100644 --- a/mount/sharedsubtree_linux_test.go +++ b/mount/sharedsubtree_linux_test.go @@ -1,4 +1,4 @@ -// +build linux,go1.13 +// +build linux package mount diff --git a/mount/unmount_unsupported.go b/mount/unmount_unsupported.go deleted file mode 100644 index 94cfb9d5..00000000 --- a/mount/unmount_unsupported.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build windows - -package mount - -func recursiveUnmount(_ string) error { - panic("Not implemented") -} - -func unmount(_ string, _ int) error { - panic("Not implemented") -}