From be26ca972d2149df09e70789fdf284da01c5e9d8 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 7 Jan 2022 09:54:44 -0500 Subject: [PATCH] syscall: in TestDirent, make as many ReadDirent calls as are needed MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Ian Lance Taylor Run-TryBot: Bryan Mills TryBot-Result: Gopher Robot --- src/syscall/dirent_test.go | 39 ++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/syscall/dirent_test.go b/src/syscall/dirent_test.go index 6570bf9217..aeb40e57c1 100644 --- a/src/syscall/dirent_test.go +++ b/src/syscall/dirent_test.go @@ -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) -- 2.50.0