fix(io): preserve Windows drive letter in local filesystem paths#398
Merged
Conversation
The fs storage relative-path logic dropped the first character of every
absolute path to turn it into a path opendal joins onto its '/' root.
This works for POSIX ('/tmp/wh' -> 'tmp/wh') but corrupts Windows paths
('C:\\wh' -> ':\\wh'), losing the drive letter so opendal fails with
'invalid filename' on every local-catalog operation.
Keep the drive specifier for Windows paths and only normalize separators
to '/', mirroring Java Paimon's Path (modeled on Hadoop) and pypaimon's
LocalFileIO: opendal then does PathBuf::from("/").join("C:/wh"), and
because the argument carries a drive prefix Path::join rebuilds the real
C:\\wh. fs_relative_path now returns Cow so the normalized form is owned
when needed, and InputFile/OutputFile store the relative path directly
instead of re-slicing the original (which would lose the normalization).
This fixes single-file local operations on Windows; the manifest tests
(read/write only) are un-gated accordingly. Directory listing on Windows
still fails inside opendal's fs lister (it strips the operator root from
entries, which a drive-rooted path escapes), so the filesystem/factory
catalog tests stay #[cfg(not(windows))] and that rework is tracked in apache#397.
Add unit tests for fs_relative_path covering POSIX, file: scheme, Windows
drive, and mixed separators.
4ce7e3d to
81d1a33
Compare
QuakeWang
approved these changes
Jun 20, 2026
QuakeWang
left a comment
Member
There was a problem hiding this comment.
LGTM. The fix is well-scoped: Windows drive-rooted local paths now preserve the drive letter and normalize separators before passing paths to opendal, while non-fs storage paths stay borrowed and unchanged.
I also checked the remaining Windows directory-listing limitation; keeping those tests skipped and tracking that separately in #397 looks reasonable for this PR's scope.
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.
Purpose
Linked issue: close #397
The local
FileIO(fsstorage) corrupts absolute Windows paths.fs_relative_pathturned an absolute path into the path opendal joins onto its/root by dropping the first character — correct for POSIX (/tmp/wh->tmp/wh), but on Windows it drops the drive letter (C:\wh->:\wh), so every local-catalog operation fails withinvalid filename (os error 123). This is why thefilesystem/factory/manifesttests were gated behind#[cfg(not(windows))]. Java Paimon does not have this bug — itsPath(modeled on Hadoop) keeps the drive letter and normalizes separators.Brief change log
fs_relative_pathnow returnsCow<str>: keeps the drive specifier and only normalizes\->/for Windows paths (opendal'sPathBuf::from("/").join("C:/wh")rebuilds the realC:\wh); POSIX behavior is byte-identical.Storage::createreturns(Operator, Cow<str>).InputFile/OutputFilestore the relative path string instead of re-slicing the original (which would discard the normalization).#[cfg(not(windows))]test gates so Windows CI now exercises the local FileIO.Tests
fs_relative_path(POSIX,file:scheme, Windows drive, mixed separators).filesystem/factory/manifestsuites now run on Windows CI.API and Format
No public API or storage-format change (the changed
InputFile/OutputFilefield is private).Documentation
N/A.