podman

Форк
0
422 строки · 9.0 Кб
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
	"io"
19
	"log"
20
	"os"
21
	"path/filepath"
22
	"strings"
23
	"sync"
24
	"time"
25

26
	"github.com/spf13/afero/mem"
27
)
28

29
const chmodBits = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky // Only a subset of bits are allowed to be changed. Documented under os.Chmod()
30

31
type MemMapFs struct {
32
	mu   sync.RWMutex
33
	data map[string]*mem.FileData
34
	init sync.Once
35
}
36

37
func NewMemMapFs() Fs {
38
	return &MemMapFs{}
39
}
40

41
func (m *MemMapFs) getData() map[string]*mem.FileData {
42
	m.init.Do(func() {
43
		m.data = make(map[string]*mem.FileData)
44
		// Root should always exist, right?
45
		// TODO: what about windows?
46
		root := mem.CreateDir(FilePathSeparator)
47
		mem.SetMode(root, os.ModeDir|0o755)
48
		m.data[FilePathSeparator] = root
49
	})
50
	return m.data
51
}
52

53
func (*MemMapFs) Name() string { return "MemMapFS" }
54

55
func (m *MemMapFs) Create(name string) (File, error) {
56
	name = normalizePath(name)
57
	m.mu.Lock()
58
	file := mem.CreateFile(name)
59
	m.getData()[name] = file
60
	m.registerWithParent(file, 0)
61
	m.mu.Unlock()
62
	return mem.NewFileHandle(file), nil
63
}
64

65
func (m *MemMapFs) unRegisterWithParent(fileName string) error {
66
	f, err := m.lockfreeOpen(fileName)
67
	if err != nil {
68
		return err
69
	}
70
	parent := m.findParent(f)
71
	if parent == nil {
72
		log.Panic("parent of ", f.Name(), " is nil")
73
	}
74

75
	parent.Lock()
76
	mem.RemoveFromMemDir(parent, f)
77
	parent.Unlock()
78
	return nil
79
}
80

81
func (m *MemMapFs) findParent(f *mem.FileData) *mem.FileData {
82
	pdir, _ := filepath.Split(f.Name())
83
	pdir = filepath.Clean(pdir)
84
	pfile, err := m.lockfreeOpen(pdir)
85
	if err != nil {
86
		return nil
87
	}
88
	return pfile
89
}
90

91
func (m *MemMapFs) registerWithParent(f *mem.FileData, perm os.FileMode) {
92
	if f == nil {
93
		return
94
	}
95
	parent := m.findParent(f)
96
	if parent == nil {
97
		pdir := filepath.Dir(filepath.Clean(f.Name()))
98
		err := m.lockfreeMkdir(pdir, perm)
99
		if err != nil {
100
			// log.Println("Mkdir error:", err)
101
			return
102
		}
103
		parent, err = m.lockfreeOpen(pdir)
104
		if err != nil {
105
			// log.Println("Open after Mkdir error:", err)
106
			return
107
		}
108
	}
109

110
	parent.Lock()
111
	mem.InitializeDir(parent)
112
	mem.AddToMemDir(parent, f)
113
	parent.Unlock()
114
}
115

116
func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error {
117
	name = normalizePath(name)
118
	x, ok := m.getData()[name]
119
	if ok {
120
		// Only return ErrFileExists if it's a file, not a directory.
121
		i := mem.FileInfo{FileData: x}
122
		if !i.IsDir() {
123
			return ErrFileExists
124
		}
125
	} else {
126
		item := mem.CreateDir(name)
127
		mem.SetMode(item, os.ModeDir|perm)
128
		m.getData()[name] = item
129
		m.registerWithParent(item, perm)
130
	}
131
	return nil
132
}
133

134
func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
135
	perm &= chmodBits
136
	name = normalizePath(name)
137

138
	m.mu.RLock()
139
	_, ok := m.getData()[name]
140
	m.mu.RUnlock()
141
	if ok {
142
		return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
143
	}
144

145
	m.mu.Lock()
146
	// Dobule check that it doesn't exist.
