-
Notifications
You must be signed in to change notification settings - Fork 232
/
directory.go
150 lines (125 loc) · 3.28 KB
/
directory.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
150
package vfs
import (
"errors"
"io"
"io/fs"
"sort"
"time"
)
type directoryContents struct {
node
childDirs map[string]*directoryContents
files map[string]*fileContents
}
// Directory is a wrapper around directoryContents which stores the state
// needed to implement ReadDirFile
type Directory struct {
*directoryContents
readDirCount int
readEntries []fs.DirEntry
closed bool
}
var (
_ fs.FileInfo = (*Directory)(nil)
_ fs.DirEntry = (*Directory)(nil)
_ fs.ReadDirFile = (*Directory)(nil)
)
func newDirectoryContents(name string) *directoryContents {
return &directoryContents{
node: node{
name: name,
parent: nil,
modTime: time.Now(),
},
childDirs: make(map[string]*directoryContents),
files: make(map[string]*fileContents),
}
}
func (d *Directory) createEntries() []fs.DirEntry {
rtn := make([]fs.DirEntry, 0, len(d.childDirs)+len(d.files))
for _, child := range d.childDirs {
rtn = append(rtn, &Directory{directoryContents: child})
}
for _, child := range d.files {
rtn = append(rtn, &File{fileContents: child})
}
sort.SliceStable(rtn, func(i, j int) bool {
return rtn[i].Name() < rtn[j].Name()
})
return rtn
}
// ReadDir reads the contents of the directory and returns
// a slice of up to n DirEntry values in directory order.
// Subsequent calls on the same file will yield further DirEntry values.
//
// If n > 0, ReadDir returns at most n DirEntry structures.
// In this case, if ReadDir returns an empty slice, it will return
// a non-nil error explaining why.
// At the end of a directory, the error is io.EOF.
//
// If n <= 0, ReadDir returns all the DirEntry values from the directory
// in a single slice. In this case, if ReadDir succeeds (reads all the way
// to the end of the directory), it returns the slice and a nil error.
// If it encounters an error before the end of the directory,
// ReadDir returns the DirEntry list read until that point and a non-nil error.
func (d *Directory) ReadDir(n int) ([]fs.DirEntry, error) {
if d.closed {
return nil, fs.ErrClosed
}
// Create the directory listing if it doesn't exist already
if d.readEntries == nil {
d.readEntries = d.createEntries()
}
// detect an EOF
if d.readDirCount == len(d.readEntries) {
if n <= 0 { // special case return
return nil, nil
}
return nil, io.EOF
}
// Create the return data with the number of requested entries
readNum := len(d.readEntries) - d.readDirCount
if readNum > n && n > 0 {
readNum = n
}
rtn := make([]fs.DirEntry, readNum)
for i := 0; i < readNum; i++ {
rtn[i] = d.readEntries[d.readDirCount]
d.readDirCount++
}
return rtn, nil
}
func (d *Directory) Read(_ []byte) (int, error) {
return 0, errors.New("cannot read directory")
}
func (d *Directory) Name() string {
return d.node.name
}
func (d *Directory) IsDir() bool {
return true
}
func (d *Directory) Type() fs.FileMode {
return fs.ModeDir
}
func (d *Directory) Info() (fs.FileInfo, error) {
return d, nil
}
func (d *Directory) Size() int64 {
return 0
}
func (d *Directory) Mode() fs.FileMode {
return d.Type()
}
func (d *Directory) ModTime() time.Time {
return d.node.modTime
}
func (d *Directory) Stat() (fs.FileInfo, error) {
return d.Info()
}
func (d *Directory) Close() error {
d.closed = true
return nil
}
func (d *Directory) Sys() any {
return nil
}