github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/layer/filestore.go (about)

     1  package layer
     2  
     3  import (
     4  	"compress/gzip"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"regexp"
    13  	"strconv"
    14  	"strings"
    15  
    16  	"github.com/docker/distribution"
    17  	"github.com/docker/docker/pkg/ioutils"
    18  	"github.com/opencontainers/go-digest"
    19  	"github.com/sirupsen/logrus"
    20  )
    21  
    22  var (
    23  	stringIDRegexp      = regexp.MustCompile(`^[a-f0-9]{64}(-init)?$`)
    24  	supportedAlgorithms = []digest.Algorithm{
    25  		digest.SHA256,
    26  		// digest.SHA384, // Currently not used
    27  		// digest.SHA512, // Currently not used
    28  	}
    29  )
    30  
    31  type fileMetadataStore struct {
    32  	root string
    33  }
    34  
    35  type fileMetadataTransaction struct {
    36  	store *fileMetadataStore
    37  	ws    *ioutils.AtomicWriteSet
    38  }
    39  
    40  // NewFSMetadataStore returns an instance of a metadata store
    41  // which is backed by files on disk using the provided root
    42  // as the root of metadata files.
    43  func NewFSMetadataStore(root string) (MetadataStore, error) {
    44  	if err := os.MkdirAll(root, 0700); err != nil {
    45  		return nil, err
    46  	}
    47  	return &fileMetadataStore{
    48  		root: root,
    49  	}, nil
    50  }
    51  
    52  func (fms *fileMetadataStore) getLayerDirectory(layer ChainID) string {
    53  	dgst := digest.Digest(layer)
    54  	return filepath.Join(fms.root, string(dgst.Algorithm()), dgst.Hex())
    55  }
    56  
    57  func (fms *fileMetadataStore) getLayerFilename(layer ChainID, filename string) string {
    58  	return filepath.Join(fms.getLayerDirectory(layer), filename)
    59  }
    60  
    61  func (fms *fileMetadataStore) getMountDirectory(mount string) string {
    62  	return filepath.Join(fms.root, "mounts", mount)
    63  }
    64  
    65  func (fms *fileMetadataStore) getMountFilename(mount, filename string) string {
    66  	return filepath.Join(fms.getMountDirectory(mount), filename)
    67  }
    68  
    69  func (fms *fileMetadataStore) StartTransaction() (MetadataTransaction, error) {
    70  	tmpDir := filepath.Join(fms.root, "tmp")
    71  	if err := os.MkdirAll(tmpDir, 0755); err != nil {
    72  		return nil, err
    73  	}
    74  	ws, err := ioutils.NewAtomicWriteSet(tmpDir)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	return &fileMetadataTransaction{
    80  		store: fms,
    81  		ws:    ws,
    82  	}, nil
    83  }
    84  
    85  func (fm *fileMetadataTransaction) SetSize(size int64) error {
    86  	content := fmt.Sprintf("%d", size)
    87  	return fm.ws.WriteFile("size", []byte(content), 0644)
    88  }
    89  
    90  func (fm *fileMetadataTransaction) SetParent(parent ChainID) error {
    91  	return fm.ws.WriteFile("parent", []byte(digest.Digest(parent).String()), 0644)
    92  }
    93  
    94  func (fm *fileMetadataTransaction) SetDiffID(diff DiffID) error {
    95  	return fm.ws.WriteFile("diff", []byte(digest.Digest(diff).String()), 0644)
    96  }
    97  
    98  func (fm *fileMetadataTransaction) SetCacheID(cacheID string) error {
    99  	return fm.ws.WriteFile("cache-id", []byte(cacheID), 0644)
   100  }
   101  
   102  func (fm *fileMetadataTransaction) SetDescriptor(ref distribution.Descriptor) error {
   103  	jsonRef, err := json.Marshal(ref)
   104  	if err != nil {
   105  		return err
   106  	}
   107  	return fm.ws.WriteFile("descriptor.json", jsonRef, 0644)
   108  }
   109  
   110  func (fm *fileMetadataTransaction) TarSplitWriter(compressInput bool) (io.WriteCloser, error) {
   111  	f, err := fm.ws.FileWriter("tar-split.json.gz", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	var wc io.WriteCloser
   116  	if compressInput {
   117  		wc = gzip.NewWriter(f)
   118  	} else {
   119  		wc = f
   120  	}
   121  
   122  	return ioutils.NewWriteCloserWrapper(wc, func() error {
   123  		wc.Close()
   124  		return f.Close()
   125  	}), nil
   126  }
   127  
   128  func (fm *fileMetadataTransaction) Commit(layer ChainID) error {
   129  	finalDir := fm.store.getLayerDirectory(layer)
   130  	if err := os.MkdirAll(filepath.Dir(finalDir), 0755); err != nil {
   131  		return err
   132  	}
   133  
   134  	return fm.ws.Commit(finalDir)
   135  }
   136  
   137  func (fm *fileMetadataTransaction) Cancel() error {
   138  	return fm.ws.Cancel()
   139  }
   140  
   141  func (fm *fileMetadataTransaction) String() string {
   142  	return fm.ws.String()
   143  }
   144  
   145  func (fms *fileMetadataStore) GetSize(layer ChainID) (int64, error) {
   146  	content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "size"))
   147  	if err != nil {
   148  		return 0, err
   149  	}
   150  
   151  	size, err := strconv.ParseInt(string(content), 10, 64)
   152  	if err != nil {
   153  		return 0, err
   154  	}
   155  
   156  	return size, nil
   157  }
   158  
   159  func (fms *fileMetadataStore) GetParent(layer ChainID) (ChainID, error) {
   160  	content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "parent"))
   161  	if err != nil {
   162  		if os.IsNotExist(err) {
   163  			return "", nil
   164  		}
   165  		return "", err
   166  	}
   167  
   168  	dgst, err := digest.Parse(strings.TrimSpace(string(content)))
   169  	if err != nil {
   170  		return "", err
   171  	}
   172  
   173  	return ChainID(dgst), nil
   174  }
   175  
   176  func (fms *fileMetadataStore) GetDiffID(layer ChainID) (DiffID, error) {
   177  	content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "diff"))
   178  	if err != nil {
   179  		return "", err
   180  	}
   181  
   182  	dgst, err := digest.Parse(strings.TrimSpace(string(content)))
   183  	if err != nil {
   184  		return "", err
   185  	}
   186  
   187  	return DiffID(dgst), nil
   188  }
   189  
   190  func (fms *fileMetadataStore) GetCacheID(layer ChainID) (string, error) {
   191  	contentBytes, err := ioutil.ReadFile(fms.getLayerFilename(layer, "cache-id"))
   192  	if err != nil {
   193  		return "", err
   194  	}
   195  	content := strings.TrimSpace(string(contentBytes))
   196  
   197  	if !stringIDRegexp.MatchString(content) {
   198  		return "", errors.New("invalid cache id value")
   199  	}
   200  
   201  	return content, nil
   202  }
   203  
   204  func (fms *fileMetadataStore) GetDescriptor(layer ChainID) (distribution.Descriptor, error) {
   205  	content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "descriptor.json"))
   206  	if err != nil {
   207  		if os.IsNotExist(err) {
   208  			// only return empty descriptor to represent what is stored
   209  			return distribution.Descriptor{}, nil
   210  		}
   211  		return distribution.Descriptor{}, err
   212  	}
   213  
   214  	var ref distribution.Descriptor
   215  	err = json.Unmarshal(content, &ref)
   216  	if err != nil {
   217  		return distribution.Descriptor{}, err
   218  	}
   219  	return ref, err
   220  }
   221  
   222  func (fms *fileMetadataStore) TarSplitReader(layer ChainID) (io.ReadCloser, error) {
   223  	fz, err := os.Open(fms.getLayerFilename(layer, "tar-split.json.gz"))
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  	f, err := gzip.NewReader(fz)
   228  	if err != nil {
   229  		fz.Close()
   230  		return nil, err
   231  	}
   232  
   233  	return ioutils.NewReadCloserWrapper(f, func() error {
   234  		f.Close()
   235  		return fz.Close()
   236  	}), nil
   237  }
   238  
   239  func (fms *fileMetadataStore) SetMountID(mount string, mountID string) error {
   240  	if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil {
   241  		return err
   242  	}
   243  	return ioutil.WriteFile(fms.getMountFilename(mount, "mount-id"), []byte(mountID), 0644)
   244  }
   245  
   246  func (fms *fileMetadataStore) SetInitID(mount string, init string) error {
   247  	if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil {
   248  		return err
   249  	}
   250  	return ioutil.WriteFile(fms.getMountFilename(mount, "init-id"), []byte(init), 0644)
   251  }
   252  
   253  func (fms *fileMetadataStore) SetMountParent(mount string, parent ChainID) error {
   254  	if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil {
   255  		return err
   256  	}
   257  	return ioutil.WriteFile(fms.getMountFilename(mount, "parent"), []byte(digest.Digest(parent).String()), 0644)
   258  }
   259  
   260  func (fms *fileMetadataStore) GetMountID(mount string) (string, error) {
   261  	contentBytes, err := ioutil.ReadFile(fms.getMountFilename(mount, "mount-id"))
   262  	if err != nil {
   263  		return "", err
   264  	}
   265  	content := strings.TrimSpace(string(contentBytes))
   266  
   267  	if !stringIDRegexp.MatchString(content) {
   268  		return "", errors.New("invalid mount id value")
   269  	}
   270  
   271  	return content, nil
   272  }
   273  
   274  func (fms *fileMetadataStore) GetInitID(mount string) (string, error) {
   275  	contentBytes, err := ioutil.ReadFile(fms.getMountFilename(mount, "init-id"))
   276  	if err != nil {
   277  		if os.IsNotExist(err) {
   278  			return "", nil
   279  		}
   280  		return "", err
   281  	}
   282  	content := strings.TrimSpace(string(contentBytes))
   283  
   284  	if !stringIDRegexp.MatchString(content) {
   285  		return "", errors.New("invalid init id value")
   286  	}
   287  
   288  	return content, nil
   289  }
   290  
   291  func (fms *fileMetadataStore) GetMountParent(mount string) (ChainID, error) {
   292  	content, err := ioutil.ReadFile(fms.getMountFilename(mount, "parent"))
   293  	if err != nil {
   294  		if os.IsNotExist(err) {
   295  			return "", nil
   296  		}
   297  		return "", err
   298  	}
   299  
   300  	dgst, err := digest.Parse(strings.TrimSpace(string(content)))
   301  	if err != nil {
   302  		return "", err
   303  	}
   304  
   305  	return ChainID(dgst), nil
   306  }
   307  
   308  func (fms *fileMetadataStore) List() ([]ChainID, []string, error) {
   309  	var ids []ChainID
   310  	for _, algorithm := range supportedAlgorithms {
   311  		fileInfos, err := ioutil.ReadDir(filepath.Join(fms.root, string(algorithm)))
   312  		if err != nil {
   313  			if os.IsNotExist(err) {
   314  				continue
   315  			}
   316  			return nil, nil, err
   317  		}
   318  
   319  		for _, fi := range fileInfos {
   320  			if fi.IsDir() && fi.Name() != "mounts" {
   321  				dgst := digest.NewDigestFromHex(string(algorithm), fi.Name())
   322  				if err := dgst.Validate(); err != nil {
   323  					logrus.Debugf("Ignoring invalid digest %s:%s", algorithm, fi.Name())
   324  				} else {
   325  					ids = append(ids, ChainID(dgst))
   326  				}
   327  			}
   328  		}
   329  	}
   330  
   331  	fileInfos, err := ioutil.ReadDir(filepath.Join(fms.root, "mounts"))
   332  	if err != nil {
   333  		if os.IsNotExist(err) {
   334  			return ids, []string{}, nil
   335  		}
   336  		return nil, nil, err
   337  	}
   338  
   339  	var mounts []string
   340  	for _, fi := range fileInfos {
   341  		if fi.IsDir() {
   342  			mounts = append(mounts, fi.Name())
   343  		}
   344  	}
   345  
   346  	return ids, mounts, nil
   347  }
   348  
   349  func (fms *fileMetadataStore) Remove(layer ChainID) error {
   350  	return os.RemoveAll(fms.getLayerDirectory(layer))
   351  }
   352  
   353  func (fms *fileMetadataStore) RemoveMount(mount string) error {
   354  	return os.RemoveAll(fms.getMountDirectory(mount))
   355  }