forked from karrick/godirwalk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
readdir_unix.go
131 lines (109 loc) · 3.47 KB
/
readdir_unix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// +build !windows
package godirwalk
import (
"os"
"syscall"
"unsafe"
)
// MinimumScratchBufferSize specifies the minimum size of the scratch buffer
// that ReadDirents, ReadDirnames, Scanner, and Walk will use when reading file
// entries from the operating system. During program startup it is initialized
// to the result from calling `os.Getpagesize()` for non Windows environments,
// and 0 for Windows.
var MinimumScratchBufferSize = os.Getpagesize()
func newScratchBuffer() []byte { return make([]byte, MinimumScratchBufferSize) }
func readDirents(osDirname string, scratchBuffer []byte) ([]*Dirent, error) {
var entries []*Dirent
var workBuffer []byte
dh, err := os.Open(osDirname)
if err != nil {
return nil, err
}
fd := int(dh.Fd())
if len(scratchBuffer) < MinimumScratchBufferSize {
scratchBuffer = newScratchBuffer()
}
var sde syscall.Dirent
for {
if len(workBuffer) == 0 {
n, err := syscall.ReadDirent(fd, scratchBuffer)
// n, err := unix.ReadDirent(fd, scratchBuffer)
if err != nil {
if err == syscall.EINTR /* || err == unix.EINTR */ {
continue
}
_ = dh.Close()
return nil, err
}
if n <= 0 { // end of directory: normal exit
if err = dh.Close(); err != nil {
return nil, err
}
return entries, nil
}
workBuffer = scratchBuffer[:n] // trim work buffer to number of bytes read
}
copy((*[unsafe.Sizeof(syscall.Dirent{})]byte)(unsafe.Pointer(&sde))[:], workBuffer)
workBuffer = workBuffer[reclen(&sde):] // advance buffer for next iteration through loop
if inoFromDirent(&sde) == 0 {
continue // inode set to 0 indicates an entry that was marked as deleted
}
nameSlice := nameFromDirent(&sde)
nameLength := len(nameSlice)
if nameLength == 0 || (nameSlice[0] == '.' && (nameLength == 1 || (nameLength == 2 && nameSlice[1] == '.'))) {
continue
}
childName := string(nameSlice)
mt, err := modeTypeFromDirent(&sde, osDirname, childName)
if err != nil {
_ = dh.Close()
return nil, err
}
entries = append(entries, &Dirent{name: childName, path: osDirname, modeType: mt})
}
}
func readDirnames(osDirname string, scratchBuffer []byte) ([]string, error) {
var entries []string
var workBuffer []byte
var sde *syscall.Dirent
dh, err := os.Open(osDirname)
if err != nil {
return nil, err
}
fd := int(dh.Fd())
if len(scratchBuffer) < MinimumScratchBufferSize {
scratchBuffer = newScratchBuffer()
}
for {
if len(workBuffer) == 0 {
n, err := syscall.ReadDirent(fd, scratchBuffer)
// n, err := unix.ReadDirent(fd, scratchBuffer)
if err != nil {
if err == syscall.EINTR /* || err == unix.EINTR */ {
continue
}
_ = dh.Close()
return nil, err
}
if n <= 0 { // end of directory: normal exit
if err = dh.Close(); err != nil {
return nil, err
}
return entries, nil
}
workBuffer = scratchBuffer[:n] // trim work buffer to number of bytes read
}
sde = (*syscall.Dirent)(unsafe.Pointer(&workBuffer[0])) // point entry to first syscall.Dirent in buffer
// Handle first entry in the work buffer.
workBuffer = workBuffer[reclen(sde):] // advance buffer for next iteration through loop
if inoFromDirent(sde) == 0 {
continue // inode set to 0 indicates an entry that was marked as deleted
}
nameSlice := nameFromDirent(sde)
nameLength := len(nameSlice)
if nameLength == 0 || (nameSlice[0] == '.' && (nameLength == 1 || (nameLength == 2 && nameSlice[1] == '.'))) {
continue
}
entries = append(entries, string(nameSlice))
}
}