...
Source file
src/os/dir_darwin.go
Documentation: os
1
2
3
4
5 package os
6
7 import (
8 "errors"
9 "io"
10 "runtime"
11 "syscall"
12 "unsafe"
13 )
14
15
16 type dirInfo struct {
17 dir uintptr
18 }
19
20 func (d *dirInfo) close() {
21 if d.dir == 0 {
22 return
23 }
24 closedir(d.dir)
25 d.dir = 0
26 }
27
28 func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
29
30 var d *dirInfo
31 for {
32 d = f.dirinfo.Load()
33 if d != nil {
34 break
35 }
36 dir, call, errno := f.pfd.OpenDir()
37 if errno != nil {
38 return nil, nil, nil, &PathError{Op: call, Path: f.name, Err: errno}
39 }
40 d = &dirInfo{dir: dir}
41 if f.dirinfo.CompareAndSwap(nil, d) {
42 break
43 }
44
45 d.close()
46 }
47
48 size := n
49 if size <= 0 {
50 size = 100
51 n = -1
52 }
53
54 var dirent syscall.Dirent
55 var entptr *syscall.Dirent
56 for len(names)+len(dirents)+len(infos) < size || n == -1 {
57 if errno := readdir_r(d.dir, &dirent, &entptr); errno != 0 {
58 if errno == syscall.EINTR {
59 continue
60 }
61 return names, dirents, infos, &PathError{Op: "readdir", Path: f.name, Err: errno}
62 }
63 if entptr == nil {
64 break
65 }
66
67
68
69
70
71
72
73
74
75 if dirent.Ino == 0 {
76 continue
77 }
78 name := (*[len(syscall.Dirent{}.Name)]byte)(unsafe.Pointer(&dirent.Name))[:]
79 for i, c := range name {
80 if c == 0 {
81 name = name[:i]
82 break
83 }
84 }
85
86 if string(name) == "." || string(name) == ".." {
87 continue
88 }
89 if mode == readdirName {
90 names = append(names, string(name))
91 } else if mode == readdirDirEntry {
92 de, err := newUnixDirent(f, string(name), dtToType(dirent.Type))
93 if IsNotExist(err) {
94
95
96 continue
97 }
98 if errors.Is(err, syscall.EBADF) {
99
100
101
102 continue
103 }
104 if err != nil {
105 return nil, dirents, nil, err
106 }
107 dirents = append(dirents, de)
108 } else {
109 info, err := f.lstatat(string(name))
110 if IsNotExist(err) {
111
112
113 continue
114 }
115 if err != nil {
116 return nil, nil, infos, err
117 }
118 infos = append(infos, info)
119 }
120 runtime.KeepAlive(f)
121 }
122
123 if n > 0 && len(names)+len(dirents)+len(infos) == 0 {
124 return nil, nil, nil, io.EOF
125 }
126 return names, dirents, infos, nil
127 }
128
129 func dtToType(typ uint8) FileMode {
130 switch typ {
131 case syscall.DT_BLK:
132 return ModeDevice
133 case syscall.DT_CHR:
134 return ModeDevice | ModeCharDevice
135 case syscall.DT_DIR:
136 return ModeDir
137 case syscall.DT_FIFO:
138 return ModeNamedPipe
139 case syscall.DT_LNK:
140 return ModeSymlink
141 case syscall.DT_REG:
142 return 0
143 case syscall.DT_SOCK:
144 return ModeSocket
145 }
146 return ^FileMode(0)
147 }
148
149
150
151
152 func closedir(dir uintptr) (err error)
153
154
155 func readdir_r(dir uintptr, entry *syscall.Dirent, result **syscall.Dirent) (res syscall.Errno)
156
View as plain text