Skip to content

gomodfs: declare the WinFsp volume case-sensitive and case-preserving - #31

Merged
bradfitz merged 1 commit into
mainfrom
bradfitz/winfsp_case_sensitive
Oct 6, 2026
Merged

bradfitz merged 1 commit into
mainfrom
bradfitz/winfsp_case_sensitive

Conversation

@bradfitz

@bradfitz bradfitz commented Oct 6, 2026

Copy link
Copy Markdown
Member

gomodfs's paths are case-sensitive, like the GOMODCACHE layout it
emulates (which escapes capital letters as "!x"), but the WinFsp mount
claimed to be case-insensitive and not case-preserving. So for opens
relative to a working directory on the mount, Windows passed gomodfs
the working directory's path upcased, e.g.
"TSGO-WINDOWS-AMD64//SRC/INTERNAL/ABI/textflag.h". gomodfs
didn't recognize those paths and answered with an empty directory for
any of them, so relative opens of files that don't exist succeeded
and relative opens of files that do returned a directory.

This broke Go builds using a Tailscale Go toolchain served from the
mount: cmd/asm runs in each package's source directory and first tries
to open #include files relative to it, so it "found" textflag.h there
and then failed reading it with "The parameter is incorrect".

Mount with winfsp.CaseSensitive(true) and
FspFSAttributeCasePreservedNames so Windows passes names through
verbatim. Add a CI test, run in the WinFsp job, that reads a file in
the mounted module cache by a relative path; it fails before this
change and passes after.

Updates tailscale/corp#24037

gomodfs's paths are case-sensitive, like the GOMODCACHE layout it
emulates (which escapes capital letters as "!x"), but the WinFsp mount
claimed to be case-insensitive and not case-preserving. So for opens
relative to a working directory on the mount, Windows passed gomodfs
the working directory's path upcased, e.g.
"TSGO-WINDOWS-AMD64/<HASH>/SRC/INTERNAL/ABI/textflag.h". gomodfs
didn't recognize those paths and answered with an empty directory for
any of them, so relative opens of files that don't exist succeeded
and relative opens of files that do returned a directory.

This broke Go builds using a Tailscale Go toolchain served from the
mount: cmd/asm runs in each package's source directory and first tries
to open #include files relative to it, so it "found" textflag.h there
and then failed reading it with "The parameter is incorrect".

Mount with winfsp.CaseSensitive(true) and
FspFSAttributeCasePreservedNames so Windows passes names through
verbatim. Add a CI test, run in the WinFsp job, that reads a file in
the mounted module cache by a relative path; it fails before this
change and passes after.

Updates tailscale/corp#24037

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
@bradfitz
bradfitz merged commit adc78e7 into main Oct 6, 2026
7 checks passed
@bradfitz
bradfitz deleted the bradfitz/winfsp_case_sensitive branch October 6, 2026 02:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant