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