Skip to content

CLI: Add --mount support for create and run - #41337

Merged
David Bennett (dkbennett) merged 17 commits into
masterfrom
user/dkbennett/mount-v2
Aug 18, 2026
Merged

David Bennett (dkbennett) merged 17 commits into
masterfrom
user/dkbennett/mount-v2

Conversation

@dkbennett

@dkbennett David Bennett (dkbennett) commented Aug 12, 2026 •

Copy link
Copy Markdown
Member

Summary of the Pull Request

Adds Docker-compatible --mount support to wslc container run and wslc container create, and consolidates all CLI mount forms into one typed mount pipeline.

--mount, --volume, and --tmpfs now produce mount::Spec values during argument validation. A single mount collection performs validation and duplicate-destination detection before WSLCContainerLauncher::AddMount translates each specification for the backend.

PR Checklist

  • Closes: Link to issue #xxx
  • Communication: I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
  • Tests: Added/updated if needed and all pass
  • Localization: All end user facing strings can be localized
  • Dev docs: Added/updated if needed
  • Documentation updated: If checked, please file a pull request on our docs repo and link it here: #xxx

Implementation

  • Adds the transport-neutral mount::Spec model and Docker-compatible parsers in src/windows/common.
  • Supports bind, named-volume, anonymous-volume, and tmpfs mounts.
  • Supports Docker aliases, CSV quoting, Go-compatible boolean values, read-only mounts, default volume type, and tmpfs size/mode options.
  • Allows colons in --mount targets because that syntax uses comma-separated key/value fields.
  • Uses the shared ParseStorageSize implementation for tmpfs sizes.
  • Preserves opaque legacy --tmpfs options such as uid, gid, nr_inodes, nosuid, nodev, and noexec.
  • Keeps AddVolume, AddNamedVolume, and AddTmpfs as compatibility wrappers that delegate to AddMount.
  • Preserves the Docker bind-source distinction:
    • --mount type=bind requires the source to exist.
    • --volume host:target creates a missing host directory.
  • Preserves the distinction between structured tmpfs mounts and legacy --tmpfs entries in the Docker request and inspect output.
  • Reports parser, unsupported-feature, and validation failures with localized errors.
  • Validates option families so type-specific options cannot be used with another mount type.
  • Detects normalized duplicate destinations across --mount, --volume, and --tmpfs using one collection.
  • Adds inspect mappings for bind, named-volume, anonymous-volume, and tmpfs mounts.
  • Excludes anonymous volumes from named-volume availability checks while retaining generated-volume cleanup behavior.

Why WSLC Parses --mount

Docker CLI converts the textual --mount grammar into typed mount objects before calling Docker Engine. WSLC must do the same because its launcher and backend boundary are structured, and bind mounts require additional Windows-host and utility-VM preparation.

WSLC also needs to reject options that its current transport cannot represent faithfully. Parsing and capability validation before the backend request prevents silent semantic loss and produces consistent CLI errors.

Validation

  • Full x64 Debug build.
  • WSLCCLIMountParserUnitTests: passed.
  • WSLCCLITmpfsParserUnitTests: 2/2 passed.
  • WSLCVolumeMountUnitTests: passed through the common volume parser.
  • Legacy --volume create E2E suite: 9/9 passed.
  • Legacy and structured tmpfs create E2E suite: 7/7 passed.
  • Anonymous and named --mount type=volume E2E coverage passed.
  • Cross-option duplicate-destination E2E coverage passed for --mount, --volume, and --tmpfs.
  • Bind missing-source E2E coverage verifies that --mount fails without creating a directory while --volume succeeds and creates it.
  • Tmpfs runtime coverage verifies the requested size and mode, not only mount usability.

Add a Docker-style --mount option to `wslc container run` and
`wslc container create`. The flag accepts comma-separated key=value
pairs (type=bind|volume|tmpfs, source/src, target/destination/dst,
readonly/ro) and is routed into the existing volume/tmpfs plumbing.

- Parse --mount into a ParsedMount (ArgumentValidation)
- Register the Mount argument for run/create
- Wire parsed mounts into ContainerOptions (ContainerTasks)
- Add localization strings (MountArgDescription, InvalidMountError)
- Add e2e tests (tmpfs, named volume, readonly-via-inspect, invalid
  type) and update run/create help-text expectations

