Move shared checks to base storage driver
This changeset moves common checks from driver implementations into base package. The Base type can be embedded in a driver implementation, ensuring that incoming arguments are checked for validity. Signed-off-by: Stephen J Day <stephen.day@docker.com>master
							parent
							
								
									624fb9b565
								
							
						
					
					
						commit
						f265a29f24
					
				| 
						 | 
					@ -0,0 +1,141 @@
 | 
				
			||||||
 | 
					// Package base provides a base implementation of the storage driver that can
 | 
				
			||||||
 | 
					// be used to implement common checks. The goal is to increase the amount of
 | 
				
			||||||
 | 
					// code sharing.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The canonical approach to use this class is to embed in the exported driver
 | 
				
			||||||
 | 
					// struct such that calls are proxied through this implementation. First,
 | 
				
			||||||
 | 
					// declare the internal driver, as follows:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// 	type driver struct { ... internal ...}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The resulting type should implement StorageDriver such that it can be the
 | 
				
			||||||
 | 
					// target of a Base struct. The exported type can then be declared as follows:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// 	type Driver struct {
 | 
				
			||||||
 | 
					// 		Base
 | 
				
			||||||
 | 
					// 	}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Because Driver embeds Base, it effectively implements Base. If the driver
 | 
				
			||||||
 | 
					// needs to intercept a call, before going to base, Driver should implement
 | 
				
			||||||
 | 
					// that method. Effectively, Driver can intercept calls before coming in and
 | 
				
			||||||
 | 
					// driver implements the actual logic.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// To further shield the embed from other packages, it is recommended to
 | 
				
			||||||
 | 
					// employ a private embed struct:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// 	type baseEmbed struct {
 | 
				
			||||||
 | 
					// 		base.Base
 | 
				
			||||||
 | 
					// 	}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Then, declare driver to embed baseEmbed, rather than Base directly:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// 	type Driver struct {
 | 
				
			||||||
 | 
					// 		baseEmbed
 | 
				
			||||||
 | 
					// 	}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The type now implements StorageDriver, proxying through Base, without
 | 
				
			||||||
 | 
					// exporting an unnessecary field.
 | 
				
			||||||
 | 
					package base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/docker/distribution/storagedriver"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Base provides a wrapper around a storagedriver implementation that provides
 | 
				
			||||||
 | 
					// common path and bounds checking.
 | 
				
			||||||
 | 
					type Base struct {
 | 
				
			||||||
 | 
						storagedriver.StorageDriver
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetContent wraps GetContent of underlying storage driver.
 | 
				
			||||||
 | 
					func (base *Base) GetContent(path string) ([]byte, error) {
 | 
				
			||||||
 | 
						if !storagedriver.PathRegexp.MatchString(path) {
 | 
				
			||||||
 | 
							return nil, storagedriver.InvalidPathError{Path: path}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return base.StorageDriver.GetContent(path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PutContent wraps PutContent of underlying storage driver.
 | 
				
			||||||
 | 
					func (base *Base) PutContent(path string, content []byte) error {
 | 
				
			||||||
 | 
						if !storagedriver.PathRegexp.MatchString(path) {
 | 
				
			||||||
 | 
							return storagedriver.InvalidPathError{Path: path}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return base.StorageDriver.PutContent(path, content)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReadStream wraps ReadStream of underlying storage driver.
 | 
				
			||||||
 | 
					func (base *Base) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
				
			||||||
 | 
						if offset < 0 {
 | 
				
			||||||
 | 
							return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !storagedriver.PathRegexp.MatchString(path) {
 | 
				
			||||||
 | 
							return nil, storagedriver.InvalidPathError{Path: path}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return base.StorageDriver.ReadStream(path, offset)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WriteStream wraps WriteStream of underlying storage driver.
 | 
				
			||||||
 | 
					func (base *Base) WriteStream(path string, offset int64, reader io.Reader) (nn int64, err error) {
 | 
				
			||||||
 | 
						if offset < 0 {
 | 
				
			||||||
 | 
							return 0, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !storagedriver.PathRegexp.MatchString(path) {
 | 
				
			||||||
 | 
							return 0, storagedriver.InvalidPathError{Path: path}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return base.StorageDriver.WriteStream(path, offset, reader)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Stat wraps Stat of underlying storage driver.
 | 
				
			||||||
 | 
					func (base *Base) Stat(path string) (storagedriver.FileInfo, error) {
 | 
				
			||||||
 | 
						if !storagedriver.PathRegexp.MatchString(path) {
 | 
				
			||||||
 | 
							return nil, storagedriver.InvalidPathError{Path: path}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return base.StorageDriver.Stat(path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// List wraps List of underlying storage driver.
 | 
				
			||||||
 | 
					func (base *Base) List(path string) ([]string, error) {
 | 
				
			||||||
 | 
						if !storagedriver.PathRegexp.MatchString(path) && path != "/" {
 | 
				
			||||||
 | 
							return nil, storagedriver.InvalidPathError{Path: path}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return base.StorageDriver.List(path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Move wraps Move of underlying storage driver.
 | 
				
			||||||
 | 
					func (base *Base) Move(sourcePath string, destPath string) error {
 | 
				
			||||||
 | 
						if !storagedriver.PathRegexp.MatchString(sourcePath) {
 | 
				
			||||||
 | 
							return storagedriver.InvalidPathError{Path: sourcePath}
 | 
				
			||||||
 | 
						} else if !storagedriver.PathRegexp.MatchString(destPath) {
 | 
				
			||||||
 | 
							return storagedriver.InvalidPathError{Path: destPath}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return base.StorageDriver.Move(sourcePath, destPath)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Delete wraps Delete of underlying storage driver.
 | 
				
			||||||
 | 
					func (base *Base) Delete(path string) error {
 | 
				
			||||||
 | 
						if !storagedriver.PathRegexp.MatchString(path) {
 | 
				
			||||||
 | 
							return storagedriver.InvalidPathError{Path: path}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return base.StorageDriver.Delete(path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// URLFor wraps URLFor of underlying storage driver.
 | 
				
			||||||
 | 
					func (base *Base) URLFor(path string, options map[string]interface{}) (string, error) {
 | 
				
			||||||
 | 
						if !storagedriver.PathRegexp.MatchString(path) {
 | 
				
			||||||
 | 
							return "", storagedriver.InvalidPathError{Path: path}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return base.StorageDriver.URLFor(path, options)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ import (
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/distribution/storagedriver"
 | 
						"github.com/docker/distribution/storagedriver"
 | 
				
			||||||
 | 
						"github.com/docker/distribution/storagedriver/base"
 | 
				
			||||||
	"github.com/docker/distribution/storagedriver/factory"
 | 
						"github.com/docker/distribution/storagedriver/factory"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,12 +28,20 @@ func (factory *filesystemDriverFactory) Create(parameters map[string]interface{}
 | 
				
			||||||
	return FromParameters(parameters), nil
 | 
						return FromParameters(parameters), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Driver is a storagedriver.StorageDriver implementation backed by a local
 | 
					type driver struct {
 | 
				
			||||||
// filesystem. All provided paths will be subpaths of the RootDirectory
 | 
					 | 
				
			||||||
type Driver struct {
 | 
					 | 
				
			||||||
	rootDirectory string
 | 
						rootDirectory string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type baseEmbed struct {
 | 
				
			||||||
 | 
						base.Base
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Driver is a storagedriver.StorageDriver implementation backed by a local
 | 
				
			||||||
 | 
					// filesystem. All provided paths will be subpaths of the RootDirectory.
 | 
				
			||||||
 | 
					type Driver struct {
 | 
				
			||||||
 | 
						baseEmbed
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FromParameters constructs a new Driver with a given parameters map
 | 
					// FromParameters constructs a new Driver with a given parameters map
 | 
				
			||||||
// Optional Parameters:
 | 
					// Optional Parameters:
 | 
				
			||||||
// - rootdirectory
 | 
					// - rootdirectory
 | 
				
			||||||
| 
						 | 
					@ -49,17 +58,21 @@ func FromParameters(parameters map[string]interface{}) *Driver {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// New constructs a new Driver with a given rootDirectory
 | 
					// New constructs a new Driver with a given rootDirectory
 | 
				
			||||||
func New(rootDirectory string) *Driver {
 | 
					func New(rootDirectory string) *Driver {
 | 
				
			||||||
	return &Driver{rootDirectory}
 | 
						return &Driver{
 | 
				
			||||||
 | 
							baseEmbed: baseEmbed{
 | 
				
			||||||
 | 
								Base: base.Base{
 | 
				
			||||||
 | 
									StorageDriver: &driver{
 | 
				
			||||||
 | 
										rootDirectory: rootDirectory,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Implement the storagedriver.StorageDriver interface
 | 
					// Implement the storagedriver.StorageDriver interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetContent retrieves the content stored at "path" as a []byte.
 | 
					// GetContent retrieves the content stored at "path" as a []byte.
 | 
				
			||||||
func (d *Driver) GetContent(path string) ([]byte, error) {
 | 
					func (d *driver) GetContent(path string) ([]byte, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc, err := d.ReadStream(path, 0)
 | 
						rc, err := d.ReadStream(path, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
| 
						 | 
					@ -75,11 +88,7 @@ func (d *Driver) GetContent(path string) ([]byte, error) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PutContent stores the []byte content at a location designated by "path".
 | 
					// PutContent stores the []byte content at a location designated by "path".
 | 
				
			||||||
func (d *Driver) PutContent(subPath string, contents []byte) error {
 | 
					func (d *driver) PutContent(subPath string, contents []byte) error {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(subPath) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: subPath}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if _, err := d.WriteStream(subPath, 0, bytes.NewReader(contents)); err != nil {
 | 
						if _, err := d.WriteStream(subPath, 0, bytes.NewReader(contents)); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -89,15 +98,7 @@ func (d *Driver) PutContent(subPath string, contents []byte) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
 | 
					// ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
 | 
				
			||||||
// given byte offset.
 | 
					// given byte offset.
 | 
				
			||||||
func (d *Driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
					func (d *driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if offset < 0 {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	file, err := os.OpenFile(d.fullPath(path), os.O_RDONLY, 0644)
 | 
						file, err := os.OpenFile(d.fullPath(path), os.O_RDONLY, 0644)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
| 
						 | 
					@ -121,15 +122,7 @@ func (d *Driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// WriteStream stores the contents of the provided io.Reader at a location
 | 
					// WriteStream stores the contents of the provided io.Reader at a location
 | 
				
			||||||
// designated by the given path.
 | 
					// designated by the given path.
 | 
				
			||||||
func (d *Driver) WriteStream(subPath string, offset int64, reader io.Reader) (nn int64, err error) {
 | 
					func (d *driver) WriteStream(subPath string, offset int64, reader io.Reader) (nn int64, err error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(subPath) {
 | 
					 | 
				
			||||||
		return 0, storagedriver.InvalidPathError{Path: subPath}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if offset < 0 {
 | 
					 | 
				
			||||||
		return 0, storagedriver.InvalidOffsetError{Path: subPath, Offset: offset}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// TODO(stevvooe): This needs to be a requirement.
 | 
						// TODO(stevvooe): This needs to be a requirement.
 | 
				
			||||||
	// if !path.IsAbs(subPath) {
 | 
						// if !path.IsAbs(subPath) {
 | 
				
			||||||
	// 	return fmt.Errorf("absolute path required: %q", subPath)
 | 
						// 	return fmt.Errorf("absolute path required: %q", subPath)
 | 
				
			||||||
| 
						 | 
					@ -165,11 +158,7 @@ func (d *Driver) WriteStream(subPath string, offset int64, reader io.Reader) (nn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Stat retrieves the FileInfo for the given path, including the current size
 | 
					// Stat retrieves the FileInfo for the given path, including the current size
 | 
				
			||||||
// in bytes and the creation time.
 | 
					// in bytes and the creation time.
 | 
				
			||||||
func (d *Driver) Stat(subPath string) (storagedriver.FileInfo, error) {
 | 
					func (d *driver) Stat(subPath string) (storagedriver.FileInfo, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(subPath) {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: subPath}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fullPath := d.fullPath(subPath)
 | 
						fullPath := d.fullPath(subPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fi, err := os.Stat(fullPath)
 | 
						fi, err := os.Stat(fullPath)
 | 
				
			||||||
| 
						 | 
					@ -189,11 +178,7 @@ func (d *Driver) Stat(subPath string) (storagedriver.FileInfo, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// List returns a list of the objects that are direct descendants of the given
 | 
					// List returns a list of the objects that are direct descendants of the given
 | 
				
			||||||
// path.
 | 
					// path.
 | 
				
			||||||
func (d *Driver) List(subPath string) ([]string, error) {
 | 
					func (d *driver) List(subPath string) ([]string, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(subPath) && subPath != "/" {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: subPath}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if subPath[len(subPath)-1] != '/' {
 | 
						if subPath[len(subPath)-1] != '/' {
 | 
				
			||||||
		subPath += "/"
 | 
							subPath += "/"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -224,13 +209,7 @@ func (d *Driver) List(subPath string) ([]string, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Move moves an object stored at sourcePath to destPath, removing the original
 | 
					// Move moves an object stored at sourcePath to destPath, removing the original
 | 
				
			||||||
// object.
 | 
					// object.
 | 
				
			||||||
func (d *Driver) Move(sourcePath string, destPath string) error {
 | 
					func (d *driver) Move(sourcePath string, destPath string) error {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(sourcePath) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: sourcePath}
 | 
					 | 
				
			||||||
	} else if !storagedriver.PathRegexp.MatchString(destPath) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: destPath}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	source := d.fullPath(sourcePath)
 | 
						source := d.fullPath(sourcePath)
 | 
				
			||||||
	dest := d.fullPath(destPath)
 | 
						dest := d.fullPath(destPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -247,11 +226,7 @@ func (d *Driver) Move(sourcePath string, destPath string) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Delete recursively deletes all objects stored at "path" and its subpaths.
 | 
					// Delete recursively deletes all objects stored at "path" and its subpaths.
 | 
				
			||||||
func (d *Driver) Delete(subPath string) error {
 | 
					func (d *driver) Delete(subPath string) error {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(subPath) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: subPath}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fullPath := d.fullPath(subPath)
 | 
						fullPath := d.fullPath(subPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := os.Stat(fullPath)
 | 
						_, err := os.Stat(fullPath)
 | 
				
			||||||
| 
						 | 
					@ -267,12 +242,12 @@ func (d *Driver) Delete(subPath string) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// URLFor returns a URL which may be used to retrieve the content stored at the given path.
 | 
					// URLFor returns a URL which may be used to retrieve the content stored at the given path.
 | 
				
			||||||
// May return an UnsupportedMethodErr in certain StorageDriver implementations.
 | 
					// May return an UnsupportedMethodErr in certain StorageDriver implementations.
 | 
				
			||||||
func (d *Driver) URLFor(path string, options map[string]interface{}) (string, error) {
 | 
					func (d *driver) URLFor(path string, options map[string]interface{}) (string, error) {
 | 
				
			||||||
	return "", storagedriver.ErrUnsupportedMethod
 | 
						return "", storagedriver.ErrUnsupportedMethod
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// fullPath returns the absolute path of a key within the Driver's storage.
 | 
					// fullPath returns the absolute path of a key within the Driver's storage.
 | 
				
			||||||
func (d *Driver) fullPath(subPath string) string {
 | 
					func (d *driver) fullPath(subPath string) string {
 | 
				
			||||||
	return path.Join(d.rootDirectory, subPath)
 | 
						return path.Join(d.rootDirectory, subPath)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ import (
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/distribution/storagedriver"
 | 
						"github.com/docker/distribution/storagedriver"
 | 
				
			||||||
 | 
						"github.com/docker/distribution/storagedriver/base"
 | 
				
			||||||
	"github.com/docker/distribution/storagedriver/factory"
 | 
						"github.com/docker/distribution/storagedriver/factory"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,31 +26,46 @@ func (factory *inMemoryDriverFactory) Create(parameters map[string]interface{})
 | 
				
			||||||
	return New(), nil
 | 
						return New(), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Driver is a storagedriver.StorageDriver implementation backed by a local map.
 | 
					type driver struct {
 | 
				
			||||||
// Intended solely for example and testing purposes.
 | 
					 | 
				
			||||||
type Driver struct {
 | 
					 | 
				
			||||||
	root  *dir
 | 
						root  *dir
 | 
				
			||||||
	mutex sync.RWMutex
 | 
						mutex sync.RWMutex
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// baseEmbed allows us to hide the Base embed.
 | 
				
			||||||
 | 
					type baseEmbed struct {
 | 
				
			||||||
 | 
						base.Base
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Driver is a storagedriver.StorageDriver implementation backed by a local map.
 | 
				
			||||||
 | 
					// Intended solely for example and testing purposes.
 | 
				
			||||||
 | 
					type Driver struct {
 | 
				
			||||||
 | 
						baseEmbed // embedded, hidden base driver.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ storagedriver.StorageDriver = &Driver{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// New constructs a new Driver.
 | 
					// New constructs a new Driver.
 | 
				
			||||||
func New() *Driver {
 | 
					func New() *Driver {
 | 
				
			||||||
	return &Driver{root: &dir{
 | 
						return &Driver{
 | 
				
			||||||
		common: common{
 | 
							baseEmbed: baseEmbed{
 | 
				
			||||||
			p:   "/",
 | 
								Base: base.Base{
 | 
				
			||||||
			mod: time.Now(),
 | 
									StorageDriver: &driver{
 | 
				
			||||||
 | 
										root: &dir{
 | 
				
			||||||
 | 
											common: common{
 | 
				
			||||||
 | 
												p:   "/",
 | 
				
			||||||
 | 
												mod: time.Now(),
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Implement the storagedriver.StorageDriver interface.
 | 
					// Implement the storagedriver.StorageDriver interface.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetContent retrieves the content stored at "path" as a []byte.
 | 
					// GetContent retrieves the content stored at "path" as a []byte.
 | 
				
			||||||
func (d *Driver) GetContent(path string) ([]byte, error) {
 | 
					func (d *driver) GetContent(path string) ([]byte, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d.mutex.RLock()
 | 
						d.mutex.RLock()
 | 
				
			||||||
	defer d.mutex.RUnlock()
 | 
						defer d.mutex.RUnlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,11 +79,7 @@ func (d *Driver) GetContent(path string) ([]byte, error) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PutContent stores the []byte content at a location designated by "path".
 | 
					// PutContent stores the []byte content at a location designated by "path".
 | 
				
			||||||
func (d *Driver) PutContent(p string, contents []byte) error {
 | 
					func (d *driver) PutContent(p string, contents []byte) error {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(p) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: p}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d.mutex.Lock()
 | 
						d.mutex.Lock()
 | 
				
			||||||
	defer d.mutex.Unlock()
 | 
						defer d.mutex.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,11 +98,7 @@ func (d *Driver) PutContent(p string, contents []byte) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
 | 
					// ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
 | 
				
			||||||
// given byte offset.
 | 
					// given byte offset.
 | 
				
			||||||
func (d *Driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
					func (d *driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d.mutex.RLock()
 | 
						d.mutex.RLock()
 | 
				
			||||||
	defer d.mutex.RUnlock()
 | 
						defer d.mutex.RUnlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -114,11 +122,7 @@ func (d *Driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// WriteStream stores the contents of the provided io.ReadCloser at a location
 | 
					// WriteStream stores the contents of the provided io.ReadCloser at a location
 | 
				
			||||||
// designated by the given path.
 | 
					// designated by the given path.
 | 
				
			||||||
func (d *Driver) WriteStream(path string, offset int64, reader io.Reader) (nn int64, err error) {
 | 
					func (d *driver) WriteStream(path string, offset int64, reader io.Reader) (nn int64, err error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return 0, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d.mutex.Lock()
 | 
						d.mutex.Lock()
 | 
				
			||||||
	defer d.mutex.Unlock()
 | 
						defer d.mutex.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,11 +163,7 @@ func (d *Driver) WriteStream(path string, offset int64, reader io.Reader) (nn in
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Stat returns info about the provided path.
 | 
					// Stat returns info about the provided path.
 | 
				
			||||||
func (d *Driver) Stat(path string) (storagedriver.FileInfo, error) {
 | 
					func (d *driver) Stat(path string) (storagedriver.FileInfo, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d.mutex.RLock()
 | 
						d.mutex.RLock()
 | 
				
			||||||
	defer d.mutex.RUnlock()
 | 
						defer d.mutex.RUnlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -189,11 +189,7 @@ func (d *Driver) Stat(path string) (storagedriver.FileInfo, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// List returns a list of the objects that are direct descendants of the given
 | 
					// List returns a list of the objects that are direct descendants of the given
 | 
				
			||||||
// path.
 | 
					// path.
 | 
				
			||||||
func (d *Driver) List(path string) ([]string, error) {
 | 
					func (d *driver) List(path string) ([]string, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) && path != "/" {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d.mutex.RLock()
 | 
						d.mutex.RLock()
 | 
				
			||||||
	defer d.mutex.RUnlock()
 | 
						defer d.mutex.RUnlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,13 +219,7 @@ func (d *Driver) List(path string) ([]string, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Move moves an object stored at sourcePath to destPath, removing the original
 | 
					// Move moves an object stored at sourcePath to destPath, removing the original
 | 
				
			||||||
// object.
 | 
					// object.
 | 
				
			||||||
func (d *Driver) Move(sourcePath string, destPath string) error {
 | 
					func (d *driver) Move(sourcePath string, destPath string) error {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(sourcePath) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: sourcePath}
 | 
					 | 
				
			||||||
	} else if !storagedriver.PathRegexp.MatchString(destPath) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: destPath}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d.mutex.Lock()
 | 
						d.mutex.Lock()
 | 
				
			||||||
	defer d.mutex.Unlock()
 | 
						defer d.mutex.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,11 +235,7 @@ func (d *Driver) Move(sourcePath string, destPath string) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Delete recursively deletes all objects stored at "path" and its subpaths.
 | 
					// Delete recursively deletes all objects stored at "path" and its subpaths.
 | 
				
			||||||
func (d *Driver) Delete(path string) error {
 | 
					func (d *driver) Delete(path string) error {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d.mutex.Lock()
 | 
						d.mutex.Lock()
 | 
				
			||||||
	defer d.mutex.Unlock()
 | 
						defer d.mutex.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -266,6 +252,6 @@ func (d *Driver) Delete(path string) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// URLFor returns a URL which may be used to retrieve the content stored at the given path.
 | 
					// URLFor returns a URL which may be used to retrieve the content stored at the given path.
 | 
				
			||||||
// May return an UnsupportedMethodErr in certain StorageDriver implementations.
 | 
					// May return an UnsupportedMethodErr in certain StorageDriver implementations.
 | 
				
			||||||
func (d *Driver) URLFor(path string, options map[string]interface{}) (string, error) {
 | 
					func (d *driver) URLFor(path string, options map[string]interface{}) (string, error) {
 | 
				
			||||||
	return "", storagedriver.ErrUnsupportedMethod
 | 
						return "", storagedriver.ErrUnsupportedMethod
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@ import (
 | 
				
			||||||
	"github.com/AdRoll/goamz/aws"
 | 
						"github.com/AdRoll/goamz/aws"
 | 
				
			||||||
	"github.com/AdRoll/goamz/s3"
 | 
						"github.com/AdRoll/goamz/s3"
 | 
				
			||||||
	"github.com/docker/distribution/storagedriver"
 | 
						"github.com/docker/distribution/storagedriver"
 | 
				
			||||||
 | 
						"github.com/docker/distribution/storagedriver/base"
 | 
				
			||||||
	"github.com/docker/distribution/storagedriver/factory"
 | 
						"github.com/docker/distribution/storagedriver/factory"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,9 +66,7 @@ func (factory *s3DriverFactory) Create(parameters map[string]interface{}) (stora
 | 
				
			||||||
	return FromParameters(parameters)
 | 
						return FromParameters(parameters)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Driver is a storagedriver.StorageDriver implementation backed by Amazon S3
 | 
					type driver struct {
 | 
				
			||||||
// Objects are stored at absolute keys in the provided bucket
 | 
					 | 
				
			||||||
type Driver struct {
 | 
					 | 
				
			||||||
	S3            *s3.S3
 | 
						S3            *s3.S3
 | 
				
			||||||
	Bucket        *s3.Bucket
 | 
						Bucket        *s3.Bucket
 | 
				
			||||||
	ChunkSize     int64
 | 
						ChunkSize     int64
 | 
				
			||||||
| 
						 | 
					@ -75,6 +74,16 @@ type Driver struct {
 | 
				
			||||||
	RootDirectory string
 | 
						RootDirectory string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type baseEmbed struct {
 | 
				
			||||||
 | 
						base.Base
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Driver is a storagedriver.StorageDriver implementation backed by Amazon S3
 | 
				
			||||||
 | 
					// Objects are stored at absolute keys in the provided bucket.
 | 
				
			||||||
 | 
					type Driver struct {
 | 
				
			||||||
 | 
						baseEmbed
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FromParameters constructs a new Driver with a given parameters map
 | 
					// FromParameters constructs a new Driver with a given parameters map
 | 
				
			||||||
// Required parameters:
 | 
					// Required parameters:
 | 
				
			||||||
// - accesskey
 | 
					// - accesskey
 | 
				
			||||||
| 
						 | 
					@ -209,22 +218,27 @@ func New(params DriverParameters) (*Driver, error) {
 | 
				
			||||||
	// 	}
 | 
						// 	}
 | 
				
			||||||
	// }
 | 
						// }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &Driver{
 | 
						d := &driver{
 | 
				
			||||||
		S3:            s3obj,
 | 
							S3:            s3obj,
 | 
				
			||||||
		Bucket:        bucket,
 | 
							Bucket:        bucket,
 | 
				
			||||||
		ChunkSize:     params.ChunkSize,
 | 
							ChunkSize:     params.ChunkSize,
 | 
				
			||||||
		Encrypt:       params.Encrypt,
 | 
							Encrypt:       params.Encrypt,
 | 
				
			||||||
		RootDirectory: params.RootDirectory}, nil
 | 
							RootDirectory: params.RootDirectory,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &Driver{
 | 
				
			||||||
 | 
							baseEmbed: baseEmbed{
 | 
				
			||||||
 | 
								Base: base.Base{
 | 
				
			||||||
 | 
									StorageDriver: d,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Implement the storagedriver.StorageDriver interface
 | 
					// Implement the storagedriver.StorageDriver interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetContent retrieves the content stored at "path" as a []byte.
 | 
					// GetContent retrieves the content stored at "path" as a []byte.
 | 
				
			||||||
func (d *Driver) GetContent(path string) ([]byte, error) {
 | 
					func (d *driver) GetContent(path string) ([]byte, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	content, err := d.Bucket.Get(d.s3Path(path))
 | 
						content, err := d.Bucket.Get(d.s3Path(path))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, parseError(path, err)
 | 
							return nil, parseError(path, err)
 | 
				
			||||||
| 
						 | 
					@ -233,25 +247,13 @@ func (d *Driver) GetContent(path string) ([]byte, error) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PutContent stores the []byte content at a location designated by "path".
 | 
					// PutContent stores the []byte content at a location designated by "path".
 | 
				
			||||||
func (d *Driver) PutContent(path string, contents []byte) error {
 | 
					func (d *driver) PutContent(path string, contents []byte) error {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return parseError(path, d.Bucket.Put(d.s3Path(path), contents, d.getContentType(), getPermissions(), d.getOptions()))
 | 
						return parseError(path, d.Bucket.Put(d.s3Path(path), contents, d.getContentType(), getPermissions(), d.getOptions()))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
 | 
					// ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
 | 
				
			||||||
// given byte offset.
 | 
					// given byte offset.
 | 
				
			||||||
func (d *Driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
					func (d *driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if offset < 0 {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	headers := make(http.Header)
 | 
						headers := make(http.Header)
 | 
				
			||||||
	headers.Add("Range", "bytes="+strconv.FormatInt(offset, 10)+"-")
 | 
						headers.Add("Range", "bytes="+strconv.FormatInt(offset, 10)+"-")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -273,15 +275,7 @@ func (d *Driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
 | 
				
			||||||
// returned. May be used to resume writing a stream by providing a nonzero
 | 
					// returned. May be used to resume writing a stream by providing a nonzero
 | 
				
			||||||
// offset. Offsets past the current size will write from the position
 | 
					// offset. Offsets past the current size will write from the position
 | 
				
			||||||
// beyond the end of the file.
 | 
					// beyond the end of the file.
 | 
				
			||||||
func (d *Driver) WriteStream(path string, offset int64, reader io.Reader) (totalRead int64, err error) {
 | 
					func (d *driver) WriteStream(path string, offset int64, reader io.Reader) (totalRead int64, err error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return 0, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if offset < 0 {
 | 
					 | 
				
			||||||
		return 0, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	partNumber := 1
 | 
						partNumber := 1
 | 
				
			||||||
	bytesRead := 0
 | 
						bytesRead := 0
 | 
				
			||||||
	var putErrChan chan error
 | 
						var putErrChan chan error
 | 
				
			||||||
| 
						 | 
					@ -556,11 +550,7 @@ func (d *Driver) WriteStream(path string, offset int64, reader io.Reader) (total
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Stat retrieves the FileInfo for the given path, including the current size
 | 
					// Stat retrieves the FileInfo for the given path, including the current size
 | 
				
			||||||
// in bytes and the creation time.
 | 
					// in bytes and the creation time.
 | 
				
			||||||
func (d *Driver) Stat(path string) (storagedriver.FileInfo, error) {
 | 
					func (d *driver) Stat(path string) (storagedriver.FileInfo, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	listResponse, err := d.Bucket.List(d.s3Path(path), "", "", 1)
 | 
						listResponse, err := d.Bucket.List(d.s3Path(path), "", "", 1)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
| 
						 | 
					@ -593,11 +583,7 @@ func (d *Driver) Stat(path string) (storagedriver.FileInfo, error) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// List returns a list of the objects that are direct descendants of the given path.
 | 
					// List returns a list of the objects that are direct descendants of the given path.
 | 
				
			||||||
func (d *Driver) List(path string) ([]string, error) {
 | 
					func (d *driver) List(path string) ([]string, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) && path != "/" {
 | 
					 | 
				
			||||||
		return nil, storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if path != "/" && path[len(path)-1] != '/' {
 | 
						if path != "/" && path[len(path)-1] != '/' {
 | 
				
			||||||
		path = path + "/"
 | 
							path = path + "/"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -633,13 +619,7 @@ func (d *Driver) List(path string) ([]string, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Move moves an object stored at sourcePath to destPath, removing the original
 | 
					// Move moves an object stored at sourcePath to destPath, removing the original
 | 
				
			||||||
// object.
 | 
					// object.
 | 
				
			||||||
func (d *Driver) Move(sourcePath string, destPath string) error {
 | 
					func (d *driver) Move(sourcePath string, destPath string) error {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(sourcePath) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: sourcePath}
 | 
					 | 
				
			||||||
	} else if !storagedriver.PathRegexp.MatchString(destPath) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: destPath}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* This is terrible, but aws doesn't have an actual move. */
 | 
						/* This is terrible, but aws doesn't have an actual move. */
 | 
				
			||||||
	_, err := d.Bucket.PutCopy(d.s3Path(destPath), getPermissions(),
 | 
						_, err := d.Bucket.PutCopy(d.s3Path(destPath), getPermissions(),
 | 
				
			||||||
		s3.CopyOptions{Options: d.getOptions(), ContentType: d.getContentType()}, d.Bucket.Name+"/"+d.s3Path(sourcePath))
 | 
							s3.CopyOptions{Options: d.getOptions(), ContentType: d.getContentType()}, d.Bucket.Name+"/"+d.s3Path(sourcePath))
 | 
				
			||||||
| 
						 | 
					@ -651,11 +631,7 @@ func (d *Driver) Move(sourcePath string, destPath string) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Delete recursively deletes all objects stored at "path" and its subpaths.
 | 
					// Delete recursively deletes all objects stored at "path" and its subpaths.
 | 
				
			||||||
func (d *Driver) Delete(path string) error {
 | 
					func (d *driver) Delete(path string) error {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	listResponse, err := d.Bucket.List(d.s3Path(path), "", "", listMax)
 | 
						listResponse, err := d.Bucket.List(d.s3Path(path), "", "", listMax)
 | 
				
			||||||
	if err != nil || len(listResponse.Contents) == 0 {
 | 
						if err != nil || len(listResponse.Contents) == 0 {
 | 
				
			||||||
		return storagedriver.PathNotFoundError{Path: path}
 | 
							return storagedriver.PathNotFoundError{Path: path}
 | 
				
			||||||
| 
						 | 
					@ -684,11 +660,7 @@ func (d *Driver) Delete(path string) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// URLFor returns a URL which may be used to retrieve the content stored at the given path.
 | 
					// URLFor returns a URL which may be used to retrieve the content stored at the given path.
 | 
				
			||||||
// May return an UnsupportedMethodErr in certain StorageDriver implementations.
 | 
					// May return an UnsupportedMethodErr in certain StorageDriver implementations.
 | 
				
			||||||
func (d *Driver) URLFor(path string, options map[string]interface{}) (string, error) {
 | 
					func (d *driver) URLFor(path string, options map[string]interface{}) (string, error) {
 | 
				
			||||||
	if !storagedriver.PathRegexp.MatchString(path) {
 | 
					 | 
				
			||||||
		return "", storagedriver.InvalidPathError{Path: path}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	methodString := "GET"
 | 
						methodString := "GET"
 | 
				
			||||||
	method, ok := options["method"]
 | 
						method, ok := options["method"]
 | 
				
			||||||
	if ok {
 | 
						if ok {
 | 
				
			||||||
| 
						 | 
					@ -710,7 +682,7 @@ func (d *Driver) URLFor(path string, options map[string]interface{}) (string, er
 | 
				
			||||||
	return d.Bucket.SignedURLWithMethod(methodString, d.s3Path(path), expiresTime, nil, nil), nil
 | 
						return d.Bucket.SignedURLWithMethod(methodString, d.s3Path(path), expiresTime, nil, nil), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Driver) s3Path(path string) string {
 | 
					func (d *driver) s3Path(path string) string {
 | 
				
			||||||
	return strings.TrimLeft(strings.TrimRight(d.RootDirectory, "/")+path, "/")
 | 
						return strings.TrimLeft(strings.TrimRight(d.RootDirectory, "/")+path, "/")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -727,7 +699,7 @@ func hasCode(err error, code string) bool {
 | 
				
			||||||
	return ok && s3err.Code == code
 | 
						return ok && s3err.Code == code
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Driver) getOptions() s3.Options {
 | 
					func (d *driver) getOptions() s3.Options {
 | 
				
			||||||
	return s3.Options{SSE: d.Encrypt}
 | 
						return s3.Options{SSE: d.Encrypt}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -735,6 +707,6 @@ func getPermissions() s3.ACL {
 | 
				
			||||||
	return s3.Private
 | 
						return s3.Private
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Driver) getContentType() string {
 | 
					func (d *driver) getContentType() string {
 | 
				
			||||||
	return "application/octet-stream"
 | 
						return "application/octet-stream"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue