Skip to content

coldhighsun/ManagedDrive

Repository files navigation

ManagedDrive

CI / Release Latest Release GitHub All Releases License: MIT

English | 中文


English

A Windows RAM disk manager built on .NET 10 and WinFsp.
Create, mount and manage in-memory volumes that appear as normal drive letters in Explorer.

Features

Core

  • Mount multiple RAM disks at once, each with its own drive letter, capacity, volume label and read-only flag
  • Dynamic memory allocation — capacity is a ceiling, not a reservation
  • Live-edit a mounted disk (label, capacity, auto-mount, image path); changing the drive letter or read-only flag remounts it
  • NTFS-compatible, so RAM disks work with tools that require NTFS (WinGet, Windows Update staging, BITS)
  • Auto-mount saved profiles on startup
  • Format instantly clears a disk's contents (read-only disks are protected)

Persistence, snapshots & cloning

  • Save to a .mdr image and restore it on next mount, or import an existing image directly (Import Disk...)
  • Import an archive (zip, 7z, rar, tar, or anything SharpCompress reads) as a read-only disk (Import Archive...), with capacity/label derived automatically
  • Optional auto-save (1–60 min interval) plus a final save before unmount/exit (disableable per disk via Save on exit); skipped when nothing changed, failures raise a tray/status-bar notification
  • Selectable image compression (Off / Fast / Balanced / Max, default Fast)
  • Snapshot / version history capped by count and/or size, deduplicated by content hash; restore via Restore Snapshot..., which also lets you delete individual snapshots
  • Clone a disk onto another mounted disk or export it to a new .mdr file (Clone Disk...)
  • Optional .mdr password protection (AES-256-GCM envelope encryption — the password only wraps a random per-disk key, so changing it never re-encrypts file data); set via "Encrypt Image" in the disk dialog (8–64 characters, with a live strength hint) and prompted for on mount whenever an image is encrypted. Sensitive buffers are zeroed from memory as soon as they're no longer needed.
  • Progress bar overlay for long operations (image save, archive import, export) instead of an unresponsive-looking app

CLI

  • mdrive (ships alongside ManagedDrive.exe) scripts mount/unmount/format/save/list/exit against the running app over a named pipe
  • Auto-launches ManagedDrive.exe if needed and waits for it to be ready before sending the command

Convenience & safety

  • Optional Explorer right-click integration: adds "Mount as RAM disk (ManagedDrive)" for zip/7z/rar/tar archives — one click mounts, auto-launching the app if needed and opening the new drive in Explorer
  • Tray icon with a hover tooltip (per-disk usage + available memory), quick menu, optional start-minimized mode, and a brief read/write flash on activity
  • Available system memory shown live in the status bar (2 s refresh)
  • Status bar also shows the most recently accessed file, pushed live (throttled to 300 ms) rather than polled, paused while the window is hidden in the tray
  • Per-disk high-usage warning (default 90%, with hysteresis)
  • Temp directory redirection to a disk's Temp folder, auto-reset on unmount/remount, with a startup warning if TEMP is left on a RAM disk
  • Exit confirmation with a saving overlay while pending saves finish; TEMP is reset first if it points at a mounted disk
  • Double-click to open a disk in Explorer; right-click for shortcuts or View Disk Contents... (a read-only, sortable Name/Size/Type tree)

UI

  • Bilingual (English / Simplified Chinese) and light/dark themes, both auto-detected with manual override, switching instantly
  • Disk cards with status badges (read-only, current-TEMP, backing image, password-protected) and a usage bar that warns past the high-usage threshold
  • Freely resizable window, no maximize/fullscreen
  • About dialog with version, GitHub link, and an "update available" link when a newer release exists
  • Optional daily update check against GitHub Releases; a tray balloon + dialog (View Release / Skip / Remind Later) appears on a new release

Installation

Two artifacts are published on the Releases page for each version — pick one:

  • ManagedDrive-Setup-X.Y.Z.exe — a guided installer. It detects whether WinFsp and the .NET 10 Desktop Runtime are already installed, silently installs the bundled WinFsp MSI if missing, prompts you to install the .NET Desktop Runtime if missing, and installs ManagedDrive into Program Files with Start Menu/desktop shortcuts. Recommended for most users.
  • ManagedDrive-vX.Y.Z-win-x64-portable.zip — small download; requires WinFsp and the .NET 10 Desktop Runtime to be installed separately.

