From 952049fe523b5cd4313b4a10ed401b58d4d1447f Mon Sep 17 00:00:00 2001 From: Arthur Sengileyev Date: Fri, 13 Jan 2023 23:25:42 +0200 Subject: [PATCH] Support for Windows paths in the source position of the volume mounts There are 2 things added. First there is added support for handling drive letters while doing value split. If drive letter is detected, then max number of elements will be increased by one, but then first two will be concatenated to reconstruct the path. Second part is basic, but working, conversion of Windows path to Unix path to be used, when target path is not explicitly specified. Signed-off-by: Arthur Sengileyev --- pkg/machine/qemu/machine.go | 54 ++++++++++++++++------------- pkg/machine/qemu/machine_unix.go | 12 +++++++ pkg/machine/qemu/machine_windows.go | 25 +++++++++++++ 3 files changed, 67 insertions(+), 24 deletions(-) diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index 4f25b4d26c..0ec1bd1958 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -301,30 +301,10 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { mounts := []machine.Mount{} for i, volume := range opts.Volumes { tag := fmt.Sprintf("vol%d", i) - paths := strings.SplitN(volume, ":", 3) - source := paths[0] - target := source - readonly := false - securityModel := "none" - if len(paths) > 1 { - target = paths[1] - } - if len(paths) > 2 { - options := paths[2] - volopts := strings.Split(options, ",") - for _, o := range volopts { - switch { - case o == "rw": - readonly = false - case o == "ro": - readonly = true - case strings.HasPrefix(o, "security_model="): - securityModel = strings.Split(o, "=")[1] - default: - fmt.Printf("Unknown option: %s\n", o) - } - } - } + paths := pathsFromVolume(volume) + source := extractSourcePath(paths) + target := extractTargetPath(paths) + readonly, securityModel := extractMountOptions(paths) if volumeType == VolumeTypeVirtfs { virtfsOptions := fmt.Sprintf("local,path=%s,mount_tag=%s,security_model=%s", source, tag, securityModel) if readonly { @@ -1756,3 +1736,29 @@ func isRootful() bool { return !rootless.IsRootless() && os.Getuid() != -1 } + +func extractSourcePath(paths []string) string { + return paths[0] +} + +func extractMountOptions(paths []string) (bool, string) { + readonly := false + securityModel := "none" + if len(paths) > 2 { + options := paths[2] + volopts := strings.Split(options, ",") + for _, o := range volopts { + switch { + case o == "rw": + readonly = false + case o == "ro": + readonly = true + case strings.HasPrefix(o, "security_model="): + securityModel = strings.Split(o, "=")[1] + default: + fmt.Printf("Unknown option: %s\n", o) + } + } + } + return readonly, securityModel +} diff --git a/pkg/machine/qemu/machine_unix.go b/pkg/machine/qemu/machine_unix.go index 84ee191d18..b798d03dba 100644 --- a/pkg/machine/qemu/machine_unix.go +++ b/pkg/machine/qemu/machine_unix.go @@ -6,6 +6,7 @@ package qemu import ( "bytes" "fmt" + "strings" "syscall" "golang.org/x/sys/unix" @@ -31,3 +32,14 @@ func checkProcessStatus(processHint string, pid int, stderrBuf *bytes.Buffer) er } return nil } + +func pathsFromVolume(volume string) []string { + return strings.SplitN(volume, ":", 3) +} + +func extractTargetPath(paths []string) string { + if len(paths) > 1 { + return paths[1] + } + return paths[0] +} diff --git a/pkg/machine/qemu/machine_windows.go b/pkg/machine/qemu/machine_windows.go index 6c63faf50c..04065cb1d3 100644 --- a/pkg/machine/qemu/machine_windows.go +++ b/pkg/machine/qemu/machine_windows.go @@ -3,6 +3,8 @@ package qemu import ( "bytes" "fmt" + "regexp" + "strings" "github.com/containers/podman/v4/pkg/machine" ) @@ -25,3 +27,26 @@ func checkProcessStatus(processHint string, pid int, stderrBuf *bytes.Buffer) er } return nil } + +func pathsFromVolume(volume string) []string { + paths := strings.SplitN(volume, ":", 3) + driveLetterMatcher := regexp.MustCompile(`^(?:\\\\[.?]\\)?[a-zA-Z]$`) + if len(paths) > 1 && driveLetterMatcher.MatchString(paths[0]) { + paths = strings.SplitN(volume, ":", 4) + paths = append([]string{paths[0] + ":" + paths[1]}, paths[2:]...) + } + return paths +} + +func extractTargetPath(paths []string) string { + if len(paths) > 1 { + return paths[1] + } + target := strings.ReplaceAll(paths[0], "\\", "/") + target = strings.ReplaceAll(target, ":", "/") + if strings.HasPrefix(target, "//./") || strings.HasPrefix(target, "//?/") { + target = target[4:] + } + dedup := regexp.MustCompile(`//+`) + return dedup.ReplaceAllLiteralString("/"+target, "/") +}