podman

Форк
0
327 строк · 7.6 Кб
1
package afero
2

3
import (
4
	"fmt"
5
	"os"
6
	"path/filepath"
7
	"syscall"
8
	"time"
9
)
10

11
var _ Lstater = (*CopyOnWriteFs)(nil)
12

13
// The CopyOnWriteFs is a union filesystem: a read only base file system with
14
// a possibly writeable layer on top. Changes to the file system will only
15
// be made in the overlay: Changing an existing file in the base layer which
16
// is not present in the overlay will copy the file to the overlay ("changing"
17
// includes also calls to e.g. Chtimes(), Chmod() and Chown()).
18
//
19
// Reading directories is currently only supported via Open(), not OpenFile().
20
type CopyOnWriteFs struct {
21
	base  Fs
22
	layer Fs
23
}
24

25
func NewCopyOnWriteFs(base Fs, layer Fs) Fs {
26
	return &CopyOnWriteFs{base: base, layer: layer}
27
}
28

29
// Returns true if the file is not in the overlay
30
func (u *CopyOnWriteFs) isBaseFile(name string) (bool, error) {
31
	if _, err := u.layer.Stat(name); err == nil {
32
		return false, nil
33
	}
34
	_, err := u.base.Stat(name)
35
	if err != nil {
36
		if oerr, ok := err.(*os.PathError); ok {
37
			if oerr.Err == os.ErrNotExist || oerr.Err == syscall.ENOENT || oerr.Err == syscall.ENOTDIR {
38
				return false, nil
39
			}
40
		}
41
		if err == syscall.ENOENT {
42
			return false, nil
43
		}
44
	}
45
	return true, err
46
}
47

48
func (u *CopyOnWriteFs) copyToLayer(name string) error {
49
	return copyToLayer(u.base, u.layer, name)
50
}
51

52
func (u *CopyOnWriteFs) Chtimes(name string, atime, mtime time.Time) error {
53
	b, err := u.isBaseFile(name)
54
	if err != nil {
55
		return err
56
	}
57
	if b {
58
		if err := u.copyToLayer(name); err != nil {
59
			return err
60
		}
61
	}
62
	return u.layer.Chtimes(name, atime, mtime)
63
}
64

65
func (u *CopyOnWriteFs) Chmod(name string, mode os.FileMode) error {
66
	b, err := u.isBaseFile(name)
67
	if err != nil {
68
		return err
69
	}
70
	if b {
71
		if err := u.copyToLayer(name); err != nil {
72
			return err
73
		}
74
	}
75
	return u.layer.Chmod(name, mode)
76
}
77

78
func (u *CopyOnWriteFs) Chown(name string, uid, gid int) error {
79
	b, err := u.isBaseFile(name)
80
	if err != nil {
81
		return err
82
	}
83
	if b {
84
		if err := u.copyToLayer(name); err != nil {
85
			return err
86
		}
87
	}
88
	return u.layer.Chown(name, uid, gid)
89
}
90

91
func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) {
92
	fi, err := u.layer.Stat(name)
93
	if err != nil {
94
		isNotExist := u.isNotExist(err)
95
		if isNotExist {
96
			return u.base.Stat(name)
97
		}
98
		return nil, err
99
	}
100
	return fi, nil
101
}
102

103
func (u *CopyOnWriteFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
104
	llayer, ok1 := u.layer.(Lstater)
105
	lbase, ok2 := u.base.(Lstater)
106

107
	if ok1 {
108
		fi, b, err := llayer.LstatIfPossible(name)
109
		if err == nil {
110
			return fi, b, nil
111
		}
112

113
		if !u.isNotExist(err) {
114
			return nil, b, err
115
		}
116
	}
117

118
	if ok2 {
119
		fi, b, err := lbase.LstatIfPossible(name)
120
		if err == nil {
121
			return fi, b, nil
122
		}
123
		if !u.isNotExist(err) {
124
			return nil, b, err
125
		}
126
	}
127

128
	fi, err := u.Stat(name)
129

130
	return fi, false, err
131
}
132

133
func (u *CopyOnWriteFs) SymlinkIfPossible(oldname, newname string) error {
134
	if slayer, ok := u.layer.(Linker); ok {
135
		return slayer.SymlinkIfPossible(oldname, newname)
136
	}
137

138
	return &os.LinkError{Op: "symlink", Old: oldname, New: newname, Err: ErrNoSymlink}
139
}
140

141
func (u *CopyOnWriteFs) ReadlinkIfPossible(name string) (string, error) {
142
	if rlayer, ok := u.layer.(LinkReader); ok {
143
		return rlayer.ReadlinkIfPossible(name)
144
	}
145

146
	if rbase, ok := u.base.(LinkReader); ok {
147
		return rbase.ReadlinkIfPossible(name)
148
	}
149

150
	return "", &os.PathError{Op: "readlink", Path: name, Err: ErrNoReadlink}
151
}
152

153
func (u *CopyOnWriteFs) isNotExist(err error) bool {
154
	if e, ok := err.(*os.PathError); ok {
155
		err = e.Err
156
	}
157
	if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR {
158
		return true
159
	}
160
	return false
161
}
162

