1 package inmemory
2
3 import (
4 "fmt"
5 "io"
6 "path"
7 "sort"
8 "strings"
9 "time"
10 )
11
12 var (
13 errExists = fmt.Errorf("exists")
14 errNotExists = fmt.Errorf("notexists")
15 errIsNotDir = fmt.Errorf("notdir")
16 errIsDir = fmt.Errorf("isdir")
17 )
18
19 type node interface {
20 name() string
21 path() string
22 isdir() bool
23 modtime() time.Time
24 }
25
26
27
28 type dir struct {
29 common
30
31
32 children map[string]node
33 }
34
35 var _ node = &dir{}
36
37 func (d *dir) isdir() bool {
38 return true
39 }
40
41
42 func (d *dir) add(n node) {
43 if d.children == nil {
44 d.children = make(map[string]node)
45 }
46
47 d.children[n.name()] = n
48 d.mod = time.Now()
49 }
50
51
52
53
54 func (d *dir) find(q string) node {
55 q = strings.Trim(q, "/")
56 i := strings.Index(q, "/")
57
58 if q == "" {
59 return d
60 }
61
62 if i == 0 {
63 panic("shouldn't happen, no root paths")
64 }
65
66 var component string
67 if i < 0 {
68
69 component = q
70 } else {
71 component = q[:i]
72 }
73
74 child, ok := d.children[component]
75 if !ok {
76
77 return d
78 }
79
80 if child.isdir() {
81
82 q = q[i+1:]
83 return child.(*dir).find(q)
84 }
85
86 return child
87 }
88
89 func (d *dir) list(p string) ([]string, error) {
90 n := d.find(p)
91
92 if n.path() != p {
93 return nil, errNotExists
94 }
95
96 if !n.isdir() {
97 return nil, errIsNotDir
98 }
99
100 var children []string
101 for _, child := range n.(*dir).children {
102 children = append(children, child.path())
103 }
104
105 sort.Strings(children)
106 return children, nil
107 }
108
109
110
111 func (d *dir) mkfile(p string) (*file, error) {
112 n := d.find(p)
113 if n.path() == p {
114 if n.isdir() {
115 return nil, errIsDir
116 }
117
118 return n.(*file), nil
119 }
120
121 dirpath, filename := path.Split(p)
122
123 n, err := d.mkdirs(dirpath)
124 if err != nil {
125 return nil, err
126 }
127
128 dd := n.(*dir)
129 n = &file{
130 common: common{
131 p: path.Join(dd.path(), filename),
132 mod: time.Now(),
133 },
134 }
135
136 dd.add(n)
137 return n.(*file), nil
138 }
139
140
141 func (d *dir) mkdirs(p string) (*dir, error) {
142 p = normalize(p)
143
144 n := d.find(p)
145
146 if !n.isdir() {
147
148 return nil, errIsNotDir
149 }
150
151 if n.path() == p {
152 return n.(*dir), nil
153 }
154
155 dd := n.(*dir)
156
157 relative := strings.Trim(strings.TrimPrefix(p, n.path()), "/")
158
159 if relative == "" {
160 return dd, nil
161 }
162
163 components := strings.Split(relative, "/")
164 for _, component := range components {
165 d, err := dd.mkdir(component)
166
167 if err != nil {
168
169 return nil, err
170 }
171 dd = d
172 }
173
174 return dd, nil
175 }
176
177
178 func (d *dir) mkdir(name string) (*dir, error) {
179 if name == "" {
180 return nil, fmt.Errorf("invalid dirname")
181 }
182
183 _, ok := d.children[name]
184 if ok {
185 return nil, errExists
186 }
187
188 child := &dir{
189 common: common{
190 p: path.Join(d.path(), name),
191 mod: time.Now(),
192 },
193 }
194 d.add(child)
195 d.mod = time.Now()
196
197 return child, nil
198 }
199
200 func (d *dir) move(src, dst string) error {
201 dstDirname, _ := path.Split(dst)
202
203 dp, err := d.mkdirs(dstDirname)
204 if err != nil {
205 return err
206 }
207
208 srcDirname, srcFilename := path.Split(src)
209 sp := d.find(srcDirname)
210
211 if normalize(srcDirname) != normalize(sp.path()) {
212 return errNotExists
213 }
214
215 spd, ok := sp.(*dir)
216 if !ok {
217 return errIsNotDir
218 }
219
220 s, ok := spd.children[srcFilename]
221 if !ok {
222 return errNotExists
223 }
224
225 delete(spd.children, srcFilename)
226
227 switch n := s.(type) {
228 case *dir:
229 n.p = dst
230 case *file:
231 n.p = dst
232 }
233
234 dp.add(s)
235
236 return nil
237 }
238
239 func (d *dir) delete(p string) error {
240 dirname, filename := path.Split(p)
241 parent := d.find(dirname)
242
243 if normalize(dirname) != normalize(parent.path()) {
244 return errNotExists
245 }
246
247 if _, ok := parent.(*dir).children[filename]; !ok {
248 return errNotExists
249 }
250
251 delete(parent.(*dir).children, filename)
252 return nil
253 }
254
255 func (d *dir) String() string {
256 return fmt.Sprintf("&dir{path: %v, children: %v}", d.p, d.children)
257 }
258
259
260
261
262 type file struct {
263 common
264 data []byte
265 }
266
267 var _ node = &file{}
268
269 func (f *file) isdir() bool {
270 return false
271 }
272
273 func (f *file) truncate() {
274 f.data = f.data[:0]
275 }
276
277 func (f *file) sectionReader(offset int64) io.Reader {
278 return io.NewSectionReader(f, offset, int64(len(f.data))-offset)
279 }
280
281 func (f *file) ReadAt(p []byte, offset int64) (n int, err error) {
282 if offset >= int64(len(f.data)) {
283 return 0, io.EOF
284 }
285 return copy(p, f.data[offset:]), nil
286 }
287
288 func (f *file) WriteAt(p []byte, offset int64) (n int, err error) {
289 off := int(offset)
290 if cap(f.data) < off+len(p) {
291 data := make([]byte, len(f.data), off+len(p))
292 copy(data, f.data)
293 f.data = data
294 }
295
296 f.mod = time.Now()
297 f.data = f.data[:off+len(p)]
298
299 return copy(f.data[off:off+len(p)], p), nil
300 }
301
302 func (f *file) String() string {
303 return fmt.Sprintf("&file{path: %q}", f.p)
304 }
305
306
307 type common struct {
308 p string
309 mod time.Time
310 }
311
312 func (c *common) name() string {
313 _, name := path.Split(c.p)
314 return name
315 }
316
317 func (c *common) path() string {
318 return c.p
319 }
320
321 func (c *common) modtime() time.Time {
322 return c.mod
323 }
324
325 func normalize(p string) string {
326 return "/" + strings.Trim(p, "/")
327 }
328
View as plain text