Remove the old API - phase 3: Move remaining flags out of WSLAApi.h (#13736)

* Remove the old API - phase 2

* Format
This commit is contained in:
Blue 2025-11-18 23:05:39 +00:00 committed by GitHub
parent f24f9299fe
commit f0d257f760
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 78 additions and 80 deletions

View File

@ -27,17 +27,17 @@ WSLAProcessLauncher::WSLAProcessLauncher(
// Add standard Fds.
if (WI_IsFlagSet(Flags, ProcessFlags::Stdin))
{
m_fds.emplace_back(WSLA_PROCESS_FD{.Fd = 0, .Type = WslFdTypeDefault, .Path = nullptr});
m_fds.emplace_back(WSLA_PROCESS_FD{.Fd = 0, .Type = WSLAFdTypeDefault, .Path = nullptr});
}
if (WI_IsFlagSet(Flags, ProcessFlags::Stdout))
{
m_fds.emplace_back(WSLA_PROCESS_FD{.Fd = 1, .Type = WslFdTypeDefault, .Path = nullptr});
m_fds.emplace_back(WSLA_PROCESS_FD{.Fd = 1, .Type = WSLAFdTypeDefault, .Path = nullptr});
}
if (WI_IsFlagSet(Flags, ProcessFlags::Stderr))
{
m_fds.emplace_back(WSLA_PROCESS_FD{.Fd = 2, .Type = WslFdTypeDefault, .Path = nullptr});
m_fds.emplace_back(WSLA_PROCESS_FD{.Fd = 2, .Type = WSLAFdTypeDefault, .Path = nullptr});
}
}
@ -96,7 +96,7 @@ RunningWSLAProcess::ProcessResult RunningWSLAProcess::WaitAndCaptureOutput(DWORD
// Add a callback on IO for each std handle.
for (size_t i = 0; i < m_fds.size(); i++)
{
if (m_fds[i].Fd == 0 || m_fds[i].Type != WslFdTypeDefault)
if (m_fds[i].Fd == 0 || m_fds[i].Type != WSLAFdTypeDefault)
{
continue; // Don't try to read from stdin or non hvsocket fds.
}

View File

@ -1582,9 +1582,9 @@ int WslaShell(_In_ std::wstring_view commandLine)
wsl::windows::common::security::ConfigureForCOMImpersonation(userSession.get());
wsl::windows::common::WSLAProcessLauncher launcher{shell, {shell}, {"TERM=xterm-256color"}, ProcessFlags::None};
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 0, .Type = WslFdTypeTerminalInput});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 1, .Type = WslFdTypeTerminalOutput});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 2, .Type = WslFdTypeTerminalControl});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 0, .Type = WSLAFdTypeTerminalInput});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 1, .Type = WSLAFdTypeTerminalOutput});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 2, .Type = WSLAFdTypeTerminalControl});
auto process = launcher.Launch(*session);

View File

