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

     1  package storage
     2  
     3  import (
     4  	"fmt"
     5  
     6  	ctxu "github.com/docker/distribution/context"
     7  	"github.com/docker/distribution/digest"
     8  	storagedriver "github.com/docker/distribution/registry/storage/driver"
     9  	"golang.org/x/net/context"
    10  )
    11  
    12  // TODO(stevvooe): Currently, the blobStore implementation used by the
    13  // manifest store. The layer store should be refactored to better leverage the
    14  // blobStore, reducing duplicated code.
    15  
    16  // blobStore implements a generalized blob store over a driver, supporting the
    17  // read side and link management. This object is intentionally a leaky
    18  // abstraction, providing utility methods that support creating and traversing
    19  // backend links.
    20  type blobStore struct {
    21  	driver storagedriver.StorageDriver
    22  	pm     *pathMapper
    23  	ctx    context.Context
    24  }
    25  
    26  // exists reports whether or not the path exists. If the driver returns error
    27  // other than storagedriver.PathNotFound, an error may be returned.
    28  func (bs *blobStore) exists(dgst digest.Digest) (bool, error) {
    29  	path, err := bs.path(dgst)
    30  
    31  	if err != nil {
    32  		return false, err
    33  	}
    34  
    35  	ok, err := exists(bs.driver, path)
    36  	if err != nil {
    37  		return false, err
    38  	}
    39  
    40  	return ok, nil
    41  }
    42  
    43  // get retrieves the blob by digest, returning it a byte slice. This should
    44  // only be used for small objects.
    45  func (bs *blobStore) get(dgst digest.Digest) ([]byte, error) {
    46  	bp, err := bs.path(dgst)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	return bs.driver.GetContent(bp)
    52  }
    53  
    54  // link links the path to the provided digest by writing the digest into the
    55  // target file.
    56  func (bs *blobStore) link(path string, dgst digest.Digest) error {
    57  	if exists, err := bs.exists(dgst); err != nil {
    58  		return err
    59  	} else if !exists {
    60  		return fmt.Errorf("cannot link non-existent blob")
    61  	}
    62  
    63  	// The contents of the "link" file are the exact string contents of the
    64  	// digest, which is specified in that package.
    65  	return bs.driver.PutContent(path, []byte(dgst))
    66  }
    67  
    68  // linked reads the link at path and returns the content.
    69  func (bs *blobStore) linked(path string) ([]byte, error) {
    70  	linked, err := bs.readlink(path)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	return bs.get(linked)
    76  }
    77  
    78  // readlink returns the linked digest at path.
    79  func (bs *blobStore) readlink(path string) (digest.Digest, error) {
    80  	content, err := bs.driver.GetContent(path)
    81  	if err != nil {
    82  		return "", err
    83  	}
    84  
    85  	linked, err := digest.ParseDigest(string(content))
    86  	if err != nil {
    87  		return "", err
    88  	}
    89  
    90  	if exists, err := bs.exists(linked); err != nil {
    91  		return "", err
    92  	} else if !exists {
    93  		return "", fmt.Errorf("link %q invalid: blob %s does not exist", path, linked)
    94  	}
    95  
    96  	return linked, nil
    97  }
    98  
    99  // resolve reads the digest link at path and returns the blob store link.
   100  func (bs *blobStore) resolve(path string) (string, error) {
   101  	dgst, err := bs.readlink(path)
   102  	if err != nil {
   103  		return "", err
   104  	}
   105  
   106  	return bs.path(dgst)
   107  }
   108  
   109  // put stores the content p in the blob store, calculating the digest. If the
   110  // content is already present, only the digest will be returned. This should
   111  // only be used for small objects, such as manifests.
   112  func (bs *blobStore) put(p []byte) (digest.Digest, error) {
   113  	dgst, err := digest.FromBytes(p)
   114  	if err != nil {
   115  		ctxu.GetLogger(bs.ctx).Errorf("error digesting content: %v, %s", err, string(p))
   116  		return "", err
   117  	}
   118  
   119  	bp, err := bs.path(dgst)
   120  	if err != nil {
   121  		return "", err
   122  	}
   123  
   124  	// If the content already exists, just return the digest.
   125  	if exists, err := bs.exists(dgst); err != nil {
   126  		return "", err
   127  	} else if exists {
   128  		return dgst, nil
   129  	}
   130  
   131  	return dgst, bs.driver.PutContent(bp, p)
   132  }
   133  
   134  // path returns the canonical path for the blob identified by digest. The blob
   135  // may or may not exist.
   136  func (bs *blobStore) path(dgst digest.Digest) (string, error) {
   137  	bp, err := bs.pm.path(blobDataPathSpec{
   138  		digest: dgst,
   139  	})
   140  
   141  	if err != nil {
   142  		return "", err
   143  	}
   144  
   145  	return bp, nil
   146  }
   147  
   148  // exists provides a utility method to test whether or not
   149  func exists(driver storagedriver.StorageDriver, path string) (bool, error) {
   150  	if _, err := driver.Stat(path); err != nil {
   151  		switch err := err.(type) {
   152  		case storagedriver.PathNotFoundError:
   153  			return false, nil
   154  		default:
   155  			return false, err
   156  		}
   157  	}
   158  
   159  	return true, nil
   160  }