diff options
Diffstat (limited to 'vendor/github.com/spf13/afero/memmap.go')
-rw-r--r-- | vendor/github.com/spf13/afero/memmap.go | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/vendor/github.com/spf13/afero/memmap.go b/vendor/github.com/spf13/afero/memmap.go new file mode 100644 index 0000000..09498e7 --- /dev/null +++ b/vendor/github.com/spf13/afero/memmap.go | |||
@@ -0,0 +1,365 @@ | |||
1 | // Copyright © 2014 Steve Francia <spf@spf13.com>. | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
7 | // | ||
8 | // Unless required by applicable law or agreed to in writing, software | ||
9 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
11 | // See the License for the specific language governing permissions and | ||
12 | // limitations under the License. | ||
13 | |||
14 | package afero | ||
15 | |||
16 | import ( | ||
17 | "fmt" | ||
18 | "log" | ||
19 | "os" | ||
20 | "path/filepath" | ||
21 | "strings" | ||
22 | "sync" | ||
23 | "time" | ||
24 | |||
25 | "github.com/spf13/afero/mem" | ||
26 | ) | ||
27 | |||
28 | type MemMapFs struct { | ||
29 | mu sync.RWMutex | ||
30 | data map[string]*mem.FileData | ||
31 | init sync.Once | ||
32 | } | ||
33 | |||
34 | func NewMemMapFs() Fs { | ||
35 | return &MemMapFs{} | ||
36 | } | ||
37 | |||
38 | func (m *MemMapFs) getData() map[string]*mem.FileData { | ||
39 | m.init.Do(func() { | ||
40 | m.data = make(map[string]*mem.FileData) | ||
41 | // Root should always exist, right? | ||
42 | // TODO: what about windows? | ||
43 | m.data[FilePathSeparator] = mem.CreateDir(FilePathSeparator) | ||
44 | }) | ||
45 | return m.data | ||
46 | } | ||
47 | |||
48 | func (*MemMapFs) Name() string { return "MemMapFS" } | ||
49 | |||
50 | func (m *MemMapFs) Create(name string) (File, error) { | ||
51 | name = normalizePath(name) | ||
52 | m.mu.Lock() | ||
53 | file := mem.CreateFile(name) | ||
54 | m.getData()[name] = file | ||
55 | m.registerWithParent(file) | ||
56 | m.mu.Unlock() | ||
57 | return mem.NewFileHandle(file), nil | ||
58 | } | ||
59 | |||
60 | func (m *MemMapFs) unRegisterWithParent(fileName string) error { | ||
61 | f, err := m.lockfreeOpen(fileName) | ||
62 | if err != nil { | ||
63 | return err | ||
64 | } | ||
65 | parent := m.findParent(f) | ||
66 | if parent == nil { | ||
67 | log.Panic("parent of ", f.Name(), " is nil") | ||
68 | } | ||
69 | |||
70 | parent.Lock() | ||
71 | mem.RemoveFromMemDir(parent, f) | ||
72 | parent.Unlock() | ||
73 | return nil | ||
74 | } | ||
75 | |||
76 | func (m *MemMapFs) findParent(f *mem.FileData) *mem.FileData { | ||
77 | pdir, _ := filepath.Split(f.Name()) | ||
78 | pdir = filepath.Clean(pdir) | ||
79 | pfile, err := m.lockfreeOpen(pdir) | ||
80 | if err != nil { | ||
81 | return nil | ||
82 | } | ||
83 | return pfile | ||
84 | } | ||
85 | |||
86 | func (m *MemMapFs) registerWithParent(f *mem.FileData) { | ||
87 | if f == nil { | ||
88 | return | ||
89 | } | ||
90 | parent := m.findParent(f) | ||
91 | if parent == nil { | ||
92 | pdir := filepath.Dir(filepath.Clean(f.Name())) | ||
93 | err := m.lockfreeMkdir(pdir, 0777) | ||
94 | if err != nil { | ||
95 | //log.Println("Mkdir error:", err) | ||
96 | return | ||
97 | } | ||
98 | parent, err = m.lockfreeOpen(pdir) | ||
99 | if err != nil { | ||
100 | //log.Println("Open after Mkdir error:", err) | ||
101 | return | ||
102 | } | ||
103 | } | ||
104 | |||
105 | parent.Lock() | ||
106 | mem.InitializeDir(parent) | ||
107 | mem.AddToMemDir(parent, f) | ||
108 | parent.Unlock() | ||
109 | } | ||
110 | |||
111 | func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error { | ||
112 | name = normalizePath(name) | ||
113 | x, ok := m.getData()[name] | ||
114 | if ok { | ||
115 | // Only return ErrFileExists if it's a file, not a directory. | ||
116 | i := mem.FileInfo{FileData: x} | ||
117 | if !i.IsDir() { | ||
118 | return ErrFileExists | ||
119 | } | ||
120 | } else { | ||
121 | item := mem.CreateDir(name) | ||
122 | m.getData()[name] = item | ||
123 | m.registerWithParent(item) | ||
124 | } | ||
125 | return nil | ||
126 | } | ||
127 | |||
128 | func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error { | ||
129 | name = normalizePath(name) | ||
130 | |||
131 | m.mu.RLock() | ||
132 | _, ok := m.getData()[name] | ||
133 | m.mu.RUnlock() | ||
134 | if ok { | ||
135 | return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists} | ||
136 | } | ||
137 | |||
138 | m.mu.Lock() | ||
139 | item := mem.CreateDir(name) | ||
140 | m.getData()[name] = item | ||
141 | m.registerWithParent(item) | ||
142 | m.mu.Unlock() | ||
143 | |||
144 | m.Chmod(name, perm|os.ModeDir) | ||
145 | |||
146 | return nil | ||
147 | } | ||
148 | |||
149 | func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error { | ||
150 | err := m.Mkdir(path, perm) | ||
151 | if err != nil { | ||
152 | if err.(*os.PathError).Err == ErrFileExists { | ||
153 | return nil | ||
154 | } | ||
155 | return err | ||
156 | } | ||
157 | return nil | ||
158 | } | ||
159 | |||
160 | // Handle some relative paths | ||
161 | func normalizePath(path string) string { | ||
162 | path = filepath.Clean(path) | ||
163 | |||
164 | switch path { | ||
165 | case ".": | ||
166 | return FilePathSeparator | ||
167 | case "..": | ||
168 | return FilePathSeparator | ||
169 | default: | ||
170 | return path | ||
171 | } | ||
172 | } | ||
173 | |||
174 | func (m *MemMapFs) Open(name string) (File, error) { | ||
175 | f, err := m.open(name) | ||
176 | if f != nil { | ||
177 | return mem.NewReadOnlyFileHandle(f), err | ||
178 | } | ||
179 | return nil, err | ||
180 | } | ||
181 | |||
182 | func (m *MemMapFs) openWrite(name string) (File, error) { | ||
183 | f, err := m.open(name) | ||
184 | if f != nil { | ||
185 | return mem.NewFileHandle(f), err | ||
186 | } | ||
187 | return nil, err | ||
188 | } | ||
189 | |||
190 | func (m *MemMapFs) open(name string) (*mem.FileData, error) { | ||
191 | name = normalizePath(name) | ||
192 | |||
193 | m.mu.RLock() | ||
194 | f, ok := m.getData()[name] | ||
195 | m.mu.RUnlock() | ||
196 | if !ok { | ||
197 | return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileNotFound} | ||
198 | } | ||
199 | return f, nil | ||
200 | } | ||
201 | |||
202 | func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) { | ||
203 | name = normalizePath(name) | ||
204 | f, ok := m.getData()[name] | ||
205 | if ok { | ||
206 | return f, nil | ||
207 | } else { | ||
208 | return nil, ErrFileNotFound | ||
209 | } | ||
210 | } | ||
211 | |||
212 | func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { | ||
213 | chmod := false | ||
214 | file, err := m.openWrite(name) | ||
215 | if os.IsNotExist(err) && (flag&os.O_CREATE > 0) { | ||
216 | file, err = m.Create(name) | ||
217 | chmod = true | ||
218 | } | ||
219 | if err != nil { | ||
220 | return nil, err | ||
221 | } | ||
222 | if flag == os.O_RDONLY { | ||
223 | file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data()) | ||
224 | } | ||
225 | if flag&os.O_APPEND > 0 { | ||
226 | _, err = file.Seek(0, os.SEEK_END) | ||
227 | if err != nil { | ||
228 | file.Close() | ||
229 | return nil, err | ||
230 | } | ||
231 | } | ||
232 | if flag&os.O_TRUNC > 0 && flag&(os.O_RDWR|os.O_WRONLY) > 0 { | ||
233 | err = file.Truncate(0) | ||
234 | if err != nil { | ||
235 | file.Close() | ||
236 | return nil, err | ||
237 | } | ||
238 | } | ||
239 | if chmod { | ||
240 | m.Chmod(name, perm) | ||
241 | } | ||
242 | return file, nil | ||
243 | } | ||
244 | |||
245 | func (m *MemMapFs) Remove(name string) error { | ||
246 | name = normalizePath(name) | ||
247 | |||
248 | m.mu.Lock() | ||
249 | defer m.mu.Unlock() | ||
250 | |||
251 | if _, ok := m.getData()[name]; ok { | ||
252 | err := m.unRegisterWithParent(name) | ||
253 | if err != nil { | ||
254 | return &os.PathError{Op: "remove", Path: name, Err: err} | ||
255 | } | ||
256 | delete(m.getData(), name) | ||
257 | } else { | ||
258 | return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist} | ||
259 | } | ||
260 | return nil | ||
261 | } | ||
262 | |||
263 | func (m *MemMapFs) RemoveAll(path string) error { | ||
264 | path = normalizePath(path) | ||
265 | m.mu.Lock() | ||
266 | m.unRegisterWithParent(path) | ||
267 | m.mu.Unlock() | ||
268 | |||
269 | m.mu.RLock() | ||
270 | defer m.mu.RUnlock() | ||
271 | |||
272 | for p, _ := range m.getData() { | ||
273 | if strings.HasPrefix(p, path) { | ||
274 | m.mu.RUnlock() | ||
275 | m.mu.Lock() | ||
276 | delete(m.getData(), p) | ||
277 | m.mu.Unlock() | ||
278 | m.mu.RLock() | ||
279 | } | ||
280 | } | ||
281 | return nil | ||
282 | } | ||
283 | |||
284 | func (m *MemMapFs) Rename(oldname, newname string) error { | ||
285 | oldname = normalizePath(oldname) | ||
286 | newname = normalizePath(newname) | ||
287 | |||
288 | if oldname == newname { | ||
289 | return nil | ||
290 | } | ||
291 | |||
292 | m.mu.RLock() | ||
293 | defer m.mu.RUnlock() | ||
294 | if _, ok := m.getData()[oldname]; ok { | ||
295 | m.mu.RUnlock() | ||
296 | m.mu.Lock() | ||
297 | m.unRegisterWithParent(oldname) | ||
298 | fileData := m.getData()[oldname] | ||
299 | delete(m.getData(), oldname) | ||
300 | mem.ChangeFileName(fileData, newname) | ||
301 | m.getData()[newname] = fileData | ||
302 | m.registerWithParent(fileData) | ||
303 | m.mu.Unlock() | ||
304 | m.mu.RLock() | ||
305 | } else { | ||
306 | return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound} | ||
307 | } | ||
308 | return nil | ||
309 | } | ||
310 | |||
311 | func (m *MemMapFs) Stat(name string) (os.FileInfo, error) { | ||
312 | f, err := m.Open(name) | ||
313 | if err != nil { | ||
314 | return nil, err | ||
315 | } | ||
316 | fi := mem.GetFileInfo(f.(*mem.File).Data()) | ||
317 | return fi, nil | ||
318 | } | ||
319 | |||
320 | func (m *MemMapFs) Chmod(name string, mode os.FileMode) error { | ||
321 | name = normalizePath(name) | ||
322 | |||
323 | m.mu.RLock() | ||
324 | f, ok := m.getData()[name] | ||
325 | m.mu.RUnlock() | ||
326 | if !ok { | ||
327 | return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound} | ||
328 | } | ||
329 | |||
330 | m.mu.Lock() | ||
331 | mem.SetMode(f, mode) | ||
332 | m.mu.Unlock() | ||
333 | |||
334 | return nil | ||
335 | } | ||
336 | |||
337 | func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error { | ||
338 | name = normalizePath(name) | ||
339 | |||
340 | m.mu.RLock() | ||
341 | f, ok := m.getData()[name] | ||
342 | m.mu.RUnlock() | ||
343 | if !ok { | ||
344 | return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound} | ||
345 | } | ||
346 | |||
347 | m.mu.Lock() | ||
348 | mem.SetModTime(f, mtime) | ||
349 | m.mu.Unlock() | ||
350 | |||
351 | return nil | ||
352 | } | ||
353 | |||
354 | func (m *MemMapFs) List() { | ||
355 | for _, x := range m.data { | ||
356 | y := mem.FileInfo{FileData: x} | ||
357 | fmt.Println(x.Name(), y.Size()) | ||
358 | } | ||
359 | } | ||
360 | |||
361 | // func debugMemMapList(fs Fs) { | ||
362 | // if x, ok := fs.(*MemMapFs); ok { | ||
363 | // x.List() | ||
364 | // } | ||
365 | // } | ||