github.com/lusis/distribution@v2.0.1+incompatible/registry/storage/driver/filesystem/driver.go (about)

     1  package filesystem
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"path"
    10  	"time"
    11  
    12  	storagedriver "github.com/docker/distribution/registry/storage/driver"
    13  	"github.com/docker/distribution/registry/storage/driver/base"
    14  	"github.com/docker/distribution/registry/storage/driver/factory"
    15  )
    16  
    17  const driverName = "filesystem"
    18  const defaultRootDirectory = "/tmp/registry/storage"
    19  
    20  func init() {
    21  	factory.Register(driverName, &filesystemDriverFactory{})
    22  }
    23  
    24  // filesystemDriverFactory implements the factory.StorageDriverFactory interface
    25  type filesystemDriverFactory struct{}
    26  
    27  func (factory *filesystemDriverFactory) Create(parameters map[string]interface{}) (storagedriver.StorageDriver, error) {
    28  	return FromParameters(parameters), nil
    29  }
    30  
    31  type driver struct {
    32  	rootDirectory string
    33  }
    34  
    35  type baseEmbed struct {
    36  	base.Base
    37  }
    38  
    39  // Driver is a storagedriver.StorageDriver implementation backed by a local
    40  // filesystem. All provided paths will be subpaths of the RootDirectory.
    41  type Driver struct {
    42  	baseEmbed
    43  }
    44  
    45  // FromParameters constructs a new Driver with a given parameters map
    46  // Optional Parameters:
    47  // - rootdirectory
    48  func FromParameters(parameters map[string]interface{}) *Driver {
    49  	var rootDirectory = defaultRootDirectory
    50  	if parameters != nil {
    51  		rootDir, ok := parameters["rootdirectory"]
    52  		if ok {
    53  			rootDirectory = fmt.Sprint(rootDir)
    54  		}
    55  	}
    56  	return New(rootDirectory)
    57  }
    58  
    59  // New constructs a new Driver with a given rootDirectory
    60  func New(rootDirectory string) *Driver {
    61  	return &Driver{
    62  		baseEmbed: baseEmbed{
    63  			Base: base.Base{
    64  				StorageDriver: &driver{
    65  					rootDirectory: rootDirectory,
    66  				},
    67  			},
    68  		},
    69  	}
    70  }
    71  
    72  // Implement the storagedriver.StorageDriver interface
    73  
    74  func (d *driver) Name() string {
    75  	return driverName
    76  }
    77  
    78  // GetContent retrieves the content stored at "path" as a []byte.
    79  func (d *driver) GetContent(path string) ([]byte, error) {
    80  	rc, err := d.ReadStream(path, 0)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	defer rc.Close()
    85  
    86  	p, err := ioutil.ReadAll(rc)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	return p, nil
    92  }
    93  
    94  // PutContent stores the []byte content at a location designated by "path".
    95  func (d *driver) PutContent(subPath string, contents []byte) error {
    96  	if _, err := d.WriteStream(subPath, 0, bytes.NewReader(contents)); err != nil {
    97  		return err
    98  	}
    99  
   100  	return os.Truncate(d.fullPath(subPath), int64(len(contents)))
   101  }
   102  
   103  // ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
   104  // given byte offset.
   105  func (d *driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
   106  	file, err := os.OpenFile(d.fullPath(path), os.O_RDONLY, 0644)
   107  	if err != nil {
   108  		if os.IsNotExist(err) {
   109  			return nil, storagedriver.PathNotFoundError{Path: path}
   110  		}
   111  
   112  		return nil, err
   113  	}
   114  
   115  	seekPos, err := file.Seek(int64(offset), os.SEEK_SET)
   116  	if err != nil {
   117  		file.Close()
   118  		return nil, err
   119  	} else if seekPos < int64(offset) {
   120  		file.Close()
   121  		return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
   122  	}
   123  
   124  	return file, nil
   125  }
   126  
   127  // WriteStream stores the contents of the provided io.Reader at a location
   128  // designated by the given path.
   129  func (d *driver) WriteStream(subPath string, offset int64, reader io.Reader) (nn int64, err error) {
   130  	// TODO(stevvooe): This needs to be a requirement.
   131  	// if !path.IsAbs(subPath) {
   132  	// 	return fmt.Errorf("absolute path required: %q", subPath)
   133  	// }
   134  
   135  	fullPath := d.fullPath(subPath)
   136  	parentDir := path.Dir(fullPath)
   137  	if err := os.MkdirAll(parentDir, 0755); err != nil {
   138  		return 0, err
   139  	}
   140  
   141  	fp, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, 0644)
   142  	if err != nil {
   143  		// TODO(stevvooe): A few missing conditions in storage driver:
   144  		//	1. What if the path is already a directory?
   145  		//  2. Should number 1 be exposed explicitly in storagedriver?
   146  		//	2. Can this path not exist, even if we create above?
   147  		return 0, err
   148  	}
   149  	defer fp.Close()
   150  
   151  	nn, err = fp.Seek(offset, os.SEEK_SET)
   152  	if err != nil {
   153  		return 0, err
   154  	}
   155  
   156  	if nn != offset {
   157  		return 0, fmt.Errorf("bad seek to %v, expected %v in fp=%v", offset, nn, fp)
   158  	}
   159  
   160  	return io.Copy(fp, reader)
   161  }
   162  
   163  // Stat retrieves the FileInfo for the given path, including the current size
   164  // in bytes and the creation time.
   165  func (d *driver) Stat(subPath string) (storagedriver.FileInfo, error) {
   166  	fullPath := d.fullPath(subPath)
   167  
   168  	fi, err := os.Stat(fullPath)
   169  	if err != nil {
   170  		if os.IsNotExist(err) {
   171  			return nil, storagedriver.PathNotFoundError{Path: subPath}
   172  		}
   173  
   174  		return nil, err
   175  	}
   176  
   177  	return fileInfo{
   178  		path:     subPath,
   179  		FileInfo: fi,
   180  	}, nil
   181  }
   182  
   183  // List returns a list of the objects that are direct descendants of the given
   184  // path.
   185  func (d *driver) List(subPath string) ([]string, error) {
   186  	if subPath[len(subPath)-1] != '/' {
   187  		subPath += "/"
   188  	}
   189  	fullPath := d.fullPath(subPath)
   190  
   191  	dir, err := os.Open(fullPath)
   192  	if err != nil {
   193  		if os.IsNotExist(err) {
   194  			return nil, storagedriver.PathNotFoundError{Path: subPath}
   195  		}
   196  		return nil, err
   197  	}
   198  
   199  	defer dir.Close()
   200  
   201  	fileNames, err := dir.Readdirnames(0)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	keys := make([]string, 0, len(fileNames))
   207  	for _, fileName := range fileNames {
   208  		keys = append(keys, path.Join(subPath, fileName))
   209  	}
   210  
   211  	return keys, nil
   212  }
   213  
   214  // Move moves an object stored at sourcePath to destPath, removing the original
   215  // object.
   216  func (d *driver) Move(sourcePath string, destPath string) error {
   217  	source := d.fullPath(sourcePath)
   218  	dest := d.fullPath(destPath)
   219  
   220  	if _, err := os.Stat(source); os.IsNotExist(err) {
   221  		return storagedriver.PathNotFoundError{Path: sourcePath}
   222  	}
   223  
   224  	if err := os.MkdirAll(path.Dir(dest), 0755); err != nil {
   225  		return err
   226  	}
   227  
   228  	err := os.Rename(source, dest)
   229  	return err
   230  }
   231  
   232  // Delete recursively deletes all objects stored at "path" and its subpaths.
   233  func (d *driver) Delete(subPath string) error {
   234  	fullPath := d.fullPath(subPath)
   235  
   236  	_, err := os.Stat(fullPath)
   237  	if err != nil && !os.IsNotExist(err) {
   238  		return err
   239  	} else if err != nil {
   240  		return storagedriver.PathNotFoundError{Path: subPath}
   241  	}
   242  
   243  	err = os.RemoveAll(fullPath)
   244  	return err
   245  }
   246  
   247  // URLFor returns a URL which may be used to retrieve the content stored at the given path.
   248  // May return an UnsupportedMethodErr in certain StorageDriver implementations.
   249  func (d *driver) URLFor(path string, options map[string]interface{}) (string, error) {
   250  	return "", storagedriver.ErrUnsupportedMethod
   251  }
   252  
   253  // fullPath returns the absolute path of a key within the Driver's storage.
   254  func (d *driver) fullPath(subPath string) string {
   255  	return path.Join(d.rootDirectory, subPath)
   256  }
   257  
   258  type fileInfo struct {
   259  	os.FileInfo
   260  	path string
   261  }
   262  
   263  var _ storagedriver.FileInfo = fileInfo{}
   264  
   265  // Path provides the full path of the target of this file info.
   266  func (fi fileInfo) Path() string {
   267  	return fi.path
   268  }
   269  
   270  // Size returns current length in bytes of the file. The return value can
   271  // be used to write to the end of the file at path. The value is
   272  // meaningless if IsDir returns true.
   273  func (fi fileInfo) Size() int64 {
   274  	if fi.IsDir() {
   275  		return 0
   276  	}
   277  
   278  	return fi.FileInfo.Size()
   279  }
   280  
   281  // ModTime returns the modification time for the file. For backends that
   282  // don't have a modification time, the creation time should be returned.
   283  func (fi fileInfo) ModTime() time.Time {
   284  	return fi.FileInfo.ModTime()
   285  }
   286  
   287  // IsDir returns true if the path is a directory.
   288  func (fi fileInfo) IsDir() bool {
   289  	return fi.FileInfo.IsDir()
   290  }