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