Skip to content

Commit 760d302

Browse files
committed
fix: Use nul instead of NUL on Windows
`NULL_DEVICE` is `/dev/null` except on Windows, where there are several possible choices. Previously we were using `NUL` because the more modern full path `\\.\NUL` is not supported by `git`. However, `git` also rejects `NUL`, when capitalized, on some Windows systems. This can be observed on Windows 11 ARM64 builds. In contrast, the lower-case `nul`, which Windows itself treats the same as `NUL`, is always accepted by Git for Windows. Although it's not readily apparent why Git for Windows accepts `NUL` on some Windows operating systems and/or platforms and not others, the preferential treatment of `nul` (not extending to `NUL`) can be seen in a few places in the Git for Windows source code, including in `mingw_access` (`strcmp` is case-sensitive): https://github.com/git-for-windows/git/blob/a36f720572491aafc59d63ff926b04d9fa787ec3/compat/mingw.c#L1093 Therefore, this changes `"NUL"` to `"nul"` for the Windows null device path. This allows some functionality where `git` is invoked that had been broken on ARM64 Windows systems to start working. See 7280a2d (GitoxideLabs#1567) and 3cf9fc1 (GitoxideLabs#1570) for further context. Git for Windows also special-cases the literal path `/dev/null` in access checks and when opening it for read or write (thought not if an attempt is made to execute or change directory to it). We nonetheless change `NUL` to `nul` on Windows, rather than changing it to `/dev/null` and using that value on all platforms. The reason is that treating `/dev/null` as the null device on Windows is specific to Git for Windows. `/dev/null` on Windows would not be the null device, nor otherwise special, if we open it ourselves, nor if opened indirectly by other programs that don't special-case it. Then it would be equivalent to `\dev\null` (a relative path, resolved as `X:\dev\null` where `X:` is replaced by the current drive, which is not what we want).
1 parent 48dfacf commit 760d302

File tree

2 files changed

+6
-2
lines changed

2 files changed

+6
-2
lines changed

gix-path/src/env/git/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,12 @@ pub(super) const EXE_NAME: &str = "git";
8484
/// The git executable is the one found in PATH or an alternative location.
8585
pub(super) static GIT_HIGHEST_SCOPE_CONFIG_PATH: Lazy<Option<BString>> = Lazy::new(exe_info);
8686

87+
// There are a number of ways to refer to the null device on Windows, but they are not all equally
88+
// well supported. Git for Windows rejects `\\.\NUL` and `\\.\nul`. On Windows 11 ARM64 (and maybe
89+
// some others), it rejects even the legacy name `NUL`, when capitalized. But it always accepts the
90+
// lower-case `nul`, handling it in various path checks, some of which are done case-insensitively.
8791
#[cfg(windows)]
88-
const NULL_DEVICE: &str = "NUL";
92+
const NULL_DEVICE: &str = "nul";
8993
#[cfg(not(windows))]
9094
const NULL_DEVICE: &str = "/dev/null";
9195

tests/tools/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ fn scripted_fixture_read_only_with_args_inner(
619619
}
620620

621621
#[cfg(windows)]
622-
const NULL_DEVICE: &str = "NUL";
622+
const NULL_DEVICE: &str = "nul"; // See `gix_path::env::git::NULL_DEVICE` on why this form is used.
623623
#[cfg(not(windows))]
624624
const NULL_DEVICE: &str = "/dev/null";
625625

0 commit comments

Comments
 (0)