Repository navigation
fix(remotefs): fix whole-file reads and writes on Windows - #479
Merged
Merged
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Append handling and read-only exclusive creation do not preserve Go OpenFile semantics.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Improves Windows remote file correctness and reduces WinRM round trips.
Changes:
- Streams whole-file reads in one rigrcp command.
- Corrects Windows open-mode/access mappings.
- Prevents growing or shrinking files from corrupting the rigrcp protocol.
| File | Description |
|---|---|
remotefs/winfs.go |
Optimizes ReadFile and documents append behavior. |
remotefs/winfs_test.go |
Adds Windows read, write, and append tests. |
remotefs/winfile.go |
Updates copy, access, mode, and append handling. |
remotefs/winfile_internal_test.go |
Tests flag mappings. |
remotefs/rigrcp.ps1 |
Copies the announced byte count exactly. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
WinFS.ReadFile read through io.ReadAll. That doesn't use io.WriterTo; it calls Read with a 512-byte buffer that grows, and every Read is its own "r N" round trip to the rigrcp helper, which over WinRM means a command, a response poll and a payload transfer each. ReadFile now reads with CopyTo, a single "r -1". To support that, winFile.CopyTo returns (0, nil) for an empty file, as PosixFile.CopyTo already did, where it used to return io.EOF. "r -1" itself was unsafe. The helper sent the remaining length as n and then ran Stream.CopyTo, which copies up to wherever the file ends by then. If the file grew in the meantime, the extra bytes were read as the next command's JSON reply. If it shrank, the Go side waited until the watchdog fired. A read that threw partway had its error JSON written into the data stream, where it was read as file content. The helper now copies exactly n bytes. After n has been sent there is no framing left to carry an error, so a short copy or a failed read ends the helper and the Go side reports the stream ending early. WinFS.WriteFile never truncated. It opens with O_CREATE|O_TRUNC, and fMode turned any O_CREATE into FileMode.OpenOrCreate and dropped the O_TRUNC. Writing "ab" over "0123456789" left "ab23456789". O_CREATE|O_TRUNC is now FileMode.Create. The same mapping had more flag bugs: - O_APPEND mapped to FileMode.Append, and only when O_CREATE was absent. FileMode.Append creates a missing file and refuses read access, and O_CREATE|O_APPEND wrote from offset 0. The file is now opened with the mode the other flags call for, and each Write moves to the end of the file before writing, as O_APPEND does for an os.File. Reading still starts at the beginning. O_APPEND without O_CREATE on a missing file now fails, as os.OpenFile does. - fAccess checked the write flags before O_RDWR, so O_RDWR|O_TRUNC was opened write-only. - A read-only open with O_CREATE|O_EXCL or O_CREATE|O_TRUNC asked for read access, which .NET rejects for CreateNew and Create. A read-only open that needs write access for its mode, or for O_APPEND, now gets ReadWrite. Before, truncation and appending got write-only access, which left the handle unable to read. The WinFS.OpenFile doc no longer claims O_EXCL is ignored, because it maps to CreateNew. Refs #475 Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
kke
force-pushed
the
fix/winfs-readfile-copyto
branch
from
September 24, 2026 07:14
890303f to
571c9b0
Compare
kke
marked this pull request as ready for review
September 24, 2026 07:39
This was referenced Sep 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

WinFS.ReadFile read through io.ReadAll. That doesn't use io.WriterTo; it calls Read with a 512-byte buffer that grows, and every Read is its own "r N" round trip to the rigrcp helper, which over WinRM means a command, a response poll and a payload transfer each. ReadFile now reads with CopyTo, a single "r -1". To support that, winFile.CopyTo returns (0, nil) for an empty file, as PosixFile.CopyTo already did, where it used to return io.EOF.
"r -1" itself was unsafe. The helper sent the remaining length as n and then ran Stream.CopyTo, which copies up to wherever the file ends by then. If the file grew in the meantime, the extra bytes were read as the next command's JSON reply. If it shrank, the Go side waited until the watchdog fired. A read that threw partway had its error JSON written into the data stream, where it was read as file content. The helper now copies exactly n bytes. After n has been sent there is no framing left to carry an error, so a short copy or a failed read ends the helper and the Go side reports the stream ending early.
WinFS.WriteFile never truncated. It opens with O_CREATE|O_TRUNC, and fMode turned any O_CREATE into FileMode.OpenOrCreate and dropped the O_TRUNC. Writing "ab" over "0123456789" left "ab23456789". O_CREATE|O_TRUNC is now FileMode.Create. The same mapping had more flag bugs:
The WinFS.OpenFile doc no longer claims O_EXCL is ignored, because it maps to CreateNew.
Refs #475