1 package inmemory
2
3 import (
4 "context"
5 "fmt"
6 "io"
7 "io/ioutil"
8 "sync"
9 "time"
10
11 storagedriver "github.com/docker/distribution/registry/storage/driver"
12 "github.com/docker/distribution/registry/storage/driver/base"
13 "github.com/docker/distribution/registry/storage/driver/factory"
14 )
15
16 const driverName = "inmemory"
17
18 func init() {
19 factory.Register(driverName, &inMemoryDriverFactory{})
20 }
21
22
23 type inMemoryDriverFactory struct{}
24
25 func (factory *inMemoryDriverFactory) Create(parameters map[string]interface{}) (storagedriver.StorageDriver, error) {
26 return New(), nil
27 }
28
29 type driver struct {
30 root *dir
31 mutex sync.RWMutex
32 }
33
34
35 type baseEmbed struct {
36 base.Base
37 }
38
39
40
41 type Driver struct {
42 baseEmbed
43 }
44
45 var _ storagedriver.StorageDriver = &Driver{}
46
47
48 func New() *Driver {
49 return &Driver{
50 baseEmbed: baseEmbed{
51 Base: base.Base{
52 StorageDriver: &driver{
53 root: &dir{
54 common: common{
55 p: "/",
56 mod: time.Now(),
57 },
58 },
59 },
60 },
61 },
62 }
63 }
64
65
66
67 func (d *driver) Name() string {
68 return driverName
69 }
70
71
72 func (d *driver) GetContent(ctx context.Context, path string) ([]byte, error) {
73 d.mutex.RLock()
74 defer d.mutex.RUnlock()
75
76 rc, err := d.reader(ctx, path, 0)
77 if err != nil {
78 return nil, err
79 }
80 defer rc.Close()
81
82 return ioutil.ReadAll(rc)
83 }
84
85
86 func (d *driver) PutContent(ctx context.Context, p string, contents []byte) error {
87 d.mutex.Lock()
88 defer d.mutex.Unlock()
89
90 normalized := normalize(p)
91
92 f, err := d.root.mkfile(normalized)
93 if err != nil {
94
95
96 return fmt.Errorf("not a file")
97 }
98
99 f.truncate()
100 f.WriteAt(contents, 0)
101
102 return nil
103 }
104
105
106
107 func (d *driver) Reader(ctx context.Context, path string, offset int64) (io.ReadCloser, error) {
108 d.mutex.RLock()
109 defer d.mutex.RUnlock()
110
111 return d.reader(ctx, path, offset)
112 }
113
114 func (d *driver) reader(ctx context.Context, path string, offset int64) (io.ReadCloser, error) {
115 if offset < 0 {
116 return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
117 }
118
119 normalized := normalize(path)
120 found := d.root.find(normalized)
121
122 if found.path() != normalized {
123 return nil, storagedriver.PathNotFoundError{Path: path}
124 }
125
126 if found.isdir() {
127 return nil, fmt.Errorf("%q is a directory", path)
128 }
129
130 return ioutil.NopCloser(found.(*file).sectionReader(offset)), nil
131 }
132
133
134
135 func (d *driver) Writer(ctx context.Context, path string, append bool) (storagedriver.FileWriter, error) {
136 d.mutex.Lock()
137 defer d.mutex.Unlock()
138
139 normalized := normalize(path)
140
141 f, err := d.root.mkfile(normalized)
142 if err != nil {
143 return nil, fmt.Errorf("not a file")
144 }
145
146 if !append {
147 f.truncate()
148 }
149
150 return d.newWriter(f), nil
151 }
152
153
154 func (d *driver) Stat(ctx context.Context, path string) (storagedriver.FileInfo, error) {
155 d.mutex.RLock()
156 defer d.mutex.RUnlock()
157
158 normalized := normalize(path)
159 found := d.root.find(normalized)
160
161 if found.path() != normalized {
162 return nil, storagedriver.PathNotFoundError{Path: path}
163 }
164
165 fi := storagedriver.FileInfoFields{
166 Path: path,
167 IsDir: found.isdir(),
168 ModTime: found.modtime(),
169 }
170
171 if !fi.IsDir {
172 fi.Size = int64(len(found.(*file).data))
173 }
174
175 return storagedriver.FileInfoInternal{FileInfoFields: fi}, nil
176 }
177
178
179
180 func (d *driver) List(ctx context.Context, path string) ([]string, error) {
181 d.mutex.RLock()
182 defer d.mutex.RUnlock()
183
184 normalized := normalize(path)
185
186 found := d.root.find(normalized)
187
188 if !found.isdir() {
189 return nil, fmt.Errorf("not a directory")
190 }
191
192 entries, err := found.(*dir).list(normalized)
193
194 if err != nil {
195 switch err {
196 case errNotExists:
197 return nil, storagedriver.PathNotFoundError{Path: path}
198 case errIsNotDir:
199 return nil, fmt.Errorf("not a directory")
200 default:
201 return nil, err
202 }
203 }
204
205 return entries, nil
206 }
207
208
209
210 func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
211 d.mutex.Lock()
212 defer d.mutex.Unlock()
213
214 normalizedSrc, normalizedDst := normalize(sourcePath), normalize(destPath)
215
216 err := d.root.move(normalizedSrc, normalizedDst)
217 switch err {
218 case errNotExists:
219 return storagedriver.PathNotFoundError{Path: destPath}
220 default:
221 return err
222 }
223 }
224
225
226 func (d *driver) Delete(ctx context.Context, path string) error {
227 d.mutex.Lock()
228 defer d.mutex.Unlock()
229
230 normalized := normalize(path)
231
232 err := d.root.delete(normalized)
233 switch err {
234 case errNotExists:
235 return storagedriver.PathNotFoundError{Path: path}
236 default:
237 return err
238 }
239 }
240
241
242
243 func (d *driver) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) {
244 return "", storagedriver.ErrUnsupportedMethod{}
245 }
246
247
248
249 func (d *driver) Walk(ctx context.Context, path string, f storagedriver.WalkFn) error {
250 return storagedriver.WalkFallback(ctx, d, path, f)
251 }
252
253 type writer struct {
254 d *driver
255 f *file
256 closed bool
257 committed bool
258 cancelled bool
259 }
260
261 func (d *driver) newWriter(f *file) storagedriver.FileWriter {
262 return &writer{
263 d: d,
264 f: f,
265 }
266 }
267
268 func (w *writer) Write(p []byte) (int, error) {
269 if w.closed {
270 return 0, fmt.Errorf("already closed")
271 } else if w.committed {
272 return 0, fmt.Errorf("already committed")
273 } else if w.cancelled {
274 return 0, fmt.Errorf("already cancelled")
275 }
276
277 w.d.mutex.Lock()
278 defer w.d.mutex.Unlock()
279
280 return w.f.WriteAt(p, int64(len(w.f.data)))
281 }
282
283 func (w *writer) Size() int64 {
284 w.d.mutex.RLock()
285 defer w.d.mutex.RUnlock()
286
287 return int64(len(w.f.data))
288 }
289
290 func (w *writer) Close() error {
291 if w.closed {
292 return fmt.Errorf("already closed")
293 }
294 w.closed = true
295 return nil
296 }
297
298 func (w *writer) Cancel() error {
299 if w.closed {
300 return fmt.Errorf("already closed")
301 } else if w.committed {
302 return fmt.Errorf("already committed")
303 }
304 w.cancelled = true
305
306 w.d.mutex.Lock()
307 defer w.d.mutex.Unlock()
308
309 return w.d.root.delete(w.f.path())
310 }
311
312 func (w *writer) Commit() error {
313 if w.closed {
314 return fmt.Errorf("already closed")
315 } else if w.committed {
316 return fmt.Errorf("already committed")
317 } else if w.cancelled {
318 return fmt.Errorf("already cancelled")
319 }
320 w.committed = true
321 return nil
322 }
323
View as plain text