forked from karrick/godirwalk
-
Notifications
You must be signed in to change notification settings - Fork 1
/
scandir_windows.go
149 lines (131 loc) · 3.94 KB
/
scandir_windows.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//go:build windows
// +build windows
package godirwalk
import (
"fmt"
"os"
)
// Scanner is an iterator to enumerate the contents of a directory.
type Scanner struct {
osDirname string
childName string
dh *os.File // dh is handle to open directory
de *Dirent
err error // err is the error associated with scanning directory
childMode os.FileMode
}
// NewScanner returns a new directory Scanner that lazily enumerates
// the contents of a single directory. To prevent resource leaks,
// caller must invoke either the Scanner's Close or Err method after
// it has completed scanning a directory.
//
// scanner, err := godirwalk.NewScanner(dirname)
// if err != nil {
// fatal("cannot scan directory: %s", err)
// }
//
// for scanner.Scan() {
// dirent, err := scanner.Dirent()
// if err != nil {
// warning("cannot get dirent: %s", err)
// continue
// }
// name := dirent.Name()
// if name == "break" {
// break
// }
// if name == "continue" {
// continue
// }
// fmt.Printf("%v %v\n", dirent.ModeType(), dirent.Name())
// }
// if err := scanner.Err(); err != nil {
// fatal("cannot scan directory: %s", err)
// }
func NewScanner(osDirname string) (*Scanner, error) {
dh, err := os.Open(osDirname)
if err != nil {
return nil, err
}
scanner := &Scanner{
osDirname: osDirname,
dh: dh,
}
return scanner, nil
}
// NewScannerWithScratchBuffer returns a new directory Scanner that
// lazily enumerates the contents of a single directory. On platforms
// other than Windows it uses the provided scratch buffer to read from
// the file system. On Windows the scratch buffer parameter is
// ignored. To prevent resource leaks, caller must invoke either the
// Scanner's Close or Err method after it has completed scanning a
// directory.
func NewScannerWithScratchBuffer(osDirname string, scratchBuffer []byte) (*Scanner, error) {
return NewScanner(osDirname)
}
// Close releases resources associated with scanning a directory. Call
// either this or the Err method when the directory no longer needs to
// be scanned.
func (s *Scanner) Close() error {
return s.Err()
}
// Dirent returns the current directory entry while scanning a directory.
func (s *Scanner) Dirent() (*Dirent, error) {
if s.de == nil {
s.de = &Dirent{
name: s.childName,
path: s.osDirname,
modeType: s.childMode,
}
}
return s.de, nil
}
// done is called when directory scanner unable to continue, with either the
// triggering error, or nil when there are simply no more entries to read from
// the directory.
func (s *Scanner) done(err error) {
if s.dh == nil {
return
}
s.err = err
if err = s.dh.Close(); s.err == nil {
s.err = err
}
s.childName, s.osDirname = "", ""
s.de, s.dh = nil, nil
}
// Err returns any error associated with scanning a directory. It is
// normal to call Err after Scan returns false, even though they both
// ensure Scanner resources are released. Call either this or the
// Close method when the directory no longer needs to be scanned.
func (s *Scanner) Err() error {
s.done(nil)
return s.err
}
// Name returns the base name of the current directory entry while scanning a
// directory.
func (s *Scanner) Name() string { return s.childName }
// Scan potentially reads and then decodes the next directory entry from the
// file system.
//
// When it returns false, this releases resources used by the Scanner then
// returns any error associated with closing the file system directory resource.
func (s *Scanner) Scan() bool {
if s.dh == nil {
return false
}
s.de = nil
fileinfos, err := s.dh.Readdir(1)
if err != nil {
s.done(err)
return false
}
if l := len(fileinfos); l != 1 {
s.done(fmt.Errorf("expected a single entry rather than %d", l))
return false
}
fi := fileinfos[0]
s.childMode = fi.Mode() & os.ModeType
s.childName = fi.Name()
return true
}