github.com/miqui/docker@v1.9.1/graph/graph.go (about)

     1  package graph
     2  
     3  import (
     4  	"compress/gzip"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"runtime"
    13  	"strconv"
    14  	"strings"
    15  	"sync"
    16  	"time"
    17  
    18  	"github.com/Sirupsen/logrus"
    19  	"github.com/docker/distribution/digest"
    20  	"github.com/docker/docker/autogen/dockerversion"
    21  	"github.com/docker/docker/daemon/graphdriver"
    22  	"github.com/docker/docker/image"
    23  	"github.com/docker/docker/pkg/archive"
    24  	"github.com/docker/docker/pkg/idtools"
    25  	"github.com/docker/docker/pkg/progressreader"
    26  	"github.com/docker/docker/pkg/streamformatter"
    27  	"github.com/docker/docker/pkg/stringid"
    28  	"github.com/docker/docker/pkg/truncindex"
    29  	"github.com/docker/docker/runconfig"
    30  	"github.com/vbatts/tar-split/tar/asm"
    31  	"github.com/vbatts/tar-split/tar/storage"
    32  )
    33  
    34  // v1Descriptor is a non-content-addressable image descriptor
    35  type v1Descriptor struct {
    36  	img *image.Image
    37  }
    38  
    39  // ID returns the image ID specified in the image structure.
    40  func (img v1Descriptor) ID() string {
    41  	return img.img.ID
    42  }
    43  
    44  // Parent returns the parent ID specified in the image structure.
    45  func (img v1Descriptor) Parent() string {
    46  	return img.img.Parent
    47  }
    48  
    49  // MarshalConfig renders the image structure into JSON.
    50  func (img v1Descriptor) MarshalConfig() ([]byte, error) {
    51  	return json.Marshal(img.img)
    52  }
    53  
    54  // The type is used to protect pulling or building related image
    55  // layers from deleteing when filtered by dangling=true
    56  // The key of layers is the images ID which is pulling or building
    57  // The value of layers is a slice which hold layer IDs referenced to
    58  // pulling or building images
    59  type retainedLayers struct {
    60  	layerHolders map[string]map[string]struct{} // map[layerID]map[sessionID]
    61  	sync.Mutex
    62  }
    63  
    64  func (r *retainedLayers) Add(sessionID string, layerIDs []string) {
    65  	r.Lock()
    66  	defer r.Unlock()
    67  	for _, layerID := range layerIDs {
    68  		if r.layerHolders[layerID] == nil {
    69  			r.layerHolders[layerID] = map[string]struct{}{}
    70  		}
    71  		r.layerHolders[layerID][sessionID] = struct{}{}
    72  	}
    73  }
    74  
    75  func (r *retainedLayers) Delete(sessionID string, layerIDs []string) {
    76  	r.Lock()
    77  	defer r.Unlock()
    78  	for _, layerID := range layerIDs {
    79  		holders, ok := r.layerHolders[layerID]
    80  		if !ok {
    81  			continue
    82  		}
    83  		delete(holders, sessionID)
    84  		if len(holders) == 0 {
    85  			delete(r.layerHolders, layerID) // Delete any empty reference set.
    86  		}
    87  	}
    88  }
    89  
    90  func (r *retainedLayers) Exists(layerID string) bool {
    91  	r.Lock()
    92  	_, exists := r.layerHolders[layerID]
    93  	r.Unlock()
    94  	return exists
    95  }
    96  
    97  // A Graph is a store for versioned filesystem images and the relationship between them.
    98  type Graph struct {
    99  	root             string
   100  	idIndex          *truncindex.TruncIndex
   101  	driver           graphdriver.Driver
   102  	imagesMutex      sync.Mutex
   103  	imageMutex       imageMutex // protect images in driver.
   104  	retained         *retainedLayers
   105  	tarSplitDisabled bool
   106  	uidMaps          []idtools.IDMap
   107  	gidMaps          []idtools.IDMap
   108  
   109  	// access to parentRefs must be protected with imageMutex locking the image id
   110  	// on the key of the map (e.g. imageMutex.Lock(img.ID), parentRefs[img.ID]...)
   111  	parentRefs map[string]int
   112  }
   113  
   114  // file names for ./graph/<ID>/
   115  const (
   116  	jsonFileName            = "json"
   117  	layersizeFileName       = "layersize"
   118  	digestFileName          = "checksum"
   119  	tarDataFileName         = "tar-data.json.gz"
   120  	v1CompatibilityFileName = "v1Compatibility"
   121  	parentFileName          = "parent"
   122  )
   123  
   124  var (
   125  	// ErrDigestNotSet is used when request the digest for a layer
   126  	// but the layer has no digest value or content to compute the
   127  	// the digest.
   128  	ErrDigestNotSet = errors.New("digest is not set for layer")
   129  )
   130  
   131  // NewGraph instantiates a new graph at the given root path in the filesystem.
   132  // `root` will be created if it doesn't exist.
   133  func NewGraph(root string, driver graphdriver.Driver, uidMaps, gidMaps []idtools.IDMap) (*Graph, error) {
   134  	abspath, err := filepath.Abs(root)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	// Create the root directory if it doesn't exists
   144  	if err := idtools.MkdirAllAs(root, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
   145  		return nil, err
   146  	}
   147  
   148  	graph := &Graph{
   149  		root:       abspath,
   150  		idIndex:    truncindex.NewTruncIndex([]string{}),
   151  		driver:     driver,
   152  		retained:   &retainedLayers{layerHolders: make(map[string]map[string]struct{})},
   153  		uidMaps:    uidMaps,
   154  		gidMaps:    gidMaps,
   155  		parentRefs: make(map[string]int),
   156  	}
   157  
   158  	// Windows does not currently support tarsplit functionality.
   159  	if runtime.GOOS == "windows" {
   160  		graph.tarSplitDisabled = true
   161  	}
   162  
   163  	if err := graph.restore(); err != nil {
   164  		return nil, err
   165  	}
   166  	return graph, nil
   167  }
   168  
   169  // IsHeld returns whether the given layerID is being used by an ongoing pull or build.
   170  func (graph *Graph) IsHeld(layerID string) bool {
   171  	return graph.retained.Exists(layerID)
   172  }
   173  
   174  func (graph *Graph) restore() error {
   175  	dir, err := ioutil.ReadDir(graph.root)
   176  	if err != nil {
   177  		return err
   178  	}
   179  	var ids = []string{}
   180  	for _, v := range dir {
   181  		id := v.Name()
   182  		if graph.driver.Exists(id) {
   183  			img, err := graph.loadImage(id)
   184  			if err != nil {
   185  				logrus.Warnf("ignoring image %s, it could not be restored: %v", id, err)
   186  				continue
   187  			}
   188  			graph.imageMutex.Lock(img.Parent)
   189  			graph.parentRefs[img.Parent]++
   190  			graph.imageMutex.Unlock(img.Parent)
   191  			ids = append(ids, id)
   192  		}
   193  	}
   194  
   195  	graph.idIndex = truncindex.NewTruncIndex(ids)
   196  	logrus.Debugf("Restored %d elements", len(ids))
   197  	return nil
   198  }
   199  
   200  // IsNotExist detects whether an image exists by parsing the incoming error
   201  // message.
   202  func (graph *Graph) IsNotExist(err error, id string) bool {
   203  	// FIXME: Implement error subclass instead of looking at the error text
   204  	// Note: This is the way golang implements os.IsNotExists on Plan9
   205  	return err != nil && (strings.Contains(strings.ToLower(err.Error()), "does not exist") || strings.Contains(strings.ToLower(err.Error()), "no such")) && strings.Contains(err.Error(), id)
   206  }
   207  
   208  // Exists returns true if an image is registered at the given id.
   209  // If the image doesn't exist or if an error is encountered, false is returned.
   210  func (graph *Graph) Exists(id string) bool {
   211  	if _, err := graph.Get(id); err != nil {
   212  		return false
   213  	}
   214  	return true
   215  }
   216  
   217  // Get returns the image with the given id, or an error if the image doesn't exist.
   218  func (graph *Graph) Get(name string) (*image.Image, error) {
   219  	id, err := graph.idIndex.Get(name)
   220  	if err != nil {
   221  		return nil, fmt.Errorf("could not find image: %v", err)
   222  	}
   223  	img, err := graph.loadImage(id)
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  	if img.ID != id {
   228  		return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
   229  	}
   230  
   231  	if img.Size < 0 {
   232  		size, err := graph.driver.DiffSize(img.ID, img.Parent)
   233  		if err != nil {
   234  			return nil, fmt.Errorf("unable to calculate size of image id %q: %s", img.ID, err)
   235  		}
   236  
   237  		img.Size = size
   238  		if err := graph.saveSize(graph.imageRoot(id), img.Size); err != nil {
   239  			return nil, err
   240  		}
   241  	}
   242  	return img, nil
   243  }
   244  
   245  // Create creates a new image and registers it in the graph.
   246  func (graph *Graph) Create(layerData io.Reader, containerID, containerImage, comment, author string, containerConfig, config *runconfig.Config) (*image.Image, error) {
   247  	img := &image.Image{
   248  		ID:            stringid.GenerateRandomID(),
   249  		Comment:       comment,
   250  		Created:       time.Now().UTC(),
   251  		DockerVersion: dockerversion.VERSION,
   252  		Author:        author,
   253  		Config:        config,
   254  		Architecture:  runtime.GOARCH,
   255  		OS:            runtime.GOOS,
   256  	}
   257  
   258  	if containerID != "" {
   259  		img.Parent = containerImage
   260  		img.Container = containerID
   261  		img.ContainerConfig = *containerConfig
   262  	}
   263  
   264  	if err := graph.Register(v1Descriptor{img}, layerData); err != nil {
   265  		return nil, err
   266  	}
   267  	return img, nil
   268  }
   269  
   270  // Register imports a pre-existing image into the graph.
   271  // Returns nil if the image is already registered.
   272  func (graph *Graph) Register(im image.Descriptor, layerData io.Reader) (err error) {
   273  	imgID := im.ID()
   274  
   275  	if err := image.ValidateID(imgID); err != nil {
   276  		return err
   277  	}
   278  
   279  	// this is needed cause pull_v2 attemptIDReuse could deadlock
   280  	graph.imagesMutex.Lock()
   281  	defer graph.imagesMutex.Unlock()
   282  
   283  	// We need this entire operation to be atomic within the engine. Note that
   284  	// this doesn't mean Register is fully safe yet.
   285  	graph.imageMutex.Lock(imgID)
   286  	defer graph.imageMutex.Unlock(imgID)
   287  
   288  	return graph.register(im, layerData)
   289  }
   290  
   291  func (graph *Graph) register(im image.Descriptor, layerData io.Reader) (err error) {
   292  	imgID := im.ID()
   293  
   294  	// Skip register if image is already registered
   295  	if graph.Exists(imgID) {
   296  		return nil
   297  	}
   298  
   299  	// The returned `error` must be named in this function's signature so that
   300  	// `err` is not shadowed in this deferred cleanup.
   301  	defer func() {
   302  		// If any error occurs, remove the new dir from the driver.
   303  		// Don't check for errors since the dir might not have been created.
   304  		if err != nil {
   305  			graph.driver.Remove(imgID)
   306  		}
   307  	}()
   308  
   309  	// Ensure that the image root does not exist on the filesystem
   310  	// when it is not registered in the graph.
   311  	// This is common when you switch from one graph driver to another
   312  	if err := os.RemoveAll(graph.imageRoot(imgID)); err != nil && !os.IsNotExist(err) {
   313  		return err
   314  	}
   315  
   316  	// If the driver has this ID but the graph doesn't, remove it from the driver to start fresh.
   317  	// (the graph is the source of truth).
   318  	// Ignore errors, since we don't know if the driver correctly returns ErrNotExist.
   319  	// (FIXME: make that mandatory for drivers).
   320  	graph.driver.Remove(imgID)
   321  
   322  	tmp, err := graph.mktemp()
   323  	if err != nil {
   324  		return err
   325  	}
   326  	defer os.RemoveAll(tmp)
   327  
   328  	parent := im.Parent()
   329  
   330  	// Create root filesystem in the driver
   331  	if err := createRootFilesystemInDriver(graph, imgID, parent, layerData); err != nil {
   332  		return err
   333  	}
   334  
   335  	// Apply the diff/layer
   336  	config, err := im.MarshalConfig()
   337  	if err != nil {
   338  		return err
   339  	}
   340  	if err := graph.storeImage(imgID, parent, config, layerData, tmp); err != nil {
   341  		return err
   342  	}
   343  	// Commit
   344  	if err := os.Rename(tmp, graph.imageRoot(imgID)); err != nil {
   345  		return err
   346  	}
   347  
   348  	graph.idIndex.Add(imgID)
   349  
   350  	graph.imageMutex.Lock(parent)
   351  	graph.parentRefs[parent]++
   352  	graph.imageMutex.Unlock(parent)
   353  
   354  	return nil
   355  }
   356  
   357  func createRootFilesystemInDriver(graph *Graph, id, parent string, layerData io.Reader) error {
   358  	if err := graph.driver.Create(id, parent); err != nil {
   359  		return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, id, err)
   360  	}
   361  	return nil
   362  }
   363  
   364  // TempLayerArchive creates a temporary archive of the given image's filesystem layer.
   365  //   The archive is stored on disk and will be automatically deleted as soon as has been read.
   366  //   If output is not nil, a human-readable progress bar will be written to it.
   367  func (graph *Graph) TempLayerArchive(id string, sf *streamformatter.StreamFormatter, output io.Writer) (*archive.TempArchive, error) {
   368  	image, err := graph.Get(id)
   369  	if err != nil {
   370  		return nil, err
   371  	}
   372  	tmp, err := graph.mktemp()
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  	defer os.RemoveAll(tmp)
   377  	a, err := graph.TarLayer(image)
   378  	if err != nil {
   379  		return nil, err
   380  	}
   381  	progressReader := progressreader.New(progressreader.Config{
   382  		In:        a,
   383  		Out:       output,
   384  		Formatter: sf,
   385  		Size:      0,
   386  		NewLines:  false,
   387  		ID:        stringid.TruncateID(id),
   388  		Action:    "Buffering to disk",
   389  	})
   390  	defer progressReader.Close()
   391  	return archive.NewTempArchive(progressReader, tmp)
   392  }
   393  
   394  // mktemp creates a temporary sub-directory inside the graph's filesystem.
   395  func (graph *Graph) mktemp() (string, error) {
   396  	dir := filepath.Join(graph.root, "_tmp", stringid.GenerateNonCryptoID())
   397  	rootUID, rootGID, err := idtools.GetRootUIDGID(graph.uidMaps, graph.gidMaps)
   398  	if err != nil {
   399  		return "", err
   400  	}
   401  	if err := idtools.MkdirAllAs(dir, 0700, rootUID, rootGID); err != nil {
   402  		return "", err
   403  	}
   404  	return dir, nil
   405  }
   406  
   407  // Delete atomically removes an image from the graph.
   408  func (graph *Graph) Delete(name string) error {
   409  	id, err := graph.idIndex.Get(name)
   410  	if err != nil {
   411  		return err
   412  	}
   413  	img, err := graph.Get(id)
   414  	if err != nil {
   415  		return err
   416  	}
   417  	graph.idIndex.Delete(id)
   418  	tmp, err := graph.mktemp()
   419  	if err != nil {
   420  		tmp = graph.imageRoot(id)
   421  	} else {
   422  		if err := os.Rename(graph.imageRoot(id), tmp); err != nil {
   423  			// On err make tmp point to old dir and cleanup unused tmp dir
   424  			os.RemoveAll(tmp)
   425  			tmp = graph.imageRoot(id)
   426  		}
   427  	}
   428  	// Remove rootfs data from the driver
   429  	graph.driver.Remove(id)
   430  
   431  	graph.imageMutex.Lock(img.Parent)
   432  	graph.parentRefs[img.Parent]--
   433  	if graph.parentRefs[img.Parent] == 0 {
   434  		delete(graph.parentRefs, img.Parent)
   435  	}
   436  	graph.imageMutex.Unlock(img.Parent)
   437  
   438  	// Remove the trashed image directory
   439  	return os.RemoveAll(tmp)
   440  }
   441  
   442  // Map returns a list of all images in the graph, addressable by ID.
   443  func (graph *Graph) Map() map[string]*image.Image {
   444  	images := make(map[string]*image.Image)
   445  	graph.walkAll(func(image *image.Image) {
   446  		images[image.ID] = image
   447  	})
   448  	return images
   449  }
   450  
   451  // walkAll iterates over each image in the graph, and passes it to a handler.
   452  // The walking order is undetermined.
   453  func (graph *Graph) walkAll(handler func(*image.Image)) {
   454  	graph.idIndex.Iterate(func(id string) {
   455  		img, err := graph.Get(id)
   456  		if err != nil {
   457  			return
   458  		}
   459  		if handler != nil {
   460  			handler(img)
   461  		}
   462  	})
   463  }
   464  
   465  // ByParent returns a lookup table of images by their parent.
   466  // If an image of key ID has 3 children images, then the value for key ID
   467  // will be a list of 3 images.
   468  // If an image has no children, it will not have an entry in the table.
   469  func (graph *Graph) ByParent() map[string][]*image.Image {
   470  	byParent := make(map[string][]*image.Image)
   471  	graph.walkAll(func(img *image.Image) {
   472  		parent, err := graph.Get(img.Parent)
   473  		if err != nil {
   474  			return
   475  		}
   476  		if children, exists := byParent[parent.ID]; exists {
   477  			byParent[parent.ID] = append(children, img)
   478  		} else {
   479  			byParent[parent.ID] = []*image.Image{img}
   480  		}
   481  	})
   482  	return byParent
   483  }
   484  
   485  // HasChildren returns whether the given image has any child images.
   486  func (graph *Graph) HasChildren(imgID string) bool {
   487  	graph.imageMutex.Lock(imgID)
   488  	count := graph.parentRefs[imgID]
   489  	graph.imageMutex.Unlock(imgID)
   490  	return count > 0
   491  }
   492  
   493  // Retain keeps the images and layers that are in the pulling chain so that
   494  // they are not deleted. If not retained, they may be deleted by rmi.
   495  func (graph *Graph) Retain(sessionID string, layerIDs ...string) {
   496  	graph.retained.Add(sessionID, layerIDs)
   497  }
   498  
   499  // Release removes the referenced image ID from the provided set of layers.
   500  func (graph *Graph) Release(sessionID string, layerIDs ...string) {
   501  	graph.retained.Delete(sessionID, layerIDs)
   502  }
   503  
   504  // Heads returns all heads in the graph, keyed by id.
   505  // A head is an image which is not the parent of another image in the graph.
   506  func (graph *Graph) Heads() map[string]*image.Image {
   507  	heads := make(map[string]*image.Image)
   508  	graph.walkAll(func(image *image.Image) {
   509  		// if it has no children, then it's not a parent, so it's an head
   510  		if !graph.HasChildren(image.ID) {
   511  			heads[image.ID] = image
   512  		}
   513  	})
   514  	return heads
   515  }
   516  
   517  // TarLayer returns a tar archive of the image's filesystem layer.
   518  func (graph *Graph) TarLayer(img *image.Image) (arch io.ReadCloser, err error) {
   519  	rdr, err := graph.assembleTarLayer(img)
   520  	if err != nil {
   521  		logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
   522  		return graph.driver.Diff(img.ID, img.Parent)
   523  	}
   524  	return rdr, nil
   525  }
   526  
   527  func (graph *Graph) imageRoot(id string) string {
   528  	return filepath.Join(graph.root, id)
   529  }
   530  
   531  // loadImage fetches the image with the given id from the graph.
   532  func (graph *Graph) loadImage(id string) (*image.Image, error) {
   533  	root := graph.imageRoot(id)
   534  
   535  	// Open the JSON file to decode by streaming
   536  	jsonSource, err := os.Open(jsonPath(root))
   537  	if err != nil {
   538  		return nil, err
   539  	}
   540  	defer jsonSource.Close()
   541  
   542  	img := &image.Image{}
   543  	dec := json.NewDecoder(jsonSource)
   544  
   545  	// Decode the JSON data
   546  	if err := dec.Decode(img); err != nil {
   547  		return nil, err
   548  	}
   549  
   550  	if img.ID == "" {
   551  		img.ID = id
   552  	}
   553  
   554  	if img.Parent == "" && img.ParentID != "" && img.ParentID.Validate() == nil {
   555  		img.Parent = img.ParentID.Hex()
   556  	}
   557  
   558  	// compatibilityID for parent
   559  	parent, err := ioutil.ReadFile(filepath.Join(root, parentFileName))
   560  	if err == nil && len(parent) > 0 {
   561  		img.Parent = string(parent)
   562  	}
   563  
   564  	if err := image.ValidateID(img.ID); err != nil {
   565  		return nil, err
   566  	}
   567  
   568  	if buf, err := ioutil.ReadFile(filepath.Join(root, layersizeFileName)); err != nil {
   569  		if !os.IsNotExist(err) {
   570  			return nil, err
   571  		}
   572  		// If the layersize file does not exist then set the size to a negative number
   573  		// because a layer size of 0 (zero) is valid
   574  		img.Size = -1
   575  	} else {
   576  		// Using Atoi here instead would temporarily convert the size to a machine
   577  		// dependent integer type, which causes images larger than 2^31 bytes to
   578  		// display negative sizes on 32-bit machines:
   579  		size, err := strconv.ParseInt(string(buf), 10, 64)
   580  		if err != nil {
   581  			return nil, err
   582  		}
   583  		img.Size = int64(size)
   584  	}
   585  
   586  	return img, nil
   587  }
   588  
   589  // saveSize stores the `size` in the provided graph `img` directory `root`.
   590  func (graph *Graph) saveSize(root string, size int64) error {
   591  	if err := ioutil.WriteFile(filepath.Join(root, layersizeFileName), []byte(strconv.FormatInt(size, 10)), 0600); err != nil {
   592  		return fmt.Errorf("Error storing image size in %s/%s: %s", root, layersizeFileName, err)
   593  	}
   594  	return nil
   595  }
   596  
   597  // SetLayerDigest sets the digest for the image layer to the provided value.
   598  func (graph *Graph) SetLayerDigest(id string, dgst digest.Digest) error {
   599  	graph.imageMutex.Lock(id)
   600  	defer graph.imageMutex.Unlock(id)
   601  
   602  	return graph.setLayerDigest(id, dgst)
   603  }
   604  func (graph *Graph) setLayerDigest(id string, dgst digest.Digest) error {
   605  	root := graph.imageRoot(id)
   606  	if err := ioutil.WriteFile(filepath.Join(root, digestFileName), []byte(dgst.String()), 0600); err != nil {
   607  		return fmt.Errorf("Error storing digest in %s/%s: %s", root, digestFileName, err)
   608  	}
   609  	return nil
   610  }
   611  
   612  // GetLayerDigest gets the digest for the provide image layer id.
   613  func (graph *Graph) GetLayerDigest(id string) (digest.Digest, error) {
   614  	graph.imageMutex.Lock(id)
   615  	defer graph.imageMutex.Unlock(id)
   616  
   617  	return graph.getLayerDigest(id)
   618  }
   619  
   620  func (graph *Graph) getLayerDigest(id string) (digest.Digest, error) {
   621  	root := graph.imageRoot(id)
   622  	cs, err := ioutil.ReadFile(filepath.Join(root, digestFileName))
   623  	if err != nil {
   624  		if os.IsNotExist(err) {
   625  			return "", ErrDigestNotSet
   626  		}
   627  		return "", err
   628  	}
   629  	return digest.ParseDigest(string(cs))
   630  }
   631  
   632  // SetV1CompatibilityConfig stores the v1Compatibility JSON data associated
   633  // with the image in the manifest to the disk
   634  func (graph *Graph) SetV1CompatibilityConfig(id string, data []byte) error {
   635  	graph.imageMutex.Lock(id)
   636  	defer graph.imageMutex.Unlock(id)
   637  
   638  	return graph.setV1CompatibilityConfig(id, data)
   639  }
   640  func (graph *Graph) setV1CompatibilityConfig(id string, data []byte) error {
   641  	root := graph.imageRoot(id)
   642  	return ioutil.WriteFile(filepath.Join(root, v1CompatibilityFileName), data, 0600)
   643  }
   644  
   645  // GetV1CompatibilityConfig reads the v1Compatibility JSON data for the image
   646  // from the disk
   647  func (graph *Graph) GetV1CompatibilityConfig(id string) ([]byte, error) {
   648  	graph.imageMutex.Lock(id)
   649  	defer graph.imageMutex.Unlock(id)
   650  
   651  	return graph.getV1CompatibilityConfig(id)
   652  }
   653  
   654  func (graph *Graph) getV1CompatibilityConfig(id string) ([]byte, error) {
   655  	root := graph.imageRoot(id)
   656  	return ioutil.ReadFile(filepath.Join(root, v1CompatibilityFileName))
   657  }
   658  
   659  // GenerateV1CompatibilityChain makes sure v1Compatibility JSON data exists
   660  // for the image. If it doesn't it generates and stores it for the image and
   661  // all of it's parents based on the image config JSON.
   662  func (graph *Graph) GenerateV1CompatibilityChain(id string) ([]byte, error) {
   663  	graph.imageMutex.Lock(id)
   664  	defer graph.imageMutex.Unlock(id)
   665  
   666  	if v1config, err := graph.getV1CompatibilityConfig(id); err == nil {
   667  		return v1config, nil
   668  	}
   669  
   670  	// generate new, store it to disk
   671  	img, err := graph.Get(id)
   672  	if err != nil {
   673  		return nil, err
   674  	}
   675  
   676  	digestPrefix := string(digest.Canonical) + ":"
   677  	img.ID = strings.TrimPrefix(img.ID, digestPrefix)
   678  
   679  	if img.Parent != "" {
   680  		parentConfig, err := graph.GenerateV1CompatibilityChain(img.Parent)
   681  		if err != nil {
   682  			return nil, err
   683  		}
   684  		var parent struct{ ID string }
   685  		err = json.Unmarshal(parentConfig, &parent)
   686  		if err != nil {
   687  			return nil, err
   688  		}
   689  		img.Parent = parent.ID
   690  	}
   691  
   692  	json, err := json.Marshal(img)
   693  	if err != nil {
   694  		return nil, err
   695  	}
   696  	if err := graph.setV1CompatibilityConfig(id, json); err != nil {
   697  		return nil, err
   698  	}
   699  	return json, nil
   700  }
   701  
   702  // RawJSON returns the JSON representation for an image as a byte array.
   703  func (graph *Graph) RawJSON(id string) ([]byte, error) {
   704  	root := graph.imageRoot(id)
   705  
   706  	buf, err := ioutil.ReadFile(jsonPath(root))
   707  	if err != nil {
   708  		return nil, fmt.Errorf("Failed to read json for image %s: %s", id, err)
   709  	}
   710  
   711  	return buf, nil
   712  }
   713  
   714  func jsonPath(root string) string {
   715  	return filepath.Join(root, jsonFileName)
   716  }
   717  
   718  // storeImage stores file system layer data for the given image to the
   719  // graph's storage driver. Image metadata is stored in a file
   720  // at the specified root directory.
   721  func (graph *Graph) storeImage(id, parent string, config []byte, layerData io.Reader, root string) (err error) {
   722  	var size int64
   723  	// Store the layer. If layerData is not nil, unpack it into the new layer
   724  	if layerData != nil {
   725  		if size, err = graph.disassembleAndApplyTarLayer(id, parent, layerData, root); err != nil {
   726  			return err
   727  		}
   728  	}
   729  
   730  	if err := graph.saveSize(root, size); err != nil {
   731  		return err
   732  	}
   733  
   734  	if err := ioutil.WriteFile(jsonPath(root), config, 0600); err != nil {
   735  		return err
   736  	}
   737  
   738  	// If image is pointing to a parent via CompatibilityID write the reference to disk
   739  	img, err := image.NewImgJSON(config)
   740  	if err != nil {
   741  		return err
   742  	}
   743  
   744  	if img.ParentID.Validate() == nil && parent != img.ParentID.Hex() {
   745  		if err := ioutil.WriteFile(filepath.Join(root, parentFileName), []byte(parent), 0600); err != nil {
   746  			return err
   747  		}
   748  	}
   749  	return nil
   750  }
   751  
   752  func (graph *Graph) disassembleAndApplyTarLayer(id, parent string, layerData io.Reader, root string) (size int64, err error) {
   753  	var ar io.Reader
   754  
   755  	if graph.tarSplitDisabled {
   756  		ar = layerData
   757  	} else {
   758  		// this is saving the tar-split metadata
   759  		mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
   760  		if err != nil {
   761  			return 0, err
   762  		}
   763  
   764  		mfz := gzip.NewWriter(mf)
   765  		metaPacker := storage.NewJSONPacker(mfz)
   766  		defer mf.Close()
   767  		defer mfz.Close()
   768  
   769  		inflatedLayerData, err := archive.DecompressStream(layerData)
   770  		if err != nil {
   771  			return 0, err
   772  		}
   773  
   774  		// we're passing nil here for the file putter, because the ApplyDiff will
   775  		// handle the extraction of the archive
   776  		rdr, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil)
   777  		if err != nil {
   778  			return 0, err
   779  		}
   780  
   781  		ar = archive.Reader(rdr)
   782  	}
   783  
   784  	if size, err = graph.driver.ApplyDiff(id, parent, ar); err != nil {
   785  		return 0, err
   786  	}
   787  
   788  	return
   789  }
   790  
   791  func (graph *Graph) assembleTarLayer(img *image.Image) (io.ReadCloser, error) {
   792  	root := graph.imageRoot(img.ID)
   793  	mFileName := filepath.Join(root, tarDataFileName)
   794  	mf, err := os.Open(mFileName)
   795  	if err != nil {
   796  		if !os.IsNotExist(err) {
   797  			logrus.Errorf("failed to open %q: %s", mFileName, err)
   798  		}
   799  		return nil, err
   800  	}
   801  	pR, pW := io.Pipe()
   802  	// this will need to be in a goroutine, as we are returning the stream of a
   803  	// tar archive, but can not close the metadata reader early (when this
   804  	// function returns)...
   805  	go func() {
   806  		defer mf.Close()
   807  		// let's reassemble!
   808  		logrus.Debugf("[graph] TarLayer with reassembly: %s", img.ID)
   809  		mfz, err := gzip.NewReader(mf)
   810  		if err != nil {
   811  			pW.CloseWithError(fmt.Errorf("[graph] error with %s:  %s", mFileName, err))
   812  			return
   813  		}
   814  		defer mfz.Close()
   815  
   816  		// get our relative path to the container
   817  		fsLayer, err := graph.driver.Get(img.ID, "")
   818  		if err != nil {
   819  			pW.CloseWithError(err)
   820  			return
   821  		}
   822  		defer graph.driver.Put(img.ID)
   823  
   824  		metaUnpacker := storage.NewJSONUnpacker(mfz)
   825  		fileGetter := storage.NewPathFileGetter(fsLayer)
   826  		logrus.Debugf("[graph] %s is at %q", img.ID, fsLayer)
   827  		ots := asm.NewOutputTarStream(fileGetter, metaUnpacker)
   828  		defer ots.Close()
   829  		if _, err := io.Copy(pW, ots); err != nil {
   830  			pW.CloseWithError(err)
   831  			return
   832  		}
   833  		pW.Close()
   834  	}()
   835  	return pR, nil
   836  }