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