github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/registry/storage/driver/base/base.go (about) 1 // Package base provides a base implementation of the storage driver that can 2 // be used to implement common checks. The goal is to increase the amount of 3 // code sharing. 4 // 5 // The canonical approach to use this class is to embed in the exported driver 6 // struct such that calls are proxied through this implementation. First, 7 // declare the internal driver, as follows: 8 // 9 // type driver struct { ... internal ...} 10 // 11 // The resulting type should implement StorageDriver such that it can be the 12 // target of a Base struct. The exported type can then be declared as follows: 13 // 14 // type Driver struct { 15 // Base 16 // } 17 // 18 // Because Driver embeds Base, it effectively implements Base. If the driver 19 // needs to intercept a call, before going to base, Driver should implement 20 // that method. Effectively, Driver can intercept calls before coming in and 21 // driver implements the actual logic. 22 // 23 // To further shield the embed from other packages, it is recommended to 24 // employ a private embed struct: 25 // 26 // type baseEmbed struct { 27 // base.Base 28 // } 29 // 30 // Then, declare driver to embed baseEmbed, rather than Base directly: 31 // 32 // type Driver struct { 33 // baseEmbed 34 // } 35 // 36 // The type now implements StorageDriver, proxying through Base, without 37 // exporting an unnecessary field. 38 package base 39 40 import ( 41 "io" 42 43 "github.com/docker/distribution/context" 44 storagedriver "github.com/docker/distribution/registry/storage/driver" 45 ) 46 47 // Base provides a wrapper around a storagedriver implementation that provides 48 // common path and bounds checking. 49 type Base struct { 50 storagedriver.StorageDriver 51 } 52 53 // Format errors received from the storage driver 54 func (base *Base) setDriverName(e error) error { 55 switch actual := e.(type) { 56 case nil: 57 return nil 58 case storagedriver.ErrUnsupportedMethod: 59 actual.DriverName = base.StorageDriver.Name() 60 return actual 61 case storagedriver.PathNotFoundError: 62 actual.DriverName = base.StorageDriver.Name() 63 return actual 64 case storagedriver.InvalidPathError: 65 actual.DriverName = base.StorageDriver.Name() 66 return actual 67 case storagedriver.InvalidOffsetError: 68 actual.DriverName = base.StorageDriver.Name() 69 return actual 70 default: 71 storageError := storagedriver.Error{ 72 DriverName: base.StorageDriver.Name(), 73 Enclosed: e, 74 } 75 76 return storageError 77 } 78 } 79 80 // GetContent wraps GetContent of underlying storage driver. 81 func (base *Base) GetContent(ctx context.Context, path string) ([]byte, error) { 82 ctx, done := context.WithTrace(ctx) 83 defer done("%s.GetContent(%q)", base.Name(), path) 84 85 if !storagedriver.PathRegexp.MatchString(path) { 86 return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()} 87 } 88 89 b, e := base.StorageDriver.GetContent(ctx, path) 90 return b, base.setDriverName(e) 91 } 92 93 // PutContent wraps PutContent of underlying storage driver. 94 func (base *Base) PutContent(ctx context.Context, path string, content []byte) error { 95 ctx, done := context.WithTrace(ctx) 96 defer done("%s.PutContent(%q)", base.Name(), path) 97 98 if !storagedriver.PathRegexp.MatchString(path) { 99 return storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()} 100 } 101 102 return base.setDriverName(base.StorageDriver.PutContent(ctx, path, content)) 103 } 104 105 // ReadStream wraps ReadStream of underlying storage driver. 106 func (base *Base) ReadStream(ctx context.Context, path string, offset int64) (io.ReadCloser, error) { 107 ctx, done := context.WithTrace(ctx) 108 defer done("%s.ReadStream(%q, %d)", base.Name(), path, offset) 109 110 if offset < 0 { 111 return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset, DriverName: base.StorageDriver.Name()} 112 } 113 114 if !storagedriver.PathRegexp.MatchString(path) { 115 return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()} 116 } 117 118 rc, e := base.StorageDriver.ReadStream(ctx, path, offset) 119 return rc, base.setDriverName(e) 120 } 121 122 // WriteStream wraps WriteStream of underlying storage driver. 123 func (base *Base) WriteStream(ctx context.Context, path string, offset int64, reader io.Reader) (nn int64, err error) { 124 ctx, done := context.WithTrace(ctx) 125 defer done("%s.WriteStream(%q, %d)", base.Name(), path, offset) 126 127 if offset < 0 { 128 return 0, storagedriver.InvalidOffsetError{Path: path, Offset: offset, DriverName: base.StorageDriver.Name()} 129 } 130 131 if !storagedriver.PathRegexp.MatchString(path) { 132 return 0, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()} 133 } 134 135 i64, e := base.StorageDriver.WriteStream(ctx, path, offset, reader) 136 return i64, base.setDriverName(e) 137 } 138 139 // Stat wraps Stat of underlying storage driver. 140 func (base *Base) Stat(ctx context.Context, path string) (storagedriver.FileInfo, error) { 141 ctx, done := context.WithTrace(ctx) 142 defer done("%s.Stat(%q)", base.Name(), path) 143 144 if !storagedriver.PathRegexp.MatchString(path) { 145 return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()} 146 } 147 148 fi, e := base.StorageDriver.Stat(ctx, path) 149 return fi, base.setDriverName(e) 150 } 151 152 // List wraps List of underlying storage driver. 153 func (base *Base) List(ctx context.Context, path string) ([]string, error) { 154 ctx, done := context.WithTrace(ctx) 155 defer done("%s.List(%q)", base.Name(), path) 156 157 if !storagedriver.PathRegexp.MatchString(path) && path != "/" { 158 return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()} 159 } 160 161 str, e := base.StorageDriver.List(ctx, path) 162 return str, base.setDriverName(e) 163 } 164 165 // Move wraps Move of underlying storage driver. 166 func (base *Base) Move(ctx context.Context, sourcePath string, destPath string) error { 167 ctx, done := context.WithTrace(ctx) 168 defer done("%s.Move(%q, %q", base.Name(), sourcePath, destPath) 169 170 if !storagedriver.PathRegexp.MatchString(sourcePath) { 171 return storagedriver.InvalidPathError{Path: sourcePath, DriverName: base.StorageDriver.Name()} 172 } else if !storagedriver.PathRegexp.MatchString(destPath) { 173 return storagedriver.InvalidPathError{Path: destPath, DriverName: base.StorageDriver.Name()} 174 } 175 176 return base.setDriverName(base.StorageDriver.Move(ctx, sourcePath, destPath)) 177 } 178 179 // Delete wraps Delete of underlying storage driver. 180 func (base *Base) Delete(ctx context.Context, path string) error { 181 ctx, done := context.WithTrace(ctx) 182 defer done("%s.Delete(%q)", base.Name(), path) 183 184 if !storagedriver.PathRegexp.MatchString(path) { 185 return storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()} 186 } 187 188 return base.setDriverName(base.StorageDriver.Delete(ctx, path)) 189 } 190 191 // URLFor wraps URLFor of underlying storage driver. 192 func (base *Base) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) { 193 ctx, done := context.WithTrace(ctx) 194 defer done("%s.URLFor(%q)", base.Name(), path) 195 196 if !storagedriver.PathRegexp.MatchString(path) { 197 return "", storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()} 198 } 199 200 str, e := base.StorageDriver.URLFor(ctx, path, options) 201 return str, base.setDriverName(e) 202 }