LayerMount 0.2.0

Prefix Reserved
dotnet add package LayerMount --version 0.2.0
                    
NuGet\Install-Package LayerMount -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LayerMount" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="LayerMount" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="LayerMount" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add LayerMount --version 0.2.0
                    
#r "nuget: LayerMount, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package LayerMount@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=LayerMount&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=LayerMount&version=0.2.0
                    
Install as a Cake Tool

LayerMount for Windows — engine

CI NuGet (LayerMount) NuGet (LayerMount.Native) Downloads License: MIT

LayerMount is a Windows engine for Linux-style overlay filesystems (union mounts) — a writable upper layer, prioritized read-only lowers, copy-up on first write, with optional VHD/VHDX and VSS snapshot sources and .lmnt layer-image packing.

What it isn't: LayerMount is not a filesystem driver. It enforces overlay semantics — copy-up, whiteouts, layer priority, image packing — over real paths in a writable upper directory. Presenting the resulting overlay as a mountable filesystem (at a drive letter or directory) is the job of a separate host adapter that targets a userspace-filesystem driver. Host adapters live in their own repositories and depend on this engine via NuGet.

This repo ships the engine: the native library (LayerMount.dll) and its managed wrapper (LayerMount.NET). The engine is host-agnostic and links only system + CRT libraries (a post-build check enforces this).

Install

dotnet add package LayerMount

LayerMount is AnyCPU and transitively pulls in LayerMount.Native, which carries the engine DLL for win-x64 and win-arm64. Windows-only at runtime.

Native C/C++ consumers

dotnet add package LayerMount.Native

LayerMount.h lands under build\native\include\ inside the package; the .def is alongside under build\native\. Either link against the import library yourself or LoadLibrary the DLL at runtime.

Versioning

LayerMount follows Semantic Versioning and ships two version axes:

  • LM_VER_MAJOR.LM_VER_MINOR.LM_VER_PATCH (in LayerMount.h, mirrored on the managed LayerMount.GetVersion()) — the SemVer string. Both NuGet packages (LayerMount and LayerMount.Native) always carry the same version and are bumped in lockstep.
  • LM_ABI_VERSION — independent of the SemVer string. Only ticks on binary-breaking changes to the public C exports in LayerMount.def; bumping it requires consumers to re-link.

