podman

Форк
0
359 строк · 7.4 Кб
1
// Copyright © 2015 Steve Francia <spf@spf13.com>.
2
// Copyright 2013 tsuru authors. All rights reserved.
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// You may obtain a copy of the License at
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package mem
16

17
import (
18
	"bytes"
19
	"errors"
20
	"io"
21
	"io/fs"
22
	"os"
23
	"path/filepath"
24
	"sync"
25
	"sync/atomic"
26
	"time"
27

28
	"github.com/spf13/afero/internal/common"
29
)
30

31
const FilePathSeparator = string(filepath.Separator)
32

33
var _ fs.ReadDirFile = &File{}
34

35
type File struct {
36
	// atomic requires 64-bit alignment for struct field access
37
	at           int64
38
	readDirCount int64
39
	closed       bool
40
	readOnly     bool
41
	fileData     *FileData
42
}
43

44
func NewFileHandle(data *FileData) *File {
45
	return &File{fileData: data}
46
}
47

48
func NewReadOnlyFileHandle(data *FileData) *File {
49
	return &File{fileData: data, readOnly: true}
50
}
51

52
func (f File) Data() *FileData {
53
	return f.fileData
54
}
55

56
type FileData struct {
57
	sync.Mutex
58
	name    string
59
	data    []byte
60
	memDir  Dir
61
	dir     bool
62
	mode    os.FileMode
63
	modtime time.Time
64
	uid     int
65
	gid     int
66
}
67

68
func (d *FileData) Name() string {
69
	d.Lock()
70
	defer d.Unlock()
71
	return d.name
72
}
73

74
func CreateFile(name string) *FileData {
75
	return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()}
76
}
77

78
func CreateDir(name string) *FileData {
79
	return &FileData{name: name, memDir: &DirMap{}, dir: true, modtime: time.Now()}
80
}
81

82
func ChangeFileName(f *FileData, newname string) {
83
	f.Lock()
84
	f.name = newname
85
	f.Unlock()
86
}
87

88
func SetMode(f *FileData, mode os.FileMode) {
89
	f.Lock()
90
	f.mode = mode
91
	f.Unlock()
92
}
93

94
func SetModTime(f *FileData, mtime time.Time) {
95
	f.Lock()
96
	setModTime(f, mtime)
97
	f.Unlock()
98
}
99

100
func setModTime(f *FileData, mtime time.Time) {
101
	f.modtime = mtime
102
}
103

104
func SetUID(f *FileData, uid int) {
105
	f.Lock()
106
	f.uid = uid
107
	f.Unlock()
108
}
109

110
func SetGID(f *FileData, gid int) {
111
	f.Lock()
112
	f.gid = gid
113
	f.Unlock()
114
}
115

116
func GetFileInfo(f *FileData) *FileInfo {
117
	return &FileInfo{f}
118
}
119

120
func (f *File) Open() error {
121
	atomic.StoreInt64(&f.at, 0)
122
	atomic.StoreInt64(&f.readDirCount, 0)
123
	f.fileData.Lock()
124
	f.closed = false
125
	f.fileData.Unlock()
126
	return nil
127
}
128

129
func (f *File) Close() error {
130
	f.fileData.Lock()
131
	f.closed = true
132
	if !f.readOnly {
133
		setModTime(f.fileData, time.Now())
134
	}
135
	f.fileData.Unlock()
136
	return nil
137
}
138

139
func (f *File) Name() string {
140
	return f.fileData.Name()
141
}
142

143
func (f *File) Stat() (os.FileInfo, error) {
144
	return &FileInfo{f.fileData}, nil
145
}
146

147
func (f *File) Sync() error {
148
	return nil
149
}
150

151
func (f *File) Readdir(count int) (res []os.FileInfo, err error) {
152
	if !f.fileData.dir {
153
		return nil, &os.PathError{Op: "readdir", Path: f.fileData.name, Err: errors.New("not a dir")}
154
	}
155
	var outLength int64
156

157
	f.fileData.Lock()
158
	files := f.fileData.memDir.Files()[f.readDirCount:]
159
	if count > 0 {
160
		if len(files) < count {
161
			outLength = int64(len(files))
162
		} else {
163
			outLength = int64(count)
164
		}
165
		if len(files) == 0 {
166
			err = io.EOF
167
		}
168
	} else {
169
		outLength = int64(len(files))
170
	}
171
	f.readDirCount += outLength
172
	f.fileData.Unlock()
173

174
	res = make([]os.FileInfo, outLength)
175
	for i := range res {
176
		res[i] = &FileInfo{files[i]}
177
	}
178

179
	return res, err
180
}
181

182
func (f *File) Readdirnames(n int) (names []string, err error) {
183
	fi, err := f.Readdir(n)
184
	names = make([]string, len(fi))
185
	for i, f := range fi {
186
		_, names[i] = filepath.Split(f.Name())
187
	}
188
	return names, err
189
}
190

191
// Implements fs.ReadDirFile
192
func (f *File) ReadDir(n int) ([]fs.DirEntry, error) {
193
	fi, err := f.Readdir(n)
194
	if err != nil {
195
		return nil, err
196
	}
197
	di := make([]fs.DirEntry, len(fi))
198
	for i, f := range fi {
199
		di[i] = common.FileInfoDirEntry{FileInfo: f}
200
	}
201
	return di, nil
202
}
203