@ -21,35 +21,6 @@ Abstract:
extern "C" {
#endif
typedef void* WslVirtualMachineHandle;
enum WslMountFlags
{
WslMountFlagsNone = 0,
WslMountFlagsChroot = 1,
WslMountFlagsWriteableOverlayFs = 2,
};
enum WslFdType
{
WslFdTypeDefault = 0,
WslFdTypeTerminalInput = 1,
WslFdTypeTerminalOutput = 2,
WslFdTypeLinuxFileInput = 4,
WslFdTypeLinuxFileOutput = 8,
WslFdTypeLinuxFileAppend = 16,
WslFdTypeLinuxFileCreate = 32,
WslFdTypeTerminalControl = 64,
};
enum WslProcessState
{
WslProcessStateUnknown,
WslProcessStateRunning,
WslProcessStateExited,
WslProcessStateSignaled
};
enum WslInstallComponent
{
WslInstallComponentNone = 0,

View File

@ -368,7 +368,7 @@ void WSLAVirtualMachine::ConfigureMounts()
{
auto [_, device] = AttachDisk(m_settings.RootVhd, true);
Mount(m_initChannel, device.c_str(), "/mnt", m_settings.RootVhdType, "ro", WslMountFlagsChroot | WslMountFlagsWriteableOverlayFs);
Mount(m_initChannel, device.c_str(), "/mnt", m_settings.RootVhdType, "ro", WSLAMountFlagsChroot | WSLAMountFlagsWriteableOverlayFs);
Mount(m_initChannel, nullptr, "/dev", "devtmpfs", "", 0);
Mount(m_initChannel, nullptr, "/sys", "sysfs", "", 0);
Mount(m_initChannel, nullptr, "/proc", "proc", "", 0);
@ -376,7 +376,7 @@ void WSLAVirtualMachine::ConfigureMounts()
if (m_settings.EnableGPU) // TODO: re-think how GPU settings should work at the session level API.
{
MountGpuLibraries("/usr/lib/wsl/lib", "/usr/lib/wsl/drivers", WslMountFlagsNone);
MountGpuLibraries("/usr/lib/wsl/lib", "/usr/lib/wsl/drivers", WSLAMountFlagsNone);
}
// TODO: Mount storage VHD here.
@ -436,14 +436,14 @@ void WSLAVirtualMachine::ConfigureNetworking()
// Launch GNS
std::vector<WSLA_PROCESS_FD> fds(1);
fds[0].Fd = -1;
fds[0].Type = WslFdType::WslFdTypeDefault;
fds[0].Type = WSLAFdType::WSLAFdTypeDefault;
std::vector<const char*> cmd{"/gns", LX_INIT_GNS_SOCKET_ARG};
// If DNS tunnelling is enabled, use an additional for its channel.
if (m_settings.EnableDnsTunneling)
{
fds.emplace_back(WSLA_PROCESS_FD{.Fd = -1, .Type = WslFdType::WslFdTypeDefault});
fds.emplace_back(WSLA_PROCESS_FD{.Fd = -1, .Type = WSLAFdType::WSLAFdTypeDefault});
THROW_IF_FAILED(wsl::core::networking::DnsResolver::LoadDnsResolverMethods());
}
@ -760,10 +760,10 @@ WSLAVirtualMachine::ConnectedSocket WSLAVirtualMachine::ConnectSocket(wsl::share
void WSLAVirtualMachine::OpenLinuxFile(wsl::shared::SocketChannel& Channel, const char* Path, uint32_t Flags, int32_t Fd)
{
static_assert(WslFdTypeLinuxFileInput == WslaOpenFlagsRead);
static_assert(WslFdTypeLinuxFileOutput == WslaOpenFlagsWrite);
static_assert(WslFdTypeLinuxFileAppend == WslaOpenFlagsAppend);
static_assert(WslFdTypeLinuxFileCreate == WslaOpenFlagsCreate);
static_assert(WSLAFdTypeLinuxFileInput == WslaOpenFlagsRead);
static_assert(WSLAFdTypeLinuxFileOutput == WslaOpenFlagsWrite);
static_assert(WSLAFdTypeLinuxFileAppend == WslaOpenFlagsAppend);
static_assert(WSLAFdTypeLinuxFileCreate == WslaOpenFlagsCreate);
shared::MessageWriter<WSLA_OPEN> message;
message->Fd = Fd;
@ -803,8 +803,8 @@ Microsoft::WRL::ComPtr<WSLAProcess> WSLAVirtualMachine::CreateLinuxProcess(_In_
std::vector<WSLAVirtualMachine::ConnectedSocket> sockets;
for (size_t i = 0; i < Options.FdsCount; i++)
{
if (Options.Fds[i].Type == WslFdTypeDefault || Options.Fds[i].Type == WslFdTypeTerminalInput ||
Options.Fds[i].Type == WslFdTypeTerminalOutput || Options.Fds[i].Type == WslFdTypeTerminalControl)
if (Options.Fds[i].Type == WSLAFdTypeDefault || Options.Fds[i].Type == WSLAFdTypeTerminalInput ||
Options.Fds[i].Type == WSLAFdTypeTerminalOutput || Options.Fds[i].Type == WSLAFdTypeTerminalControl)
{
THROW_HR_IF_MSG(
E_INVALIDARG, Options.Fds[i].Path != nullptr, "Fd[%zu] has a non-null path but flags: %i", i, Options.Fds[i].Type);
@ -814,7 +814,7 @@ Microsoft::WRL::ComPtr<WSLAProcess> WSLAVirtualMachine::CreateLinuxProcess(_In_
{
THROW_HR_IF_MSG(
E_INVALIDARG,
WI_IsAnyFlagSet(Options.Fds[i].Type, WslFdTypeTerminalInput | WslFdTypeTerminalOutput | WslFdTypeTerminalControl),
WI_IsAnyFlagSet(Options.Fds[i].Type, WSLAFdTypeTerminalInput | WSLAFdTypeTerminalOutput | WSLAFdTypeTerminalControl),
"Invalid flags: %i",
Options.Fds[i].Type);
@ -892,9 +892,9 @@ Microsoft::WRL::ComPtr<WSLAProcess> WSLAVirtualMachine::CreateLinuxProcess(_In_
void WSLAVirtualMachine::Mount(shared::SocketChannel& Channel, LPCSTR Source, LPCSTR Target, LPCSTR Type, LPCSTR Options, ULONG Flags)
{
static_assert(WslMountFlagsNone == WSLA_MOUNT::None);
static_assert(WslMountFlagsChroot == WSLA_MOUNT::Chroot);
static_assert(WslMountFlagsWriteableOverlayFs == WSLA_MOUNT::OverlayFs);
static_assert(WSLAMountFlagsNone == WSLA_MOUNT::None);
static_assert(WSLAMountFlagsChroot == WSLA_MOUNT::Chroot);
static_assert(WSLAMountFlagsWriteableOverlayFs == WSLA_MOUNT::OverlayFs);
wsl::shared::MessageWriter<WSLA_MOUNT> message;
@ -1013,17 +1013,17 @@ bool WSLAVirtualMachine::ParseTtyInformation(
for (ULONG i = 0; i < FdCount; i++)
{
if (Fds[i].Type == WslFdTypeTerminalInput)
if (Fds[i].Type == WSLAFdTypeTerminalInput)
{
THROW_HR_IF_MSG(E_INVALIDARG, *TtyInput != nullptr, "Only one TtyInput fd can be passed. Index=%lu", i);
*TtyInput = &Fds[i];
}
else if (Fds[i].Type == WslFdTypeTerminalOutput)
else if (Fds[i].Type == WSLAFdTypeTerminalOutput)
{
THROW_HR_IF_MSG(E_INVALIDARG, *TtyOutput != nullptr, "Only one TtyOutput fd can be passed. Index=%lu", i);
*TtyOutput = &Fds[i];
}
else if (Fds[i].Type == WslFdTypeTerminalControl)
else if (Fds[i].Type == WSLAFdTypeTerminalControl)
{
THROW_HR_IF_MSG(E_INVALIDARG, *TtyControl != nullptr, "Only one TtyOutput fd can be passed. Index=%lu", i);
*TtyControl = &Fds[i];
@ -1117,10 +1117,10 @@ CATCH_RETURN();
HRESULT WSLAVirtualMachine::MountWindowsFolder(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly)
{
return MountWindowsFolderImpl(WindowsPath, LinuxPath, ReadOnly, WslMountFlagsNone);
return MountWindowsFolderImpl(WindowsPath, LinuxPath, ReadOnly, WSLAMountFlagsNone);
}
HRESULT WSLAVirtualMachine::MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly, _In_ WslMountFlags Flags)
HRESULT WSLAVirtualMachine::MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly, _In_ WSLAMountFlags Flags)
try
{
std::filesystem::path Path(WindowsPath);
@ -1203,7 +1203,7 @@ CATCH_RETURN();
void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_ LPCSTR DriversMountpoint, _In_ DWORD Flags)
{
THROW_HR_IF_MSG(E_INVALIDARG, WI_IsAnyFlagSet(Flags, ~WslMountFlagsWriteableOverlayFs), "Unexpected flags: %lu", Flags);
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_CONFIG_VALUE), !m_settings.EnableGPU);
auto [channel, _, __] = Fork(WSLA_FORK::Thread);
@ -1211,7 +1211,7 @@ void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_
// Mount drivers.
THROW_IF_FAILED(MountWindowsFolderImpl(
std::format(L"{}\\System32\\DriverStore\\FileRepository", windowsPath).c_str(), DriversMountpoint, true, static_cast<WslMountFlags>(Flags)));
std::format(L"{}\\System32\\DriverStore\\FileRepository", windowsPath).c_str(), DriversMountpoint, true, static_cast<WSLAMountFlags>(Flags)));
// Mount the inbox libraries.
auto inboxLibPath = std::format(L"{}\\System32\\lxss\\lib", windowsPath);

View File

@ -21,6 +21,13 @@ Abstract:
namespace wsl::windows::service::wsla {
enum WSLAMountFlags
{
WSLAMountFlagsNone = 0,
WSLAMountFlagsChroot = 1,
WSLAMountFlagsWriteableOverlayFs = 2,
};
class WSLAUserSessionImpl;
class DECLSPEC_UUID("0CFC5DC1-B6A7-45FC-8034-3FA9ED73CE30") WSLAVirtualMachine
@ -90,7 +97,7 @@ private:
Microsoft::WRL::ComPtr<WSLAProcess> CreateLinuxProcessImpl(
_In_ const WSLA_PROCESS_OPTIONS& Options, int* Errno = nullptr, const TPrepareCommandLine& PrepareCommandLine = [](const auto&) {});
HRESULT MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly, _In_ WslMountFlags Flags);
HRESULT MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly, _In_ WSLAMountFlags Flags);
void WatchForExitedProcesses(wsl::shared::SocketChannel& Channel);

View File

@ -27,10 +27,30 @@ struct _WSLA_VERSION {
ULONG Revision;
} WSLA_VERSION;
typedef enum _WSLAFdType
{
WSLAFdTypeDefault = 0,
WSLAFdTypeTerminalInput = 1,
WSLAFdTypeTerminalOutput = 2,
WSLAFdTypeLinuxFileInput = 4,
WSLAFdTypeLinuxFileOutput = 8,
WSLAFdTypeLinuxFileAppend = 16,
WSLAFdTypeLinuxFileCreate = 32,
WSLAFdTypeTerminalControl = 64,
} WSLAFdType;
typedef enum _WSLAProcessState
{
WSLAProcessStateUnknown,
WSLAProcessStateRunning,
WSLAProcessStateExited,
WSLAProcessStateSignaled
} WSLAProcessState;
typedef struct _WSLA_PROCESS_FD
{
LONG Fd;
int Type;
WSLAFdType Type;
[string, unique] LPCSTR Path;
} WSLA_PROCESS_FD;

View File

@ -266,9 +266,9 @@ class WSLATests
auto session = CreateSession(settings);
WSLAProcessLauncher launcher("/bin/sh", {"/bin/sh"}, {"TERM=xterm-256color"}, ProcessFlags::None);
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 0, .Type = WslFdTypeTerminalInput});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 1, .Type = WslFdTypeTerminalOutput});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 2, .Type = WslFdTypeTerminalControl});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 0, .Type = WSLAFdTypeTerminalInput});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 1, .Type = WSLAFdTypeTerminalOutput});
launcher.AddFd(WSLA_PROCESS_FD{.Fd = 2, .Type = WSLAFdTypeTerminalControl});
auto process = launcher.Launch(*session);
@ -377,7 +377,7 @@ class WSLATests
struct FileFd
{
int Fd;
WslFdType Flags;
WSLAFdType Flags;
const char* Path;
};
@ -396,7 +396,8 @@ class WSLATests
};
{
auto process = createProcess({"/bin/cat"}, {{0, WslFdTypeLinuxFileInput, "/proc/self/comm"}, {1, WslFdTypeDefault, nullptr}});
auto process =
createProcess({"/bin/cat"}, {{0, WSLAFdTypeLinuxFileInput, "/proc/self/comm"}, {1, WSLAFdTypeDefault, nullptr}});
VERIFY_ARE_EQUAL(process->WaitAndCaptureOutput().Output[1], "cat\n");
}
@ -404,15 +405,16 @@ class WSLATests
{
auto read = [&]() {
auto process = createProcess({"/bin/cat"}, {{0, WslFdTypeLinuxFileInput, "/tmp/output"}, {1, WslFdTypeDefault, nullptr}});
auto process =
createProcess({"/bin/cat"}, {{0, WSLAFdTypeLinuxFileInput, "/tmp/output"}, {1, WSLAFdTypeDefault, nullptr}});
return process->WaitAndCaptureOutput().Output[1];
};
// Write to a new file.
auto process = createProcess(
{"/bin/cat"},
{{0, WslFdTypeDefault, nullptr},
{1, static_cast<WslFdType>(WslFdTypeLinuxFileOutput | WslFdTypeLinuxFileCreate), "/tmp/output"}});
{{0, WSLAFdTypeDefault, nullptr},
{1, static_cast<WSLAFdType>(WSLAFdTypeLinuxFileOutput | WSLAFdTypeLinuxFileCreate), "/tmp/output"}});
constexpr auto content = "TestOutput";
VERIFY_IS_TRUE(WriteFile(process->GetStdHandle(0).get(), content, static_cast<DWORD>(strlen(content)), nullptr, nullptr));
@ -424,8 +426,8 @@ class WSLATests
// Append content to the same file
auto appendProcess = createProcess(
{"/bin/cat"},
{{0, WslFdTypeDefault, nullptr},
{1, static_cast<WslFdType>(WslFdTypeLinuxFileOutput | WslFdTypeLinuxFileAppend), "/tmp/output"}});
{{0, WSLAFdTypeDefault, nullptr},
{1, static_cast<WSLAFdType>(WSLAFdTypeLinuxFileOutput | WSLAFdTypeLinuxFileAppend), "/tmp/output"}});
VERIFY_IS_TRUE(WriteFile(appendProcess->GetStdHandle(0).get(), content, static_cast<DWORD>(strlen(content)), nullptr, nullptr));
VERIFY_ARE_EQUAL(appendProcess->WaitAndCaptureOutput().Code, 0);
@ -435,7 +437,7 @@ class WSLATests
// Truncate the file
auto truncProcess = createProcess(
{"/bin/cat"},
{{0, WslFdTypeDefault, nullptr}, {1, static_cast<WslFdType>(WslFdTypeLinuxFileOutput), "/tmp/output"}});
{{0, WSLAFdTypeDefault, nullptr}, {1, static_cast<WSLAFdType>(WSLAFdTypeLinuxFileOutput), "/tmp/output"}});
VERIFY_IS_TRUE(WriteFile(truncProcess->GetStdHandle(0).get(), content, static_cast<DWORD>(strlen(content)), nullptr, nullptr));
VERIFY_ARE_EQUAL(truncProcess->WaitAndCaptureOutput().Code, 0);
@ -445,19 +447,19 @@ class WSLATests
// Test various error paths
{
createProcess({"/bin/cat"}, {{0, static_cast<WslFdType>(WslFdTypeLinuxFileOutput), "/tmp/DoesNotExist"}}, E_FAIL);
createProcess({"/bin/cat"}, {{0, static_cast<WslFdType>(WslFdTypeLinuxFileOutput), nullptr}}, E_INVALIDARG);
createProcess({"/bin/cat"}, {{0, static_cast<WslFdType>(WslFdTypeDefault), "should-be-null"}}, E_INVALIDARG);
createProcess({"/bin/cat"}, {{0, static_cast<WslFdType>(WslFdTypeDefault | WslFdTypeLinuxFileOutput), nullptr}}, E_INVALIDARG);
createProcess({"/bin/cat"}, {{0, static_cast<WslFdType>(WslFdTypeLinuxFileAppend), nullptr}}, E_INVALIDARG);
createProcess({"/bin/cat"}, {{0, static_cast<WslFdType>(WslFdTypeLinuxFileInput | WslFdTypeLinuxFileAppend), nullptr}}, E_INVALIDARG);
createProcess({"/bin/cat"}, {{0, static_cast<WSLAFdType>(WSLAFdTypeLinuxFileOutput), "/tmp/DoesNotExist"}}, E_FAIL);
createProcess({"/bin/cat"}, {{0, static_cast<WSLAFdType>(WSLAFdTypeLinuxFileOutput), nullptr}}, E_INVALIDARG);
createProcess({"/bin/cat"}, {{0, static_cast<WSLAFdType>(WSLAFdTypeDefault), "should-be-null"}}, E_INVALIDARG);
createProcess({"/bin/cat"}, {{0, static_cast<WSLAFdType>(WSLAFdTypeDefault | WSLAFdTypeLinuxFileOutput), nullptr}}, E_INVALIDARG);
createProcess({"/bin/cat"}, {{0, static_cast<WSLAFdType>(WSLAFdTypeLinuxFileAppend), nullptr}}, E_INVALIDARG);
createProcess({"/bin/cat"}, {{0, static_cast<WSLAFdType>(WSLAFdTypeLinuxFileInput | WSLAFdTypeLinuxFileAppend), nullptr}}, E_INVALIDARG);
}
// Validate that read & write modes are respected
{
auto process = createProcess(
{"/bin/cat"},
{{0, WslFdTypeLinuxFileInput, "/proc/self/comm"}, {1, WslFdTypeLinuxFileInput, "/tmp/output"}, {2, WslFdTypeDefault, nullptr}});
{{0, WSLAFdTypeLinuxFileInput, "/proc/self/comm"}, {1, WSLAFdTypeLinuxFileInput, "/tmp/output"}, {2, WSLAFdTypeDefault, nullptr}});
auto result = process->WaitAndCaptureOutput();
VERIFY_ARE_EQUAL(result.Output[2], "/bin/cat: write error: Bad file descriptor\n");
@ -465,7 +467,7 @@ class WSLATests
}
{
auto process = createProcess({"/bin/cat"}, {{0, WslFdTypeLinuxFileOutput, "/tmp/output"}, {2, WslFdTypeDefault, nullptr}});
auto process = createProcess({"/bin/cat"}, {{0, WSLAFdTypeLinuxFileOutput, "/tmp/output"}, {2, WSLAFdTypeDefault, nullptr}});
auto result = process->WaitAndCaptureOutput();
VERIFY_ARE_EQUAL(result.Output[2], "/bin/cat: standard output: Bad file descriptor\n");
@ -763,7 +765,6 @@ class WSLATests
// Validate that the GPU device is available.
ExpectCommandResult(session.get(), {"/bin/bash", "-c", "test -c /dev/dxg"}, 0);
auto expectMount = [&](const std::string& target, const std::optional<std::string>& options) {
auto cmd = std::format("set -o pipefail ; findmnt '{}' | tail -n 1", target);
WSLAProcessLauncher launcher{"/bin/bash", {"/bin/bash", "-c", cmd}};
@ -796,7 +797,6 @@ class WSLATests
// Validate that trying to mount the shares without GPU support disabled fails.
{
settings.EnableGPU = false;
session = CreateSession(settings);
wil::com_ptr<IWSLAVirtualMachine> vm;