Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions localization/strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ Arguments for managing Windows Subsystem for Linux:
Move the distribution to a new location.

--set-sparse, -s <true|false>
Set the vhdx of distro to be sparse, allowing disk space to be automatically reclaimed.
Set the VHD of distro to be sparse, allowing disk space to be automatically reclaimed.

--set-default-user <Username>
Set the default user of the distribution.
Expand Down Expand Up @@ -546,11 +546,11 @@ Arguments for managing distributions in Windows Subsystem for Linux:
Specifies the version to use for the new distribution.

--vhd
Specifies that the provided file is a .vhdx file, not a tar file.
This operation makes a copy of the .vhdx file at the specified install location.
Specifies that the provided file is a .vhd or .vhdx file, not a tar file.
This operation makes a copy of the VHD file at the specified install location.

--import-in-place <Distro> <FileName>
Imports the specified .vhdx file as a new distribution.
Imports the specified VHD file as a new distribution.
This virtual hard disk must be formatted with the ext4 filesystem type.

--list, -l [Options]
Expand Down Expand Up @@ -626,7 +626,7 @@ Build time: {}</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageCustomKernelModulesNotFound" xml:space="preserve">
<value>The custom kernel modules vhd in {} was not found: '{}'.</value>
<value>The custom kernel modules VHD in {} was not found: '{}'.</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageCustomSystemDistroError" xml:space="preserve">
Expand Down Expand Up @@ -704,8 +704,13 @@ The system may need to be restarted so the changes can take effect.</value>
<comment>{Locked="--install "}{Locked="--no-distribution
"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageRequiresVhdxFileExtension" xml:space="preserve">
<value>The specified file must have the .vhdx file extension.</value>
<data name="MessageRequiresFileExtension" xml:space="preserve">
<value>The specified file must have the {} file extension.</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageRequiresFileExtensions" xml:space="preserve">
<value>The specified file must have the {} or {} file extension.</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageVmSwitchNotFound" xml:space="preserve">
<value>The VmSwitch '{}' was not found. Available switches: {}</value>
Expand Down Expand Up @@ -998,15 +1003,15 @@ Falling back to NAT networking.</value>
<value>See Docs</value>
</data>
<data name="MessageVhdInUse" xml:space="preserve">
<value>The operation could not be completed because the vhdx is currently in use. To force WSL to stop use: wsl.exe --shutdown</value>
<value>The operation could not be completed because the VHD is currently in use. To force WSL to stop use: wsl.exe --shutdown</value>
<comment>{Locked="--shutdown"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageInvalidBoolean" xml:space="preserve">
<value>{} is not a valid boolean, &lt;true|false&gt;</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageSparseVhdWsl2Only" xml:space="preserve">
<value>Sparse vhdx is supported on WSL2 only.</value>
<value>Sparse VHD is supported on WSL2 only.</value>
</data>
<data name="MessageLocalSystemNotSupported" xml:space="preserve">
<value>Running WSL as local system is not supported.</value>
Expand Down Expand Up @@ -1055,7 +1060,7 @@ Falling back to NAT networking.</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessagePassVhdFlag" xml:space="preserve">
<value>This looks like a VHDX file. Use --vhd to import a VHDX instead of a tar.</value>
<value>This looks like a VHD file. Use --vhd to import a VHD instead of a tar.</value>
<comment>{Locked="--vhd "}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageDistroStoreInstallFailed" xml:space="preserve">
Expand Down Expand Up @@ -1107,7 +1112,7 @@ Error code: {}</value>
</data>
<data name="MessageSparseVhdDisabled" xml:space="preserve">
<value>Sparse VHD support is currently disabled due to potential data corruption.
To force a distribution to use a sparse vhd, please run:
To force a distribution to use a sparse VHD, please run:
wsl.exe --manage &lt;DistributionName&gt; --set-sparse true --allow-unsafe</value>
<comment>{Locked="--manage "}{Locked="--set-sparse "}{Locked="--allow-unsafe"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
Expand Down
26 changes: 3 additions & 23 deletions src/windows/common/WslClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,14 +275,6 @@ int ExportDistribution(_In_ std::wstring_view commandLine)
}
else
{
// If exporting to a vhd, ensure the filename ends with the vhdx file extension.
if (WI_IsFlagSet(flags, LXSS_EXPORT_DISTRO_FLAGS_VHD) &&
!wsl::windows::common::string::IsPathComponentEqual(filePath.extension().native(), wsl::windows::common::wslutil::c_vhdxFileExtension))
{
wsl::windows::common::wslutil::PrintMessage(wsl::shared::Localization::MessageRequiresVhdxFileExtension());
return -1;
}

file.reset(CreateFileW(
filePath.c_str(), GENERIC_WRITE, (FILE_SHARE_READ | FILE_SHARE_DELETE), nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr));

Expand Down Expand Up @@ -371,22 +363,10 @@ int ImportDistribution(_In_ std::wstring_view commandLine)
}
else
{
bool isVhd = wsl::windows::common::string::IsPathComponentEqual(
filePath.extension().native(), wsl::windows::common::wslutil::c_vhdxFileExtension);

if (WI_IsFlagSet(flags, LXSS_IMPORT_DISTRO_FLAGS_VHD))
{
// If importing from a vhd, ensure the filename ends with the vhdx file extension.
if (!isVhd)
{
wsl::windows::common::wslutil::PrintMessage(wsl::shared::Localization::MessageRequiresVhdxFileExtension());
return -1;
}
}
else
if (WI_IsFlagClear(flags, LXSS_IMPORT_DISTRO_FLAGS_VHD))
{
// Fail if we expect a tar, but the file name has the .vhdx extension.
if (isVhd)
// Fail if expecting a tar, but the file name has the .vhd or .vhdx extension.
if (wsl::windows::common::wslutil::IsVhdFile(filePath))
{
wsl::windows::common::wslutil::PrintMessage(wsl::shared::Localization::MessagePassVhdFlag());
return -1;
Expand Down
7 changes: 7 additions & 0 deletions src/windows/common/wslutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,13 @@ bool wsl::windows::common::wslutil::IsRunningInMsix()
return false;
}
}

bool wsl::windows::common::wslutil::IsVhdFile(_In_ const std::filesystem::path& path)
{
return wsl::windows::common::string::IsPathComponentEqual(path.extension().native(), c_vhdFileExtension) ||
wsl::windows::common::string::IsPathComponentEqual(path.extension().native(), c_vhdxFileExtension);
}

std::vector<DWORD> wsl::windows::common::wslutil::ListRunningProcesses()
{
std::vector<DWORD> pids(1024);
Expand Down
2 changes: 2 additions & 0 deletions src/windows/common/wslutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ void InitializeWil();

bool IsRunningInMsix();

bool IsVhdFile(_In_ const std::filesystem::path& path);

bool IsVirtualMachinePlatformInstalled();

std::vector<DWORD> ListRunningProcesses();
Expand Down
48 changes: 39 additions & 9 deletions src/windows/service/exe/LxssUserSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ HRESULT LxssUserSessionImpl::MoveDistribution(_In_ LPCGUID DistroGuid, _In_ LPCW
std::filesystem::path newVhdPath = Location;
RETURN_HR_IF(E_INVALIDARG, newVhdPath.empty());

newVhdPath /= LXSS_VM_MODE_VHD_NAME;
newVhdPath /= distro.VhdFilePath.filename();

auto impersonate = wil::CoImpersonateClient();

Expand All @@ -952,7 +952,7 @@ HRESULT LxssUserSessionImpl::MoveDistribution(_In_ LPCGUID DistroGuid, _In_ LPCW

// Update the registry location
registration.Write(Property::BasePath, Location);
registration.Write(Property::VhdFileName, LXSS_VM_MODE_VHD_NAME);
registration.Write(Property::VhdFileName, newVhdPath.filename().c_str());

revert.release();

Expand Down Expand Up @@ -1079,6 +1079,22 @@ HRESULT LxssUserSessionImpl::ExportDistribution(_In_opt_ LPCGUID DistroGuid, _In
{
const wil::unique_handle userToken = wsl::windows::common::security::GetUserToken(TokenImpersonation);
auto runAsUser = wil::impersonate_token(userToken.get());

// Ensure the target file has the correct file extension.
if (GetFileType(FileHandle) == FILE_TYPE_DISK)
{
std::wstring exportPath;
THROW_IF_FAILED(wil::GetFinalPathNameByHandleW(FileHandle, exportPath));

const auto sourceFileExtension = configuration.VhdFilePath.extension().native();
const auto targetFileExtension = std::filesystem::path(exportPath).extension().native();
if (!wsl::windows::common::string::IsPathComponentEqual(sourceFileExtension, targetFileExtension))
{
THROW_HR_WITH_USER_ERROR(
WSL_E_EXPORT_FAILED, wsl::shared::Localization::MessageRequiresFileExtension(sourceFileExtension.c_str()));
}
}

const wil::unique_hfile vhdFile(CreateFileW(
configuration.VhdFilePath.c_str(), GENERIC_READ, (FILE_SHARE_READ | FILE_SHARE_DELETE), nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));

Expand Down Expand Up @@ -1258,13 +1274,9 @@ LxssUserSessionImpl::ImportDistributionInplace(_In_ LPCWSTR DistributionName, _I

s_ValidateDistroName(DistributionName);

// Return an error if the path is not absolute or does not end in the .vhdx file extension.
// Return an error if the path is not absolute or does not have a valid VHD file extension.
const std::filesystem::path path{VhdPath};
RETURN_HR_IF(
E_INVALIDARG,
!path.is_absolute() ||
(!wsl::windows::common::string::IsPathComponentEqual(path.extension().native(), wsl::windows::common::wslutil::c_vhdFileExtension) &&
!wsl::windows::common::string::IsPathComponentEqual(path.extension().c_str(), wsl::windows::common::wslutil::c_vhdxFileExtension)));
RETURN_HR_IF(E_INVALIDARG, !path.is_absolute() || !wsl::windows::common::wslutil::IsVhdFile(path));

const wil::unique_hkey lxssKey = s_OpenLxssUserKey();
std::lock_guard lock(m_instanceLock);
Expand Down Expand Up @@ -1448,6 +1460,24 @@ HRESULT LxssUserSessionImpl::RegisterDistribution(
wil::CreateDirectoryDeep(distributionPath.c_str());
}

// If importing a vhd, determine if it is a .vhd or .vhdx.
std::wstring vhdName{LXSS_VM_MODE_VHD_NAME};
if ((WI_IsFlagSet(Flags, LXSS_IMPORT_DISTRO_FLAGS_VHD)) && (GetFileType(FileHandle) == FILE_TYPE_DISK))
{
std::wstring pathBuffer;
THROW_IF_FAILED(wil::GetFinalPathNameByHandleW(FileHandle, pathBuffer));

std::filesystem::path vhdPath{std::move(pathBuffer)};
if (!wsl::windows::common::wslutil::IsVhdFile(vhdPath))
{
using namespace wsl::windows::common::wslutil;
THROW_HR_WITH_USER_ERROR(
WSL_E_IMPORT_FAILED, wsl::shared::Localization::MessageRequiresFileExtensions(c_vhdFileExtension, c_vhdxFileExtension));
}

vhdName = vhdPath.filename();
}

registration = DistributionRegistration::Create(
lxssKey.get(),
DistributionId,
Expand All @@ -1457,7 +1487,7 @@ HRESULT LxssUserSessionImpl::RegisterDistribution(
flags,
LX_UID_ROOT,
PackageFamilyName,
LXSS_VM_MODE_VHD_NAME,
vhdName.c_str(),
WI_IsFlagClear(Flags, LXSS_IMPORT_DISTRO_FLAGS_NO_OOBE));

configuration = s_GetDistributionConfiguration(registration, DistributionName == nullptr);
Expand Down
4 changes: 1 addition & 3 deletions src/windows/service/exe/WslCoreFilesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,7 @@ void wsl::core::filesystem::CreateVhd(_In_ LPCWSTR target, _In_ ULONGLONG maximu

wil::unique_handle wsl::core::filesystem::OpenVhd(_In_ LPCWSTR Path, _In_ VIRTUAL_DISK_ACCESS_MASK Mask)
{
WI_ASSERT(
wsl::shared::string::IsEqual(std::filesystem::path{Path}.extension().c_str(), windows::common::wslutil::c_vhdFileExtension, true) ||
wsl::shared::string::IsEqual(std::filesystem::path{Path}.extension().c_str(), windows::common::wslutil::c_vhdxFileExtension, true));
WI_ASSERT(wsl::windows::common::wslutil::IsVhdFile(std::filesystem::path{Path}));

// N.B. Specifying unknown for device and vendor means the system will determine the type of VHD.
VIRTUAL_STORAGE_TYPE storageType{};
Expand Down
4 changes: 2 additions & 2 deletions test/windows/SimpleTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class SimpleTests
std::format(L"{} {} {} {}", WSL_IMPORT_ARG, tempDistro, vhdDir.wstring(), tar.wstring()).c_str(),
L"The operation completed successfully. \r\n",
L"wsl: Sparse VHD support is currently disabled due to potential data corruption.\r\n"
L"To force a distribution to use a sparse vhd, please run:\r\n"
L"To force a distribution to use a sparse VHD, please run:\r\n"
L"wsl.exe --manage <DistributionName> --set-sparse true --allow-unsafe\r\n",
0);

Expand All @@ -122,7 +122,7 @@ class SimpleTests
ValidateOutput(
std::format(L"{} {} {} {}", WSL_MANAGE_ARG, tempDistro, WSL_MANAGE_ARG_SET_SPARSE_OPTION_LONG, L"true").c_str(),
L"Sparse VHD support is currently disabled due to potential data corruption.\r\n"
L"To force a distribution to use a sparse vhd, please run:\r\n"
L"To force a distribution to use a sparse VHD, please run:\r\n"
L"wsl.exe --manage <DistributionName> --set-sparse true --allow-unsafe\r\nError code: Wsl/Service/E_INVALIDARG\r\n",
L"",
-1);
Expand Down
Loading