|
7 | 7 | package os_test
|
8 | 8 |
|
9 | 9 | import (
|
| 10 | + "io" |
| 11 | + "io/ioutil" |
10 | 12 | . "os"
|
| 13 | + "path/filepath" |
11 | 14 | "runtime"
|
| 15 | + "strings" |
12 | 16 | "syscall"
|
13 | 17 | "testing"
|
14 | 18 | )
|
@@ -178,3 +182,38 @@ func TestLchown(t *testing.T) {
|
178 | 182 | checkUidGid(t, f.Name(), int(sys.Uid), int(sys.Gid))
|
179 | 183 | }
|
180 | 184 | }
|
| 185 | + |
| 186 | +// Issue 16919: Readdir must return a non-empty slice or an error. |
| 187 | +func TestReaddirRemoveRace(t *testing.T) { |
| 188 | + oldStat := *LstatP |
| 189 | + defer func() { *LstatP = oldStat }() |
| 190 | + *LstatP = func(name string) (FileInfo, error) { |
| 191 | + if strings.HasSuffix(name, "some-file") { |
| 192 | + // Act like it's been deleted. |
| 193 | + return nil, ErrNotExist |
| 194 | + } |
| 195 | + return oldStat(name) |
| 196 | + } |
| 197 | + dir := newDir("TestReaddirRemoveRace", t) |
| 198 | + defer RemoveAll(dir) |
| 199 | + if err := ioutil.WriteFile(filepath.Join(dir, "some-file"), []byte("hello"), 0644); err != nil { |
| 200 | + t.Fatal(err) |
| 201 | + } |
| 202 | + d, err := Open(dir) |
| 203 | + if err != nil { |
| 204 | + t.Fatal(err) |
| 205 | + } |
| 206 | + defer d.Close() |
| 207 | + fis, err := d.Readdir(2) // notably, greater than zero |
| 208 | + if len(fis) == 0 && err == nil { |
| 209 | + // This is what used to happen (Issue 16919) |
| 210 | + t.Fatal("Readdir = empty slice & err == nil") |
| 211 | + } |
| 212 | + if len(fis) != 0 || err != io.EOF { |
| 213 | + t.Errorf("Readdir = %d entries: %v; want 0, io.EOF", len(fis), err) |
| 214 | + for i, fi := range fis { |
| 215 | + t.Errorf(" entry[%d]: %q, %v", i, fi.Name(), fi.Mode()) |
| 216 | + } |
| 217 | + t.FailNow() |
| 218 | + } |
| 219 | +} |
0 commit comments