If using the ZIP, extract it anywhere and run ManagedDrive.exe directly. ManagedDrive.exe is a single-file executable — the ZIP contains it plus one small companion winfsp-msil.dll (the managed WinFsp interop assembly, which can't be embedded in the single-file bundle) that must stay next to it. The only registry write is the optional "Run at startup" setting; nothing else touches the registry. WinFsp must be installed separately first with the ZIP (see Prerequisites below); the installer handles this automatically.

The ZIP also includes mdrive.exe, a companion CLI (see CLI Usage below), and wingetx.exe, a winget wrapper (see wingetx: winget wrapper below). Add the extraction folder to your PATH to run mdrive/wingetx from any shell. The installer adds both to the machine-wide PATH automatically.

Prerequisites

Requirement Notes
Windows 10 / 11 (64-bit) ARM64 is not currently tested
WinFsp 2.2.26194 (2026 Beta3) Must be installed before running ManagedDrive. Download the installer directly: winfsp-2.2.26194.msi — do not use winget install WinFsp.WinFsp, as the winget package lags behind the latest release. The managed assembly winfsp-msil.dll is installed to C:\Program Files (x86)\WinFsp\bin\ and is referenced by the project automatically.
.NET 10 Desktop Runtime Required for the -portable ZIP (framework-dependent).
.NET 10 SDK Required to build.

Getting Started

# 1. Download and install WinFsp 2.2.26194 (2026 Beta3)
# https://github.com/winfsp/winfsp/releases/download/v2.2B3/winfsp-2.2.26194.msi

# 2. Clone the repository
git clone https://github.com/coldhighsun/ManagedDrive
cd ManagedDrive

# 3. Build
dotnet build

# 4. Run
dotnet run --project src/ManagedDrive.App -c Release

Alternatively open ManagedDrive.slnx in Visual Studio 2022+ and press F5.

Solution Structure

ManagedDrive/
├── src/
│   ├── ManagedDrive.Core/              # In-memory file system engine (WinFsp), no UI dependency
│   │   ├── FileSystem/                 #   FileNode, FileNodeMap, MemoryFileSystem, WildcardMatcher, DirectoryEnumeration
│   │   ├── Mounting/                   #   DiskOptions, RamDisk, MountManager, MountOptionsFactory
│   │   ├── Persistence/                #   DiskImageSerializer (.mdr format)
│   │   ├── Snapshots/                  #   SnapshotManager, SnapshotStore
│   │   ├── Archive/                    #   ArchiveNodeMapBuilder (import), ArchiveNodeMapWriter (export)
│   │   └── DiskCreation/               #   CreateDiskOptionsBuilder, ByteUnitConverter
│   ├── ManagedDrive.App/               # WPF desktop application — tray icon, dialogs, settings, localization/theming
│   ├── ManagedDrive.Cli.Core/          # Shared CLI parsing/protocol library (System.CommandLine + named-pipe wire format)
│   ├── ManagedDrive.Cli/               # `mdrive.exe`, the console entry point
│   ├── ManagedDrive.HelperProtocol/    # Named-pipe protocol shared between the app and the SYSTEM helper service
│   ├── ManagedDrive.Service/           # `ManagedDriveHelper.exe`, optional LocalSystem service publishing global DOS-device symlinks for cross-session TEMP visibility (see Known Issues)
│   └── ManagedDrive.WingetExtension/   # `wingetx.exe`, a transparent winget wrapper (see wingetx: winget wrapper)
├── tests/
│   └── ManagedDrive.Tests/             # xUnit v3 unit tests (pure-managed code only)
└── benchmarks/
    └── ManagedDrive.Benchmarks/        # BenchmarkDotNet throughput/latency benchmarks

How It Works

ManagedDrive uses WinFsp (Windows File System Proxy) to present an in-memory directory tree as a real Windows volume, via a signed kernel driver that forwards file I/O to MemoryFileSystem, which stores data in .NET byte arrays.

Key classes:

  • FileNode — a node's Fsp.Interop.FileInfo metadata, byte[] data buffer, cached leaf name, and security descriptor.
  • FileNodeMap — a case-insensitive SortedDictionary<string, FileNode> mapping full paths to nodes; supports paginated child enumeration and O(1) allocated-byte tracking. Thread-safe via the C# 13 Lock type.
  • MemoryFileSystem : FileSystemBase — implements all 21 WinFsp callbacks (Create, Read, Write, Rename, etc.), enforces a configurable capacity ceiling (STATUS_DISK_FULL when exceeded), and only allocates the bytes actually written.
  • RamDisk — combines MemoryFileSystem with a FileSystemHost. Create() mounts the volume, waits for the drive letter to appear (up to 2.5 s), and refreshes Explorer; Dispose() unmounts. An optional auto-save timer and a final save on Dispose() (skippable via "Save on exit") keep the backing image current, skipping saves when nothing changed. A SaveFailed event surfaces any save/snapshot failure, including background ones that would otherwise fail silently. Optional per-disk encryption keeps a random content-encryption key in memory only, wrapped by the user's password.
  • MountManager — thread-safe registry of active RamDisk instances, firing DiskMounted/DiskUnmounted events.
  • DiskImageSerializer — reads/writes .mdr files (metadata, ACLs, file data), optionally gzip-compressed; Save reports progress per node via IProgress<double>.
  • SnapshotManager / SnapshotStore — write a timestamped, read-only copy of the disk next to its .mdr image after each save, list/prune them, and restore one back. Content is deduplicated by SHA-256 into a shared blob store, so snapshots of a mostly-unchanged disk cost little extra space.

Disk Image Format (.mdr)

A little-endian binary format:

Field Type Description
Magic byte[4] MDRD
Version int32 Currently 3
CompressionLevel byte ImageCompressionLevel value (0=None/1=Fastest/2=Optimal/3=SmallestSize)
Capacity uint64 Configured capacity in bytes (always plaintext, even when encrypted)
VolumeLabel string Length-prefixed UTF-8 (always plaintext, even when encrypted)
Encryption info Present only when the image is password-protected: PBKDF2 salt and the wrapped content-encryption key
NodeCount int32 Number of nodes that follow
Node entries Path, metadata (10 fields), security descriptor, file data — gzip-compressed as a block when CompressionLevel != None, then AES-256-GCM encrypted on top when the image is password-protected

Version 1 (no CompressionLevel byte, always uncompressed) and version 2 (whole node region compressed, no encryption) images remain readable for backward compatibility.

Snapshot Format

Snapshots use a separate format from .mdr images. For disk.mdr, snapshots are named disk.yyyyMMdd-HHmmss.mdr in the same folder — a small binary index file (magic MDRS) listing each file/directory's metadata plus, for non-empty files, a SHA-256 hash. File content lives in a shared, content-addressed blob store at disk.snapblobs/ (sharded into 2-char hex subfolders), gzip-compressed per blob — identical content across snapshots is stored once. Encrypted disks additionally encrypt each blob with the same key via AES-256-GCM. Pruning or deleting a snapshot (via Restore Snapshot...) garbage-collects any now-unreferenced blobs; clearing a disk's password deletes all of its snapshots outright, since old blobs are unrecoverable without the discarded key.

Settings & Persistence

  • Settings are stored as JSON at %APPDATA%\ManagedDrive\settings.json, including each disk's own high-usage warning threshold (or its disabled state).
  • Windows startup registration uses HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run (no elevation required).
  • Version is derived from git tags (v-prefixed, e.g. v0.1.0) via MinVer.

Performance

Measured with BenchmarkDotNet (Intel Core i9-13980HX, 64 GB RAM, KIOXIA KXG8AZNV1T02 NVMe SSD, Windows 11 Pro, .NET 10.0.10):

Scenario RAM Disk NVMe SSD Ratio
Sequential write, 4 KB 2.2 MB/s 0.8 MB/s 2.9× faster
Sequential write, 1 MB 580 MB/s 104 MB/s 5.6× faster
Sequential read, 4 KB / 1 MB 3.0 MB/s / 643 MB/s 3.0 MB/s / 677 MB/s ≈ parity
Random 4 KB read, 30 seeks over 16 MB 1.9–2.3 ms 1.6 ms ~1.2–1.4× slower
30× small-file (4 KB) create+write 51.6 ms (1.72 ms/file) 80.7 ms (2.69 ms/file) 1.6× faster
  • Writes win big — the RAM disk skips block allocation, journaling, and the physical write.
  • Sequential reads land near parity with an OS-cache hit — a user-mode file system crosses WinFsp's kernel–userspace bridge, so it can't consistently beat the kernel's own DRAM page cache; only a kernel-mode driver could. These numbers vary run-to-run with page-cache state.
  • Random reads are modestly slower — each seek pays a kernel–userspace round-trip through WinFsp.
  • Small-file create+write is the other big win — file creation skips block allocation and journaling, at the cost of higher managed-memory allocation per operation.
  • Writes allocate far less managed memory now that file content is held in chunked, right-sized buffers (a 4 KB write allocates ~5.8 KB, down from ~65 KB when each file rounded up to a full buffer).

Run dotnet run --project benchmarks/ManagedDrive.Benchmarks -c Release for raw latency numbers and further scenarios (see Running Benchmarks below).

Running Tests

dotnet test tests/ManagedDrive.Tests

Tests cover FileNode, FileNodeMap (CRUD, lookup, pagination, rename, capacity tracking), MemoryFileSystem disk-cloning, directory enumeration and the wildcard matcher, DiskImageSerializer (round-trips across compression levels, legacy images, concurrent mutation during save), archive import/export, MountOptionsFactory, CreateDiskOptionsBuilder/ByteUnitConverter (create-disk dialog validation, kept WPF-free for testability), and PasswordStrengthEstimator. Mount/unmount integration tests need the WinFsp driver and must be run manually.

Running Benchmarks

WinFsp must be installed. The benchmark project auto-selects the first free drive letter between D: and Z: — no manual configuration needed.

dotnet run --project benchmarks/ManagedDrive.Benchmarks -c Release

BenchmarkDotNet will prompt you to pick which benchmark class(es) to run (SequentialReadWriteBenchmarks, RandomAccessBenchmarks, ConcurrentAccessBenchmarks, or any combination). Results are written to BenchmarkDotNet.Artifacts/results/ in the working directory.

CLI Usage

mdrive.exe ships alongside ManagedDrive.exe and forwards commands to the running app over a named pipe, so scripts can drive ManagedDrive without opening the UI. If the app isn't already running, mdrive launches it and retries for up to 10 seconds before giving up.

mdrive mount C:\disks\scratch.mdr R: --auto-mount --compression Optimal
mdrive list
mdrive save R:
mdrive format R: --yes
mdrive unmount R:
mdrive exit
Command Description
mount <image-path> <drive-letter> [options] Mounts an existing .mdr image at a drive letter. Options: --read-only, --auto-mount, --auto-save-minutes, --compression <None|Fastest|Optimal|SmallestSize>, --max-snapshot-count, --max-snapshot-size-mb, --high-usage-warn-percent, --password, --password-file (mutually exclusive; needed only if the image is encrypted — --password-file reads the first line of a file and is recommended over --password to avoid exposing it in shell history or the process list). Any option left unset keeps the image's saved profile value (or its default).
mount-archive <archive-path> [drive-letter] Imports an archive (zip/7z/rar/tar/...) as a read-only disk and opens it in Explorer once mounted. drive-letter is optional — if omitted, the first free letter from Z: down to D: is used. Used internally by the Explorer right-click menu entry.
unmount <drive-letter> Unmounts a mounted disk.
format <drive-letter> --yes Deletes all files on a mounted disk. Requires --yes/-y to confirm.
save <drive-letter> Saves a mounted disk's contents to its backing image immediately.
list Lists currently mounted disks with usage and capacity.
exit Exits the running ManagedDrive application.

Run mdrive --help or mdrive <command> --help for the full option list.

wingetx: winget wrapper

wingetx.exe is a transparent wrapper around winget that ships alongside ManagedDrive.exe/mdrive.exe. Use it as a drop-in replacement for winget:

wingetx install <package>
wingetx upgrade <package>

If %TEMP% isn't currently on a ManagedDrive volume, or the requested subcommand isn't install/upgrade, wingetx just forwards the call to winget.exe unchanged — so it's always safe to alias winget to wingetx.

When %TEMP% is set to a ManagedDrive volume, wingetx install/wingetx upgrade routes MSI- and exe-based packages through winget download followed by a manual launch of the downloaded installer (msiexec for MSI/WiX, the installer exe directly otherwise), instead of a plain winget install. This sidesteps both failure modes described in Known Issues below: msiexec's Mount-Manager source-volume check, and the cross-session exit-code-1 issue affecting exe installers. Installer types it can't confidently handle this way (msix, appx, zip, portable, ...) are forwarded to plain winget install/upgrade automatically.

  • The installer's UI stays visible (SilentWithProgress switches) unless --silent or --disable-interactivity is passed, matching winget's own behavior.
  • The downloaded installer is staged in %LOCALAPPDATA%\Temp\wingetx — a real, non-WinFsp volume — before it's launched.

Known Issues

Certain installers may fail when TEMP is set to a RAM disk

WinFsp mounts a drive letter into the current logon session's device namespace, so processes in another session or logon (a session-0 system service, or an elevated process under the linked admin token) can't resolve it. Two distinct failure modes result:

  1. Cross-session drive-letter visibility — a system-level process (e.g. winget's Package Manager service) launching from Z:\Temp\...\setup.exe fails with 0x800704b3 (The network path was not found). Known affected: WeChatWin_*.exe, 7z*.exe, Git-*.exe. Fixed by the optional SYSTEM helper service below, which publishes a global (\GLOBAL??) symlink for the drive.
  2. MSI installers via the Windows Installer servicemsiexec's SYSTEM/session-0 half does a Mount Manager volume-identity query on the source volume before reading it; WinFsp's per-session mount isn't Mount-Manager-registered, so the query fails with system error 1005 → MSI error 2755/1603. The helper service's symlink doesn't fix this — the volume still isn't Mount-Manager-registered. Affects winget MSI installs and standalone .msi files sourced from the RAM disk; a proper fix would need a larger Mount-Manager-based mount rearchitecture, out of scope for the helper service.

Optional SYSTEM helper service (ManagedDriveHelper) resolves failure mode 1 by publishing a cross-session global symlink for whichever disk is the current TEMP target; it does not address failure mode 2.

  • Installer builds (ManagedDrive-Setup-*.exe) register and remove the service automatically — no action needed.
  • Portable ZIP: install it yourself from an elevated (Administrator) terminal in the extracted folder:
    sc create ManagedDriveHelper binPath= "%cd%\ManagedDriveHelper.exe" start= auto
    sc start ManagedDriveHelper
    
    Remove later with sc stop ManagedDriveHelper then sc delete ManagedDriveHelper. Entirely optional — ManagedDrive works normally without it; skipping it just leaves failure mode 1 unresolved.

Fixing MSI installs: reset TEMP to the Windows default (toolbar button) before installing MSI-based software, then retry — or download the installer from the vendor and run it manually. Or use wingetx in place of winget, which works around both failure modes without touching TEMP.

ManagedDrive warns once when TEMP is set to a RAM disk, and again on every startup while it stays that way.

License

MIT

This project bundles WinFsp and SharpCompress; see THIRD-PARTY-NOTICES.md for their copyright and license information.


中文

基于 .NET 10 和 WinFsp 构建的 Windows RAM 虚拟磁盘管理器。
创建、挂载并管理内存盘,它们在文件资源管理器中以普通驱动器号的形式呈现。

功能特性

核心功能

  • 同时挂载多个 RAM 磁盘,各自拥有独立的驱动器号、容量、卷标和只读标志
  • 动态内存分配——容量为上限而非预分配
  • 实时编辑已挂载磁盘(卷标、容量、自动挂载、镜像路径);更改盘符或只读标志会自动重挂
  • NTFS 兼容,可作为需要 NTFS 卷的工具(WinGet、Windows Update 暂存、BITS)的目标路径
  • 启动时自动挂载已保存的磁盘配置
  • 格式化立即清空磁盘内容(只读磁盘受保护)

持久化、快照与克隆

  • 保存为 .mdr 镜像并在下次挂载时还原,或直接导入已有镜像(导入磁盘...
  • 导入压缩包(zip/7z/rar/tar 等 SharpCompress 支持的格式)为只读磁盘(导入压缩包...),容量/卷标自动推算
  • 可选自动保存(1-60 分钟)及卸载/退出前的收尾保存(可按磁盘通过退出时保存关闭);内容未变时跳过,失败会有托盘/状态栏提示
  • 可选镜像压缩级别(不压缩/快速/均衡/最高,默认快速)
  • 按数量/大小上限保留的快照版本历史,内容去重存储;通过**还原快照...**还原或删除单个快照
  • 克隆磁盘到另一已挂载磁盘,或导出为新 .mdr 文件(克隆磁盘...
  • 可选 .mdr 密码保护(AES-256-GCM 信封加密——密码仅包裹一个随机每盘密钥,改密码无需重新加密文件);在磁盘对话框中通过"加密镜像"设置(8–64 位,带实时强度提示),加密镜像挂载时会提示输入密码;敏感缓冲区用完即从内存清零
  • 长耗时操作(保存镜像、导入/导出压缩包)显示带进度条的忙碌遮罩,避免应用看起来无响应

便利与安全

  • 可选资源管理器右键集成:为 zip/7z/rar/tar 添加**"挂载为内存盘 (ManagedDrive)"**菜单项,一键挂载并自动启动应用、打开资源管理器
  • 托盘图标带悬浮提示(各盘用量+可用内存)、快捷菜单、可选最小化启动,读写活动时短暂闪烁指示
  • 状态栏实时显示可用系统内存(2 秒刷新)
  • 状态栏同时推送最近访问的文件(节流至 300 毫秒一次,非轮询),窗口最小化到托盘时暂停
  • 每磁盘可配置高用量警告(默认 90%,带回滞防抖)
  • 临时目录重定向到某磁盘的 Temp 文件夹,卸载/重挂自动恢复,TEMP 遗留在内存盘上时启动提示
  • 退出确认并显示保存遮罩直至待处理保存完成;TEMP 指向已挂载磁盘时会先重置
  • 双击在资源管理器中打开磁盘;右键提供快捷方式或查看磁盘内容...(只读、可排序的名称/大小/类型树状列表)

界面

  • 双语(中/英)及浅色/深色主题,均可自动检测或手动切换,即时生效
  • 磁盘卡片带状态角标(只读、当前临时目录、绑定镜像、密码保护)及超阈值变色的使用率进度条
  • 窗口可自由拖拽调整大小,不支持最大化/全屏
  • 关于对话框显示版本、GitHub 链接,有新版本时显示更新链接
  • 可选每日检查更新;发现新版本时弹出托盘气泡+对话框(查看发布页/忽略/稍后提醒)

命令行

  • mdrive(随 ManagedDrive.exe 发布)通过命名管道对运行中的应用执行 mount/unmount/format/save/list/exit
  • 若应用未运行会自动启动并等待就绪后发送命令

安装

Releases 页面为每个版本发布了两种安装方式,任选其一:

  • ManagedDrive-Setup-X.Y.Z.exe —— 引导式安装程序。会自动检测 WinFsp 和 .NET 10 桌面运行时是否已安装,若缺少 WinFsp 会静默安装内置的 WinFsp 安装包,若缺少 .NET 桌面运行时会提示安装,并将 ManagedDrive 安装到 Program Files,创建开始菜单/桌面快捷方式。推荐大多数用户使用。
  • ManagedDrive-vX.Y.Z-win-x64-portable.zip —— 体积较小;需要单独安装 WinFsp 和 .NET 10 桌面运行时

若使用 ZIP,解压到任意目录后直接运行 ManagedDrive.exe 即可。ManagedDrive.exe 是单文件可执行程序——ZIP 中还附带一个体积很小的 winfsp-msil.dll(WinFsp 托管互操作程序集,无法打包进单文件中),需与 exe 保持在同一目录下。唯一会写入注册表的操作是可选的"开机自启"设置,除此之外不会写入注册表。使用 ZIP 时仍需提前单独安装 WinFsp(见下方环境要求);安装程序会自动处理这一步。

ZIP 中还包含 mdrive.exe(配套命令行工具,见下方命令行用法)和 wingetx.exewinget 包装工具,见下方wingetx: winget 包装工具)。将解压目录加入 PATH 后即可在任意终端中运行 mdrive/wingetx。安装程序会自动将两者加入系统级 PATH

环境要求

要求 说明
Windows 10 / 11(64 位) 暂未测试 ARM64
WinFsp 2.2.26194(2026 Beta3) 必须安装此版本才能运行 ManagedDrive。请直接下载安装包:winfsp-2.2.26194.msi——不要使用 winget install WinFsp.WinFsp 安装,因为该 winget 包更新不及时,落后于最新发布版本。托管程序集 winfsp-msil.dll 将安装至 C:\Program Files (x86)\WinFsp\bin\,项目会自动引用。
.NET 10 桌面运行时 "绿色版"(框架依赖型)ZIP 需要。
.NET 10 SDK 编译所需。

快速开始

# 1. 下载并安装 WinFsp 2.2.26194(2026 Beta3)
# https://github.com/winfsp/winfsp/releases/download/v2.2B3/winfsp-2.2.26194.msi

# 2. 克隆仓库
git clone https://github.com/coldhighsun/ManagedDrive
cd ManagedDrive

# 3. 编译
dotnet build

# 4. 运行
dotnet run --project src/ManagedDrive.App -c Release

或者在 Visual Studio 2022+ 中打开 ManagedDrive.slnx 并按 F5

解决方案结构

ManagedDrive/
├── src/
│   ├── ManagedDrive.Core/              # 内存文件系统引擎(WinFsp),不依赖任何 UI
│   │   ├── FileSystem/                 #   FileNode、FileNodeMap、MemoryFileSystem、WildcardMatcher、DirectoryEnumeration
│   │   ├── Mounting/                   #   DiskOptions、RamDisk、MountManager、MountOptionsFactory
│   │   ├── Persistence/                #   DiskImageSerializer(.mdr 格式)
│   │   ├── Snapshots/                  #   SnapshotManager、SnapshotStore
│   │   ├── Archive/                    #   ArchiveNodeMapBuilder(导入)、ArchiveNodeMapWriter(导出)
│   │   └── DiskCreation/               #   CreateDiskOptionsBuilder、ByteUnitConverter
│   ├── ManagedDrive.App/               # WPF 桌面应用程序——托盘图标、各类对话框、设置、多语言/主题
│   ├── ManagedDrive.Cli.Core/          # 共享的 CLI 解析/协议库(System.CommandLine + 命名管道协议)
│   ├── ManagedDrive.Cli/               # `mdrive.exe` 控制台入口点
│   ├── ManagedDrive.HelperProtocol/    # 应用与 SYSTEM 辅助服务之间共享的命名管道协议
│   ├── ManagedDrive.Service/           # `ManagedDriveHelper.exe`——可选的 LocalSystem 服务,发布全局 DOS 设备符号链接以实现跨会话 TEMP 可见性(见"已知问题")
│   └── ManagedDrive.WingetExtension/   # `wingetx.exe`——透明的 winget 包装工具(见"wingetx: winget 包装工具")
├── tests/
│   └── ManagedDrive.Tests/             # xUnit v3 单元测试(仅纯托管代码)
└── benchmarks/
    └── ManagedDrive.Benchmarks/        # BenchmarkDotNet 吞吐量/延迟基准测试

工作原理

ManagedDrive 使用 WinFsp(Windows 文件系统代理)将内存目录树呈现为真实的 Windows 卷,通过已签名内核驱动把文件 I/O 转发至 MemoryFileSystem,数据存储在 .NET 字节数组中。

核心类:

  • FileNode — 节点的 Fsp.Interop.FileInfo 元数据、byte[] 数据缓冲区、缓存的叶子名称及安全描述符。
  • FileNodeMap — 不区分大小写的 SortedDictionary<string, FileNode>,支持分页子节点枚举和 O(1) 已分配字节追踪,通过 C# 13 Lock 保证线程安全。
  • MemoryFileSystem : FileSystemBase — 实现全部 21 个 WinFsp 回调(CreateReadWriteRename 等),强制容量上限(超出返回 STATUS_DISK_FULL),仅分配实际写入的字节。
  • RamDisk — 组合 MemoryFileSystemFileSystemHostCreate() 挂载卷、等待盘符出现(最长 2.5 秒)并刷新资源管理器;Dispose() 执行卸载。可选自动保存计时器与 Dispose() 时的收尾保存(可通过"退出时保存"关闭)保持镜像最新,内容未变时跳过。SaveFailed 事件会上报任何保存/快照失败,包括原本会被静默吞掉的后台失败。可选的每盘加密仅在内存中保留一个由用户密码包裹的随机密钥。
  • MountManager — 线程安全的活动 RamDisk 注册表,提供 DiskMounted/DiskUnmounted 事件。
  • DiskImageSerializer — 读写 .mdr 文件(元数据、ACL、文件数据),可选 gzip 压缩;Save 通过 IProgress<double> 按节点上报进度。
  • SnapshotManager / SnapshotStore — 每次保存后在主镜像旁写入带时间戳的只读快照,支持列出、清理及还原。内容按 SHA-256 去重存储,因此对基本未变化的磁盘做快照额外占用很小。

磁盘镜像格式(.mdr

小端序二进制格式:

字段 类型 说明
魔数 byte[4] MDRD
版本 int32 当前为 3
压缩级别 byte ImageCompressionLevel 取值(0=不压缩/1=快速/2=均衡/3=最高)
容量 uint64 配置的容量(字节,即便镜像已加密也始终为明文)
卷标 string 长度前缀 UTF-8(即便镜像已加密也始终为明文)
加密信息 仅当镜像已加密时存在:PBKDF2 盐值及被包裹的内容加密密钥
节点数 int32 后续节点数量
节点条目 路径、元数据(10 个字段)、安全描述符、文件数据——压缩级别非 0 时整体经 gzip 压缩,镜像已加密时再整体经 AES-256-GCM 加密

版本 1(不含压缩级别字段,始终不压缩)和版本 2(节点区整体压缩,不支持加密)的镜像仍可正常读取,保持向后兼容。

快照格式

快照采用与 .mdr 镜像独立的格式。对于主镜像 disk.mdr,快照命名为同目录下的 disk.yyyyMMdd-HHmmss.mdr——一个小型二进制索引文件(魔数 MDRS),列出文件/目录元数据,非空文件附带 SHA-256 哈希。文件内容存储在共享的内容寻址块存储 disk.snapblobs/ 中(按哈希前 2 位分片),逐块 gzip 压缩——相同内容跨快照只保存一份。加密磁盘的每个块还会用同一密钥做 AES-256-GCM 加密。清理或删除单个快照(还原快照...)会垃圾回收不再被引用的块;清除密码会直接删除该磁盘的所有快照,因为旧块在密钥丢弃后已无法恢复。

配置与持久化

  • 配置以 JSON 格式存储于 %APPDATA%\ManagedDrive\settings.json,包括每个磁盘各自的高用量告警阈值(或已禁用状态)。
  • 开机自启通过 HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run 注册表项实现(无需提升权限)。
  • 版本号由 MinVer 从 git 标签派生(v 前缀,例如 v0.1.0)。

性能基准

使用 BenchmarkDotNet 测量(Intel Core i9-13980HX、64 GB 内存、KIOXIA KXG8AZNV1T02 NVMe SSD、Windows 11 Pro、.NET 10.0.10):

场景 内存盘 NVMe SSD 倍率
顺序写入,4 KB 2.2 MB/s 0.8 MB/s 快 2.9×
顺序写入,1 MB 580 MB/s 104 MB/s 快 5.6×
顺序读取,4 KB / 1 MB 3.0 MB/s / 643 MB/s 3.0 MB/s / 677 MB/s ≈ 持平
随机 4 KB 读取,对 16 MB 文件寻址 30 次 1.9–2.3 ms 1.6 ms 慢 ~1.2–1.4×
30 次小文件(4 KB)创建+写入 51.6 ms(1.72 ms/文件) 80.7 ms(2.69 ms/文件) 快 1.6×
  • 写入优势明显——内存盘跳过了物理块分配、日志记录和实际落盘。
  • 顺序读取与 OS 页缓存命中基本持平——用户态文件系统要经过 WinFsp 的内核–用户态桥接,无法稳定超越内核自身的 DRAM 页缓存,只有内核态驱动才可能做到;这组数据会随页缓存状态逐次波动。
  • 随机读取略慢——每次寻址都要经过 WinFsp 的内核–用户态往返。
  • 小文件创建+写入是另一大优势——文件创建跳过了物理块分配和日志记录,代价是每次操作的托管内存分配更高。
  • 得益于分块、按需精确分配的内容缓冲,写入的托管内存分配已大幅下降(一次 4 KB 写入约分配 5.8 KB,此前约 65 KB)。

运行 dotnet run --project benchmarks/ManagedDrive.Benchmarks -c Release 可获取原始延迟数据及更多场景(见下方运行基准测试)。

运行测试

dotnet test tests/ManagedDrive.Tests

测试覆盖 FileNodeFileNodeMap(增删改查、查找、分页、重命名、容量追踪)、MemoryFileSystem 的磁盘克隆逻辑、目录枚举及通配符匹配、DiskImageSerializer(各压缩级别的保存/加载往返、旧版本镜像、并发修改)、压缩包导入/导出、MountOptionsFactoryCreateDiskOptionsBuilder/ByteUnitConverter(下沉到 Core 以便脱离 WPF 单测),以及 PasswordStrengthEstimator。挂载/卸载集成测试需要 WinFsp 驱动,须手动运行。

运行基准测试

须已安装 WinFsp。基准测试项目会自动选择 D:Z: 之间第一个空闲盘符,无需手动配置。

dotnet run --project benchmarks/ManagedDrive.Benchmarks -c Release

BenchmarkDotNet 会提示你选择要运行的基准测试类(SequentialReadWriteBenchmarksRandomAccessBenchmarksConcurrentAccessBenchmarks,或任意组合)。结果将写入工作目录下的 BenchmarkDotNet.Artifacts/results/

命令行用法

mdrive.exeManagedDrive.exe 一同发布,通过命名管道将命令转发给正在运行的应用,因此脚本无需打开界面即可操作 ManagedDrive。若应用尚未运行,mdrive 会自动启动它,并在最长 10 秒内重试。

mdrive mount C:\disks\scratch.mdr R: --auto-mount --compression Optimal
mdrive list
mdrive save R:
mdrive format R: --yes
mdrive unmount R:
mdrive exit
命令 说明
mount <镜像路径> <盘符> [选项] 将已有的 .mdr 镜像挂载到指定盘符。可选项:--read-only--auto-mount--auto-save-minutes--compression <None|Fastest|Optimal|SmallestSize>--max-snapshot-count--max-snapshot-size-mb--high-usage-warn-percent--password--password-file(二者互斥;仅当镜像已加密时需要——推荐使用 --password-file(读取文件首行作为密码)而非 --password,以避免密码出现在 shell 历史或进程列表中)。未指定的选项沿用该镜像已保存的配置值(或其默认值)。
mount-archive <压缩包路径> [盘符] 将压缩包(zip/7z/rar/tar 等)作为只读磁盘导入挂载,挂载完成后会自动在资源管理器中打开该盘符。盘符可省略——省略时自动从 Z: 向下查找第一个可用盘符。资源管理器右键菜单项内部即调用此命令。
unmount <盘符> 卸载已挂载的磁盘。
format <盘符> --yes 清空已挂载磁盘上的所有文件,须加 --yes/-y 确认。
save <盘符> 立即将已挂载磁盘的内容保存到其绑定的镜像文件。
list 列出当前已挂载的磁盘及其用量与容量。
exit 退出正在运行的 ManagedDrive 应用。

运行 mdrive --helpmdrive <命令> --help 可查看完整的选项列表。

wingetx: winget 包装工具

wingetx.exewinget 的透明包装工具,随 ManagedDrive.exe/mdrive.exe 一同发布。可直接把它当作 winget 的替代品使用:

wingetx install <包名>
wingetx upgrade <包名>

如果 %TEMP% 当前不在 ManagedDrive 内存盘上,或所调用的子命令不是 install/upgradewingetx 会原样把调用转发给 winget.exe——因此把 winget 直接别名为 wingetx 始终是安全的。

%TEMP% 确实设为 ManagedDrive 内存盘时,wingetx install/wingetx upgrade 会将 MSI 及 exe 类型的包改为先执行 winget download,再手动启动下载好的安装程序(MSI/WiX 用 msiexec,其余直接运行安装包本身),而不是直接执行 winget install。这样可以绕开下方已知问题中描述的两种失败模式:msiexec 的卷装载管理器(Mount Manager)源卷检查,以及影响 exe 安装包的跨会话退出码 1 问题。它无法确信处理的安装包类型(msix、appx、zip、便携版等)会自动转发给普通的 winget install/upgrade

  • 除非传入 --silent--disable-interactivity,安装程序界面默认保持可见(SilentWithProgress 开关),与 winget 自身行为一致。
  • 下载的安装包会先暂存到 %LOCALAPPDATA%\Temp\wingetx(一个真实的、非 WinFsp 的卷)再启动。

已知问题

将 TEMP 设为内存盘后,某些安装包可能报错

WinFsp 把盘符挂载在**当前登录会话(logon session)**的设备命名空间中,因此其他会话或登录令牌下的进程(session 0 的系统服务、或提权后跑在链接管理员令牌下的进程)无法解析该盘符,由此产生两种失败模式:

  1. 跨会话盘符可见性——系统级进程(如 winget 的软件包管理器服务)从 Z:\Temp\...\setup.exe 启动时看不到该盘,报 0x800704b3网络路径未找到)。已知受影响:WeChatWin_*.exe(微信)、7z*.exe(7-Zip)、Git-*.exe(Git)。可由下方可选的 SYSTEM 辅助服务解决——它会为该盘发布一个全局(\GLOBAL??)符号链接。
  2. 通过 Windows Installer 服务安装的 MSI——msiexec 以 SYSTEM 身份跑在 session 0 的那一半,在读取源文件前会对源卷做一次卷身份查询(询问 Mount Manager);WinFsp 的 per-session 挂载没有在 Mount Manager 里注册,所以该查询以系统错误 1005 失败 → MSI 错误 2755/1603。辅助服务的符号链接修不了这个——卷依然不是 Mount-Manager 注册的系统卷。影响 winget 安装 MSI 包及源文件位于内存盘上的独立 .msi 文件;根治需要改为通过 Windows Mount Manager 挂载(更大的服务化挂载重构),不在辅助服务的能力范围内。

可选 SYSTEM 辅助服务ManagedDriveHelper)通过为当前 TEMP 目标盘发布跨会话全局符号链接来解决失败模式 1,对失败模式 2 无效。

  • 安装包版本(ManagedDrive-Setup-*.exe)会自动注册/移除该服务,无需手动操作。
  • 便携式 ZIP:需自己在解压目录下打开管理员终端手动执行:
    sc create ManagedDriveHelper binPath= "%cd%\ManagedDriveHelper.exe" start= auto
    sc start ManagedDriveHelper
    
    之后可用 sc stop ManagedDriveHelpersc delete ManagedDriveHelper 移除。完全是可选的——不做这一步 ManagedDrive 照常挂载和使用,只是失败模式 1 得不到解决。

MSI 安装的解决办法: 安装 MSI 类软件前,先用工具栏按钮把 TEMP 恢复为 Windows 默认值再重试;或直接前往官网下载安装包手动安装;也可以用 wingetx 代替 winget——它无需重置 TEMP 即可绕开上述两种失败模式。

ManagedDrive 会在 TEMP 被设为内存盘时提示一次,此后只要 TEMP 仍指向内存盘,每次启动都会再次提示——恢复默认值即可停止。

许可证

MIT

本项目内置了 WinFspSharpCompress,其版权与许可证信息见 THIRD-PARTY-NOTICES.md

About

A Windows RAM disk manager built on .NET 10 and [WinFsp](https://winfsp.dev). Create, mount and manage in-memory volumes that appear as normal drive letters in Explorer.

Topics

Resources

Stars

Watchers

Forks

Releases

Used by

Contributors

Languages