Co-authored-by: Copilot <[email protected]>
Copilot AI lite review requested due to automatic review settings August 12, 2026 23:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Docker-compatible --mount parsing and plumbing for wslc container run / wslc container create, translating validated mount specs into the existing bind/volume/tmpfs execution paths and adding unit + E2E coverage plus localized error strings.

Changes:

  • Introduces a common mount::Spec model and Docker-grammar --mount parser under src/windows/common/.
  • Wires --mount into argument validation and container option construction, including duplicate-destination rejection across --mount/--volume/--tmpfs.
  • Adds table-driven unit tests and new E2E scenarios for --mount.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/windows/wslc/WSLCCLIMountParserUnitTests.cpp Adds table-driven unit tests for --mount parsing and destination de-duplication behavior.
test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp Adds E2E coverage for --mount tmpfs/volume/readonly and failure cases.
src/windows/wslc/tasks/ContainerTasks.cpp Plumbs parsed mount specs from CLI args into ContainerOptions and validates uniqueness.
src/windows/wslc/services/ContainerService.cpp Translates mount::Spec into launcher calls for bind/volume/tmpfs.
src/windows/wslc/services/ContainerModel.h Extends ContainerOptions with Mounts and declares destination uniqueness validation.
src/windows/wslc/services/ContainerModel.cpp Reuses named-volume validation from common parser and implements duplicate-destination detection.
src/windows/wslc/commands/ContainerRunCommand.cpp Adds --mount to container run arguments.
src/windows/wslc/commands/ContainerCreateCommand.cpp Adds --mount to container create arguments.
src/windows/wslc/arguments/SpecParsing.cpp Adds a standard header include used by parsing utilities.
src/windows/wslc/arguments/ArgumentValidation.cpp Validates/parses --mount and surfaces localized user-facing errors.
src/windows/wslc/arguments/ArgumentDefinitions.h Declares the new --mount argument in the X-macro table.
src/windows/wslc/arguments/ArgumentConvertedTypes.h Adds the converted type alias mapping for parsed mount specs.
src/windows/common/MountSpecParsing.h Declares the mount grammar version, spec model, and parsing/normalization helpers.
src/windows/common/MountSpecParsing.cpp Implements Docker-compatible --mount parsing and tmpfs option formatting.
src/windows/common/CMakeLists.txt Adds the new common parser sources/headers to the build.
localization/strings/en-US/Resources.resw Adds localized strings for invalid mount syntax and duplicate mount destinations.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/windows/common/MountSpecParsing.cpp Resolved
Comment thread src/windows/common/MountSpecParsing.cpp Resolved
Copilot AI review requested due to automatic review settings August 13, 2026 16:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/windows/common/MountSpecParsing.cpp:583

  • FormatTmpfsOptions also omits an explicitly provided tmpfs-size=0 by skipping size when the parsed value is 0. If the user passes tmpfs-size=0, that intent should be preserved and forwarded (and kept consistent with existing --tmpfs behavior, which can pass size=0).
    if (mount.TmpfsSizeBytes.has_value() && mount.TmpfsSizeBytes.value() != 0)
    {
        options.emplace_back(std::format("size={}", FormatDockerTmpfsSize(mount.TmpfsSizeBytes.value())));
    }

src/windows/common/MountSpecParsing.cpp:579

  • FormatTmpfsOptions drops an explicitly provided tmpfs-mode=0000 because it omits the mode option when the parsed value is 0. That changes user-requested semantics (and differs from --tmpfs, which forwards options verbatim), since mode=0 is a meaningful tmpfs setting.

This issue also appears on line 580 of the same file.

    if (mount.TmpfsMode.has_value() && mount.TmpfsMode.value() != 0)
    {
        options.emplace_back(std::format("mode={:o}", mount.TmpfsMode.value()));
    }

