1
2
3
4 package afero
5
6 import (
7 "io"
8 "io/fs"
9 "os"
10 "path"
11 "sort"
12 "time"
13
14 "github.com/spf13/afero/internal/common"
15 )
16
17
18 type IOFS struct {
19 Fs
20 }
21
22 func NewIOFS(fs Fs) IOFS {
23 return IOFS{Fs: fs}
24 }
25
26 var (
27 _ fs.FS = IOFS{}
28 _ fs.GlobFS = IOFS{}
29 _ fs.ReadDirFS = IOFS{}
30 _ fs.ReadFileFS = IOFS{}
31 _ fs.StatFS = IOFS{}
32 _ fs.SubFS = IOFS{}
33 )
34
35 func (iofs IOFS) Open(name string) (fs.File, error) {
36 const op = "open"
37
38
39 if !fs.ValidPath(name) {
40 return nil, iofs.wrapError(op, name, fs.ErrInvalid)
41 }
42
43 file, err := iofs.Fs.Open(name)
44 if err != nil {
45 return nil, iofs.wrapError(op, name, err)
46 }
47
48
49 if _, ok := file.(fs.ReadDirFile); !ok {
50 file = readDirFile{file}
51 }
52
53 return file, nil
54 }
55
56 func (iofs IOFS) Glob(pattern string) ([]string, error) {
57 const op = "glob"
58
59
60 if _, err := path.Match(pattern, ""); err != nil {
61 return nil, iofs.wrapError(op, pattern, err)
62 }
63
64 items, err := Glob(iofs.Fs, pattern)
65 if err != nil {
66 return nil, iofs.wrapError(op, pattern, err)
67 }
68
69 return items, nil
70 }
71
72 func (iofs IOFS) ReadDir(name string) ([]fs.DirEntry, error) {
73 f, err := iofs.Fs.Open(name)
74 if err != nil {
75 return nil, iofs.wrapError("readdir", name, err)
76 }
77
78 defer f.Close()
79
80 if rdf, ok := f.(fs.ReadDirFile); ok {
81 items, err := rdf.ReadDir(-1)
82 if err != nil {
83 return nil, iofs.wrapError("readdir", name, err)
84 }
85 sort.Slice(items, func(i, j int) bool { return items[i].Name() < items[j].Name() })
86 return items, nil
87 }
88
89 items, err := f.Readdir(-1)
90 if err != nil {
91 return nil, iofs.wrapError("readdir", name, err)
92 }
93 sort.Sort(byName(items))
94
95 ret := make([]fs.DirEntry, len(items))
96 for i := range items {
97 ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
98 }
99
100 return ret, nil
101 }
102
103 func (iofs IOFS) ReadFile(name string) ([]byte, error) {
104 const op = "readfile"
105
106 if !fs.ValidPath(name) {
107 return nil, iofs.wrapError(op, name, fs.ErrInvalid)
108 }
109
110 bytes, err := ReadFile(iofs.Fs, name)
111 if err != nil {
112 return nil, iofs.wrapError(op, name, err)
113 }
114
115 return bytes, nil
116 }
117
118 func (iofs IOFS) Sub(dir string) (fs.FS, error) { return IOFS{NewBasePathFs(iofs.Fs, dir)}, nil }
119
120 func (IOFS) wrapError(op, path string, err error) error {
121 if _, ok := err.(*fs.PathError); ok {
122 return err
123 }
124
125 return &fs.PathError{
126 Op: op,
127 Path: path,
128 Err: err,
129 }
130 }
131
132
133 type readDirFile struct {
134 File
135 }
136
137 var _ fs.ReadDirFile = readDirFile{}
138
139 func (r readDirFile) ReadDir(n int) ([]fs.DirEntry, error) {
140 items, err := r.File.Readdir(n)
141 if err != nil {
142 return nil, err
143 }
144
145 ret := make([]fs.DirEntry, len(items))
146 for i := range items {
147 ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
148 }
149
150 return ret, nil
151 }
152
153
154
155
156 type FromIOFS struct {
157 fs.FS
158 }
159
160 var _ Fs = FromIOFS{}
161
162 func (f FromIOFS) Create(name string) (File, error) { return nil, notImplemented("create", name) }
163
164 func (f FromIOFS) Mkdir(name string, perm os.FileMode) error { return notImplemented("mkdir", name) }
165
166 func (f FromIOFS) MkdirAll(path string, perm os.FileMode) error {
167 return notImplemented("mkdirall", path)
168 }
169
170 func (f FromIOFS) Open(name string) (File, error) {
171 file, err := f.FS.Open(name)
172 if err != nil {
173 return nil, err
174 }
175
176 return fromIOFSFile{File: file, name: name}, nil
177 }
178
179 func (f FromIOFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
180 return f.Open(name)
181 }
182
183 func (f FromIOFS) Remove(name string) error {
184 return notImplemented("remove", name)
185 }
186
187 func (f FromIOFS) RemoveAll(path string) error {
188 return notImplemented("removeall", path)
189 }
190
191 func (f FromIOFS) Rename(oldname, newname string) error {
192 return notImplemented("rename", oldname)
193 }
194
195 func (f FromIOFS) Stat(name string) (os.FileInfo, error) { return fs.Stat(f.FS, name) }
196
197 func (f FromIOFS) Name() string { return "fromiofs" }
198
199 func (f FromIOFS) Chmod(name string, mode os.FileMode) error {
200 return notImplemented("chmod", name)
201 }
202
203 func (f FromIOFS) Chown(name string, uid, gid int) error {
204 return notImplemented("chown", name)
205 }
206
207 func (f FromIOFS) Chtimes(name string, atime time.Time, mtime time.Time) error {
208 return notImplemented("chtimes", name)
209 }
210
211 type fromIOFSFile struct {
212 fs.File
213 name string
214 }
215
216 func (f fromIOFSFile) ReadAt(p []byte, off int64) (n int, err error) {
217 readerAt, ok := f.File.(io.ReaderAt)
218 if !ok {
219 return -1, notImplemented("readat", f.name)
220 }
221
222 return readerAt.ReadAt(p, off)
223 }
224
225 func (f fromIOFSFile) Seek(offset int64, whence int) (int64, error) {
226 seeker, ok := f.File.(io.Seeker)
227 if !ok {
228 return -1, notImplemented("seek", f.name)
229 }
230
231 return seeker.Seek(offset, whence)
232 }
233
234 func (f fromIOFSFile) Write(p []byte) (n int, err error) {
235 return -1, notImplemented("write", f.name)
236 }
237
238 func (f fromIOFSFile) WriteAt(p []byte, off int64) (n int, err error) {
239 return -1, notImplemented("writeat", f.name)
240 }
241
242 func (f fromIOFSFile) Name() string { return f.name }
243
244 func (f fromIOFSFile) Readdir(count int) ([]os.FileInfo, error) {
245 rdfile, ok := f.File.(fs.ReadDirFile)
246 if !ok {
247 return nil, notImplemented("readdir", f.name)
248 }
249
250 entries, err := rdfile.ReadDir(count)
251 if err != nil {
252 return nil, err
253 }
254
255 ret := make([]os.FileInfo, len(entries))
256 for i := range entries {
257 ret[i], err = entries[i].Info()
258
259 if err != nil {
260 return nil, err
261 }
262 }
263
264 return ret, nil
265 }
266
267 func (f fromIOFSFile) Readdirnames(n int) ([]string, error) {
268 rdfile, ok := f.File.(fs.ReadDirFile)
269 if !ok {
270 return nil, notImplemented("readdir", f.name)
271 }
272
273 entries, err := rdfile.ReadDir(n)
274 if err != nil {
275 return nil, err
276 }
277
278 ret := make([]string, len(entries))
279 for i := range entries {
280 ret[i] = entries[i].Name()
281 }
282
283 return ret, nil
284 }
285
286 func (f fromIOFSFile) Sync() error { return nil }
287
288 func (f fromIOFSFile) Truncate(size int64) error {
289 return notImplemented("truncate", f.name)
290 }
291
292 func (f fromIOFSFile) WriteString(s string) (ret int, err error) {
293 return -1, notImplemented("writestring", f.name)
294 }
295
296 func notImplemented(op, path string) error {
297 return &fs.PathError{Op: op, Path: path, Err: fs.ErrPermission}
298 }
299
View as plain text