github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/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, err := os.MkdirTemp("", "dirent-test") 31 if err != nil { 32 t.Fatalf("tempdir: %v", err) 33 } 34 defer os.RemoveAll(d) 35 t.Logf("tmpdir: %s", d) 36 37 for i, c := range []byte("0123456789") { 38 name := string(bytes.Repeat([]byte{c}, filenameMinSize+i)) 39 err = os.WriteFile(filepath.Join(d, name), nil, 0644) 40 if err != nil { 41 t.Fatalf("writefile: %v", err) 42 } 43 } 44 45 buf := bytes.Repeat([]byte("DEADBEAF"), direntBufSize/8) 46 fd, err := syscall.Open(d, syscall.O_RDONLY, 0) 47 if err != nil { 48 t.Fatalf("syscall.open: %v", err) 49 } 50 defer syscall.Close(fd) 51 n, err := syscall.ReadDirent(fd, buf) 52 if err != nil { 53 t.Fatalf("syscall.readdir: %v", err) 54 } 55 buf = buf[:n] 56 57 names := make([]string, 0, 10) 58 for len(buf) > 0 { 59 var bc int 60 bc, _, names = syscall.ParseDirent(buf, -1, names) 61 buf = buf[bc:] 62 } 63 64 sort.Strings(names) 65 t.Logf("names: %q", names) 66 67 if len(names) != 10 { 68 t.Errorf("got %d names; expected 10", len(names)) 69 } 70 for i, name := range names { 71 ord, err := strconv.Atoi(name[:1]) 72 if err != nil { 73 t.Fatalf("names[%d] is non-integer %q: %v", i, names[i], err) 74 } 75 if expected := string(strings.Repeat(name[:1], filenameMinSize+ord)); name != expected { 76 t.Errorf("names[%d] is %q (len %d); expected %q (len %d)", i, name, len(name), expected, len(expected)) 77 } 78 } 79 } 80 81 func TestDirentRepeat(t *testing.T) { 82 const N = 100 83 // Note: the size of the buffer is small enough that the loop 84 // below will need to execute multiple times. See issue #31368. 85 size := N * unsafe.Offsetof(syscall.Dirent{}.Name) / 4 86 if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" { 87 if size < 1024 { 88 size = 1024 // DIRBLKSIZ, see issue 31403. 89 } 90 if runtime.GOOS == "freebsd" { 91 t.Skip("need to fix issue 31416 first") 92 } 93 } 94 95 // Make a directory containing N files 96 d, err := os.MkdirTemp("", "direntRepeat-test") 97 if err != nil { 98 t.Fatalf("tempdir: %v", err) 99 } 100 defer os.RemoveAll(d) 101 102 var files []string 103 for i := 0; i < N; i++ { 104 files = append(files, fmt.Sprintf("file%d", i)) 105 } 106 for _, file := range files { 107 err = os.WriteFile(filepath.Join(d, file), []byte("contents"), 0644) 108 if err != nil { 109 t.Fatalf("writefile: %v", err) 110 } 111 } 112 113 // Read the directory entries using ReadDirent. 114 fd, err := syscall.Open(d, syscall.O_RDONLY, 0) 115 if err != nil { 116 t.Fatalf("syscall.open: %v", err) 117 } 118 defer syscall.Close(fd) 119 var files2 []string 120 for { 121 buf := make([]byte, size) 122 n, err := syscall.ReadDirent(fd, buf) 123 if err != nil { 124 t.Fatalf("syscall.readdir: %v", err) 125 } 126 if n == 0 { 127 break 128 } 129 buf = buf[:n] 130 for len(buf) > 0 { 131 var consumed int 132 consumed, _, files2 = syscall.ParseDirent(buf, -1, files2) 133 buf = buf[consumed:] 134 } 135 } 136 137 // Check results 138 sort.Strings(files) 139 sort.Strings(files2) 140 if strings.Join(files, "|") != strings.Join(files2, "|") { 141 t.Errorf("bad file list: want\n%q\ngot\n%q", files, files2) 142 } 143 }