147
	if _, ok := m.getData()[name]; ok {
148
		m.mu.Unlock()
149
		return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
150
	}
151
	item := mem.CreateDir(name)
152
	mem.SetMode(item, os.ModeDir|perm)
153
	m.getData()[name] = item
154
	m.registerWithParent(item, perm)
155
	m.mu.Unlock()
156

157
	return m.setFileMode(name, perm|os.ModeDir)
158
}
159

160
func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error {
161
	err := m.Mkdir(path, perm)
162
	if err != nil {
163
		if err.(*os.PathError).Err == ErrFileExists {
164
			return nil
165
		}
166
		return err
167
	}
168
	return nil
169
}
170

171
// Handle some relative paths
172
func normalizePath(path string) string {
173
	path = filepath.Clean(path)
174

175
	switch path {
176
	case ".":
177
		return FilePathSeparator
178
	case "..":
179
		return FilePathSeparator
180
	default:
181
		return path
182
	}
183
}
184

185
func (m *MemMapFs) Open(name string) (File, error) {
186
	f, err := m.open(name)
187
	if f != nil {
188
		return mem.NewReadOnlyFileHandle(f), err
189
	}
190
	return nil, err
191
}
192

193
func (m *MemMapFs) openWrite(name string) (File, error) {
194
	f, err := m.open(name)
195
	if f != nil {
196
		return mem.NewFileHandle(f), err
197
	}
198
	return nil, err
199
}
200

201
func (m *MemMapFs) open(name string) (*mem.FileData, error) {
202
	name = normalizePath(name)
203

204
	m.mu.RLock()
205
	f, ok := m.getData()[name]
206
	m.mu.RUnlock()
207
	if !ok {
208
		return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileNotFound}
209
	}
210
	return f, nil
211
}
212

213
func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) {
214
	name = normalizePath(name)
215
	f, ok := m.getData()[name]
216
	if ok {
217
		return f, nil
218
	} else {
219
		return nil, ErrFileNotFound
220
	}
221
}
222

223
func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
224
	perm &= chmodBits
225
	chmod := false
226
	file, err := m.openWrite(name)
227
	if err == nil && (flag&os.O_EXCL > 0) {
228
		return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileExists}
229
	}
230
	if os.IsNotExist(err) && (flag&os.O_CREATE > 0) {
231
		file, err = m.Create(name)
232
		chmod = true
233
	}
234
	if err != nil {
235
		return nil, err
236
	}
237
	if flag == os.O_RDONLY {
238
		file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data())
239
	}
240
	if flag&os.O_APPEND > 0 {
241
		_, err = file.Seek(0, io.SeekEnd)
242
		if err != nil {
243
			file.Close()
244
			return nil, err
245
		}
246
	}
247
	if flag&os.O_TRUNC > 0 && flag&(os.O_RDWR|os.O_WRONLY) > 0 {
248
		err = file.Truncate(0)
249
		if err != nil {
250
			file.Close()
251
			return nil, err
252
		}
253
	}
254
	if chmod {
255
		return file, m.setFileMode(name, perm)
256
	}
257
	return file, nil
258
}
259

260
func (m *MemMapFs) Remove(name string) error {
261
	name = normalizePath(name)
262

263
	m.mu.Lock()
264
	defer m.mu.Unlock()
265

266
	if _, ok := m.getData()[name]; ok {
267
		err := m.unRegisterWithParent(name)
268
		if err != nil {
269
			return &os.PathError{Op: "remove", Path: name, Err: err}
270
		}
271
		delete(m.getData(), name)
272
	} else {
273
		return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist}
274
	}
275
	return nil
276
}
277

278
func (m *MemMapFs) RemoveAll(path string) error {
279
	path = normalizePath(path)
280
	m.mu.Lock()
281
	m.unRegisterWithParent(path)
282
	m.mu.Unlock()
283

284
	m.mu.RLock()
285
	defer m.mu.RUnlock()
286

287
	for p := range m.getData() {
288
		if p == path || strings.HasPrefix(p, path+FilePathSeparator) {
289
			m.mu.RUnlock()
290
			m.mu.Lock()
291
			delete(m.getData(), p)
292
			m.mu.Unlock()
293
			m.mu.RLock()
294
		}
295
	}
296
	return nil
297
}
298

