Source file
src/os/dir_unix.go
1
2
3
4
5
6
7 package os
8
9 import (
10 "internal/goarch"
11 "io"
12 "runtime"
13 "sync"
14 "syscall"
15 "unsafe"
16 )
17
18
19 type dirInfo struct {
20 mu sync.Mutex
21 buf *[]byte
22 nbuf int
23 bufp int
24 }
25
26 const (
27
28 blockSize = 8192
29 )
30
31 var dirBufPool = sync.Pool{
32 New: func() any {
33
34 buf := make([]byte, blockSize)
35 return &buf
36 },
37 }
38
39 func (d *dirInfo) close() {
40 if d.buf != nil {
41 dirBufPool.Put(d.buf)
42 d.buf = nil
43 }
44 }
45
46 func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
47
48 d := f.dirinfo.Load()
49 if d == nil {
50 d = new(dirInfo)
51 f.dirinfo.Store(d)
52 }
53 d.mu.Lock()
54 defer d.mu.Unlock()
55 if d.buf == nil {
56 d.buf = dirBufPool.Get().(*[]byte)
57 }
58
59
60
61
62
63
64
65
66
67
68 if n == 0 {
69 n = -1
70 }
71
72 for n != 0 {
73
74 if d.bufp >= d.nbuf {
75 d.bufp = 0
76 var errno error
77 d.nbuf, errno = f.pfd.ReadDirent(*d.buf)
78 runtime.KeepAlive(f)
79 if errno != nil {
80 return names, dirents, infos, &PathError{Op: "readdirent", Path: f.name, Err: errno}
81 }
82 if d.nbuf <= 0 {
83
84 dirBufPool.Put(d.buf)
85 d.buf = nil
86 break
87 }
88 }
89
90
91 buf := (*d.buf)[d.bufp:d.nbuf]
92 reclen, ok := direntReclen(buf)
93 if !ok || reclen > uint64(len(buf)) {
94 break
95 }
96 rec := buf[:reclen]
97 d.bufp += int(reclen)
98 ino, ok := direntIno(rec)
99 if !ok {
100 break
101 }
102
103
104
105
106 if ino == 0 && runtime.GOOS != "wasip1" {
107 continue
108 }
109 const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))
110 namlen, ok := direntNamlen(rec)
111 if !ok || namoff+namlen > uint64(len(rec)) {
112 break
113 }
114 name := rec[namoff : namoff+namlen]
115 for i, c := range name {
116 if c == 0 {
117 name = name[:i]
118 break
119 }
120 }
121
122 if string(name) == "." || string(name) == ".." {
123 continue
124 }
125 if n > 0 {
126 n--
127 }
128 if mode == readdirName {
129 names = append(names, string(name))
130 } else if mode == readdirDirEntry {
131 de, err := newUnixDirent(f.name, string(name), direntType(rec))
132 if IsNotExist(err) {
133
134
135 continue
136 }
137 if err != nil {
138 return nil, dirents, nil, err
139 }
140 dirents = append(dirents, de)
141 } else {
142 info, err := lstat(f.name + "/" + string(name))
143 if IsNotExist(err) {
144
145
146 continue
147 }
148 if err != nil {
149 return nil, nil, infos, err
150 }
151 infos = append(infos, info)
152 }
153 }
154
155 if n > 0 && len(names)+len(dirents)+len(infos) == 0 {
156 return nil, nil, nil, io.EOF
157 }
158 return names, dirents, infos, nil
159 }
160
161
162 func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
163 if len(b) < int(off+size) {
164 return 0, false
165 }
166 if goarch.BigEndian {
167 return readIntBE(b[off:], size), true
168 }
169 return readIntLE(b[off:], size), true
170 }
171
172 func readIntBE(b []byte, size uintptr) uint64 {
173 switch size {
174 case 1:
175 return uint64(b[0])
176 case 2:
177 _ = b[1]
178 return uint64(b[1]) | uint64(b[0])<<8
179 case 4:
180 _ = b[3]
181 return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
182 case 8:
183 _ = b[7]
184 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
185 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
186 default:
187 panic("syscall: readInt with unsupported size")
188 }
189 }
190
191 func readIntLE(b []byte, size uintptr) uint64 {
192 switch size {
193 case 1:
194 return uint64(b[0])
195 case 2:
196 _ = b[1]
197 return uint64(b[0]) | uint64(b[1])<<8
198 case 4:
199 _ = b[3]
200 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
201 case 8:
202 _ = b[7]
203 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
204 uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
205 default:
206 panic("syscall: readInt with unsupported size")
207 }
208 }
209
View as plain text