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