299
func (m *MemMapFs) Rename(oldname, newname string) error {
300
	oldname = normalizePath(oldname)
301
	newname = normalizePath(newname)
302

303
	if oldname == newname {
304
		return nil
305
	}
306

307
	m.mu.RLock()
308
	defer m.mu.RUnlock()
309
	if _, ok := m.getData()[oldname]; ok {
310
		m.mu.RUnlock()
311
		m.mu.Lock()
312
		m.unRegisterWithParent(oldname)
313
		fileData := m.getData()[oldname]
314
		delete(m.getData(), oldname)
315
		mem.ChangeFileName(fileData, newname)
316
		m.getData()[newname] = fileData
317
		m.registerWithParent(fileData, 0)
318
		m.mu.Unlock()
319
		m.mu.RLock()
320
	} else {
321
		return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound}
322
	}
323

324
	for p, fileData := range m.getData() {
325
		if strings.HasPrefix(p, oldname+FilePathSeparator) {
326
			m.mu.RUnlock()
327
			m.mu.Lock()
328
			delete(m.getData(), p)
329
			p := strings.Replace(p, oldname, newname, 1)
330
			m.getData()[p] = fileData
331
			m.mu.Unlock()
332
			m.mu.RLock()
333
		}
334
	}
335
	return nil
336
}
337

338
func (m *MemMapFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
339
	fileInfo, err := m.Stat(name)
340
	return fileInfo, false, err
341
}
342

343
func (m *MemMapFs) Stat(name string) (os.FileInfo, error) {
344
	f, err := m.Open(name)
345
	if err != nil {
346
		return nil, err
347
	}
348
	fi := mem.GetFileInfo(f.(*mem.File).Data())
349
	return fi, nil
350
}
351

352
func (m *MemMapFs) Chmod(name string, mode os.FileMode) error {
353
	mode &= chmodBits
354

355
	m.mu.RLock()
356
	f, ok := m.getData()[name]
357
	m.mu.RUnlock()
358
	if !ok {
359
		return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound}
360
	}
361
	prevOtherBits := mem.GetFileInfo(f).Mode() & ^chmodBits
362

363
	mode = prevOtherBits | mode
364
	return m.setFileMode(name, mode)
365
}
366

367
func (m *MemMapFs) setFileMode(name string, mode os.FileMode) error {
368
	name = normalizePath(name)
369

370
	m.mu.RLock()
371
	f, ok := m.getData()[name]
372
	m.mu.RUnlock()
373
	if !ok {
374
		return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound}
375
	}
376

377
	m.mu.Lock()
378
	mem.SetMode(f, mode)
379
	m.mu.Unlock()
380

381
	return nil
382
}
383

384
func (m *MemMapFs) Chown(name string, uid, gid int) error {
385
	name = normalizePath(name)
386

387
	m.mu.RLock()
388
	f, ok := m.getData()[name]
389
	m.mu.RUnlock()
390
	if !ok {
391
		return &os.PathError{Op: "chown", Path: name, Err: ErrFileNotFound}
392
	}
393

394
	mem.SetUID(f, uid)
395
	mem.SetGID(f, gid)
396

397
	return nil
398
}
399

400
func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
401
	name = normalizePath(name)
402

403
	m.mu.RLock()
404
	f, ok := m.getData()[name]
405
	m.mu.RUnlock()
406
	if !ok {
407
		return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound}
408
	}
409

410
	m.mu.Lock()
411
	mem.SetModTime(f, mtime)
412
	m.mu.Unlock()
413

414
	return nil
415
}
416

417
func (m *MemMapFs) List() {
418
	for _, x := range m.data {
419
		y := mem.FileInfo{FileData: x}
420
		fmt.Println(x.Name(), y.Size())
421
	}
422
}
423

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.