github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/syscall/dirent_test.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris 6 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris 7 8 package syscall_test 9 10 import ( 11 "bytes" 12 "fmt" 13 "os" 14 "path/filepath" 15 "runtime" 16 "sort" 17 "strconv" 18 "strings" 19 "syscall" 20 "testing" 21 "unsafe" 22 ) 23 24 func TestDirent(t *testing.T) { 25 const ( 26 direntBufSize = 2048 27 filenameMinSize = 11 28 ) 29 30 d := t.TempDir() 31 t.Logf("tmpdir: %s", d) 32 33 for i, c := range []byte("0123456789") { 34 name := string(bytes.Repeat([]byte{c}, filenameMinSize+i)) 35 err := os.WriteFile(filepath.Join(d, name), nil, 0644) 36 if err != nil { 37 t.Fatalf("writefile: %v", err) 38 } 39 } 40 41 buf := bytes.Repeat([]byte("DEADBEAF"), direntBufSize/8) 42 fd, err := syscall.Open(d, syscall.O_RDONLY, 0) 43 if err != nil { 44 t.Fatalf("syscall.open: %v", err) 45 } 46 defer syscall.Close(fd) 47 n, err := syscall.ReadDirent(fd, buf) 48 if err != nil { 49 t.Fatalf("syscall.readdir: %v", err) 50 } 51 buf = buf[:n] 52 53 names := make([]string, 0, 10) 54 for len(buf) > 0 { 55 var bc int 56 bc, _, names = syscall.ParseDirent(buf, -1, names) 57 buf = buf[bc:] 58 } 59 60 sort.Strings(names) 61 t.Logf("names: %q", names) 62 63 if len(names) != 10 { 64 t.Errorf("got %d names; expected 10", len(names)) 65 } 66 for i, name := range names { 67 ord, err := strconv.Atoi(name[:1]) 68 if err != nil { 69 t.Fatalf("names[%d] is non-integer %q: %v", i, names[i], err) 70 } 71 if expected := string(strings.Repeat(name[:1], filenameMinSize+ord)); name != expected { 72 t.Errorf("names[%d] is %q (len %d); expected %q (len %d)", i, name, len(name), expected, len(expected)) 73 } 74 } 75 } 76 77 func TestDirentRepeat(t *testing.T) { 78 const N = 100 79 // Note: the size of the buffer is small enough that the loop 80 // below will need to execute multiple times. See issue #31368. 81 size := N * unsafe.Offsetof(syscall.Dirent{}.Name) / 4 82 if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" { 83 if size < 1024 { 84 size = 1024 // DIRBLKSIZ, see issue 31403. 85 } 86 if runtime.GOOS == "freebsd" { 87 t.Skip("need to fix issue 31416 first") 88 } 89 } 90 91 // Make a directory containing N files 92 d := t.TempDir() 93 94 var files []string 95 for i := 0; i < N; i++ { 96 files = append(files, fmt.Sprintf("file%d", i)) 97 } 98 for _, file := range files { 99 err := os.WriteFile(filepath.Join(d, file), []byte("contents"), 0644) 100 if err != nil { 101 t.Fatalf("writefile: %v", err) 102 } 103 } 104 105 // Read the directory entries using ReadDirent. 106 fd, err := syscall.Open(d, syscall.O_RDONLY, 0) 107 if err != nil { 108 t.Fatalf("syscall.open: %v", err) 109 } 110 defer syscall.Close(fd) 111 var files2 []string 112 for { 113 buf := make([]byte, size) 114 n, err := syscall.ReadDirent(fd, buf) 115 if err != nil { 116 t.Fatalf("syscall.readdir: %v", err) 117 } 118 if n == 0 { 119 break 120 } 121 buf = buf[:n] 122 for len(buf) > 0 { 123 var consumed int 124 consumed, _, files2 = syscall.ParseDirent(buf, -1, files2) 125 buf = buf[consumed:] 126 } 127 } 128 129 // Check results 130 sort.Strings(files) 131 sort.Strings(files2) 132 if strings.Join(files, "|") != strings.Join(files2, "|") { 133 t.Errorf("bad file list: want\n%q\ngot\n%q", files, files2) 134 } 135 }