Copilot AI review requested due to automatic review settings August 13, 2026 16:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/windows/common/MountSpecParsing.cpp:14

  • New files should use the repository’s single-line copyright header format (// Copyright (C) Microsoft Corporation. All rights reserved.). This file currently uses the older block header style.
/*++

Copyright (c) Microsoft. All rights reserved.

src/windows/common/MountSpecParsing.h:14

  • New files should use the repository’s single-line copyright header format (// Copyright (C) Microsoft Corporation. All rights reserved.). This header currently uses the older block header style.
/*++

Copyright (c) Microsoft. All rights reserved.

test/windows/wslc/WSLCCLIMountParserUnitTests.cpp:14

  • New files should use the repository’s single-line copyright header format (// Copyright (C) Microsoft Corporation. All rights reserved.). This test file currently uses the older block header style.
/*++

Copyright (c) Microsoft. All rights reserved.

Copilot AI review requested due to automatic review settings August 13, 2026 19:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/windows/common/MountSpecParsing.cpp:159

  • Minor typo in the digit set passed to find_last_of: it includes an extra '0' ("01234567890. "), which is confusing to readers even though it likely doesn’t change behavior.
        const auto separator = input.find_last_of("01234567890. ");

src/windows/wslc/arguments/ArgumentValidation.cpp:234

  • The mount parser’s ValidationException::Reason() is composed of hard-coded English strings (from MountSpecParsing.cpp) and is surfaced directly to users via WSLCCLI_InvalidMountError. This means a significant portion of the user-facing error text is not localizable, which conflicts with the PR’s stated goal of localized errors for unsupported/invalid mount specs.
            catch (const mount::ValidationException& ex)
            {
                throw ArgumentException(Localization::WSLCCLI_InvalidMountError(value, ex.Reason()));
            }

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated no new comments.

Suppressed comments (4)

test/windows/wslc/WSLCCLIMountParserUnitTests.cpp:222

  • This mount spec (type=volume,...,bind-recursive=enabled) is listed as a valid case here, but the same exact input is also listed as an invalid (bind-* family mismatch) case later in c_invalidMountCases (lines ~350-351). With the current parser, bind-recursive is a bind-only option, so this entry will make the valid-case loop fail.
        {L"type=volume,source=data-volume,target=/data,bind-recursive=enabled",
         mount::Type::Volume,
         L"data-volume",
         "/data",
         false,
         {},
         {},
         ""},

test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp:802

  • This test is in WSLCE2EContainerCreateTests.cpp and is named Container_Create_*, but it invokes container run. Because run has additional behavior (and can exercise different code paths than create), this doesn’t reliably validate container create rejecting missing bind sources.
        auto result = RunWslc(std::format(
            L"container run --name {} --mount \"type=bind,source={},target=/data\" {} true",
            WslcContainerName,
            source.wstring(),
            AlpineImage.NameAndTag()));
        result.Verify({.Stdout = L"", .Stderr = FormatWslcError(Localization::MessageWslcBindSourcePathNotFound(source.wstring())), .ExitCode = 1});

test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp:820

  • This Container_Create_* test also runs container run instead of container create, so it’s not specifically exercising the create path’s behavior around creating missing bind-source directories. Either switch to container create (and clean up the created container), or rename/move the test so it’s clear it’s validating run.
        auto result = RunWslc(std::format(
            L"container run --name {} --volume \"{}:/data\" {} true", WslcContainerName, source.wstring(), AlpineImage.NameAndTag()));
        result.Verify({.Stdout = L"", .Stderr = L"", .ExitCode = 0});
        VERIFY_IS_TRUE(std::filesystem::is_directory(source));
        EnsureContainerDoesNotExist(WslcContainerName);

src/windows/common/MountSpecParsing.cpp:585

  • PR description says anonymous volumes are rejected, but ValidateMountSpec currently allows type=volume with an empty source (i.e., anonymous volume) as long as the name is either empty or a valid named volume. Either update the PR description to match the implemented behavior, or enforce source for type=volume if anonymous volumes truly aren’t supported.
    case Type::Volume:
        if (!mount.Source.empty() && !IsValidNamedVolumeName(mount.Source))
        {
            ThrowValidation(Localization::WSLCCLI_MountVolumeSourceInvalidError());
        }

Copilot AI review requested due to automatic review settings August 17, 2026 21:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated no new comments.

Suppressed comments (6)

test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp:817

  • This test is in the ContainerCreate suite but the command uses container run, so it’s not actually validating container create behavior when a host --volume source is missing.
        auto result = RunWslc(std::format(
            L"container run --name {} --volume \"{}:/data\" {} true", WslcContainerName, source.wstring(), AlpineImage.NameAndTag()));

test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp:801

  • These two E2E tests are in the ContainerCreate suite and are named ..._Container_Create_..., but the command under test uses container run. That means the test is exercising the run code path (which may have additional behaviors) instead of create, so it won’t reliably catch regressions specific to container create.

This issue also appears on line 816 of the same file.

        auto result = RunWslc(std::format(
            L"container run --name {} --mount \"type=bind,source={},target=/data\" {} true",
            WslcContainerName,
            source.wstring(),
            AlpineImage.NameAndTag()));

src/windows/wslc/services/ContainerService.cpp:32

  • namespace mount = wsl::windows::common::mount; is declared but never used in this translation unit (there are no mount:: references). This can trigger unused-alias warnings depending on compiler settings and adds noise.
namespace mount = wsl::windows::common::mount;

test/windows/wslc/e2e/WSLCE2EHelpers.h:29

  • FormatWslcError uses std::format and std::wstring_view but this header doesn’t include <format> / <string_view>. Relying on transitive includes makes the header brittle and can break if include order changes.
inline std::wstring FormatWslcError(const std::wstring& message, std::wstring_view errorCode = L"E_INVALIDARG")
{
    return std::format(L"{}\r\nError code: {}\r\n", message, errorCode);
}

src/windows/wslcsession/WSLCContainer.cpp:643

  • If a mount destination pointer is unexpectedly null (e.g., Volumes[i].ContainerPath, NamedVolumes[i].ContainerPath, or Tmpfs[i].Destination), this currently throws E_INVALIDARG without any context. Using the _MSG form here makes failures much easier to diagnose.
    const auto addDestination = [&](const char* destination) {
        THROW_HR_IF_NULL(E_INVALIDARG, destination);

src/windows/wslcsession/WSLCContainer.cpp:1859

  • There’s a nearby TODO saying “Return mounts once --mount is implemented”, but HostConfig.Mounts is already being used here to enrich inspect output. Updating/removing that TODO would avoid misleading future readers.
        wslc_schema::InspectMount mountInfo{};
        mountInfo.Type = volume.Type;
        mountInfo.Name = volume.Name;
        const auto structuredMount = std::ranges::find_if(dockerInspect.HostConfig.Mounts, [&](const auto& mount) {
            return mount.Type == "volume" && mount.Target == volume.Destination;

Copilot AI review requested due to automatic review settings August 17, 2026 22:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/windows/wslc/services/ContainerModel.cpp:290

  • ValidateUniqueMountDestinations rethrows mount::MountException for non-duplicate errors. If this function is ever called with a mount spec that bypassed arg validation (or new validation is added later), that would propagate a non-WIL exception through the CLI path and produce inconsistent error handling.

Consider translating all mount::MountException instances to a user-facing HRESULT here (similar to other validation helpers).

void ValidateUniqueMountDestinations(const ContainerOptions& options)
{
    try
    {
        mount::ValidateMountCollection(options.Mounts);
    }
    catch (const mount::MountException& ex)
    {
        if (ex.Error() == mount::ValidationError::DuplicateDestination)
        {
            THROW_HR_WITH_USER_ERROR(E_INVALIDARG, Localization::WSLCCLI_DuplicateMountDestinationError(MultiByteToWide(ex.Destination())));
        }

        throw;
    }

src/windows/common/MountSpecParsing.cpp:566

  • The PR description says anonymous volumes are rejected, but ValidateMountSpec currently allows Type::Volume mounts with an empty Source (which enables anonymous volumes, and is also exercised by the added e2e coverage).

Please align behavior with the stated intent by either rejecting empty volume sources here, or updating the PR description/notes to reflect that anonymous volumes are supported.

    case Type::Volume:
        if (!mount.Source.empty() && !IsValidNamedVolumeName(mount.Source))
        {
            ThrowValidation(Localization::WSLCCLI_MountVolumeSourceInvalidError());
        }
        break;

Copilot AI review requested due to automatic review settings August 17, 2026 22:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/windows/wslc/services/ContainerService.cpp:34

  • Unused namespace alias mount was introduced but is never referenced in this file. This can trigger unused-declaration warnings (and adds noise).
namespace wsl::windows::wslc::services {
namespace mount = wsl::windows::common::mount;

test/windows/wslc/WSLCCLIMountParserUnitTests.cpp:66

  • PR description says anonymous volumes are rejected, but the parser/tests explicitly accept type=volume,target=... (empty source) which results in an anonymous volume. Please either update the PR description to match the implemented behavior, or change validation to reject empty volume sources if that was the intent.
    constexpr ValidMountCase c_validMountCases[] = {
        {L"type=volume,target=/data", mount::Type::Volume, L"", "/data", false, {}, {}, ""},
        {L"source=data-volume,target=/data", mount::Type::Volume, L"data-volume", "/data", false, {}, {}, ""},

@dkbennett
David Bennett (dkbennett) marked this pull request as ready for review August 17, 2026 23:21
Copilot AI review requested due to automatic review settings August 18, 2026 00:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated no new comments.

Suppressed comments (4)

src/windows/wslcsession/WSLCContainer.cpp:695

  • ConvertAndValidateMounts() checks NamedVolumes[].Name for null but can pass a null NamedVolumes[].ContainerPath into addDestination(), which produces an unhelpful generic failure. Add an explicit null check with index context before addDestination().
    THROW_HR_IF(E_INVALIDARG, containerOptions.NamedVolumesCount > 0 && containerOptions.NamedVolumes == nullptr);
    for (ULONG i = 0; i < containerOptions.NamedVolumesCount; ++i)
    {
        THROW_HR_IF_NULL_MSG(E_INVALIDARG, containerOptions.NamedVolumes[i].Name, "NamedVolume at index %lu has null Name", i);
        addDestination(containerOptions.NamedVolumes[i].ContainerPath);
    }

src/windows/wslcsession/WSLCContainer.cpp:701

  • ConvertAndValidateMounts() can pass a null Tmpfs[*].Destination into addDestination(), which fails without any index context. Add an explicit null check with a message before calling addDestination().
    THROW_HR_IF(E_INVALIDARG, containerOptions.TmpfsCount > 0 && containerOptions.Tmpfs == nullptr);
    for (ULONG i = 0; i < containerOptions.TmpfsCount; ++i)
    {
        addDestination(containerOptions.Tmpfs[i].Destination);
    }

src/windows/wslcsession/WSLCContainer.cpp:688

  • ConvertAndValidateMounts() validates Volumes[].HostPath but can pass a null Volumes[].ContainerPath into addDestination(), which then fails with a generic E_INVALIDARG and no index context. Add an explicit null check with an index-specific message before calling addDestination().

This issue also appears in the following locations of the same file:

  • line 690
  • line 697
    for (ULONG i = 0; i < containerOptions.VolumesCount; ++i)
    {
        THROW_HR_IF_NULL_MSG(E_INVALIDARG, containerOptions.Volumes[i].HostPath, "Volumes[%lu].HostPath is null", i);
        addDestination(containerOptions.Volumes[i].ContainerPath);
    }

src/windows/wslcsession/WSLCContainer.cpp:747

  • PrepareBindMount() calls std::filesystem::is_regular_file(hostPath) without the error_code overload. On access/permission issues this can throw std::filesystem::filesystem_error, bypassing the HRESULT/user-error flow and potentially failing the operation with an unhandled exception. Use the error_code overload and convert failures into a localized user error.
        std::error_code ec;
        hostPath = std::filesystem::canonical(hostPath, ec);
        if (!ec)
        {
            if (std::filesystem::is_regular_file(hostPath))

Copilot AI review requested due to automatic review settings August 18, 2026 00:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/windows/wslcsession/WSLCContainer.cpp:695

  • ConvertAndValidateMounts() does not emit an indexed diagnostic if NamedVolumes[i].ContainerPath is null (it falls back to addDestination()'s generic null check). Adding an explicit THROW_HR_IF_NULL_MSG here would make failures actionable.
    for (ULONG i = 0; i < containerOptions.NamedVolumesCount; ++i)
    {
        THROW_HR_IF_NULL_MSG(E_INVALIDARG, containerOptions.NamedVolumes[i].Name, "NamedVolume at index %lu has null Name", i);
        addDestination(containerOptions.NamedVolumes[i].ContainerPath);
    }

src/windows/wslcsession/WSLCContainer.cpp:688

  • ConvertAndValidateMounts() relies on addDestination()'s generic null check for Volumes[i].ContainerPath. This loses the index/context in the failure, and it’s inconsistent with the explicit HostPath null check above.

This issue also appears on line 691 of the same file.

    for (ULONG i = 0; i < containerOptions.VolumesCount; ++i)
    {
        THROW_HR_IF_NULL_MSG(E_INVALIDARG, containerOptions.Volumes[i].HostPath, "Volumes[%lu].HostPath is null", i);
        addDestination(containerOptions.Volumes[i].ContainerPath);
    }

src/windows/wslcsession/WSLCContainer.cpp:701

  • ConvertAndValidateMounts() should report which tmpfs entry is invalid when Tmpfs[i].Destination is null (currently it throws E_INVALIDARG without context via addDestination()).
    for (ULONG i = 0; i < containerOptions.TmpfsCount; ++i)
    {
        addDestination(containerOptions.Tmpfs[i].Destination);
    }

@dkbennett
David Bennett (dkbennett) enabled auto-merge (squash) August 18, 2026 01:15
@dkbennett
David Bennett (dkbennett) merged commit 84f479b into master Aug 18, 2026
12 checks passed
@dkbennett
David Bennett (dkbennett) deleted the user/dkbennett/mount-v2 branch August 18, 2026 02:17
if (GetFileAttributesW(source.c_str()) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_INVALID_NAME)
{
ThrowParse(Localization::WSLCCLI_VolumeHostPathInvalid(value, rawSource));
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I recommend using wsl::windows::common::filesystem::GetCanonicalPath() since it's what we use in other places


std::string NormalizeDestination(std::string destination)
{
std::replace(destination.begin(), destination.end(), '\\', '/');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm following correctly, this is the container path, and in Linux '\' is actually valid in a path so we shouldn't translate it to /

const auto component = destination.substr(start, end - start);
if (!component.empty() && component != ".")
{
if (component == "..")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need to do this ? I would expect that the docker API does that for us


namespace wsl::windows::common::mount {

inline constexpr std::string_view c_dockerCliMountGrammarVersion = "25.0.3";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks unused

{
result.m_containerPath = value;
return result;
mount::ValidateMountCollection(options.Mounts);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to do this in the client side, I would expect the docker API to give us an error if this happens

const auto sourceExists = std::filesystem::exists(mount.Source, error);
if (error)
{
throw mount::MountValidationException(Localization::MessageWslcBindSourcePathError(mount.Source, error.message()));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I would recommend throwing the user error directly to make things a bit easier to follow

GUID volumeId;
THROW_IF_FAILED(CoCreateGuid(&volumeId));

auto parentVMPath = std::format("/mnt/{}", wsl::shared::string::GuidToString<char>(volumeId));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This could be constructed later since we don't use it until line 749

std::wstring sourceFilename;
{
std::error_code ec;
hostPath = std::filesystem::canonical(hostPath, ec);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I recommend using wsl::windows::common::filesystem::GetCanonicalPath() here (probably didn't exist when you started working on this change)

WSLCMountSpecFlagsTmpfsOptions = 8,
} WSLCMountSpecFlags;

cpp_quote("#define WSLCMountSpecFlagsValid (WSLCMountSpecFlagsTmpfsSize | WSLCMountSpecFlagsTmpfsMode | WSLCMountSpecFlagsCreateSourceIfMissing | WSLCMountSpecFlagsTmpfsOptions)")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need WSLCMountSpecFlagsTmpfsOptions or could we just set TmpfsOptions to null when unset ?

WSLCMountSpec mount{};
switch (Mount.MountType)
{
case mount::Type::Bind:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I recommend using the same enum here as well so we don't need to map

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants