]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: in TestDirent, make as many ReadDirent calls as are needed
authorBryan C. Mills <bcmills@google.com>
Fri, 7 Jan 2022 14:54:44 +0000 (09:54 -0500)
committerBryan Mills <bcmills@google.com>
Fri, 7 Jan 2022 21:15:14 +0000 (21:15 +0000)
ReadDirent returns only as many directory entries as will fit in the
buffer, and each entry is variable-length — so we have no guarantee in
general that a buffer of a given arbitrary size can hold even one
entry, let alone all ten entries expected by the test.

Instead, iterate calls to ReadDirent until one of the calls returns
zero entries and no error, indicating that the directory has been read
to completion.

Fixes #37323

Change-Id: I7f1cedde7666107256604e4ea1ac13c71f22151a
Reviewed-on: https://go-review.googlesource.com/c/go/+/376334
Trust: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/syscall/dirent_test.go

index 6570bf92179d51738d3c3ac7291a0d6bb57748ee..aeb40e57c1834434e0ce34b4c4cc469e956b927d 100644 (file)
@@ -22,7 +22,7 @@ import (
 
 func TestDirent(t *testing.T) {
        const (
-               direntBufSize   = 2048
+               direntBufSize   = 2048 // arbitrary? See https://go.dev/issue/37323.
                filenameMinSize = 11
        )
 
@@ -37,23 +37,38 @@ func TestDirent(t *testing.T) {
                }
        }
 
-       buf := bytes.Repeat([]byte("DEADBEAF"), direntBufSize/8)
+       names := make([]string, 0, 10)
+
        fd, err := syscall.Open(d, syscall.O_RDONLY, 0)
        if err != nil {
                t.Fatalf("syscall.open: %v", err)
        }
        defer syscall.Close(fd)
-       n, err := syscall.ReadDirent(fd, buf)
-       if err != nil {
-               t.Fatalf("syscall.readdir: %v", err)
-       }
-       buf = buf[:n]
 
-       names := make([]string, 0, 10)
-       for len(buf) > 0 {
-               var bc int
-               bc, _, names = syscall.ParseDirent(buf, -1, names)
-               buf = buf[bc:]
+       buf := bytes.Repeat([]byte{0xCD}, direntBufSize)
+       for {
+               n, err := syscall.ReadDirent(fd, buf)
+               if err == syscall.EINVAL {
+                       // On linux, 'man getdents64' says that EINVAL indicates “result buffer is too small”.
+                       // Try a bigger buffer.
+                       t.Logf("ReadDirent: %v; retrying with larger buffer", err)
+                       buf = bytes.Repeat([]byte{0xCD}, len(buf)*2)
+                       continue
+               }
+               if err != nil {
+                       t.Fatalf("syscall.readdir: %v", err)
+               }
+               t.Logf("ReadDirent: read %d bytes", n)
+               if n == 0 {
+                       break
+               }
+
+               var consumed, count int
+               consumed, count, names = syscall.ParseDirent(buf[:n], -1, names)
+               t.Logf("ParseDirent: %d new name(s)", count)
+               if consumed != n {
+                       t.Fatalf("ParseDirent: consumed %d bytes; expected %d", consumed, n)
+               }
        }
 
        sort.Strings(names)