LayerMount is currently in the 0.x series. While on 0.x, minor bumps may carry breaking changes (per the SemVer spec's pre-1.0 guidance) — those are called out explicitly in CHANGELOG.md. The contract stabilizes at 1.0.0.


Concepts

An overlay is composed of three path roles, borrowed from Linux overlayfs:

  • Upper — the writable layer. All new writes land here. Required.
  • Lower — read-only layers, prioritized left-to-right (first lower wins for reads). Zero or more.
  • Work dir — scratch space used for atomic copy-up. Defaults to <upperParent>\.layermount-work if not supplied.

When a file exists only in a lower layer, reads pass through. The first write promotes (copies up) the file into the upper layer and subsequent access reads/writes the upper copy. Lower layers are never modified.

Two additional layer sources can stand in for a directory path:

  • VHD / VHDX — attached at mount, the volume GUID is used as a lower. Requires admin.
  • VSS snapshot — a snapshot of a volume taken at mount time, used as a lower. Requires admin.

For the deeper engine architecture (path resolution, whiteouts, copy-up flavors, metadata, caching), see docs/engine/ARCHITECTURE.md.


Features

  • Overlay semantics — upper / lower / work paths with copy-up on first write, file and directory whiteouts, opaque-directory markers.
  • Lazy copy-up — metacopy promotes metadata immediately and completes data copy on first read or close, keeping mount-time fast.
  • VHD / VHDX layers — attach a virtual disk at mount time and use its volume GUID as a high-priority lower.
  • VSS snapshot layers — take a Volume Shadow Copy at mount time and use it as a read-only lower without holding open file handles.
  • .lmnt layer images — pack a directory tree into a portable zstd-compressed image with SHA-256 footer; supports differential packs against a base image and multi-image manifests.
  • Capability-gated fallbacks — opt out of ADS, reparse points, sparse files, multiple streams, or NTFS ACLs and the engine routes around the missing feature instead of erroring.
  • Reparse-point and ADS preservation — both surface on copy-up.
  • ACL preservation — DACL on every copy-up; SACL too when the process holds SE_SECURITY_NAME.
  • Per-process access tracking — optional access log and JSON-rule-driven gating, keyed by (pid, image path, creation time).
  • Diagnostic events — single managed event stream for warnings, copy-ups, whiteouts, and access denials.
  • Host-agnostic — links only system + CRT libraries (a post-build check enforces this); zero dependency on any userspace-filesystem driver.
  • AOT-compatible managed wrapper[LibraryImport]-based P/Invoke with trim analysis enabled; ships as AnyCPU with per-RID native via LayerMount.Native.

Quick start

using LayerMount;

// Two-layer overlay: writable upper + one read-only lower.
var config = new LayerMountConfig
{
    UpperPath   = @"C:\overlays\my-app\upper",
    WorkDirPath = @"C:\overlays\my-app\work",
    LowerPaths  = new[] { @"C:\overlays\my-app\base" },
};

using var mount = LayerMount.Create(config);

// Diagnostic events: warnings, copy-up, whiteouts, denials.
mount.Event += (_, e) => Console.WriteLine($"[{e.Kind}] {e.Path}");

// Path resolution: tells you which layer a relative path resolves to,
// and surfaces whiteouts / opaque-dir markers.
var resolved = mount.ResolvePath(@"bin\app.exe");
Console.WriteLine($"{resolved.FullPath}  (origin: {resolved.Origin})");

// Pack the upper layer into a portable, zstd-compressed image.
mount.Images.Pack(
    sourceDir:    config.UpperPath,
    outputPath:   @"C:\images\my-app-0.1.lmnt",
    description:  "first build");

For mount-driven I/O (OpenFile / CreateFile / Read / Write), the engine takes Win32-style access masks and create options because it's designed to be wired straight to a userspace-filesystem driver's I/O requests. The managed unit tests under src/LayerMount.NET.Tests/ are the most practical reference for the I/O patterns.

API surface

The managed wrapper lives in the LayerMount namespace; the native C ABI is src/LayerMount.dll/public/LayerMount.h + LayerMount.def. Top-level entry points:

Type Purpose
LayerMount Top-level overlay handle. Static factories Create(LayerMountConfig) and CreateTransient(workDir); instance methods for path/file ops, stats, volume info; Event for diagnostics.
LayerMountConfig Construction parameters: UpperPath, WorkDirPath, LowerPaths, Capabilities, process-tracking knobs.
LayerMountFile Handle returned by OpenFile / CreateFile. Read / Write accept managed Span<byte> and an originator PID.
LayerMount.Vhd Create / Open VHD/VHDX layer files; ListLayers against a manifest directory.
LayerMount.Vss CreateSnapshot / DeleteSnapshot / ListSnapshots / Cleanup. Admin required.
LayerMount.Images Pack, PackDifferential, Unpack, Validate, GetMetadata; CreateManifest / GetManifest for multi-image bundles.
LayerMount.ProcessTracker Per-process access log and rule-based gating (config-gated).

The native ABI exports the same surface as C functions; consumers who want to bypass the managed wrapper can LoadLibrary LayerMount.dll and call directly against LayerMount.h.


Building from source

msbuild LayerMount.sln /p:Configuration=Release /p:Platform=x64
# Optional: cross-compile the native engine for arm64 as well
msbuild LayerMount.sln /p:Configuration=Release /p:Platform=ARM64

Outputs land in <Platform>\<Configuration>\ (e.g. x64\Release\ or ARM64\Release\). Debug builds work too (/p:Configuration=Debug). The native engine builds on both x64 and ARM64; test projects and the managed wrapper are x64 for dotnet test.

  • LayerMount.dll (native engine)
  • LayerMount.NET.dll (managed wrapper around the native engine)
  • LayerMount.Tests.dll, LayerMount.AbiTests.dll (native test DLLs)
  • LayerMount.NET.Tests.dll, LayerMount.TestShared.dll (managed wrapper tests + shared test helpers)

Tests:

# Native: VS Test Explorer / vstest.console.exe x64\<Config>\LayerMount.Tests.dll
dotnet test src/LayerMount.NET.Tests   # managed wrapper unit tests

Adapter-specific build prerequisites, exit codes, troubleshooting, and host-spawning E2E tests live with the adapter projects, not in this repo.

Releases

Releases are cut by a manually-triggered GitHub Actions workflow (release.yml) that runs Versionize over the conventional commits since the previous tag, bumps version.props and CHANGELOG.md, builds + packs both NuGet packages (LayerMount and LayerMount.Native) for win-x64 and win-arm64, pushes them to nuget.org, and creates a GitHub Release with the .nupkg / .snupkg files attached.

See CONTRIBUTING.md for the full release procedure.

License

MIT. Bundled third-party components are listed in THIRD_PARTY_NOTICES.md.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 96 5/22/2026
0.1.2 99 5/16/2026
0.1.1 93 5/16/2026
0.1.0 88 5/16/2026