diff --git a/lib/vagrant/util/platform.rb b/lib/vagrant/util/platform.rb index c8f8fa7b9..7f0d6f039 100644 --- a/lib/vagrant/util/platform.rb +++ b/lib/vagrant/util/platform.rb @@ -305,7 +305,8 @@ module Vagrant logger = Log4r::Logger.new("vagrant::util::platform::wsl") # Check for lxrun installation first - paths = [[wsl_windows_appdata_local, "lxss"].join("\\")] + lxrun_path = [wsl_windows_appdata_local, "lxss"].join("\\") + paths = [lxrun_path] logger.debug("checking registry for WSL installation path") paths += PowerShell.execute_cmd( @@ -363,6 +364,11 @@ module Vagrant raise Vagrant::Errors::WSLRootFsNotFoundError if @_wsl_rootfs.nil? end + # Attach the rootfs leaf to the path + if @_wsl_rootfs != lxrun_path + @_wsl_rootfs = "#{@_wsl_rootfs}\\rootfs" + end + logger.debug("detected `#{@_wsl_rootfs}` as current WSL instance") @_wsl_rootfs @@ -375,11 +381,17 @@ module Vagrant # @param [String, Pathname] path Path to convert # @return [String] def wsl_to_windows_path(path) - if wsl? && wsl_windows_access? + if wsl? && wsl_windows_access? && !path.match(/^[a-zA-Z]:/) if wsl_path?(path) parts = path.split("/") parts.delete_if(&:empty?) - [wsl_rootfs, *parts].join("\\") + root_path = wsl_rootfs + # lxrun splits home separate so we need to account + # for it's specialness here when we build the path + if root_path.end_with?("lxss") && parts.first != "home" + root_path = "#{root_path}\\rootfs" + end + [root_path, *parts].join("\\") else path = path.to_s.sub("/mnt/", "") parts = path.split("/") diff --git a/test/unit/vagrant/util/platform_test.rb b/test/unit/vagrant/util/platform_test.rb index ba3cf17be..8b4046188 100644 --- a/test/unit/vagrant/util/platform_test.rb +++ b/test/unit/vagrant/util/platform_test.rb @@ -281,12 +281,69 @@ describe Vagrant::Util::Platform do it "should return the matching path" do expect(Dir).to receive(:open).with(/#{matching_part}/).and_yield(double("path", path: matching_part)) - expect(subject.wsl_rootfs).to eq(matching_path) + expect(subject.wsl_rootfs).to start_with(matching_path) end it "should return matching path when access error encountered" do expect(Dir).to receive(:open).with(/#{matching_part}/).and_raise(Errno::EACCES) - expect(subject.wsl_rootfs).to eq(matching_path) + expect(subject.wsl_rootfs).to start_with(matching_path) + end + end + end + end + + describe ".wsl_to_windows_path" do + let(:path){ "/home/vagrant/test" } + + context "when not within WSL" do + before{ allow(subject).to receive(:wsl?).and_return(false) } + + it "should return the path unmodified" do + expect(subject.wsl_to_windows_path(path)).to eq(path) + end + end + + context "when within WSL" do + before{ allow(subject).to receive(:wsl?).and_return(true) } + + context "when windows access is not enabled" do + before{ allow(subject).to receive(:wsl_windows_access?).and_return(false) } + + it "should return the path unmodified" do + expect(subject.wsl_to_windows_path(path)).to eq(path) + end + end + + context "when windows access is enabled" do + let(:rootfs_path){ "C:\\WSL\\rootfs" } + + before do + allow(subject).to receive(:wsl_windows_access?).and_return(true) + allow(subject).to receive(:wsl_rootfs).and_return(rootfs_path) + end + + it "should generate expanded path when within WSL" do + expect(subject.wsl_to_windows_path(path)).to eq("#{rootfs_path}#{path.gsub("/", "\\")}") + end + + it "should generate direct path when outside the WSL" do + expect(subject.wsl_to_windows_path("/mnt/c/vagrant")).to eq("c:\\vagrant") + end + + it "should not modify path when already in windows format" do + expect(subject.wsl_to_windows_path("C:\\vagrant")).to eq("C:\\vagrant") + end + + context "when within lxrun generated WSL instance" do + let(:rootfs_path){ "C:\\WSL\\lxss" } + + it "should not include rootfs when accessing home" do + expect(subject.wsl_to_windows_path("/home/vagrant")).not_to include("rootfs") + end + + it "should include rootfs when accessing non-home path" do + expect(subject.wsl_to_windows_path("/tmp/test")).to include("rootfs") + end end end end