Source file
src/os/dir_unix.go
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 if ino == 0 {
93 continue
94 }
95 const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))
96 namlen, ok := direntNamlen(rec)
97 if !ok || namoff+namlen > uint64(len(rec)) {
98 break
99 }
100 name := rec[namoff : namoff+namlen]
101 for i, c := range name {
102 if c == 0 {
103 name = name[:i]
104 break
105 }
106 }
107
108 if string(name) == "." || string(name) == ".." {
109 continue
110 }
111 if n > 0 {
112 n--
113 }
114 if mode == readdirName {
115 names = append(names, string(name))
116 } else if mode == readdirDirEntry {
117 de, err := newUnixDirent(f.name, string(name), direntType(rec))
118 if IsNotExist(err) {
119
120
121 continue
122 }
123 if err != nil {
124 return nil, dirents, nil, err
125 }
126 dirents = append(dirents, de)
127 } else {
128 info, err := lstat(f.name + "/" + string(name))
129 if IsNotExist(err) {
130
131
132 continue
133 }
134 if err != nil {
135 return nil, nil, infos, err
136 }
137 infos = append(infos, info)
138 }
139 }
140
141 if n > 0 && len(names)+len(dirents)+len(infos) == 0 {
142 return nil, nil, nil, io.EOF
143 }
144 return names, dirents, infos, nil
145 }
146
147
148 func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
149 if len(b) < int(off+size) {
150 return 0, false
151 }
152 if isBigEndian {
153 return readIntBE(b[off:], size), true
154 }
155 return readIntLE(b[off:], size), true
156 }
157
158 func readIntBE(b []byte, size uintptr) uint64 {
159 switch size {
160 case 1:
161 return uint64(b[0])
162 case 2:
163 _ = b[1]
164 return uint64(b[1]) | uint64(b[0])<<8
165 case 4:
166 _ = b[3]
167 return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
168 case 8:
169 _ = b[7]
170 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
171 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
172 default:
173 panic("syscall: readInt with unsupported size")
174 }
175 }
176
177 func readIntLE(b []byte, size uintptr) uint64 {
178 switch size {
179 case 1:
180 return uint64(b[0])
181 case 2:
182 _ = b[1]
183 return uint64(b[0]) | uint64(b[1])<<8
184 case 4:
185 _ = b[3]
186 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
187 case 8:
188 _ = b[7]
189 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
190 uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
191 default:
192 panic("syscall: readInt with unsupported size")
193 }
194 }
195
View as plain text