204
func (f *File) Read(b []byte) (n int, err error) {
205
	f.fileData.Lock()
206
	defer f.fileData.Unlock()
207
	if f.closed {
208
		return 0, ErrFileClosed
209
	}
210
	if len(b) > 0 && int(f.at) == len(f.fileData.data) {
211
		return 0, io.EOF
212
	}
213
	if int(f.at) > len(f.fileData.data) {
214
		return 0, io.ErrUnexpectedEOF
215
	}
216
	if len(f.fileData.data)-int(f.at) >= len(b) {
217
		n = len(b)
218
	} else {
219
		n = len(f.fileData.data) - int(f.at)
220
	}
221
	copy(b, f.fileData.data[f.at:f.at+int64(n)])
222
	atomic.AddInt64(&f.at, int64(n))
223
	return
224
}
225

226
func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
227
	prev := atomic.LoadInt64(&f.at)
228
	atomic.StoreInt64(&f.at, off)
229
	n, err = f.Read(b)
230
	atomic.StoreInt64(&f.at, prev)
231
	return
232
}
233

234
func (f *File) Truncate(size int64) error {
235
	if f.closed {
236
		return ErrFileClosed
237
	}
238
	if f.readOnly {
239
		return &os.PathError{Op: "truncate", Path: f.fileData.name, Err: errors.New("file handle is read only")}
240
	}
241
	if size < 0 {
242
		return ErrOutOfRange
243
	}
244
	f.fileData.Lock()
245
	defer f.fileData.Unlock()
246
	if size > int64(len(f.fileData.data)) {
247
		diff := size - int64(len(f.fileData.data))
248
		f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{0o0}, int(diff))...)
249
	} else {
250
		f.fileData.data = f.fileData.data[0:size]
251
	}
252
	setModTime(f.fileData, time.Now())
253
	return nil
254
}
255

256
func (f *File) Seek(offset int64, whence int) (int64, error) {
257
	if f.closed {
258
		return 0, ErrFileClosed
259
	}
260
	switch whence {
261
	case io.SeekStart:
262
		atomic.StoreInt64(&f.at, offset)
263
	case io.SeekCurrent:
264
		atomic.AddInt64(&f.at, offset)
265
	case io.SeekEnd:
266
		atomic.StoreInt64(&f.at, int64(len(f.fileData.data))+offset)
267
	}
268
	return f.at, nil
269
}
270

271
func (f *File) Write(b []byte) (n int, err error) {
272
	if f.closed {
273
		return 0, ErrFileClosed
274
	}
275
	if f.readOnly {
276
		return 0, &os.PathError{Op: "write", Path: f.fileData.name, Err: errors.New("file handle is read only")}
277
	}
278
	n = len(b)
279
	cur := atomic.LoadInt64(&f.at)
280
	f.fileData.Lock()
281
	defer f.fileData.Unlock()
282
	diff := cur - int64(len(f.fileData.data))
283
	var tail []byte
284
	if n+int(cur) < len(f.fileData.data) {
285
		tail = f.fileData.data[n+int(cur):]
286
	}
287
	if diff > 0 {
288
		f.fileData.data = append(f.fileData.data, append(bytes.Repeat([]byte{0o0}, int(diff)), b...)...)
289
		f.fileData.data = append(f.fileData.data, tail...)
290
	} else {
291
		f.fileData.data = append(f.fileData.data[:cur], b...)
292
		f.fileData.data = append(f.fileData.data, tail...)
293
	}
294
	setModTime(f.fileData, time.Now())
295

296
	atomic.AddInt64(&f.at, int64(n))
297
	return
298
}
299

300
func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
301
	atomic.StoreInt64(&f.at, off)
302
	return f.Write(b)
303
}
304

305
func (f *File) WriteString(s string) (ret int, err error) {
306
	return f.Write([]byte(s))
307
}
308

309
func (f *File) Info() *FileInfo {
310
	return &FileInfo{f.fileData}
311
}
312

313
type FileInfo struct {
314
	*FileData
315
}
316

317
// Implements os.FileInfo
318
func (s *FileInfo) Name() string {
319
	s.Lock()
320
	_, name := filepath.Split(s.name)
321
	s.Unlock()
322
	return name
323
}
324

325
func (s *FileInfo) Mode() os.FileMode {
326
	s.Lock()
327
	defer s.Unlock()
328
	return s.mode
329
}
330

331
func (s *FileInfo) ModTime() time.Time {
332
	s.Lock()
333
	defer s.Unlock()
334
	return s.modtime
335
}
336

337
func (s *FileInfo) IsDir() bool {
338
	s.Lock()
339
	defer s.Unlock()
340
	return s.dir
341
}
342
func (s *FileInfo) Sys() interface{} { return nil }
343
func (s *FileInfo) Size() int64 {
344
	if s.IsDir() {
345
		return int64(42)
346
	}
347
	s.Lock()
348
	defer s.Unlock()
349
	return int64(len(s.data))
350
}
351

352
var (
353
	ErrFileClosed        = errors.New("File is closed")
354
	ErrOutOfRange        = errors.New("out of range")
355
	ErrTooLarge          = errors.New("too large")
356
	ErrFileNotFound      = os.ErrNotExist
357
	ErrFileExists        = os.ErrExist
358
	ErrDestinationExists = os.ErrExist
359
)
360

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

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

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

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