fix: strip nested BasePathFs base segment from BasePathFile.Name

BasePathFile.Name trimmed only filepath.Clean(path) from the wrapped
file name. filepath.Clean drops the trailing separator, and a nested
BasePathFile reports a name whose base segment is preceded by a leading
separator (for example "/123/x"), which the cleaned base ("123") does
not match. The base then leaked into Name and callers double-prepended
it. Trim the separator-prefixed form too so nested BasePathFs report a
name that round-trips.

Fixes #428
This commit is contained in:
dualfroz committed 2026-09-02 11:39:06 +02:00
1 parent 9f78513f63
commit b778e8e78b
2 files changed
+38 -1

No files matched your search

+28
View File
@@ -307,3 +307,31 @@ func TestBasePathTempFile(t *testing.T) {
t.Fatalf("TempFile realpath leaked: expected %s, got %s", expected, actual)
}
}
// Regression test for #428: a nested BasePathFs must strip its own base
// segment from BasePathFile.Name(), even though filepath.Clean drops the
// leading separator that the wrapped (inner) file name carries.
func TestNestedBasePathFileName(t *testing.T) {
baseFs := &MemMapFs{}
if err := baseFs.MkdirAll("/files/123", 0o777); err != nil {
t.Fatal(err)
}
fs1 := NewBasePathFs(baseFs, "/files")
fs2 := NewBasePathFs(fs1, "123")
f, err := fs2.OpenFile("/afero-test.txt", os.O_CREATE|os.O_RDWR, 0o644)
if err != nil {
t.Fatalf("open through nested BasePathFs failed: %v", err)
}
defer f.Close()
if expected, actual := "/afero-test.txt", f.Name(); expected != actual {
t.Fatalf("nested BasePathFile.Name() = %q, want %q", actual, expected)
}
// The returned name must round-trip: using it via fs2 resolves back to
// the same file instead of double-prepending the base segment.
if err := fs2.Chmod(f.Name(), 0o600); err != nil {
t.Fatalf("chmod via returned name failed: %v", err)
}
}