--- name: windows-filename-guidance os: win32 description: "Use for Windows filename rules and failures involving reserved DOS device names such as NUL, invalid or trailing characters, inaccessible cross-platform names, long paths, or files that Windows cannot inspect, rename, or delete normally." --- # Windows Filename Guidance ## Model Separate three layers: 1. the filesystem's on-disk rules 2. Windows path namespace and normalization 3. the application's API and path handling A name can exist on NTFS yet be unreachable through an ordinary Win32 path. This commonly happens when another operating system, namespace, share, or tool created it. It does not by itself prove corruption or bad permissions. ## Normal Windows Names For portable Windows names: - Do not use control characters U+0000 through U+001F or `<>:"/\|?*`. - Do not end a component with a space or period; Win32 normally strips them. - Do not use `.` or `..` as components. - Do not use `CON`, `PRN`, `AUX`, `NUL`, `COM1` through `COM9`, or `LPT1` through `LPT9`, regardless of case. An extension does not help: `NUL.txt` still resolves as `NUL`. - Treat `:` as the drive/alternate-data-stream separator, not filename text. - Assume case-insensitive lookup even though case is preserved. - Keep each component within the filesystem limit. Path-length support depends on the filesystem, API, application, and whether long paths are enabled. Use these rules when generating archives, repositories, build output, or shared files intended for Windows. ## Diagnose 1. Get the exact absolute path, error text, filesystem, and whether the target is a file or directory. 2. Enumerate the parent rather than probing the suspect name directly: ```cmd cmd.exe /d /c dir /a /x "C:\absolute\parent" ``` 3. Classify the failure: - reserved device name - trailing space/period or other Win32-invalid name - path too long for the current tool - open handle - ACL/ownership denial - filesystem corruption supported by disk or event-log errors 4. Prefer the same namespace, share, or program that created the entry when it can safely rename or remove it. Never use `Test-Path NUL` or `if exist NUL` to prove a file exists; those can address the device. ## Extended Paths For an existing local entry that ordinary Win32 normalization cannot address, use an exact absolute extended path: ```text \\?\C:\absolute\path ``` For UNC paths, convert `\\server\share\path` to: ```text \\?\UNC\server\share\path ``` The `\\?\` prefix bypasses ordinary Win32 parsing; it does not bypass the filesystem's rules, ACLs, locks, or corruption. Do not combine it with a relative path. ## Git Bash Boundary Git Bash/MSYS2 rewrites path-looking arguments passed to native Windows executables. This can also affect shell program text passed as one argument, such as a remote command containing `2>/dev/null`. Preserve literal POSIX text at that boundary with the documented exclusion variable: ```bash MSYS2_ARG_CONV_EXCL='*' podman.exe machine ssh 'command 2>/dev/null' ``` Do not assume `MSYS_NO_PATHCONV` covers every native executable. Bash double quotes reduce a leading `\\` to `\`. Therefore `"\\?\C:\absolute\path\NUL"` reaches a child process as the malformed `\?\C:\absolute\path\NUL`. When invoking `cmd.exe` from Bash, preserve the literal path and disable MSYS2 argument conversion: ```bash MSYS2_ARG_CONV_EXCL='*' cmd.exe /d /c del '\\?\C:\absolute\path\NUL' ``` The `cmd` examples below are native `cmd.exe` syntax. Do not paste their quoted paths unchanged into a Bash command. ## Delete Problem Entries Show the exact target and obtain explicit confirmation first. Reject wildcards, relative paths, drive/share roots, and ambiguous targets. If Git Bash created the entry and can enumerate its exact absolute POSIX path, prefer removing it through that same layer: ```bash rm -- "$PWD/NUL" ``` File through native `cmd.exe`: ```cmd cmd.exe /d /c del "\\?\C:\absolute\path\NUL" ``` Read-only file, only after reporting why: ```cmd cmd.exe /d /c del /f "\\?\C:\absolute\path\NUL" ``` Empty directory: ```cmd cmd.exe /d /c rd "\\?\C:\absolute\path\NUL" ``` Nonempty directory: enumerate its contents and obtain separate recursive-delete confirmation before running: ```cmd cmd.exe /d /c rd /s /q "\\?\C:\absolute\path\NUL" ``` Preserve exact spelling, extension, spaces, and periods. Enumerate the parent again; report success only when the literal entry is absent. `git status` is not direct filesystem verification. If deletion succeeds and parent enumeration no longer contains the literal entry, but Git still reports it, bypass its filesystem monitor and untracked cache once: ```bash git -c core.fsmonitor=false -c core.untrackedCache=false status --short ``` If that removes the report and the repository uses the built-in monitor, restart it. Do not issue further deletion commands solely because cached Git status still names the entry. If the extended path still fails, use `dir /a /x` on the parent. Verify the 8.3 short name maps to the exact target before proposing deletion through that name. ## Other Causes - Open handle: identify and close the owning process before retrying. - ACL denial: inspect ownership and permissions; request elevation or ownership changes only when confirmed necessary. - Deep path: use an extended path, shorten a parent, map a deeper drive/share, or use a tool that supports the full path. - Corruption: run filesystem repair only when independent evidence supports it; an odd filename alone is insufficient. - Missing parent entry: stop. A successful reference to `NUL` alone is the null device, not evidence of a file. ## Sources - [MSYS2: filesystem paths and argument conversion](https://www.msys2.org/docs/filesystem-paths/) - [GNU Bash: double-quote backslash handling](https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html) - [Git: built-in filesystem monitor](https://git-scm.com/docs/git-fsmonitor--daemon) - [Super User: removing a file named NUL](https://superuser.com/questions/282194/how-do-i-remove-a-file-named-nul-on-windows) - [Microsoft KB 320081: undeletable NTFS entries](https://learn.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/cannot-delete-file-folder-on-ntfs-file-system) - [Microsoft: Naming Files, Paths, and Namespaces](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file) - [Wikipedia: filename limitations](https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations)