* Release COM DLLs before installer test MSI operations
Add PrepareForMsiOperation() that calls CoFreeUnusedLibrariesEx(0)
before each msiexec invocation. This releases in-process COM DLLs
like wslserviceproxystub.dll loaded by prior test classes, preventing
the Restart Manager from detecting the test process as holding file
locks and failing the install on older Server SKUs like ni_release.
* fix CoFreeUnusedLibrariesEx
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
* Remove unused callback parameter from CreateInternal
The IProgressCallback* parameter was always passed as nullptr by both
callers. The auto-pull path creates its own PullImageCallback locally.
Remove the dead parameter entirely per review feedback.
* format
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Both static functions in ContainerService.cpp are defined but never
called from anywhere in the codebase. They appear to be remnants of
an earlier implementation before the WSLCContainerLauncher and
WSLCProcessLauncher classes took over this responsibility.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
* Add week/month/year support to FormatRelativeTime
Previously only handled seconds, minutes, hours, and days. Containers
older than a week would show e.g. '720 days ago' instead of '2 years ago'.
Now matches Docker-style output with weeks, months, and years.
Also refactors repeated pluralization logic into a lambda.
* Handle timestamp==0 sentinel in FormatRelativeTime
Callers pass 0 to mean 'unknown' (e.g. ImageTasks when Created <= 0).
Previously this would produce '56 years ago'. Now returns empty string.
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Replace manual PrintMessage + THROW_HR(E_FAIL) with the standard
THROW_HR_WITH_USER_ERROR pattern used throughout the codebase. This
ensures the error message is properly captured by the ExecutionContext
error collection system rather than being printed directly to stderr.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
When the WSL MSIX package is updated via the Microsoft Store, the
WslInstaller service automatically upgrades the MSI package by calling
MsiInstallProduct. This call was made with INSTALLUILEVEL_NONE (silent
install) but without setting the REBOOT=ReallySuppress property.
Per Windows Installer documentation, when a silent install encounters
files in use and REBOOT is not suppressed, the system reboots
automatically without any user prompt. This could cause unexpected
machine restarts after a Store update when WSL binaries (e.g.
wslservice.exe) were in use during the upgrade.
Every deployment script in the repo already passes /norestart to
msiexec (deploy-to-host.ps1, deploy-to-vm.ps1, install-latest-wsl.ps1,
test-setup.ps1), but the programmatic MsiInstallProduct path used by
the WslInstaller service lacked the equivalent property.
This change:
- Always appends REBOOT=ReallySuppress to MsiInstallProduct arguments
in UpgradeViaMsi, preventing Windows Installer from ever initiating
a system restart during install/upgrade.
- Switches UninstallViaMsi from MsiConfigureProduct to
MsiConfigureProductEx so we can pass REBOOT=ReallySuppress during
uninstall as well.
- Propagates ERROR_SUCCESS_REBOOT_REQUIRED (3010) to callers instead
of swallowing it. User-facing paths (wsl --update, wsl --uninstall)
print a reboot-needed message to stderr. The background WslInstaller
service silently treats 3010 as success since it has no console.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Prototype
* Save state
* Save state
* Save state
* Save state
* Save state
* Save state
* Remove zeroing
* Apply PR feedback
* Add test coverage
* Format
* Add test coverage for null handles
Implements `WslcCanRun` using existing primitives. Updates the component flag names to help better describe their meaning and adds comments to further do so.
Also changes the error returned when we cannot create a `WSLASessionManager` and WSL is installed at a version below the minimum for WSLC support.
* Save state
* Add test coverage
* Rename method
* Require input handle in the service
* Apply PR feedback
* Format
* Apply PR feedback + update tests
* Format
* Validate empty host path in VolumeMount::Parse
When parsing volume mount specs without a mode suffix (e.g. ':container'),
the host path validation was skipped, producing a VolumeMount with an empty
host path. This would propagate to MountWindowsFolder('') and produce a
confusing error.
Add validation after computing m_hostPath to reject empty host paths with
a clear error message in all cases.
* add test coverage
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
GetState/GetInitProcess/GetId/GetName could race with DisconnectComWrapper:
the cache check saw empty, then disconnect populated the cache and nulled
the impl, so the forwarded call failed with RPC_E_DISCONNECTED even though
the cached value was now available.
Fix by removing the upfront cache check and instead calling through to the
impl first. If the call fails with RPC_E_DISCONNECTED, fall back to the
cache which DisconnectComWrapper guarantees is populated.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
* Clean up Docker container on Create() failure
If InspectContainer or the WSLCContainerImpl constructor throws after
CreateContainer succeeds, the Docker container is permanently orphaned
with no way to manage it through WSLC APIs.
Add a scope_exit to delete the Docker container on failure, released
on success.
* pr feedback (capture by value)
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Use weak_ptr in m_trackedProcesses so WatchForExitedProcesses can safely
lock a reference and call OnExited() outside m_trackedProcessesLock.
weak_ptr avoids a circular reference: the vector no longer prevents
VMProcessControl destruction, so the destructor's OnProcessReleased
cleanup runs normally. Expired entries are also pruned in OnProcessReleased.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
When the TtyMaster fd is non-blocking, write() can return fewer bytes than
requested (partial write). The existing code only handled the EAGAIN/EWOULDBLOCK
case by buffering into pendingStdin, but silently dropped data on successful
partial writes.
Add handling for 0 < bytesWritten < bytesRead to buffer the unwritten bytes
into pendingStdin, matching the existing retry logic.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
WaitForMultipleObjects has a 64-handle limit. The accept thread uses
1 handle for the exit event, leaving room for 63 port mappings.
Reject new port mappings with ERROR_TOO_MANY_OPEN_FILES when the limit
is reached, rather than crashing the relay thread. Existing mappings
continue to work.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
std::stoul returns unsigned long (32-bit on Windows), truncating Content-Length
values >4GB. This corrupts the socket stream for large image save/export
operations.
Replace with std::stoull to parse as 64-bit unsigned.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
WSLCDeleteImageFlagsForce (from WSLCDeleteImageFlags enum) was used instead
of WSLCDeleteFlagsForce (from WSLCDeleteFlags enum). Both values are currently
1, so no functional issue today, but this is a type confusion that will break
silently if either enum changes.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>