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:
1 parent
9f78513f63
commit
b778e8e78b
2 files changed
+38
-1
No files matched your search
+10
-1
@@ -37,7 +37,16 @@ type BasePathFile struct {
|
|||||||
|
|
||||||
func (f *BasePathFile) Name() string {
|
func (f *BasePathFile) Name() string {
|
||||||
sourcename := f.File.Name()
|
sourcename := f.File.Name()
|
||||||
return strings.TrimPrefix(sourcename, filepath.Clean(f.path))
|
base := filepath.Clean(f.path)
|
||||||
|
name := strings.TrimPrefix(sourcename, base)
|
||||||
|
if name == sourcename {
|
||||||
|
// filepath.Clean drops the leading separator from the base path, so a
|
||||||
|
// name produced by a wrapped (nested) BasePathFile can still carry the
|
||||||
|
// base preceded by a separator. Strip that form as well, otherwise the
|
||||||
|
// base segment leaks into the reported name.
|
||||||
|
name = strings.TrimPrefix(sourcename, string(filepath.Separator)+base)
|
||||||
|
}
|
||||||
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *BasePathFile) ReadDir(n int) ([]fs.DirEntry, error) {
|
func (f *BasePathFile) ReadDir(n int) ([]fs.DirEntry, error) {
|
||||||
|
|||||||
@@ -307,3 +307,31 @@ func TestBasePathTempFile(t *testing.T) {
|
|||||||
t.Fatalf("TempFile realpath leaked: expected %s, got %s", expected, actual)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user