Use bind filer for mounts
The bind filter supports bind-like mounts and volume mounts. It also allows us to have read-only mounts. Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
@@ -36,8 +36,16 @@ var (
|
||||
|
||||
// Mount to the provided target.
|
||||
func (m *Mount) mount(target string) error {
|
||||
readOnly := false
|
||||
for _, option := range m.Options {
|
||||
if option == "ro" {
|
||||
readOnly = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if m.Type == "bind" {
|
||||
if err := m.bindMount(target); err != nil {
|
||||
if err := ApplyFileBinding(target, m.Source, readOnly); err != nil {
|
||||
return fmt.Errorf("failed to bind-mount to %s: %w", target, err)
|
||||
}
|
||||
return nil
|
||||
@@ -81,12 +89,12 @@ func (m *Mount) mount(target string) error {
|
||||
return fmt.Errorf("failed to get volume path for layer %s: %w", m.Source, err)
|
||||
}
|
||||
|
||||
if err = setVolumeMountPoint(target, volume); err != nil {
|
||||
if err = ApplyFileBinding(target, volume, readOnly); err != nil {
|
||||
return fmt.Errorf("failed to set volume mount path for layer %s: %w", m.Source, err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
deleteVolumeMountPoint(target)
|
||||
RemoveFileBinding(target)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -120,50 +128,60 @@ func (m *Mount) GetParentPaths() ([]string, error) {
|
||||
|
||||
// Unmount the mount at the provided path
|
||||
func Unmount(mount string, flags int) error {
|
||||
var err error
|
||||
mount = filepath.Clean(mount)
|
||||
|
||||
// Helpfully, both reparse points and symlinks look like links to Go
|
||||
// Less-helpfully, ReadLink cannot return \\?\Volume{GUID} for a volume mount,
|
||||
// and ends up returning the directory we gave it for some reason.
|
||||
if mountTarget, err := os.Readlink(mount); err != nil {
|
||||
// Not a mount point.
|
||||
// This isn't an error, per the EINVAL handling in the Linux version
|
||||
return nil
|
||||
} else if mount != filepath.Clean(mountTarget) {
|
||||
// Directory symlink
|
||||
if err := bindUnmount(mount); err != nil {
|
||||
return fmt.Errorf("failed to bind-unmount from %s: %w", mount, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
layerPathb, err := os.ReadFile(mount + ":" + sourceStreamName)
|
||||
|
||||
// This should expand paths like ADMINI~1 and PROGRA~1 to long names.
|
||||
mount, err = getFinalPath(mount)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve source for layer %s: %w", mount, err)
|
||||
return fmt.Errorf("fetching real path: %w", err)
|
||||
}
|
||||
|
||||
layerPath := string(layerPathb)
|
||||
|
||||
if err := deleteVolumeMountPoint(mount); err != nil {
|
||||
return fmt.Errorf("failed failed to release volume mount path for layer %s: %w", mount, err)
|
||||
mounts, err := GetBindMappings(mount)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fetching bind mappings: %w", err)
|
||||
}
|
||||
|
||||
var (
|
||||
home, layerID = filepath.Split(layerPath)
|
||||
di = hcsshim.DriverInfo{
|
||||
HomeDir: home,
|
||||
found := false
|
||||
for _, mnt := range mounts {
|
||||
if mnt.MountPoint == mount {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
)
|
||||
|
||||
if err := hcsshim.UnprepareLayer(di, layerID); err != nil {
|
||||
return fmt.Errorf("failed to unprepare layer %s: %w", mount, err)
|
||||
}
|
||||
if !found {
|
||||
// not a mount point
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := hcsshim.DeactivateLayer(di, layerID); err != nil {
|
||||
return fmt.Errorf("failed to deactivate layer %s: %w", mount, err)
|
||||
adsFile := mount + ":" + sourceStreamName
|
||||
var layerPath string
|
||||
|
||||
if _, err := os.Lstat(adsFile); err == nil {
|
||||
layerPathb, err := os.ReadFile(mount + ":" + sourceStreamName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve source for layer %s: %w", mount, err)
|
||||
}
|
||||
layerPath = string(layerPathb)
|
||||
}
|
||||
|
||||
if err := RemoveFileBinding(mount); err != nil {
|
||||
return fmt.Errorf("removing mount: %w", err)
|
||||
}
|
||||
|
||||
if layerPath != "" {
|
||||
var (
|
||||
home, layerID = filepath.Split(layerPath)
|
||||
di = hcsshim.DriverInfo{
|
||||
HomeDir: home,
|
||||
}
|
||||
)
|
||||
|
||||
if err := hcsshim.UnprepareLayer(di, layerID); err != nil {
|
||||
return fmt.Errorf("failed to unprepare layer %s: %w", mount, err)
|
||||
}
|
||||
|
||||
if err := hcsshim.DeactivateLayer(di, layerID); err != nil {
|
||||
return fmt.Errorf("failed to deactivate layer %s: %w", mount, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -183,21 +201,13 @@ func UnmountRecursive(mount string, flags int) error {
|
||||
}
|
||||
|
||||
func (m *Mount) bindMount(target string) error {
|
||||
readOnly := false
|
||||
for _, option := range m.Options {
|
||||
if option == "ro" {
|
||||
return fmt.Errorf("read-only bind mount: %w", ErrNotImplementOnWindows)
|
||||
readOnly = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Remove(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: We don't honour the Read-Only flag.
|
||||
// It's possible that Windows simply lacks this.
|
||||
return os.Symlink(m.Source, target)
|
||||
}
|
||||
|
||||
func bindUnmount(target string) error {
|
||||
return os.Remove(target)
|
||||
return ApplyFileBinding(target, m.Source, readOnly)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user