1
2
3
4
5
6
7 package unix_test
8
9 import (
10 "bytes"
11 "fmt"
12 "os"
13 "path/filepath"
14 "runtime"
15 "sort"
16 "strconv"
17 "strings"
18 "testing"
19 "unsafe"
20
21 "golang.org/x/sys/unix"
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.Fatal(err)
38 }
39 }
40
41 names := make([]string, 0, 10)
42
43 fd, err := unix.Open(d, unix.O_RDONLY, 0)
44 if err != nil {
45 t.Fatalf("Open: %v", err)
46 }
47 defer unix.Close(fd)
48
49 buf := bytes.Repeat([]byte{0xCD}, direntBufSize)
50 for {
51 n, err := unix.ReadDirent(fd, buf)
52 if err == unix.EINVAL {
53
54
55 t.Logf("ReadDirent: %v; retrying with larger buffer", err)
56 buf = bytes.Repeat([]byte{0xCD}, len(buf)*2)
57 continue
58 }
59 if err != nil {
60 t.Fatalf("ReadDirent: %v", err)
61 }
62 t.Logf("ReadDirent: read %d bytes", n)
63 if n == 0 {
64 break
65 }
66
67 var consumed, count int
68 consumed, count, names = unix.ParseDirent(buf[:n], -1, names)
69 t.Logf("ParseDirent: %d new name(s)", count)
70 if consumed != n {
71 t.Fatalf("ParseDirent: consumed %d bytes; expected %d", consumed, n)
72 }
73 }
74
75 sort.Strings(names)
76 t.Logf("names: %q", names)
77
78 if len(names) != 10 {
79 t.Errorf("got %d names; expected 10", len(names))
80 }
81 for i, name := range names {
82 ord, err := strconv.Atoi(name[:1])
83 if err != nil {
84 t.Fatalf("names[%d] is non-integer %q: %v", i, names[i], err)
85 }
86 if expected := string(strings.Repeat(name[:1], filenameMinSize+ord)); name != expected {
87 t.Errorf("names[%d] is %q (len %d); expected %q (len %d)", i, name, len(name), expected, len(expected))
88 }
89 }
90 }
91
92 func TestDirentRepeat(t *testing.T) {
93 const N = 100
94
95
96 size := N * unsafe.Offsetof(unix.Dirent{}.Name) / 4
97 if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" {
98 if size < 1024 {
99 size = 1024
100 }
101 if runtime.GOOS == "freebsd" {
102 t.Skip("need to fix issue 31416 first")
103 }
104 }
105
106
107 d := t.TempDir()
108
109 var files []string
110 for i := 0; i < N; i++ {
111 files = append(files, fmt.Sprintf("file%d", i))
112 }
113 for _, file := range files {
114 err := os.WriteFile(filepath.Join(d, file), []byte("contents"), 0644)
115 if err != nil {
116 t.Fatal(err)
117 }
118 }
119
120
121 fd, err := unix.Open(d, unix.O_RDONLY, 0)
122 if err != nil {
123 t.Fatalf("Open: %v", err)
124 }
125 defer unix.Close(fd)
126 var files2 []string
127 for {
128 buf := make([]byte, size)
129 n, err := unix.ReadDirent(fd, buf)
130 if err != nil {
131 t.Fatalf("ReadDirent: %v", err)
132 }
133 if n == 0 {
134 break
135 }
136 buf = buf[:n]
137 for len(buf) > 0 {
138 var consumed int
139 consumed, _, files2 = unix.ParseDirent(buf, -1, files2)
140 if consumed == 0 && len(buf) > 0 {
141 t.Fatal("no progress")
142 }
143 buf = buf[consumed:]
144 }
145 }
146
147
148 sort.Strings(files)
149 sort.Strings(files2)
150 if strings.Join(files, "|") != strings.Join(files2, "|") {
151 t.Errorf("bad file list: want\n%q\ngot\n%q", files, files2)
152 }
153 }
154
View as plain text