This repository has been archived by the owner on Oct 22, 2021. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathreaddir_unix.go
153 lines (135 loc) · 3.13 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
package fs
import (
"context"
"os"
"path"
"path/filepath"
"golang.org/x/sys/unix"
typ "github.com/aos-dev/go-storage/v2/types"
)
// Available value for Dirent Type
//
// Copied from linux kernel <dirent.h>
// #define DT_UNKNOWN 0
// #define DT_FIFO 1
// #define DT_CHR 2
// #define DT_DIR 4
// #define DT_BLK 6
// #define DT_REG 8
// #define DT_LNK 10
// #define DT_SOCK 12
// #define DT_WHT 14
const (
// The file type is unknown.
DirentTypeUnknown = 0
// This is a named pipe (FIFO).
DirentTypeFIFO = 1
// This is a character device.
DirentTypeCharDevice = 2
// This is a directory.
DirentTypeDirectory = 4
// This is a block device.
DirentTypeBlockDevice = 6
// This is a regular file.
DirentTypeRegular = 8
// This is a symbolic link.
DirentTypeLink = 10
// This is a UNIX domain socket.
DirentTypeSocket = 12
// WhiteOut from BSD, don't know what's it mean.
DirentTypeWhiteOut = 14
)
func (s *Storage) listDirNext(ctx context.Context, page *typ.ObjectPage) (err error) {
input := page.Status.(*listDirInput)
defer func() {
err = s.formatError("list_dir_next", err, input.rp)
}()
defer func() {
// Make sure file has been close every time we return an error
if err != nil && input.f != nil {
_ = input.f.Close()
input.f = nil
}
}()
// Open dir before we read it.
if input.f == nil {
input.f, err = os.Open(input.rp)
if err != nil {
return
}
}
n, err := unix.ReadDirent(int(input.f.Fd()), input.buf)
if err != nil {
return err
}
if n <= 0 {
return typ.IterateDone
}
buf := input.buf
for len(buf) > 0 {
// Get and check reclen
reclen, ok := direntReclen(buf)
if !ok || reclen > uint64(len(buf)) {
return
}
// current dirent
rec := buf[:reclen]
// remaining dirents
buf = buf[reclen:]
// Get and check inode
ino, ok := direntIno(rec)
if !ok {
break
}
if ino == 0 { // File absent in directory.
continue
}
// Get and check type
ty, ok := direntType(rec)
if !ok {
continue
}
// Get and check name
name := rec[direntOffsetName:reclen]
for i, c := range name {
if c == 0 {
name = name[:i]
break
}
}
// Format object
fname := string(name)
// Check for useless names before allocating a string.
if fname == "." || fname == ".." {
continue
}
if !input.started {
if fname != input.continuationToken {
continue
}
// ContinuationToken is the next file, we should include this file.
input.started = true
}
o := s.newObject(false)
// FIXME: filepath.Join and path.Join is really slow here, we need handle this.
// Always keep service original name as ID.
o.ID = filepath.Join(input.rp, fname)
// Object's name should always be separated by slash (/)
o.Name = path.Join(input.dir, fname)
switch ty {
case DirentTypeDirectory:
o.Type = typ.ObjectTypeDir
case DirentTypeRegular:
o.Type = typ.ObjectTypeFile
case DirentTypeLink:
o.Type = typ.ObjectTypeLink
default:
o.Type = typ.ObjectTypeUnknown
}
// Set update name here.
input.continuationToken = o.Name
page.Data = append(page.Data, o)
}
return
}