163
// Renaming files present only in the base layer is not permitted
164
func (u *CopyOnWriteFs) Rename(oldname, newname string) error {
165
	b, err := u.isBaseFile(oldname)
166
	if err != nil {
167
		return err
168
	}
169
	if b {
170
		return syscall.EPERM
171
	}
172
	return u.layer.Rename(oldname, newname)
173
}
174

175
// Removing files present only in the base layer is not permitted. If
176
// a file is present in the base layer and the overlay, only the overlay
177
// will be removed.
178
func (u *CopyOnWriteFs) Remove(name string) error {
179
	err := u.layer.Remove(name)
180
	switch err {
181
	case syscall.ENOENT:
182
		_, err = u.base.Stat(name)
183
		if err == nil {
184
			return syscall.EPERM
185
		}
186
		return syscall.ENOENT
187
	default:
188
		return err
189
	}
190
}
191

192
func (u *CopyOnWriteFs) RemoveAll(name string) error {
193
	err := u.layer.RemoveAll(name)
194
	switch err {
195
	case syscall.ENOENT:
196
		_, err = u.base.Stat(name)
197
		if err == nil {
198
			return syscall.EPERM
199
		}
200
		return syscall.ENOENT
201
	default:
202
		return err
203
	}
204
}
205

206
func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
207
	b, err := u.isBaseFile(name)
208
	if err != nil {
209
		return nil, err
210
	}
211

212
	if flag&(os.O_WRONLY|os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
213
		if b {
214
			if err = u.copyToLayer(name); err != nil {
215
				return nil, err
216
			}
217
			return u.layer.OpenFile(name, flag, perm)
218
		}
219

220
		dir := filepath.Dir(name)
221
		isaDir, err := IsDir(u.base, dir)
222
		if err != nil && !os.IsNotExist(err) {
223
			return nil, err
224
		}
225
		if isaDir {
226
			if err = u.layer.MkdirAll(dir, 0o777); err != nil {
227
				return nil, err
228
			}
229
			return u.layer.OpenFile(name, flag, perm)
230
		}
231

232
		isaDir, err = IsDir(u.layer, dir)
233
		if err != nil {
234
			return nil, err
235
		}
236
		if isaDir {
237
			return u.layer.OpenFile(name, flag, perm)
238
		}
239

240
		return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOTDIR} // ...or os.ErrNotExist?
241
	}
242
	if b {
243
		return u.base.OpenFile(name, flag, perm)
244
	}
245
	return u.layer.OpenFile(name, flag, perm)
246
}
247

248
// This function handles the 9 different possibilities caused
249
// by the union which are the intersection of the following...
250
//
251
//	layer: doesn't exist, exists as a file, and exists as a directory
252
//	base:  doesn't exist, exists as a file, and exists as a directory
253
func (u *CopyOnWriteFs) Open(name string) (File, error) {
254
	// Since the overlay overrides the base we check that first
255
	b, err := u.isBaseFile(name)
256
	if err != nil {
257
		return nil, err
258
	}
259

260
	// If overlay doesn't exist, return the base (base state irrelevant)
261
	if b {
262
		return u.base.Open(name)
263
	}
264

265
	// If overlay is a file, return it (base state irrelevant)
266
	dir, err := IsDir(u.layer, name)
267
	if err != nil {
268
		return nil, err
269
	}
270
	if !dir {
271
		return u.layer.Open(name)
272
	}
273

274
	// Overlay is a directory, base state now matters.
275
	// Base state has 3 states to check but 2 outcomes:
276
	// A. It's a file or non-readable in the base (return just the overlay)
277
	// B. It's an accessible directory in the base (return a UnionFile)
278

279
	// If base is file or nonreadable, return overlay
280
	dir, err = IsDir(u.base, name)
281
	if !dir || err != nil {
282
		return u.layer.Open(name)
283
	}
284

285
	// Both base & layer are directories
286
	// Return union file (if opens are without error)
287
	bfile, bErr := u.base.Open(name)
288
	lfile, lErr := u.layer.Open(name)
289

290
	// If either have errors at this point something is very wrong. Return nil and the errors
291
	if bErr != nil || lErr != nil {
292
		return nil, fmt.Errorf("BaseErr: %v\nOverlayErr: %v", bErr, lErr)
293
	}
294

295
	return &UnionFile{Base: bfile, Layer: lfile}, nil
296
}
297

298
func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error {
299
	dir, err := IsDir(u.base, name)
300
	if err != nil {
301
		return u.layer.MkdirAll(name, perm)
302
	}
303
	if dir {
304
		return ErrFileExists
305
	}
306
	return u.layer.MkdirAll(name, perm)
307
}
308

309
func (u *CopyOnWriteFs) Name() string {
310
	return "CopyOnWriteFs"
311
}
312

313
func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error {
314
	dir, err := IsDir(u.base, name)
315
	if err != nil {
316
		return u.layer.MkdirAll(name, perm)
317
	}
318
	if dir {
319
		// This is in line with how os.MkdirAll behaves.
320
		return nil
321
	}
322
	return u.layer.MkdirAll(name, perm)
323
}
324

325
func (u *CopyOnWriteFs) Create(name string) (File, error) {
326
	return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o666)
327
}
328

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

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

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

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