mirror of
https://github.com/golang/go
synced 2024-11-17 17:54:48 -07:00
os: seek should invalidate any cached directory reads
When we seek on the underlying FD, discard any directory entries we've already read and cached. This makes sure we won't return the same entry twice. We already fixed this for Darwin in CL 209961. Fixes #37161 Change-Id: I20e1ac8d751443135e67fb4c43c18d69befb643b Reviewed-on: https://go-review.googlesource.com/c/go/+/219143 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
a4f7b0879c
commit
529988d62c
@ -24,16 +24,6 @@ func (d *dirInfo) close() {
|
||||
d.dir = 0
|
||||
}
|
||||
|
||||
func (f *File) seekInvalidate() {
|
||||
if f.dirinfo == nil {
|
||||
return
|
||||
}
|
||||
// Free cached dirinfo, so we allocate a new one if we
|
||||
// access this file as a directory again. See #35767.
|
||||
f.dirinfo.close()
|
||||
f.dirinfo = nil
|
||||
}
|
||||
|
||||
func (f *File) readdirnames(n int) (names []string, err error) {
|
||||
if f.dirinfo == nil {
|
||||
dir, call, errno := f.pfd.OpenDir()
|
||||
|
@ -26,8 +26,6 @@ const (
|
||||
|
||||
func (d *dirInfo) close() {}
|
||||
|
||||
func (f *File) seekInvalidate() {}
|
||||
|
||||
func (f *File) readdirnames(n int) (names []string, err error) {
|
||||
// If this file has no dirinfo, create one.
|
||||
if f.dirinfo == nil {
|
||||
|
@ -295,7 +295,12 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) {
|
||||
// relative to the current offset, and 2 means relative to the end.
|
||||
// It returns the new offset and an error, if any.
|
||||
func (f *File) seek(offset int64, whence int) (ret int64, err error) {
|
||||
f.seekInvalidate()
|
||||
if f.dirinfo != nil {
|
||||
// Free cached dirinfo, so we allocate a new one if we
|
||||
// access this file as a directory again. See #35767 and #37161.
|
||||
f.dirinfo.close()
|
||||
f.dirinfo = nil
|
||||
}
|
||||
ret, err = f.pfd.Seek(offset, whence)
|
||||
runtime.KeepAlive(f)
|
||||
return ret, err
|
||||
|
@ -2496,3 +2496,34 @@ func TestDirSeek(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReaddirSmallSeek(t *testing.T) {
|
||||
// See issue 37161. Read only one entry from a directory,
|
||||
// seek to the beginning, and read again. We should not see
|
||||
// duplicate entries.
|
||||
if runtime.GOOS == "windows" {
|
||||
testenv.SkipFlaky(t, 36019)
|
||||
}
|
||||
wd, err := Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
df, err := Open(filepath.Join(wd, "testdata", "issue37161"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
names1, err := df.Readdirnames(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = df.Seek(0, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
names2, err := df.Readdirnames(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(names2) != 3 {
|
||||
t.Fatalf("first names: %v, second names: %v", names1, names2)
|
||||
}
|
||||
}
|
||||
|
1
src/os/testdata/issue37161/a
vendored
Normal file
1
src/os/testdata/issue37161/a
vendored
Normal file
@ -0,0 +1 @@
|
||||
a
|
1
src/os/testdata/issue37161/b
vendored
Normal file
1
src/os/testdata/issue37161/b
vendored
Normal file
@ -0,0 +1 @@
|
||||
b
|
1
src/os/testdata/issue37161/c
vendored
Normal file
1
src/os/testdata/issue37161/c
vendored
Normal file
@ -0,0 +1 @@
|
||||
c
|
Loading…
Reference in New Issue
Block a user