]> Cypherpunks repositories - gostls13.git/commitdiff
os: seek should invalidate any cached directory reads
authorKeith Randall <khr@golang.org>
Wed, 12 Feb 2020 01:49:52 +0000 (17:49 -0800)
committerKeith Randall <khr@golang.org>
Sun, 1 Mar 2020 22:26:33 +0000 (22:26 +0000)
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>
src/os/dir_darwin.go
src/os/dir_unix.go
src/os/file_unix.go
src/os/os_test.go
src/os/testdata/issue37161/a [new file with mode: 0644]
src/os/testdata/issue37161/b [new file with mode: 0644]
src/os/testdata/issue37161/c [new file with mode: 0644]

index a274dd126808eba7c18faf5198a40b28bcf2b547..2f9ba78d680517ca315668a7c9110c4bbed2d743 100644 (file)
@@ -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()
index 2856a2dc0ff427556bc8b3dc2769b0cfa208d60f..e0c4989756b1a0ec983d21e19241a7f2e143b439 100644 (file)
@@ -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 {
index 6945937fd61d0f00983fca423c6a3dc50234192c..32e4442e5d06740dc229a539cc90eceeb746ec3c 100644 (file)
@@ -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
index cc03b91d72a3c711d0c7335cffbabd45816ca9d2..44e1434dbe795a84b93b01c613e767fbbce949f9 100644 (file)
@@ -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)
+       }
+}
diff --git a/src/os/testdata/issue37161/a b/src/os/testdata/issue37161/a
new file mode 100644 (file)
index 0000000..7898192
--- /dev/null
@@ -0,0 +1 @@
+a
diff --git a/src/os/testdata/issue37161/b b/src/os/testdata/issue37161/b
new file mode 100644 (file)
index 0000000..6178079
--- /dev/null
@@ -0,0 +1 @@
+b
diff --git a/src/os/testdata/issue37161/c b/src/os/testdata/issue37161/c
new file mode 100644 (file)
index 0000000..f2ad6c7
--- /dev/null
@@ -0,0 +1 @@
+c