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