Skip to content

Instantly share code, notes, and snippets.

@vmfunc
Created February 11, 2026 21:44
Show Gist options
  • Select an option

  • Save vmfunc/e5bcb30361f79218e94f88f67c099528 to your computer and use it in GitHub Desktop.

Select an option

Save vmfunc/e5bcb30361f79218e94f88f67c099528 to your computer and use it in GitHub Desktop.
virtiofs reparse point workaround using bindflt CreateBindLink
/*
* cowork-drives - bind windows drive roots into a folder via bindflt
*
* virtiofs cant follow NTFS reparse points (junctions/symlinks),
* so we use CreateBindLink to create kernel-level bind mounts
* that show up as real directories. must run as SYSTEM.
*
* usage: cowork-drives.exe <folder> <letter> [letter ...]
* example: cowork-drives.exe C:\Users\me\AllDrives C D F
*/
#include <windows.h>
#include <stdio.h>
typedef HRESULT (WINAPI *CreateBindLinkFn)(
LPCWSTR virtualPath,
LPCWSTR backingPath,
ULONG flags,
ULONG extraInfoCount,
void *extraInfo
);
typedef HRESULT (WINAPI *RemoveBindLinkFn)(LPCWSTR virtualPath);
int wmain(int argc, wchar_t *argv[]) {
if (argc < 3) {
wprintf(L"usage: %s <folder> <drive> [drive ...]\n", argv[0]);
wprintf(L"example: %s C:\\Users\\me\\AllDrives C D F\n", argv[0]);
return 1;
}
HMODULE lib = LoadLibraryW(L"bindfltapi.dll");
if (!lib) {
wprintf(L"err: cant load bindfltapi.dll (%lu)\n", GetLastError());
return 1;
}
CreateBindLinkFn bind =
(CreateBindLinkFn)GetProcAddress(lib, "CreateBindLink");
RemoveBindLinkFn unbind =
(RemoveBindLinkFn)GetProcAddress(lib, "RemoveBindLink");
if (!bind) {
wprintf(L"err: CreateBindLink not in bindfltapi.dll\n");
FreeLibrary(lib);
return 1;
}
LPCWSTR root = argv[1];
CreateDirectoryW(root, NULL);
int ok = 0, fail = 0, skip = 0;
for (int i = 2; i < argc; i++) {
wchar_t letter = argv[i][0];
if (letter >= L'a' && letter <= L'z')
letter -= 32;
/* build paths */
wchar_t virt[MAX_PATH], target[8];
swprintf(virt, MAX_PATH, L"%s\\%c", root, letter);
swprintf(target, 8, L"%c:\\", letter);
/* check drive exists */
if (GetDriveTypeW(target) == DRIVE_NO_ROOT_DIR) {
wprintf(L" skip %c (drive not found)\n", letter);
skip++;
continue;
}
/* remove old junction/symlink if present */
DWORD attr = GetFileAttributesW(virt);
if (attr != INVALID_FILE_ATTRIBUTES &&
(attr & FILE_ATTRIBUTE_REPARSE_POINT)) {
RemoveDirectoryW(virt);
}
CreateDirectoryW(virt, NULL);
if (unbind) unbind(virt);
HRESULT hr = bind(virt, target, 0, 0, NULL);
if (SUCCEEDED(hr)) {
wprintf(L" ok %c %s -> %s\n", letter, virt, target);
ok++;
} else {
wprintf(L" FAIL %c 0x%08lX\n", letter, hr);
fail++;
}
}
wprintf(L"\n%d ok, %d failed, %d skipped\n", ok, fail, skip);
if (ok > 0)
wprintf(L"bind links active until reboot\n");
FreeLibrary(lib);
return fail > 0 ? 1 : 0;
}
#requires -RunAsAdministrator
<#
.SYNOPSIS
mounts windows drives into a folder so cowork's virtiofs can see them.
.DESCRIPTION
virtiofs cant follow NTFS reparse points (junctions/symlinks), so this
script uses CreateBindLink (via bindflt minifilter) to create kernel-level
bind mounts that show up as real directories.
CreateBindLink requires SYSTEM privileges, so the script creates a
one-shot scheduled task to run the bind tool as SYSTEM.
bind links persist until reboot. run this after each boot before
opening cowork, or set it up as a startup task.
.PARAMETER Folder
target folder. defaults to $env:USERPROFILE\AllDrives
.PARAMETER Drives
drive letters to bind. defaults to all fixed drives on the system.
#>
param(
[string]$Folder = "$env:USERPROFILE\AllDrives",
[string[]]$Drives
)
# self-elevate if needed
if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
$args_str = "-Folder `"$Folder`""
if ($Drives) { $args_str += " -Drives $($Drives -join ',')" }
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" $args_str" -Verb RunAs
exit
}
$scriptDir = Split-Path -Parent $PSCommandPath
$exe = Join-Path $scriptDir "cowork-drives.exe"
if (-not (Test-Path $exe)) {
Write-Host "error: cowork-drives.exe not found at $exe" -ForegroundColor Red
Write-Host "put it next to this script"
exit 1
}
# auto-detect fixed drives if none specified
if (-not $Drives) {
$Drives = (Get-WmiObject Win32_LogicalDisk | Where-Object { $_.DriveType -eq 3 }).DeviceID -replace ':', ''
Write-Host "detected drives: $($Drives -join ', ')"
}
# clean up old junctions in the folder
if (Test-Path $Folder) {
Get-ChildItem $Folder -Directory | ForEach-Object {
if ($_.Attributes -band [IO.FileAttributes]::ReparsePoint) {
Write-Host "removing old junction: $($_.Name)"
[IO.Directory]::Delete($_.FullName)
}
}
}
# build args
$driveArgs = ($Drives | ForEach-Object { $_.Substring(0,1).ToUpper() }) -join ' '
$argString = "`"$Folder`" $driveArgs"
# write a bat to capture output
$logFile = Join-Path $scriptDir "cowork-drives.log"
$batFile = Join-Path $env:TEMP "cowork-drives-run.bat"
"@echo off`r`n`"$exe`" $argString > `"$logFile`" 2>&1" | Out-File $batFile -Encoding ascii
# run as SYSTEM via scheduled task
$taskName = "CoworkDrivesBind"
try {
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
} catch {}
$action = New-ScheduledTaskAction -Execute $batFile
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$task = New-ScheduledTask -Action $action -Principal $principal
Register-ScheduledTask -TaskName $taskName -InputObject $task -Force | Out-Null
Start-ScheduledTask -TaskName $taskName
# wait for it
$timeout = 10
for ($i = 0; $i -lt $timeout; $i++) {
Start-Sleep 1
$info = Get-ScheduledTaskInfo -TaskName $taskName -ErrorAction SilentlyContinue
if ($info -and $info.LastTaskResult -ne 267009) { break } # 267009 = still running
}
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
# show results
if (Test-Path $logFile) {
Write-Host ""
Get-Content $logFile | Write-Host
}
Write-Host ""
Write-Host "drives mounted at: $Folder" -ForegroundColor Green
Write-Host "these persist until reboot. run this script again after rebooting."
@echo off
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0cowork-mount-drives.ps1"
pause
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment