mirror of https://github.com/containers/podman.git
				
				
				
			Vendor in latest containers/storage and containers/image
Containers/storage brings in support for UserNS ID Mappings This means we can start experimenting with User NS Support in podman Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Closes: #596 Approved by: TomSweeneyRedHat
This commit is contained in:
		
							parent
							
								
									fbc9d189b1
								
							
						
					
					
						commit
						c3e2b00333
					
				| 
						 | 
				
			
			@ -10,8 +10,8 @@ github.com/containerd/cgroups 7a5fdd8330119dc70d850260db8f3594d89d6943
 | 
			
		|||
github.com/containerd/continuity master
 | 
			
		||||
github.com/containernetworking/cni v0.4.0
 | 
			
		||||
github.com/containernetworking/plugins master
 | 
			
		||||
github.com/containers/image fbc14df0f25a15b456c4f7ec69a1afbb19395544
 | 
			
		||||
github.com/containers/storage ff8a6d2bf496daf46ab1a153f783a0f6b8762a54
 | 
			
		||||
github.com/containers/image 54ea27515e713429b1ae1bf5a63002c15c25a206
 | 
			
		||||
github.com/containers/storage 5d52f079f1709f0408a6c086c603d259b0e5da3e
 | 
			
		||||
github.com/coreos/go-systemd v14
 | 
			
		||||
github.com/cri-o/ocicni master
 | 
			
		||||
github.com/cyphar/filepath-securejoin v0.2.1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,17 +27,24 @@ func newDockerClient(ctx *types.SystemContext) (*dockerclient.Client, error) {
 | 
			
		|||
	// regardless of the values in the *tls.Config), and we would have to call sockets.ConfigureTransport.
 | 
			
		||||
	//
 | 
			
		||||
	// We don't really want to configure anything for unix:// sockets, so just pass a nil *http.Client.
 | 
			
		||||
	//
 | 
			
		||||
	// Similarly, if we want to communicate over plain HTTP on a TCP socket, we also need to set
 | 
			
		||||
	// TLSClientConfig to nil. This can be achieved by using the form `http://`
 | 
			
		||||
	proto, _, _, err := dockerclient.ParseHost(host)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	var httpClient *http.Client
 | 
			
		||||
	if proto != "unix" {
 | 
			
		||||
		hc, err := tlsConfig(ctx)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		if proto == "http" {
 | 
			
		||||
			httpClient = httpConfig()
 | 
			
		||||
		} else {
 | 
			
		||||
			hc, err := tlsConfig(ctx)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			httpClient = hc
 | 
			
		||||
		}
 | 
			
		||||
		httpClient = hc
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return dockerclient.NewClient(host, defaultAPIVersion, httpClient, nil)
 | 
			
		||||
| 
						 | 
				
			
			@ -67,3 +74,12 @@ func tlsConfig(ctx *types.SystemContext) (*http.Client, error) {
 | 
			
		|||
		CheckRedirect: dockerclient.CheckRedirect,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func httpConfig() *http.Client {
 | 
			
		||||
	return &http.Client{
 | 
			
		||||
		Transport: &http.Transport{
 | 
			
		||||
			TLSClientConfig: nil,
 | 
			
		||||
		},
 | 
			
		||||
		CheckRedirect: dockerclient.CheckRedirect,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -544,7 +544,7 @@ func (s *storageImageDestination) Commit() error {
 | 
			
		|||
			return errors.Errorf("error applying blob %q: content not found", blob.Digest)
 | 
			
		||||
		}
 | 
			
		||||
		// Build the new layer using the diff, regardless of where it came from.
 | 
			
		||||
		layer, _, err := s.imageRef.transport.store.PutLayer(id, lastLayer, nil, "", false, diff)
 | 
			
		||||
		layer, _, err := s.imageRef.transport.store.PutLayer(id, lastLayer, nil, "", false, nil, diff)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "error adding layer with blob %q", blob.Digest)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ import (
 | 
			
		|||
	"path/filepath"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/storage/pkg/idtools"
 | 
			
		||||
	"github.com/containers/storage/pkg/ioutils"
 | 
			
		||||
	"github.com/containers/storage/pkg/stringid"
 | 
			
		||||
	"github.com/containers/storage/pkg/truncindex"
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +57,12 @@ type Container struct {
 | 
			
		|||
	// is set before using it.
 | 
			
		||||
	Created time.Time `json:"created,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// UIDMap and GIDMap are used for setting up a container's root
 | 
			
		||||
	// filesystem for use inside of a user namespace where UID mapping is
 | 
			
		||||
	// being used.
 | 
			
		||||
	UIDMap []idtools.IDMap `json:"uidmap,omitempty"`
 | 
			
		||||
	GIDMap []idtools.IDMap `json:"gidmap,omitempty"`
 | 
			
		||||
 | 
			
		||||
	Flags map[string]interface{} `json:"flags,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +77,9 @@ type ContainerStore interface {
 | 
			
		|||
	// random one if an empty value is supplied) and optional names,
 | 
			
		||||
	// based on the specified image, using the specified layer as its
 | 
			
		||||
	// read-write layer.
 | 
			
		||||
	Create(id string, names []string, image, layer, metadata string) (*Container, error)
 | 
			
		||||
	// The maps in the container's options structure are recorded for the
 | 
			
		||||
	// convenience of the caller, nothing more.
 | 
			
		||||
	Create(id string, names []string, image, layer, metadata string, options *ContainerOptions) (*Container, error)
 | 
			
		||||
 | 
			
		||||
	// SetNames updates the list of names associated with the container
 | 
			
		||||
	// with the specified ID.
 | 
			
		||||
| 
						 | 
				
			
			@ -117,6 +126,8 @@ func copyContainer(c *Container) *Container {
 | 
			
		|||
		BigDataSizes:   copyStringInt64Map(c.BigDataSizes),
 | 
			
		||||
		BigDataDigests: copyStringDigestMap(c.BigDataDigests),
 | 
			
		||||
		Created:        c.Created,
 | 
			
		||||
		UIDMap:         copyIDMap(c.UIDMap),
 | 
			
		||||
		GIDMap:         copyIDMap(c.GIDMap),
 | 
			
		||||
		Flags:          copyStringInterfaceMap(c.Flags),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -252,7 +263,7 @@ func (r *containerStore) SetFlag(id string, flag string, value interface{}) erro
 | 
			
		|||
	return r.Save()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *containerStore) Create(id string, names []string, image, layer, metadata string) (container *Container, err error) {
 | 
			
		||||
func (r *containerStore) Create(id string, names []string, image, layer, metadata string, options *ContainerOptions) (container *Container, err error) {
 | 
			
		||||
	if id == "" {
 | 
			
		||||
		id = stringid.GenerateRandomID()
 | 
			
		||||
		_, idInUse := r.byid[id]
 | 
			
		||||
| 
						 | 
				
			
			@ -282,6 +293,8 @@ func (r *containerStore) Create(id string, names []string, image, layer, metadat
 | 
			
		|||
			BigDataDigests: make(map[string]digest.Digest),
 | 
			
		||||
			Created:        time.Now().UTC(),
 | 
			
		||||
			Flags:          make(map[string]interface{}),
 | 
			
		||||
			UIDMap:         copyIDMap(options.UIDMap),
 | 
			
		||||
			GIDMap:         copyIDMap(options.GIDMap),
 | 
			
		||||
		}
 | 
			
		||||
		r.containers = append(r.containers, container)
 | 
			
		||||
		r.byid[id] = container
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
 | 
			
		||||
// source: ./containers.go
 | 
			
		||||
// source: containers.go
 | 
			
		||||
 | 
			
		||||
package storage
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ import (
 | 
			
		|||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/containers/storage/pkg/idtools"
 | 
			
		||||
	"github.com/opencontainers/go-digest"
 | 
			
		||||
	fflib "github.com/pquerna/ffjson/fflib/v1"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -126,6 +127,46 @@ func (j *Container) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
 | 
			
		|||
		}
 | 
			
		||||
		buf.WriteByte(',')
 | 
			
		||||
	}
 | 
			
		||||
	if len(j.UIDMap) != 0 {
 | 
			
		||||
		buf.WriteString(`"uidmap":`)
 | 
			
		||||
		if j.UIDMap != nil {
 | 
			
		||||
			buf.WriteString(`[`)
 | 
			
		||||
			for i, v := range j.UIDMap {
 | 
			
		||||
				if i != 0 {
 | 
			
		||||
					buf.WriteString(`,`)
 | 
			
		||||
				}
 | 
			
		||||
				/* Struct fall back. type=idtools.IDMap kind=struct */
 | 
			
		||||
				err = buf.Encode(&v)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			buf.WriteString(`]`)
 | 
			
		||||
		} else {
 | 
			
		||||
			buf.WriteString(`null`)
 | 
			
		||||
		}
 | 
			
		||||
		buf.WriteByte(',')
 | 
			
		||||
	}
 | 
			
		||||
	if len(j.GIDMap) != 0 {
 | 
			
		||||
		buf.WriteString(`"gidmap":`)
 | 
			
		||||
		if j.GIDMap != nil {
 | 
			
		||||
			buf.WriteString(`[`)
 | 
			
		||||
			for i, v := range j.GIDMap {
 | 
			
		||||
				if i != 0 {
 | 
			
		||||
					buf.WriteString(`,`)
 | 
			
		||||
				}
 | 
			
		||||
				/* Struct fall back. type=idtools.IDMap kind=struct */
 | 
			
		||||
				err = buf.Encode(&v)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			buf.WriteString(`]`)
 | 
			
		||||
		} else {
 | 
			
		||||
			buf.WriteString(`null`)
 | 
			
		||||
		}
 | 
			
		||||
		buf.WriteByte(',')
 | 
			
		||||
	}
 | 
			
		||||
	if len(j.Flags) != 0 {
 | 
			
		||||
		buf.WriteString(`"flags":`)
 | 
			
		||||
		/* Falling back. type=map[string]interface {} kind=map */
 | 
			
		||||
| 
						 | 
				
			
			@ -162,6 +203,10 @@ const (
 | 
			
		|||
 | 
			
		||||
	ffjtContainerCreated
 | 
			
		||||
 | 
			
		||||
	ffjtContainerUIDMap
 | 
			
		||||
 | 
			
		||||
	ffjtContainerGIDMap
 | 
			
		||||
 | 
			
		||||
	ffjtContainerFlags
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -183,6 +228,10 @@ var ffjKeyContainerBigDataDigests = []byte("big-data-digests")
 | 
			
		|||
 | 
			
		||||
var ffjKeyContainerCreated = []byte("created")
 | 
			
		||||
 | 
			
		||||
var ffjKeyContainerUIDMap = []byte("uidmap")
 | 
			
		||||
 | 
			
		||||
var ffjKeyContainerGIDMap = []byte("gidmap")
 | 
			
		||||
 | 
			
		||||
var ffjKeyContainerFlags = []byte("flags")
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON umarshall json - template of ffjson
 | 
			
		||||
| 
						 | 
				
			
			@ -280,6 +329,14 @@ mainparse:
 | 
			
		|||
						goto mainparse
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				case 'g':
 | 
			
		||||
 | 
			
		||||
					if bytes.Equal(ffjKeyContainerGIDMap, kn) {
 | 
			
		||||
						currentKey = ffjtContainerGIDMap
 | 
			
		||||
						state = fflib.FFParse_want_colon
 | 
			
		||||
						goto mainparse
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				case 'i':
 | 
			
		||||
 | 
			
		||||
					if bytes.Equal(ffjKeyContainerID, kn) {
 | 
			
		||||
| 
						 | 
				
			
			@ -317,6 +374,14 @@ mainparse:
 | 
			
		|||
						goto mainparse
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				case 'u':
 | 
			
		||||
 | 
			
		||||
					if bytes.Equal(ffjKeyContainerUIDMap, kn) {
 | 
			
		||||
						currentKey = ffjtContainerUIDMap
 | 
			
		||||
						state = fflib.FFParse_want_colon
 | 
			
		||||
						goto mainparse
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if fflib.EqualFoldRight(ffjKeyContainerFlags, kn) {
 | 
			
		||||
| 
						 | 
				
			
			@ -325,6 +390,18 @@ mainparse:
 | 
			
		|||
					goto mainparse
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if fflib.SimpleLetterEqualFold(ffjKeyContainerGIDMap, kn) {
 | 
			
		||||
					currentKey = ffjtContainerGIDMap
 | 
			
		||||
					state = fflib.FFParse_want_colon
 | 
			
		||||
					goto mainparse
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if fflib.SimpleLetterEqualFold(ffjKeyContainerUIDMap, kn) {
 | 
			
		||||
					currentKey = ffjtContainerUIDMap
 | 
			
		||||
					state = fflib.FFParse_want_colon
 | 
			
		||||
					goto mainparse
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if fflib.SimpleLetterEqualFold(ffjKeyContainerCreated, kn) {
 | 
			
		||||
					currentKey = ffjtContainerCreated
 | 
			
		||||
					state = fflib.FFParse_want_colon
 | 
			
		||||
| 
						 | 
				
			
			@ -423,6 +500,12 @@ mainparse:
 | 
			
		|||
				case ffjtContainerCreated:
 | 
			
		||||
					goto handle_Created
 | 
			
		||||
 | 
			
		||||
				case ffjtContainerUIDMap:
 | 
			
		||||
					goto handle_UIDMap
 | 
			
		||||
 | 
			
		||||
				case ffjtContainerGIDMap:
 | 
			
		||||
					goto handle_GIDMap
 | 
			
		||||
 | 
			
		||||
				case ffjtContainerFlags:
 | 
			
		||||
					goto handle_Flags
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -931,6 +1014,142 @@ handle_Created:
 | 
			
		|||
	state = fflib.FFParse_after_value
 | 
			
		||||
	goto mainparse
 | 
			
		||||
 | 
			
		||||
handle_UIDMap:
 | 
			
		||||
 | 
			
		||||
	/* handler: j.UIDMap type=[]idtools.IDMap kind=slice quoted=false*/
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			if tok != fflib.FFTok_left_brace && tok != fflib.FFTok_null {
 | 
			
		||||
				return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if tok == fflib.FFTok_null {
 | 
			
		||||
			j.UIDMap = nil
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			j.UIDMap = []idtools.IDMap{}
 | 
			
		||||
 | 
			
		||||
			wantVal := true
 | 
			
		||||
 | 
			
		||||
			for {
 | 
			
		||||
 | 
			
		||||
				var tmpJUIDMap idtools.IDMap
 | 
			
		||||
 | 
			
		||||
				tok = fs.Scan()
 | 
			
		||||
				if tok == fflib.FFTok_error {
 | 
			
		||||
					goto tokerror
 | 
			
		||||
				}
 | 
			
		||||
				if tok == fflib.FFTok_right_brace {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if tok == fflib.FFTok_comma {
 | 
			
		||||
					if wantVal == true {
 | 
			
		||||
						// TODO(pquerna): this isn't an ideal error message, this handles
 | 
			
		||||
						// things like [,,,] as an array value.
 | 
			
		||||
						return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
 | 
			
		||||
					}
 | 
			
		||||
					continue
 | 
			
		||||
				} else {
 | 
			
		||||
					wantVal = true
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				/* handler: tmpJUIDMap type=idtools.IDMap kind=struct quoted=false*/
 | 
			
		||||
 | 
			
		||||
				{
 | 
			
		||||
					/* Falling back. type=idtools.IDMap kind=struct */
 | 
			
		||||
					tbuf, err := fs.CaptureField(tok)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fs.WrapErr(err)
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					err = json.Unmarshal(tbuf, &tmpJUIDMap)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fs.WrapErr(err)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				j.UIDMap = append(j.UIDMap, tmpJUIDMap)
 | 
			
		||||
 | 
			
		||||
				wantVal = false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state = fflib.FFParse_after_value
 | 
			
		||||
	goto mainparse
 | 
			
		||||
 | 
			
		||||
handle_GIDMap:
 | 
			
		||||
 | 
			
		||||
	/* handler: j.GIDMap type=[]idtools.IDMap kind=slice quoted=false*/
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			if tok != fflib.FFTok_left_brace && tok != fflib.FFTok_null {
 | 
			
		||||
				return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if tok == fflib.FFTok_null {
 | 
			
		||||
			j.GIDMap = nil
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			j.GIDMap = []idtools.IDMap{}
 | 
			
		||||
 | 
			
		||||
			wantVal := true
 | 
			
		||||
 | 
			
		||||
			for {
 | 
			
		||||
 | 
			
		||||
				var tmpJGIDMap idtools.IDMap
 | 
			
		||||
 | 
			
		||||
				tok = fs.Scan()
 | 
			
		||||
				if tok == fflib.FFTok_error {
 | 
			
		||||
					goto tokerror
 | 
			
		||||
				}
 | 
			
		||||
				if tok == fflib.FFTok_right_brace {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if tok == fflib.FFTok_comma {
 | 
			
		||||
					if wantVal == true {
 | 
			
		||||
						// TODO(pquerna): this isn't an ideal error message, this handles
 | 
			
		||||
						// things like [,,,] as an array value.
 | 
			
		||||
						return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
 | 
			
		||||
					}
 | 
			
		||||
					continue
 | 
			
		||||
				} else {
 | 
			
		||||
					wantVal = true
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				/* handler: tmpJGIDMap type=idtools.IDMap kind=struct quoted=false*/
 | 
			
		||||
 | 
			
		||||
				{
 | 
			
		||||
					/* Falling back. type=idtools.IDMap kind=struct */
 | 
			
		||||
					tbuf, err := fs.CaptureField(tok)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fs.WrapErr(err)
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					err = json.Unmarshal(tbuf, &tmpJGIDMap)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fs.WrapErr(err)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				j.GIDMap = append(j.GIDMap, tmpJGIDMap)
 | 
			
		||||
 | 
			
		||||
				wantVal = false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state = fflib.FFParse_after_value
 | 
			
		||||
	goto mainparse
 | 
			
		||||
 | 
			
		||||
handle_Flags:
 | 
			
		||||
 | 
			
		||||
	/* handler: j.Flags type=map[string]interface {} kind=map quoted=false*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -167,7 +167,7 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	a.naiveDiff = graphdriver.NewNaiveDiffDriver(a, uidMaps, gidMaps)
 | 
			
		||||
	a.naiveDiff = graphdriver.NewNaiveDiffDriver(a, a)
 | 
			
		||||
	return a, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +250,7 @@ func (a *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
 | 
			
		|||
		return fmt.Errorf("--storage-opt is not supported for aufs")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := a.createDirsFor(id); err != nil {
 | 
			
		||||
	if err := a.createDirsFor(id, parent); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// Write the layers metadata
 | 
			
		||||
| 
						 | 
				
			
			@ -281,21 +281,26 @@ func (a *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
 | 
			
		|||
 | 
			
		||||
// createDirsFor creates two directories for the given id.
 | 
			
		||||
// mnt and diff
 | 
			
		||||
func (a *Driver) createDirsFor(id string) error {
 | 
			
		||||
func (a *Driver) createDirsFor(id, parent string) error {
 | 
			
		||||
	paths := []string{
 | 
			
		||||
		"mnt",
 | 
			
		||||
		"diff",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rootUID, rootGID, err := idtools.GetRootUIDGID(a.uidMaps, a.gidMaps)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// Directory permission is 0755.
 | 
			
		||||
	// The path of directories are <aufs_root_path>/mnt/<image_id>
 | 
			
		||||
	// and <aufs_root_path>/diff/<image_id>
 | 
			
		||||
	for _, p := range paths {
 | 
			
		||||
		if err := idtools.MkdirAllAs(path.Join(a.rootPath(), p, id), 0755, rootUID, rootGID); err != nil {
 | 
			
		||||
		rootPair := idtools.NewIDMappingsFromMaps(a.uidMaps, a.gidMaps).RootPair()
 | 
			
		||||
		if parent != "" {
 | 
			
		||||
			st, err := system.Stat(path.Join(a.rootPath(), p, parent))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			rootPair.UID = int(st.UID())
 | 
			
		||||
			rootPair.GID = int(st.GID())
 | 
			
		||||
		}
 | 
			
		||||
		if err := idtools.MkdirAllAndChownNew(path.Join(a.rootPath(), p, id), os.FileMode(0755), rootPair); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -463,17 +468,21 @@ func (a *Driver) isParent(id, parent string) bool {
 | 
			
		|||
 | 
			
		||||
// Diff produces an archive of the changes between the specified
 | 
			
		||||
// layer and its parent layer which may be "".
 | 
			
		||||
func (a *Driver) Diff(id, parent, mountLabel string) (io.ReadCloser, error) {
 | 
			
		||||
func (a *Driver) Diff(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (io.ReadCloser, error) {
 | 
			
		||||
	if !a.isParent(id, parent) {
 | 
			
		||||
		return a.naiveDiff.Diff(id, parent, mountLabel)
 | 
			
		||||
		return a.naiveDiff.Diff(id, idMappings, parent, parentMappings, mountLabel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if idMappings == nil {
 | 
			
		||||
		idMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// AUFS doesn't need the parent layer to produce a diff.
 | 
			
		||||
	return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
 | 
			
		||||
		Compression:     archive.Uncompressed,
 | 
			
		||||
		ExcludePatterns: []string{archive.WhiteoutMetaPrefix + "*", "!" + archive.WhiteoutOpaqueDir},
 | 
			
		||||
		UIDMaps:         a.uidMaps,
 | 
			
		||||
		GIDMaps:         a.gidMaps,
 | 
			
		||||
		UIDMaps:         idMappings.UIDs(),
 | 
			
		||||
		GIDMaps:         idMappings.GIDs(),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -492,19 +501,22 @@ func (a *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
 | 
			
		|||
	return fileGetNilCloser{storage.NewPathFileGetter(p)}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *Driver) applyDiff(id string, diff io.Reader) error {
 | 
			
		||||
func (a *Driver) applyDiff(id string, idMappings *idtools.IDMappings, diff io.Reader) error {
 | 
			
		||||
	if idMappings == nil {
 | 
			
		||||
		idMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	return chrootarchive.UntarUncompressed(diff, path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
 | 
			
		||||
		UIDMaps: a.uidMaps,
 | 
			
		||||
		GIDMaps: a.gidMaps,
 | 
			
		||||
		UIDMaps: idMappings.UIDs(),
 | 
			
		||||
		GIDMaps: idMappings.GIDs(),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DiffSize calculates the changes between the specified id
 | 
			
		||||
// and its parent and returns the size in bytes of the changes
 | 
			
		||||
// relative to its base filesystem directory.
 | 
			
		||||
func (a *Driver) DiffSize(id, parent, mountLabel string) (size int64, err error) {
 | 
			
		||||
func (a *Driver) DiffSize(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (size int64, err error) {
 | 
			
		||||
	if !a.isParent(id, parent) {
 | 
			
		||||
		return a.naiveDiff.DiffSize(id, parent, mountLabel)
 | 
			
		||||
		return a.naiveDiff.DiffSize(id, idMappings, parent, parentMappings, mountLabel)
 | 
			
		||||
	}
 | 
			
		||||
	// AUFS doesn't need the parent layer to calculate the diff size.
 | 
			
		||||
	return directory.Size(path.Join(a.rootPath(), "diff", id))
 | 
			
		||||
| 
						 | 
				
			
			@ -513,24 +525,24 @@ func (a *Driver) DiffSize(id, parent, mountLabel string) (size int64, err error)
 | 
			
		|||
// ApplyDiff extracts the changeset from the given diff into the
 | 
			
		||||
// layer with the specified id and parent, returning the size of the
 | 
			
		||||
// new layer in bytes.
 | 
			
		||||
func (a *Driver) ApplyDiff(id, parent, mountLabel string, diff io.Reader) (size int64, err error) {
 | 
			
		||||
func (a *Driver) ApplyDiff(id string, idMappings *idtools.IDMappings, parent, mountLabel string, diff io.Reader) (size int64, err error) {
 | 
			
		||||
	if !a.isParent(id, parent) {
 | 
			
		||||
		return a.naiveDiff.ApplyDiff(id, parent, mountLabel, diff)
 | 
			
		||||
		return a.naiveDiff.ApplyDiff(id, idMappings, parent, mountLabel, diff)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// AUFS doesn't need the parent id to apply the diff if it is the direct parent.
 | 
			
		||||
	if err = a.applyDiff(id, diff); err != nil {
 | 
			
		||||
	if err = a.applyDiff(id, idMappings, diff); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return a.DiffSize(id, parent, mountLabel)
 | 
			
		||||
	return directory.Size(path.Join(a.rootPath(), "diff", id))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Changes produces a list of changes between the specified layer
 | 
			
		||||
// and its parent layer. If parent is "", then all changes will be ADD changes.
 | 
			
		||||
func (a *Driver) Changes(id, parent, mountLabel string) ([]archive.Change, error) {
 | 
			
		||||
func (a *Driver) Changes(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) ([]archive.Change, error) {
 | 
			
		||||
	if !a.isParent(id, parent) {
 | 
			
		||||
		return a.naiveDiff.Changes(id, parent, mountLabel)
 | 
			
		||||
		return a.naiveDiff.Changes(id, idMappings, parent, parentMappings, mountLabel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// AUFS doesn't have snapshots, so we need to get changes from all parent
 | 
			
		||||
| 
						 | 
				
			
			@ -689,3 +701,9 @@ func useDirperm() bool {
 | 
			
		|||
	})
 | 
			
		||||
	return enableDirperm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateLayerIDMap updates ID mappings in a layer from matching the ones
 | 
			
		||||
// specified by toContainer to those specified by toHost.
 | 
			
		||||
func (a *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMappings, mountLabel string) error {
 | 
			
		||||
	return fmt.Errorf("aufs doesn't support changing ID mappings")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return graphdriver.NewNaiveDiffDriver(driver, uidMaps, gidMaps), nil
 | 
			
		||||
	return graphdriver.NewNaiveDiffDriver(driver, graphdriver.NewNaiveLayerIDMapUpdater(driver)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseOptions(opt []string) (btrfsOptions, bool, error) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,167 @@
 | 
			
		|||
package graphdriver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/storage/pkg/idtools"
 | 
			
		||||
	"github.com/containers/storage/pkg/reexec"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	chownByMapsCmd = "storage-chown-by-maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	reexec.Register(chownByMapsCmd, chownByMapsMain)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func chownByMapsMain() {
 | 
			
		||||
	if len(os.Args) < 2 {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "requires mapping configuration on stdin and directory path")
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
	// Read and decode our configuration.
 | 
			
		||||
	discreteMaps := [4][]idtools.IDMap{}
 | 
			
		||||
	config := bytes.Buffer{}
 | 
			
		||||
	if _, err := config.ReadFrom(os.Stdin); err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "error reading configuration: %v", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
	if err := json.Unmarshal(config.Bytes(), &discreteMaps); err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "error decoding configuration: %v", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
	// Try to chroot.  This may not be possible, and on some systems that
 | 
			
		||||
	// means we just Chdir() to the directory, so from here on we should be
 | 
			
		||||
	// using relative paths.
 | 
			
		||||
	if err := chrootOrChdir(os.Args[1]); err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "error chrooting to %q: %v", os.Args[1], err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
	// Build the mapping objects.
 | 
			
		||||
	toContainer := idtools.NewIDMappingsFromMaps(discreteMaps[0], discreteMaps[1])
 | 
			
		||||
	if len(toContainer.UIDs()) == 0 && len(toContainer.GIDs()) == 0 {
 | 
			
		||||
		toContainer = nil
 | 
			
		||||
	}
 | 
			
		||||
	toHost := idtools.NewIDMappingsFromMaps(discreteMaps[2], discreteMaps[3])
 | 
			
		||||
	if len(toHost.UIDs()) == 0 && len(toHost.GIDs()) == 0 {
 | 
			
		||||
		toHost = nil
 | 
			
		||||
	}
 | 
			
		||||
	chown := func(path string, info os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("error walking to %q: %v", path, err)
 | 
			
		||||
		}
 | 
			
		||||
		sysinfo := info.Sys()
 | 
			
		||||
		if st, ok := sysinfo.(*syscall.Stat_t); ok {
 | 
			
		||||
			// Map an on-disk UID/GID pair from host to container
 | 
			
		||||
			// using the first map, then back to the host using the
 | 
			
		||||
			// second map.  Skip that first step if they're 0, to
 | 
			
		||||
			// compensate for cases where a parent layer should
 | 
			
		||||
			// have had a mapped value, but didn't.
 | 
			
		||||
			uid, gid := int(st.Uid), int(st.Gid)
 | 
			
		||||
			if toContainer != nil {
 | 
			
		||||
				pair := idtools.IDPair{
 | 
			
		||||
					UID: uid,
 | 
			
		||||
					GID: gid,
 | 
			
		||||
				}
 | 
			
		||||
				mappedUid, mappedGid, err := toContainer.ToContainer(pair)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					if (uid != 0) || (gid != 0) {
 | 
			
		||||
						return fmt.Errorf("error mapping host ID pair %#v for %q to container: %v", pair, path, err)
 | 
			
		||||
					}
 | 
			
		||||
					mappedUid, mappedGid = uid, gid
 | 
			
		||||
				}
 | 
			
		||||
				uid, gid = mappedUid, mappedGid
 | 
			
		||||
			}
 | 
			
		||||
			if toHost != nil {
 | 
			
		||||
				pair := idtools.IDPair{
 | 
			
		||||
					UID: uid,
 | 
			
		||||
					GID: gid,
 | 
			
		||||
				}
 | 
			
		||||
				mappedPair, err := toHost.ToHost(pair)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return fmt.Errorf("error mapping container ID pair %#v for %q to host: %v", pair, path, err)
 | 
			
		||||
				}
 | 
			
		||||
				uid, gid = mappedPair.UID, mappedPair.GID
 | 
			
		||||
			}
 | 
			
		||||
			if uid != int(st.Uid) || gid != int(st.Gid) {
 | 
			
		||||
				// Make the change.
 | 
			
		||||
				if err := syscall.Lchown(path, uid, gid); err != nil {
 | 
			
		||||
					return fmt.Errorf("%s: chown(%q): %v", os.Args[0], path, err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if err := filepath.Walk(".", chown); err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "error during chown: %v", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
	os.Exit(0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChownPathByMaps walks the filesystem tree, changing the ownership
 | 
			
		||||
// information using the toContainer and toHost mappings, using them to replace
 | 
			
		||||
// on-disk owner UIDs and GIDs which are "host" values in the first map with
 | 
			
		||||
// UIDs and GIDs for "host" values from the second map which correspond to the
 | 
			
		||||
// same "container" IDs.
 | 
			
		||||
func ChownPathByMaps(path string, toContainer, toHost *idtools.IDMappings) error {
 | 
			
		||||
	if toContainer == nil {
 | 
			
		||||
		toContainer = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	if toHost == nil {
 | 
			
		||||
		toHost = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config, err := json.Marshal([4][]idtools.IDMap{toContainer.UIDs(), toContainer.GIDs(), toHost.UIDs(), toHost.GIDs()})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	cmd := reexec.Command(chownByMapsCmd, path)
 | 
			
		||||
	cmd.Stdin = bytes.NewReader(config)
 | 
			
		||||
	output, err := cmd.CombinedOutput()
 | 
			
		||||
	if len(output) > 0 && err != nil {
 | 
			
		||||
		return fmt.Errorf("%v: %s", err, string(output))
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if len(output) > 0 {
 | 
			
		||||
		return fmt.Errorf("%s", string(output))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type naiveLayerIDMapUpdater struct {
 | 
			
		||||
	ProtoDriver
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewNaiveLayerIDMapUpdater wraps the ProtoDriver in a LayerIDMapUpdater that
 | 
			
		||||
// uses ChownPathByMaps to update the ownerships in a layer's filesystem tree.
 | 
			
		||||
func NewNaiveLayerIDMapUpdater(driver ProtoDriver) LayerIDMapUpdater {
 | 
			
		||||
	return &naiveLayerIDMapUpdater{ProtoDriver: driver}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateLayerIDMap walks the layer's filesystem tree, changing the ownership
 | 
			
		||||
// information using the toContainer and toHost mappings, using them to replace
 | 
			
		||||
// on-disk owner UIDs and GIDs which are "host" values in the first map with
 | 
			
		||||
// UIDs and GIDs for "host" values from the second map which correspond to the
 | 
			
		||||
// same "container" IDs.
 | 
			
		||||
func (n *naiveLayerIDMapUpdater) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMappings, mountLabel string) error {
 | 
			
		||||
	driver := n.ProtoDriver
 | 
			
		||||
	layerFs, err := driver.Get(id, mountLabel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		driver.Put(id)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	return ChownPathByMaps(layerFs, toContainer, toHost)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
// +build linux darwin freebsd solaris
 | 
			
		||||
 | 
			
		||||
package graphdriver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// chrootOrChdir() is either a chdir() to the specified path, or a chroot() to the
 | 
			
		||||
// specified path followed by chdir() to the new root directory
 | 
			
		||||
func chrootOrChdir(path string) error {
 | 
			
		||||
	if err := syscall.Chroot(path); err != nil {
 | 
			
		||||
		return fmt.Errorf("error chrooting to %q: %v", path, err)
 | 
			
		||||
	}
 | 
			
		||||
	if err := syscall.Chdir(string(os.PathSeparator)); err != nil {
 | 
			
		||||
		return fmt.Errorf("error changing to %q: %v", path, err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
package graphdriver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// chrootOrChdir() is either a chdir() to the specified path, or a chroot() to the
 | 
			
		||||
// specified path followed by chdir() to the new root directory
 | 
			
		||||
func chrootOrChdir(path string) error {
 | 
			
		||||
	if err := syscall.Chdir(path); err != nil {
 | 
			
		||||
		return fmt.Errorf("error changing to %q: %v", path, err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
 | 
			
		|||
		locker:    locker.New(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil
 | 
			
		||||
	return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Driver) String() string {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,25 +92,39 @@ type ProtoDriver interface {
 | 
			
		|||
type DiffDriver interface {
 | 
			
		||||
	// Diff produces an archive of the changes between the specified
 | 
			
		||||
	// layer and its parent layer which may be "".
 | 
			
		||||
	Diff(id, parent, mountLabel string) (io.ReadCloser, error)
 | 
			
		||||
	Diff(id string, idMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, mountLabel string) (io.ReadCloser, error)
 | 
			
		||||
	// Changes produces a list of changes between the specified layer
 | 
			
		||||
	// and its parent layer. If parent is "", then all changes will be ADD changes.
 | 
			
		||||
	Changes(id, parent, mountLabel string) ([]archive.Change, error)
 | 
			
		||||
	Changes(id string, idMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, mountLabel string) ([]archive.Change, error)
 | 
			
		||||
	// ApplyDiff extracts the changeset from the given diff into the
 | 
			
		||||
	// layer with the specified id and parent, returning the size of the
 | 
			
		||||
	// new layer in bytes.
 | 
			
		||||
	// The io.Reader must be an uncompressed stream.
 | 
			
		||||
	ApplyDiff(id, parent, mountLabel string, diff io.Reader) (size int64, err error)
 | 
			
		||||
	ApplyDiff(id string, idMappings *idtools.IDMappings, parent string, mountLabel string, diff io.Reader) (size int64, err error)
 | 
			
		||||
	// DiffSize calculates the changes between the specified id
 | 
			
		||||
	// and its parent and returns the size in bytes of the changes
 | 
			
		||||
	// relative to its base filesystem directory.
 | 
			
		||||
	DiffSize(id, parent, mountLabel string) (size int64, err error)
 | 
			
		||||
	DiffSize(id string, idMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, mountLabel string) (size int64, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LayerIDMapUpdater is the interface that implements ID map changes for layers.
 | 
			
		||||
type LayerIDMapUpdater interface {
 | 
			
		||||
	// UpdateLayerIDMap walks the layer's filesystem tree, changing the ownership
 | 
			
		||||
	// information using the toContainer and toHost mappings, using them to replace
 | 
			
		||||
	// on-disk owner UIDs and GIDs which are "host" values in the first map with
 | 
			
		||||
	// UIDs and GIDs for "host" values from the second map which correspond to the
 | 
			
		||||
	// same "container" IDs.  This method should only be called after a layer is
 | 
			
		||||
	// first created and populated, and before it is mounted, as other changes made
 | 
			
		||||
	// relative to a parent layer, but before this method is called, may be discarded
 | 
			
		||||
	// by Diff().
 | 
			
		||||
	UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMappings, mountLabel string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Driver is the interface for layered/snapshot file system drivers.
 | 
			
		||||
type Driver interface {
 | 
			
		||||
	ProtoDriver
 | 
			
		||||
	DiffDriver
 | 
			
		||||
	LayerIDMapUpdater
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Capabilities defines a list of capabilities a driver may implement.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,29 +24,33 @@ var (
 | 
			
		|||
// Notably, the AUFS driver doesn't need to be wrapped like this.
 | 
			
		||||
type NaiveDiffDriver struct {
 | 
			
		||||
	ProtoDriver
 | 
			
		||||
	uidMaps []idtools.IDMap
 | 
			
		||||
	gidMaps []idtools.IDMap
 | 
			
		||||
	LayerIDMapUpdater
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewNaiveDiffDriver returns a fully functional driver that wraps the
 | 
			
		||||
// given ProtoDriver and adds the capability of the following methods which
 | 
			
		||||
// it may or may not support on its own:
 | 
			
		||||
//     Diff(id, parent, mountLabel string) (io.ReadCloser, error)
 | 
			
		||||
//     Changes(id, parent, mountLabel string) ([]archive.Change, error)
 | 
			
		||||
//     ApplyDiff(id, parent, mountLabel string, diff io.Reader) (size int64, err error)
 | 
			
		||||
//     DiffSize(id, parent, mountLabel string) (size int64, err error)
 | 
			
		||||
func NewNaiveDiffDriver(driver ProtoDriver, uidMaps, gidMaps []idtools.IDMap) Driver {
 | 
			
		||||
	return &NaiveDiffDriver{ProtoDriver: driver,
 | 
			
		||||
		uidMaps: uidMaps,
 | 
			
		||||
		gidMaps: gidMaps}
 | 
			
		||||
//     Diff(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (io.ReadCloser, error)
 | 
			
		||||
//     Changes(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) ([]archive.Change, error)
 | 
			
		||||
//     ApplyDiff(id string, idMappings *idtools.IDMappings, parent, mountLabel string, diff io.Reader) (size int64, err error)
 | 
			
		||||
//     DiffSize(id string, idMappings *idtools.IDMappings, parent, parentMappings *idtools.IDMappings, mountLabel string) (size int64, err error)
 | 
			
		||||
func NewNaiveDiffDriver(driver ProtoDriver, updater LayerIDMapUpdater) Driver {
 | 
			
		||||
	return &NaiveDiffDriver{ProtoDriver: driver, LayerIDMapUpdater: updater}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Diff produces an archive of the changes between the specified
 | 
			
		||||
// layer and its parent layer which may be "".
 | 
			
		||||
func (gdw *NaiveDiffDriver) Diff(id, parent, mountLabel string) (arch io.ReadCloser, err error) {
 | 
			
		||||
func (gdw *NaiveDiffDriver) Diff(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (arch io.ReadCloser, err error) {
 | 
			
		||||
	startTime := time.Now()
 | 
			
		||||
	driver := gdw.ProtoDriver
 | 
			
		||||
 | 
			
		||||
	if idMappings == nil {
 | 
			
		||||
		idMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	if parentMappings == nil {
 | 
			
		||||
		parentMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	layerFs, err := driver.Get(id, mountLabel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +63,11 @@ func (gdw *NaiveDiffDriver) Diff(id, parent, mountLabel string) (arch io.ReadClo
 | 
			
		|||
	}()
 | 
			
		||||
 | 
			
		||||
	if parent == "" {
 | 
			
		||||
		archive, err := archive.Tar(layerFs, archive.Uncompressed)
 | 
			
		||||
		archive, err := archive.TarWithOptions(layerFs, &archive.TarOptions{
 | 
			
		||||
			Compression: archive.Uncompressed,
 | 
			
		||||
			UIDMaps:     idMappings.UIDs(),
 | 
			
		||||
			GIDMaps:     idMappings.GIDs(),
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -76,12 +84,12 @@ func (gdw *NaiveDiffDriver) Diff(id, parent, mountLabel string) (arch io.ReadClo
 | 
			
		|||
	}
 | 
			
		||||
	defer driver.Put(parent)
 | 
			
		||||
 | 
			
		||||
	changes, err := archive.ChangesDirs(layerFs, parentFs)
 | 
			
		||||
	changes, err := archive.ChangesDirs(layerFs, idMappings, parentFs, parentMappings)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	archive, err := archive.ExportChanges(layerFs, changes, gdw.uidMaps, gdw.gidMaps)
 | 
			
		||||
	archive, err := archive.ExportChanges(layerFs, changes, idMappings.UIDs(), idMappings.GIDs())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -101,9 +109,16 @@ func (gdw *NaiveDiffDriver) Diff(id, parent, mountLabel string) (arch io.ReadClo
 | 
			
		|||
 | 
			
		||||
// Changes produces a list of changes between the specified layer
 | 
			
		||||
// and its parent layer. If parent is "", then all changes will be ADD changes.
 | 
			
		||||
func (gdw *NaiveDiffDriver) Changes(id, parent, mountLabel string) ([]archive.Change, error) {
 | 
			
		||||
func (gdw *NaiveDiffDriver) Changes(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) ([]archive.Change, error) {
 | 
			
		||||
	driver := gdw.ProtoDriver
 | 
			
		||||
 | 
			
		||||
	if idMappings == nil {
 | 
			
		||||
		idMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	if parentMappings == nil {
 | 
			
		||||
		parentMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	layerFs, err := driver.Get(id, mountLabel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -120,15 +135,19 @@ func (gdw *NaiveDiffDriver) Changes(id, parent, mountLabel string) ([]archive.Ch
 | 
			
		|||
		defer driver.Put(parent)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return archive.ChangesDirs(layerFs, parentFs)
 | 
			
		||||
	return archive.ChangesDirs(layerFs, idMappings, parentFs, parentMappings)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplyDiff extracts the changeset from the given diff into the
 | 
			
		||||
// layer with the specified id and parent, returning the size of the
 | 
			
		||||
// new layer in bytes.
 | 
			
		||||
func (gdw *NaiveDiffDriver) ApplyDiff(id, parent, mountLabel string, diff io.Reader) (size int64, err error) {
 | 
			
		||||
func (gdw *NaiveDiffDriver) ApplyDiff(id string, applyMappings *idtools.IDMappings, parent, mountLabel string, diff io.Reader) (size int64, err error) {
 | 
			
		||||
	driver := gdw.ProtoDriver
 | 
			
		||||
 | 
			
		||||
	if applyMappings == nil {
 | 
			
		||||
		applyMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Mount the root filesystem so we can apply the diff/layer.
 | 
			
		||||
	layerFs, err := driver.Get(id, mountLabel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -136,8 +155,11 @@ func (gdw *NaiveDiffDriver) ApplyDiff(id, parent, mountLabel string, diff io.Rea
 | 
			
		|||
	}
 | 
			
		||||
	defer driver.Put(id)
 | 
			
		||||
 | 
			
		||||
	options := &archive.TarOptions{UIDMaps: gdw.uidMaps,
 | 
			
		||||
		GIDMaps: gdw.gidMaps}
 | 
			
		||||
	options := &archive.TarOptions{}
 | 
			
		||||
	if applyMappings != nil {
 | 
			
		||||
		options.UIDMaps = applyMappings.UIDs()
 | 
			
		||||
		options.GIDMaps = applyMappings.GIDs()
 | 
			
		||||
	}
 | 
			
		||||
	start := time.Now().UTC()
 | 
			
		||||
	logrus.Debug("Start untar layer")
 | 
			
		||||
	if size, err = ApplyUncompressedLayer(layerFs, diff, options); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -151,10 +173,17 @@ func (gdw *NaiveDiffDriver) ApplyDiff(id, parent, mountLabel string, diff io.Rea
 | 
			
		|||
// DiffSize calculates the changes between the specified layer
 | 
			
		||||
// and its parent and returns the size in bytes of the changes
 | 
			
		||||
// relative to its base filesystem directory.
 | 
			
		||||
func (gdw *NaiveDiffDriver) DiffSize(id, parent, mountLabel string) (size int64, err error) {
 | 
			
		||||
func (gdw *NaiveDiffDriver) DiffSize(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (size int64, err error) {
 | 
			
		||||
	driver := gdw.ProtoDriver
 | 
			
		||||
 | 
			
		||||
	changes, err := gdw.Changes(id, parent, mountLabel)
 | 
			
		||||
	if idMappings == nil {
 | 
			
		||||
		idMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	if parentMappings == nil {
 | 
			
		||||
		parentMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	changes, err := gdw.Changes(id, idMappings, parent, parentMappings, mountLabel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,7 +169,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
 | 
			
		|||
		options:       *opts,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps)
 | 
			
		||||
	d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, d)
 | 
			
		||||
 | 
			
		||||
	if backingFs == "xfs" {
 | 
			
		||||
		// Try to enable project quota support over xfs.
 | 
			
		||||
| 
						 | 
				
			
			@ -267,16 +267,22 @@ func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGI
 | 
			
		|||
		_ = idtools.MkdirAs(lower2Dir, 0700, rootUID, rootGID)
 | 
			
		||||
		flags := fmt.Sprintf("lowerdir=%s:%s", lower1Dir, lower2Dir)
 | 
			
		||||
		if len(flags) < unix.Getpagesize() {
 | 
			
		||||
			if mountFrom(filepath.Dir(home), "overlay", mergedDir, "overlay", 0, flags) == nil {
 | 
			
		||||
			err := mountFrom(filepath.Dir(home), "overlay", mergedDir, "overlay", 0, flags)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				logrus.Debugf("overlay test mount with multiple lowers succeeded")
 | 
			
		||||
				return supportsDType, nil
 | 
			
		||||
			} else {
 | 
			
		||||
				logrus.Debugf("overlay test mount with multiple lowers failed %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		flags = fmt.Sprintf("lowerdir=%s", lower1Dir)
 | 
			
		||||
		if len(flags) < unix.Getpagesize() {
 | 
			
		||||
			if mountFrom(filepath.Dir(home), "overlay", mergedDir, "overlay", 0, flags) == nil {
 | 
			
		||||
			err := mountFrom(filepath.Dir(home), "overlay", mergedDir, "overlay", 0, flags)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				logrus.Errorf("overlay test mount with multiple lowers failed, but succeeded with a single lower")
 | 
			
		||||
				return supportsDType, errors.Wrap(graphdriver.ErrNotSupported, "kernel too old to provide multiple lowers feature for overlay")
 | 
			
		||||
			} else {
 | 
			
		||||
				logrus.Debugf("overlay test mount with a single lower failed %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		logrus.Errorf("'overlay' is not supported over %s at %q", backingFs, home)
 | 
			
		||||
| 
						 | 
				
			
			@ -387,6 +393,14 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
 | 
			
		|||
	if err := idtools.MkdirAllAs(path.Dir(dir), 0700, rootUID, rootGID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if parent != "" {
 | 
			
		||||
		st, err := system.Stat(d.dir(parent))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		rootUID = int(st.UID())
 | 
			
		||||
		rootGID = int(st.GID())
 | 
			
		||||
	}
 | 
			
		||||
	if err := idtools.MkdirAs(dir, 0700, rootUID, rootGID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -562,8 +576,32 @@ func (d *Driver) Get(id, mountLabel string) (_ string, retErr error) {
 | 
			
		|||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newlowers := ""
 | 
			
		||||
	// absLowers is the list of lowers as absolute paths, which works well with additional stores.
 | 
			
		||||
	absLowers := []string{}
 | 
			
		||||
	// relLowers is the list of lowers as paths relative to the driver's home directory.
 | 
			
		||||
	relLowers := []string{}
 | 
			
		||||
 | 
			
		||||
	// Check if $link/../diff{1-*} exist.  If they do, add them, in order, as the front of the lowers
 | 
			
		||||
	// lists that we're building.  "diff" itself is the upper, so it won't be in the lists.
 | 
			
		||||
	link, err := ioutil.ReadFile(path.Join(dir, "link"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	diffN := 1
 | 
			
		||||
	_, err = os.Stat(filepath.Join(dir, nameWithSuffix("diff", diffN)))
 | 
			
		||||
	for err == nil {
 | 
			
		||||
		absLowers = append(absLowers, filepath.Join(dir, nameWithSuffix("diff", diffN)))
 | 
			
		||||
		relLowers = append(relLowers, dumbJoin(string(link), "..", nameWithSuffix("diff", diffN)))
 | 
			
		||||
		diffN++
 | 
			
		||||
		_, err = os.Stat(filepath.Join(dir, nameWithSuffix("diff", diffN)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// For each lower, resolve its path, and append it and any additional diffN
 | 
			
		||||
	// directories to the lowers list.
 | 
			
		||||
	for _, l := range strings.Split(string(lowers), ":") {
 | 
			
		||||
		if l == "" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		lower := ""
 | 
			
		||||
		newpath := path.Join(d.home, l)
 | 
			
		||||
		if _, err := os.Stat(newpath); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -580,15 +618,23 @@ func (d *Driver) Get(id, mountLabel string) (_ string, retErr error) {
 | 
			
		|||
		} else {
 | 
			
		||||
			lower = newpath
 | 
			
		||||
		}
 | 
			
		||||
		if newlowers == "" {
 | 
			
		||||
			newlowers = lower
 | 
			
		||||
		} else {
 | 
			
		||||
			newlowers = newlowers + ":" + lower
 | 
			
		||||
		absLowers = append(absLowers, lower)
 | 
			
		||||
		relLowers = append(relLowers, l)
 | 
			
		||||
		diffN = 1
 | 
			
		||||
		_, err = os.Stat(dumbJoin(lower, "..", nameWithSuffix("diff", diffN)))
 | 
			
		||||
		for err == nil {
 | 
			
		||||
			absLowers = append(absLowers, dumbJoin(lower, "..", nameWithSuffix("diff", diffN)))
 | 
			
		||||
			relLowers = append(relLowers, dumbJoin(l, "..", nameWithSuffix("diff", diffN)))
 | 
			
		||||
			diffN++
 | 
			
		||||
			_, err = os.Stat(dumbJoin(lower, "..", nameWithSuffix("diff", diffN)))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(lowers) == 0 {
 | 
			
		||||
		newlowers = path.Join(dir, "empty")
 | 
			
		||||
		lowers = []byte(newlowers)
 | 
			
		||||
 | 
			
		||||
	// If the lowers list is still empty, use an empty lower so that we can still force an
 | 
			
		||||
	// SELinux context for the mount.
 | 
			
		||||
	if len(absLowers) == 0 {
 | 
			
		||||
		absLowers = append(absLowers, path.Join(dir, "empty"))
 | 
			
		||||
		relLowers = append(relLowers, path.Join(id, "empty"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mergedDir := path.Join(dir, "merged")
 | 
			
		||||
| 
						 | 
				
			
			@ -606,7 +652,7 @@ func (d *Driver) Get(id, mountLabel string) (_ string, retErr error) {
 | 
			
		|||
	}()
 | 
			
		||||
 | 
			
		||||
	workDir := path.Join(dir, "work")
 | 
			
		||||
	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", newlowers, diffDir, workDir)
 | 
			
		||||
	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), diffDir, workDir)
 | 
			
		||||
	mountData := label.FormatMountLabel(opts, mountLabel)
 | 
			
		||||
	mount := unix.Mount
 | 
			
		||||
	mountTarget := mergedDir
 | 
			
		||||
| 
						 | 
				
			
			@ -619,7 +665,7 @@ func (d *Driver) Get(id, mountLabel string) (_ string, retErr error) {
 | 
			
		|||
	// smaller at the expense of requiring a fork exec to chroot.
 | 
			
		||||
	if len(mountData) > pageSize {
 | 
			
		||||
		//FIXME: We need to figure out to get this to work with additional stores
 | 
			
		||||
		opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work"))
 | 
			
		||||
		opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(relLowers, ":"), path.Join(id, "diff"), path.Join(id, "work"))
 | 
			
		||||
		mountData = label.FormatMountLabel(opts, mountLabel)
 | 
			
		||||
		if len(mountData) > pageSize {
 | 
			
		||||
			return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData))
 | 
			
		||||
| 
						 | 
				
			
			@ -697,9 +743,13 @@ func (d *Driver) isParent(id, parent string) bool {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// ApplyDiff applies the new layer into a root
 | 
			
		||||
func (d *Driver) ApplyDiff(id, parent, mountLabel string, diff io.Reader) (size int64, err error) {
 | 
			
		||||
func (d *Driver) ApplyDiff(id string, idMappings *idtools.IDMappings, parent string, mountLabel string, diff io.Reader) (size int64, err error) {
 | 
			
		||||
	if !d.isParent(id, parent) {
 | 
			
		||||
		return d.naiveDiff.ApplyDiff(id, parent, mountLabel, diff)
 | 
			
		||||
		return d.naiveDiff.ApplyDiff(id, idMappings, parent, mountLabel, diff)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if idMappings == nil {
 | 
			
		||||
		idMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	applyDir := d.getDiffPath(id)
 | 
			
		||||
| 
						 | 
				
			
			@ -707,8 +757,8 @@ func (d *Driver) ApplyDiff(id, parent, mountLabel string, diff io.Reader) (size
 | 
			
		|||
	logrus.Debugf("Applying tar in %s", applyDir)
 | 
			
		||||
	// Overlay doesn't need the parent id to apply the diff
 | 
			
		||||
	if err := untar(diff, applyDir, &archive.TarOptions{
 | 
			
		||||
		UIDMaps:        d.uidMaps,
 | 
			
		||||
		GIDMaps:        d.gidMaps,
 | 
			
		||||
		UIDMaps:        idMappings.UIDs(),
 | 
			
		||||
		GIDMaps:        idMappings.GIDs(),
 | 
			
		||||
		WhiteoutFormat: archive.OverlayWhiteoutFormat,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
| 
						 | 
				
			
			@ -726,18 +776,22 @@ func (d *Driver) getDiffPath(id string) string {
 | 
			
		|||
// DiffSize calculates the changes between the specified id
 | 
			
		||||
// and its parent and returns the size in bytes of the changes
 | 
			
		||||
// relative to its base filesystem directory.
 | 
			
		||||
func (d *Driver) DiffSize(id, parent, mountLabel string) (size int64, err error) {
 | 
			
		||||
func (d *Driver) DiffSize(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (size int64, err error) {
 | 
			
		||||
	if useNaiveDiff(d.home) || !d.isParent(id, parent) {
 | 
			
		||||
		return d.naiveDiff.DiffSize(id, parent, mountLabel)
 | 
			
		||||
		return d.naiveDiff.DiffSize(id, idMappings, parent, parentMappings, mountLabel)
 | 
			
		||||
	}
 | 
			
		||||
	return directory.Size(d.getDiffPath(id))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Diff produces an archive of the changes between the specified
 | 
			
		||||
// layer and its parent layer which may be "".
 | 
			
		||||
func (d *Driver) Diff(id, parent, mountLabel string) (io.ReadCloser, error) {
 | 
			
		||||
func (d *Driver) Diff(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (io.ReadCloser, error) {
 | 
			
		||||
	if useNaiveDiff(d.home) || !d.isParent(id, parent) {
 | 
			
		||||
		return d.naiveDiff.Diff(id, parent, mountLabel)
 | 
			
		||||
		return d.naiveDiff.Diff(id, idMappings, parent, parentMappings, mountLabel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if idMappings == nil {
 | 
			
		||||
		idMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lowerDirs, err := d.getLowerDirs(id)
 | 
			
		||||
| 
						 | 
				
			
			@ -749,8 +803,8 @@ func (d *Driver) Diff(id, parent, mountLabel string) (io.ReadCloser, error) {
 | 
			
		|||
	logrus.Debugf("Tar with options on %s", diffPath)
 | 
			
		||||
	return archive.TarWithOptions(diffPath, &archive.TarOptions{
 | 
			
		||||
		Compression:    archive.Uncompressed,
 | 
			
		||||
		UIDMaps:        d.uidMaps,
 | 
			
		||||
		GIDMaps:        d.gidMaps,
 | 
			
		||||
		UIDMaps:        idMappings.UIDs(),
 | 
			
		||||
		GIDMaps:        idMappings.GIDs(),
 | 
			
		||||
		WhiteoutFormat: archive.OverlayWhiteoutFormat,
 | 
			
		||||
		WhiteoutData:   lowerDirs,
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			@ -758,9 +812,9 @@ func (d *Driver) Diff(id, parent, mountLabel string) (io.ReadCloser, error) {
 | 
			
		|||
 | 
			
		||||
// Changes produces a list of changes between the specified layer
 | 
			
		||||
// and its parent layer. If parent is "", then all changes will be ADD changes.
 | 
			
		||||
func (d *Driver) Changes(id, parent, mountLabel string) ([]archive.Change, error) {
 | 
			
		||||
func (d *Driver) Changes(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) ([]archive.Change, error) {
 | 
			
		||||
	if useNaiveDiff(d.home) || !d.isParent(id, parent) {
 | 
			
		||||
		return d.naiveDiff.Changes(id, parent, mountLabel)
 | 
			
		||||
		return d.naiveDiff.Changes(id, idMappings, parent, parentMappings, mountLabel)
 | 
			
		||||
	}
 | 
			
		||||
	// Overlay doesn't have snapshots, so we need to get changes from all parent
 | 
			
		||||
	// layers.
 | 
			
		||||
| 
						 | 
				
			
			@ -777,3 +831,73 @@ func (d *Driver) Changes(id, parent, mountLabel string) ([]archive.Change, error
 | 
			
		|||
func (d *Driver) AdditionalImageStores() []string {
 | 
			
		||||
	return d.options.imageStores
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateLayerIDMap updates ID mappings in a from matching the ones specified
 | 
			
		||||
// by toContainer to those specified by toHost.
 | 
			
		||||
func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMappings, mountLabel string) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	dir := d.dir(id)
 | 
			
		||||
	diffDir := filepath.Join(dir, "diff")
 | 
			
		||||
 | 
			
		||||
	rootUID, rootGID := 0, 0
 | 
			
		||||
	if toHost != nil {
 | 
			
		||||
		rootUID, rootGID, err = idtools.GetRootUIDGID(toHost.UIDs(), toHost.GIDs())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Mount the new layer and handle ownership changes and possible copy_ups in it.
 | 
			
		||||
	layerFs, err := d.Get(id, mountLabel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = graphdriver.ChownPathByMaps(layerFs, toContainer, toHost)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err2 := d.Put(id); err2 != nil {
 | 
			
		||||
			logrus.Errorf("%v; error unmounting %v: %v", err, id, err2)
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err = d.Put(id); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Rotate the diff directories.
 | 
			
		||||
	i := 0
 | 
			
		||||
	_, err = os.Stat(nameWithSuffix(diffDir, i))
 | 
			
		||||
	for err == nil {
 | 
			
		||||
		i++
 | 
			
		||||
		_, err = os.Stat(nameWithSuffix(diffDir, i))
 | 
			
		||||
	}
 | 
			
		||||
	for i > 0 {
 | 
			
		||||
		err = os.Rename(nameWithSuffix(diffDir, i-1), nameWithSuffix(diffDir, i))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		i--
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Re-create the directory that we're going to use as the upper layer.
 | 
			
		||||
	if err := idtools.MkdirAs(diffDir, 0755, rootUID, rootGID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// dumbJoin is more or less a dumber version of filepath.Join, but one which
 | 
			
		||||
// won't Clean() the path, allowing us to append ".." as a component and trust
 | 
			
		||||
// pathname resolution to do some non-obvious work.
 | 
			
		||||
func dumbJoin(names ...string) string {
 | 
			
		||||
	if len(names) == 0 {
 | 
			
		||||
		return string(os.PathSeparator)
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Join(names, string(os.PathSeparator))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func nameWithSuffix(name string, number int) string {
 | 
			
		||||
	if number == 0 {
 | 
			
		||||
		return name
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%s%d", name, number)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
 | 
			
		|||
			continue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil
 | 
			
		||||
	return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Driver holds information about the driver, home directory of the driver.
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +91,14 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
 | 
			
		|||
	if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0700, rootIDs); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if parent != "" {
 | 
			
		||||
		st, err := system.Stat(d.dir(parent))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		rootIDs.UID = int(st.UID())
 | 
			
		||||
		rootIDs.GID = int(st.GID())
 | 
			
		||||
	}
 | 
			
		||||
	if err := idtools.MkdirAndChown(dir, 0755, rootIDs); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -472,7 +472,7 @@ func (d *Driver) Cleanup() error {
 | 
			
		|||
// Diff produces an archive of the changes between the specified
 | 
			
		||||
// layer and its parent layer which may be "".
 | 
			
		||||
// The layer should be mounted when calling this function
 | 
			
		||||
func (d *Driver) Diff(id, parent, mountLabel string) (_ io.ReadCloser, err error) {
 | 
			
		||||
func (d *Driver) Diff(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (_ io.ReadCloser, err error) {
 | 
			
		||||
	panicIfUsedByLcow()
 | 
			
		||||
	rID, err := d.resolveID(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -509,7 +509,7 @@ func (d *Driver) Diff(id, parent, mountLabel string) (_ io.ReadCloser, err error
 | 
			
		|||
// Changes produces a list of changes between the specified layer
 | 
			
		||||
// and its parent layer. If parent is "", then all changes will be ADD changes.
 | 
			
		||||
// The layer should not be mounted when calling this function.
 | 
			
		||||
func (d *Driver) Changes(id, parent, mountLabel string) ([]archive.Change, error) {
 | 
			
		||||
func (d *Driver) Changes(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) ([]archive.Change, error) {
 | 
			
		||||
	panicIfUsedByLcow()
 | 
			
		||||
	rID, err := d.resolveID(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -565,7 +565,7 @@ func (d *Driver) Changes(id, parent, mountLabel string) ([]archive.Change, error
 | 
			
		|||
// layer with the specified id and parent, returning the size of the
 | 
			
		||||
// new layer in bytes.
 | 
			
		||||
// The layer should not be mounted when calling this function
 | 
			
		||||
func (d *Driver) ApplyDiff(id, parent, mountLabel string, diff io.Reader) (int64, error) {
 | 
			
		||||
func (d *Driver) ApplyDiff(id string, idMappings *idtools.IDMappings, parent, mountLabel string, diff io.Reader) (int64, error) {
 | 
			
		||||
	panicIfUsedByLcow()
 | 
			
		||||
	var layerChain []string
 | 
			
		||||
	if parent != "" {
 | 
			
		||||
| 
						 | 
				
			
			@ -600,14 +600,14 @@ func (d *Driver) ApplyDiff(id, parent, mountLabel string, diff io.Reader) (int64
 | 
			
		|||
// DiffSize calculates the changes between the specified layer
 | 
			
		||||
// and its parent and returns the size in bytes of the changes
 | 
			
		||||
// relative to its base filesystem directory.
 | 
			
		||||
func (d *Driver) DiffSize(id, parent, mountLabel string) (size int64, err error) {
 | 
			
		||||
func (d *Driver) DiffSize(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (size int64, err error) {
 | 
			
		||||
	panicIfUsedByLcow()
 | 
			
		||||
	rPId, err := d.resolveID(parent)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	changes, err := d.Changes(id, rPId, mountLabel)
 | 
			
		||||
	changes, err := d.Changes(id, idMappings, rPId, parentMappings, mountLabel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -940,6 +940,17 @@ func (d *Driver) AdditionalImageStores() []string {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AdditionalImageStores returns additional image stores supported by the driver
 | 
			
		||||
func (d *Driver) AdditionalImageStores() []string {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateLayerIDMap changes ownerships in the layer's filesystem tree from
 | 
			
		||||
// matching those in toContainer to matching those in toHost.
 | 
			
		||||
func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMappings, mountLabel string) error {
 | 
			
		||||
	return fmt.Errorf("windows doesn't support changing ID mappings")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type storageOptions struct {
 | 
			
		||||
	size uint64
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,7 +119,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
 | 
			
		|||
		gidMaps:          gidMaps,
 | 
			
		||||
		ctr:              graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()),
 | 
			
		||||
	}
 | 
			
		||||
	return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil
 | 
			
		||||
	return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseOptions(opt []string) (zfsOptions, error) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,4 +53,6 @@ var (
 | 
			
		|||
	ErrInvalidBigDataName = errors.New("not a valid name for a big data item")
 | 
			
		||||
	// ErrDigestUnknown indicates that we were unable to compute the digest of a specified item.
 | 
			
		||||
	ErrDigestUnknown = errors.New("could not compute digest of item")
 | 
			
		||||
	// ErrLayerNotMounted is returned when the requested information can only be computed for a mounted layer, and the layer is not mounted.
 | 
			
		||||
	ErrLayerNotMounted = errors.New("layer is not mounted")
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
 | 
			
		||||
// source: ./images.go
 | 
			
		||||
// source: images.go
 | 
			
		||||
 | 
			
		||||
package storage
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,12 +8,16 @@ import (
 | 
			
		|||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	drivers "github.com/containers/storage/drivers"
 | 
			
		||||
	"github.com/containers/storage/pkg/archive"
 | 
			
		||||
	"github.com/containers/storage/pkg/idtools"
 | 
			
		||||
	"github.com/containers/storage/pkg/ioutils"
 | 
			
		||||
	"github.com/containers/storage/pkg/stringid"
 | 
			
		||||
	"github.com/containers/storage/pkg/system"
 | 
			
		||||
	"github.com/containers/storage/pkg/truncindex"
 | 
			
		||||
	digest "github.com/opencontainers/go-digest"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
| 
						 | 
				
			
			@ -93,6 +97,11 @@ type Layer struct {
 | 
			
		|||
 | 
			
		||||
	// Flags is arbitrary data about the layer.
 | 
			
		||||
	Flags map[string]interface{} `json:"flags,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// UIDMap and GIDMap are used for setting up a layer's contents
 | 
			
		||||
	// for use inside of a user namespace where UID mapping is being used.
 | 
			
		||||
	UIDMap []idtools.IDMap `json:"uidmap,omitempty"`
 | 
			
		||||
	GIDMap []idtools.IDMap `json:"gidmap,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type layerMountPoint struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -178,13 +187,13 @@ type LayerStore interface {
 | 
			
		|||
	// underlying drivers can accept a "size" option.  At this time, most
 | 
			
		||||
	// underlying drivers do not themselves distinguish between writeable
 | 
			
		||||
	// and read-only layers.
 | 
			
		||||
	Create(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool) (*Layer, error)
 | 
			
		||||
	Create(id string, parent *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool) (*Layer, error)
 | 
			
		||||
 | 
			
		||||
	// CreateWithFlags combines the functions of Create and SetFlag.
 | 
			
		||||
	CreateWithFlags(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}) (layer *Layer, err error)
 | 
			
		||||
	CreateWithFlags(id string, parent *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, flags map[string]interface{}) (layer *Layer, err error)
 | 
			
		||||
 | 
			
		||||
	// Put combines the functions of CreateWithFlags and ApplyDiff.
 | 
			
		||||
	Put(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}, diff io.Reader) (*Layer, int64, error)
 | 
			
		||||
	Put(id string, parent *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, flags map[string]interface{}, diff io.Reader) (*Layer, int64, error)
 | 
			
		||||
 | 
			
		||||
	// SetNames replaces the list of names associated with a layer with the
 | 
			
		||||
	// supplied values.
 | 
			
		||||
| 
						 | 
				
			
			@ -204,6 +213,10 @@ type LayerStore interface {
 | 
			
		|||
	// Unmount unmounts a layer when it is no longer in use.
 | 
			
		||||
	Unmount(id string) error
 | 
			
		||||
 | 
			
		||||
	// ParentOwners returns the UIDs and GIDs of parents of the layer's mountpoint
 | 
			
		||||
	// for which the layer's UID and GID maps don't contain corresponding entries.
 | 
			
		||||
	ParentOwners(id string) (uids, gids []int, err error)
 | 
			
		||||
 | 
			
		||||
	// ApplyDiff reads a tarstream which was created by a previous call to Diff and
 | 
			
		||||
	// applies its changes to a specified layer.
 | 
			
		||||
	ApplyDiff(to string, diff io.Reader) (int64, error)
 | 
			
		||||
| 
						 | 
				
			
			@ -221,6 +234,8 @@ type layerStore struct {
 | 
			
		|||
	bymount           map[string]*Layer
 | 
			
		||||
	bycompressedsum   map[digest.Digest][]string
 | 
			
		||||
	byuncompressedsum map[digest.Digest][]string
 | 
			
		||||
	uidMap            []idtools.IDMap
 | 
			
		||||
	gidMap            []idtools.IDMap
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyLayer(l *Layer) *Layer {
 | 
			
		||||
| 
						 | 
				
			
			@ -239,6 +254,8 @@ func copyLayer(l *Layer) *Layer {
 | 
			
		|||
		UncompressedSize:   l.UncompressedSize,
 | 
			
		||||
		CompressionType:    l.CompressionType,
 | 
			
		||||
		Flags:              copyStringInterfaceMap(l.Flags),
 | 
			
		||||
		UIDMap:             copyIDMap(l.UIDMap),
 | 
			
		||||
		GIDMap:             copyIDMap(l.GIDMap),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -382,7 +399,7 @@ func (r *layerStore) Save() error {
 | 
			
		|||
	return ioutils.AtomicWriteFile(mpath, jmdata, 0600)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newLayerStore(rundir string, layerdir string, driver drivers.Driver) (LayerStore, error) {
 | 
			
		||||
func newLayerStore(rundir string, layerdir string, driver drivers.Driver, uidMap, gidMap []idtools.IDMap) (LayerStore, error) {
 | 
			
		||||
	if err := os.MkdirAll(rundir, 0700); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -403,6 +420,8 @@ func newLayerStore(rundir string, layerdir string, driver drivers.Driver) (Layer
 | 
			
		|||
		byid:     make(map[string]*Layer),
 | 
			
		||||
		bymount:  make(map[string]*Layer),
 | 
			
		||||
		byname:   make(map[string]*Layer),
 | 
			
		||||
		uidMap:   copyIDMap(uidMap),
 | 
			
		||||
		gidMap:   copyIDMap(gidMap),
 | 
			
		||||
	}
 | 
			
		||||
	if err := rlstore.Load(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -489,7 +508,7 @@ func (r *layerStore) Status() ([][2]string, error) {
 | 
			
		|||
	return r.driver.Status(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) Put(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}, diff io.Reader) (layer *Layer, size int64, err error) {
 | 
			
		||||
func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, flags map[string]interface{}, diff io.Reader) (layer *Layer, size int64, err error) {
 | 
			
		||||
	if !r.IsReadWrite() {
 | 
			
		||||
		return nil, -1, errors.Wrapf(ErrStoreIsReadOnly, "not allowed to create new layers at %q", r.layerspath())
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -500,11 +519,6 @@ func (r *layerStore) Put(id, parent string, names []string, mountLabel string, o
 | 
			
		|||
	if err := os.MkdirAll(r.layerdir, 0700); err != nil {
 | 
			
		||||
		return nil, -1, err
 | 
			
		||||
	}
 | 
			
		||||
	if parent != "" {
 | 
			
		||||
		if parentLayer, ok := r.lookup(parent); ok {
 | 
			
		||||
			parent = parentLayer.ID
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if id == "" {
 | 
			
		||||
		id = stringid.GenerateRandomID()
 | 
			
		||||
		_, idInUse := r.byid[id]
 | 
			
		||||
| 
						 | 
				
			
			@ -522,6 +536,15 @@ func (r *layerStore) Put(id, parent string, names []string, mountLabel string, o
 | 
			
		|||
			return nil, -1, ErrDuplicateName
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	parent := ""
 | 
			
		||||
	var parentMappings *idtools.IDMappings
 | 
			
		||||
	if parentLayer != nil {
 | 
			
		||||
		parent = parentLayer.ID
 | 
			
		||||
		parentMappings = idtools.NewIDMappingsFromMaps(parentLayer.UIDMap, parentLayer.GIDMap)
 | 
			
		||||
	} else {
 | 
			
		||||
		parentMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	idMappings := idtools.NewIDMappingsFromMaps(moreOptions.UIDMap, moreOptions.GIDMap)
 | 
			
		||||
	opts := drivers.CreateOpts{
 | 
			
		||||
		MountLabel: mountLabel,
 | 
			
		||||
		StorageOpt: options,
 | 
			
		||||
| 
						 | 
				
			
			@ -531,6 +554,15 @@ func (r *layerStore) Put(id, parent string, names []string, mountLabel string, o
 | 
			
		|||
	} else {
 | 
			
		||||
		err = r.driver.Create(id, parent, &opts)
 | 
			
		||||
	}
 | 
			
		||||
	if !reflect.DeepEqual(parentMappings.UIDs(), idMappings.UIDs()) || !reflect.DeepEqual(parentMappings.GIDs(), idMappings.GIDs()) {
 | 
			
		||||
		err = r.driver.UpdateLayerIDMap(id, parentMappings, idMappings, mountLabel)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// We don't have a record of this layer, but at least
 | 
			
		||||
			// try to clean it up underneath us.
 | 
			
		||||
			r.driver.Remove(id)
 | 
			
		||||
			return nil, -1, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		layer = &Layer{
 | 
			
		||||
			ID:         id,
 | 
			
		||||
| 
						 | 
				
			
			@ -539,6 +571,8 @@ func (r *layerStore) Put(id, parent string, names []string, mountLabel string, o
 | 
			
		|||
			MountLabel: mountLabel,
 | 
			
		||||
			Created:    time.Now().UTC(),
 | 
			
		||||
			Flags:      make(map[string]interface{}),
 | 
			
		||||
			UIDMap:     copyIDMap(moreOptions.UIDMap),
 | 
			
		||||
			GIDMap:     copyIDMap(moreOptions.GIDMap),
 | 
			
		||||
		}
 | 
			
		||||
		r.layers = append(r.layers, layer)
 | 
			
		||||
		r.idindex.Add(id)
 | 
			
		||||
| 
						 | 
				
			
			@ -580,13 +614,13 @@ func (r *layerStore) Put(id, parent string, names []string, mountLabel string, o
 | 
			
		|||
	return copyLayer(layer), size, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) CreateWithFlags(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}) (layer *Layer, err error) {
 | 
			
		||||
	layer, _, err = r.Put(id, parent, names, mountLabel, options, writeable, flags, nil)
 | 
			
		||||
func (r *layerStore) CreateWithFlags(id string, parent *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, flags map[string]interface{}) (layer *Layer, err error) {
 | 
			
		||||
	layer, _, err = r.Put(id, parent, names, mountLabel, options, moreOptions, writeable, flags, nil)
 | 
			
		||||
	return layer, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) Create(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool) (layer *Layer, err error) {
 | 
			
		||||
	return r.CreateWithFlags(id, parent, names, mountLabel, options, writeable, nil)
 | 
			
		||||
func (r *layerStore) Create(id string, parent *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool) (layer *Layer, err error) {
 | 
			
		||||
	return r.CreateWithFlags(id, parent, names, mountLabel, options, moreOptions, writeable, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) Mount(id, mountLabel string) (string, error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -645,6 +679,67 @@ func (r *layerStore) Unmount(id string) error {
 | 
			
		|||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) ParentOwners(id string) (uids, gids []int, err error) {
 | 
			
		||||
	layer, ok := r.lookup(id)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, nil, ErrLayerUnknown
 | 
			
		||||
	}
 | 
			
		||||
	if len(layer.UIDMap) == 0 && len(layer.GIDMap) == 0 {
 | 
			
		||||
		// We're not using any mappings, so there aren't any unmapped IDs on parent directories.
 | 
			
		||||
		return nil, nil, nil
 | 
			
		||||
	}
 | 
			
		||||
	if layer.MountPoint == "" {
 | 
			
		||||
		// We don't know which directories to examine.
 | 
			
		||||
		return nil, nil, ErrLayerNotMounted
 | 
			
		||||
	}
 | 
			
		||||
	rootuid, rootgid, err := idtools.GetRootUIDGID(layer.UIDMap, layer.GIDMap)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, errors.Wrapf(err, "error reading root ID values for layer %q", layer.ID)
 | 
			
		||||
	}
 | 
			
		||||
	m := idtools.NewIDMappingsFromMaps(layer.UIDMap, layer.GIDMap)
 | 
			
		||||
	fsuids := make(map[int]struct{})
 | 
			
		||||
	fsgids := make(map[int]struct{})
 | 
			
		||||
	for dir := filepath.Dir(layer.MountPoint); dir != "" && dir != string(os.PathSeparator); dir = filepath.Dir(dir) {
 | 
			
		||||
		st, err := system.Stat(dir)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, errors.Wrapf(err, "error reading ownership of directory %q", dir)
 | 
			
		||||
		}
 | 
			
		||||
		lst, err := system.Lstat(dir)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, errors.Wrapf(err, "error reading ownership of directory-in-case-it's-a-symlink %q", dir)
 | 
			
		||||
		}
 | 
			
		||||
		fsuid := int(st.UID())
 | 
			
		||||
		fsgid := int(st.GID())
 | 
			
		||||
		if _, _, err := m.ToContainer(idtools.IDPair{UID: fsuid, GID: rootgid}); err != nil {
 | 
			
		||||
			fsuids[fsuid] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
		if _, _, err := m.ToContainer(idtools.IDPair{UID: rootuid, GID: fsgid}); err != nil {
 | 
			
		||||
			fsgids[fsgid] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
		fsuid = int(lst.UID())
 | 
			
		||||
		fsgid = int(lst.GID())
 | 
			
		||||
		if _, _, err := m.ToContainer(idtools.IDPair{UID: fsuid, GID: rootgid}); err != nil {
 | 
			
		||||
			fsuids[fsuid] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
		if _, _, err := m.ToContainer(idtools.IDPair{UID: rootuid, GID: fsgid}); err != nil {
 | 
			
		||||
			fsgids[fsgid] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for uid := range fsuids {
 | 
			
		||||
		uids = append(uids, uid)
 | 
			
		||||
	}
 | 
			
		||||
	for gid := range fsgids {
 | 
			
		||||
		gids = append(gids, gid)
 | 
			
		||||
	}
 | 
			
		||||
	if len(uids) > 1 {
 | 
			
		||||
		sort.Ints(uids)
 | 
			
		||||
	}
 | 
			
		||||
	if len(gids) > 1 {
 | 
			
		||||
		sort.Ints(gids)
 | 
			
		||||
	}
 | 
			
		||||
	return uids, gids, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) removeName(layer *Layer, name string) {
 | 
			
		||||
	layer.Names = stringSliceWithoutValue(layer.Names, name)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -771,12 +866,11 @@ func (r *layerStore) Wipe() error {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) findParentAndLayer(from, to string) (fromID string, toID string, toLayer *Layer, err error) {
 | 
			
		||||
func (r *layerStore) findParentAndLayer(from, to string) (fromID string, toID string, fromLayer, toLayer *Layer, err error) {
 | 
			
		||||
	var ok bool
 | 
			
		||||
	var fromLayer *Layer
 | 
			
		||||
	toLayer, ok = r.lookup(to)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return "", "", nil, ErrLayerUnknown
 | 
			
		||||
		return "", "", nil, nil, ErrLayerUnknown
 | 
			
		||||
	}
 | 
			
		||||
	to = toLayer.ID
 | 
			
		||||
	if from == "" {
 | 
			
		||||
| 
						 | 
				
			
			@ -793,15 +887,22 @@ func (r *layerStore) findParentAndLayer(from, to string) (fromID string, toID st
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return from, to, toLayer, nil
 | 
			
		||||
	return from, to, fromLayer, toLayer, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) layerMappings(layer *Layer) *idtools.IDMappings {
 | 
			
		||||
	if layer == nil {
 | 
			
		||||
		return &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	return idtools.NewIDMappingsFromMaps(layer.UIDMap, layer.GIDMap)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) Changes(from, to string) ([]archive.Change, error) {
 | 
			
		||||
	from, to, toLayer, err := r.findParentAndLayer(from, to)
 | 
			
		||||
	from, to, fromLayer, toLayer, err := r.findParentAndLayer(from, to)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, ErrLayerUnknown
 | 
			
		||||
	}
 | 
			
		||||
	return r.driver.Changes(to, from, toLayer.MountLabel)
 | 
			
		||||
	return r.driver.Changes(to, r.layerMappings(toLayer), from, r.layerMappings(fromLayer), toLayer.MountLabel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type simpleGetCloser struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -836,7 +937,7 @@ func (r *layerStore) newFileGetter(id string) (drivers.FileGetCloser, error) {
 | 
			
		|||
func (r *layerStore) Diff(from, to string, options *DiffOptions) (io.ReadCloser, error) {
 | 
			
		||||
	var metadata storage.Unpacker
 | 
			
		||||
 | 
			
		||||
	from, to, toLayer, err := r.findParentAndLayer(from, to)
 | 
			
		||||
	from, to, fromLayer, toLayer, err := r.findParentAndLayer(from, to)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, ErrLayerUnknown
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -874,7 +975,7 @@ func (r *layerStore) Diff(from, to string, options *DiffOptions) (io.ReadCloser,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if from != toLayer.Parent {
 | 
			
		||||
		diff, err := r.driver.Diff(to, from, toLayer.MountLabel)
 | 
			
		||||
		diff, err := r.driver.Diff(to, r.layerMappings(toLayer), from, r.layerMappings(fromLayer), toLayer.MountLabel)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -886,7 +987,7 @@ func (r *layerStore) Diff(from, to string, options *DiffOptions) (io.ReadCloser,
 | 
			
		|||
		if !os.IsNotExist(err) {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		diff, err := r.driver.Diff(to, from, toLayer.MountLabel)
 | 
			
		||||
		diff, err := r.driver.Diff(to, r.layerMappings(toLayer), from, r.layerMappings(fromLayer), toLayer.MountLabel)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -925,12 +1026,12 @@ func (r *layerStore) Diff(from, to string, options *DiffOptions) (io.ReadCloser,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) DiffSize(from, to string) (size int64, err error) {
 | 
			
		||||
	var toLayer *Layer
 | 
			
		||||
	from, to, toLayer, err = r.findParentAndLayer(from, to)
 | 
			
		||||
	var fromLayer, toLayer *Layer
 | 
			
		||||
	from, to, fromLayer, toLayer, err = r.findParentAndLayer(from, to)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, ErrLayerUnknown
 | 
			
		||||
	}
 | 
			
		||||
	return r.driver.DiffSize(to, from, toLayer.MountLabel)
 | 
			
		||||
	return r.driver.DiffSize(to, r.layerMappings(toLayer), from, r.layerMappings(fromLayer), toLayer.MountLabel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -970,7 +1071,7 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		return -1, err
 | 
			
		||||
	}
 | 
			
		||||
	size, err = r.driver.ApplyDiff(layer.ID, layer.Parent, layer.MountLabel, payload)
 | 
			
		||||
	size, err = r.driver.ApplyDiff(layer.ID, r.layerMappings(layer), layer.Parent, layer.MountLabel, payload)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
 | 
			
		||||
// source: ./layers.go
 | 
			
		||||
// source: layers.go
 | 
			
		||||
 | 
			
		||||
package storage
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ import (
 | 
			
		|||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/containers/storage/pkg/archive"
 | 
			
		||||
	"github.com/containers/storage/pkg/idtools"
 | 
			
		||||
	"github.com/opencontainers/go-digest"
 | 
			
		||||
	fflib "github.com/pquerna/ffjson/fflib/v1"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -323,6 +324,46 @@ func (j *Layer) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
 | 
			
		|||
		}
 | 
			
		||||
		buf.WriteByte(',')
 | 
			
		||||
	}
 | 
			
		||||
	if len(j.UIDMap) != 0 {
 | 
			
		||||
		buf.WriteString(`"uidmap":`)
 | 
			
		||||
		if j.UIDMap != nil {
 | 
			
		||||
			buf.WriteString(`[`)
 | 
			
		||||
			for i, v := range j.UIDMap {
 | 
			
		||||
				if i != 0 {
 | 
			
		||||
					buf.WriteString(`,`)
 | 
			
		||||
				}
 | 
			
		||||
				/* Struct fall back. type=idtools.IDMap kind=struct */
 | 
			
		||||
				err = buf.Encode(&v)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			buf.WriteString(`]`)
 | 
			
		||||
		} else {
 | 
			
		||||
			buf.WriteString(`null`)
 | 
			
		||||
		}
 | 
			
		||||
		buf.WriteByte(',')
 | 
			
		||||
	}
 | 
			
		||||
	if len(j.GIDMap) != 0 {
 | 
			
		||||
		buf.WriteString(`"gidmap":`)
 | 
			
		||||
		if j.GIDMap != nil {
 | 
			
		||||
			buf.WriteString(`[`)
 | 
			
		||||
			for i, v := range j.GIDMap {
 | 
			
		||||
				if i != 0 {
 | 
			
		||||
					buf.WriteString(`,`)
 | 
			
		||||
				}
 | 
			
		||||
				/* Struct fall back. type=idtools.IDMap kind=struct */
 | 
			
		||||
				err = buf.Encode(&v)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			buf.WriteString(`]`)
 | 
			
		||||
		} else {
 | 
			
		||||
			buf.WriteString(`null`)
 | 
			
		||||
		}
 | 
			
		||||
		buf.WriteByte(',')
 | 
			
		||||
	}
 | 
			
		||||
	buf.Rewind(1)
 | 
			
		||||
	buf.WriteByte('}')
 | 
			
		||||
	return nil
 | 
			
		||||
| 
						 | 
				
			
			@ -355,6 +396,10 @@ const (
 | 
			
		|||
	ffjtLayerCompressionType
 | 
			
		||||
 | 
			
		||||
	ffjtLayerFlags
 | 
			
		||||
 | 
			
		||||
	ffjtLayerUIDMap
 | 
			
		||||
 | 
			
		||||
	ffjtLayerGIDMap
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var ffjKeyLayerID = []byte("id")
 | 
			
		||||
| 
						 | 
				
			
			@ -381,6 +426,10 @@ var ffjKeyLayerCompressionType = []byte("compression")
 | 
			
		|||
 | 
			
		||||
var ffjKeyLayerFlags = []byte("flags")
 | 
			
		||||
 | 
			
		||||
var ffjKeyLayerUIDMap = []byte("uidmap")
 | 
			
		||||
 | 
			
		||||
var ffjKeyLayerGIDMap = []byte("gidmap")
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON umarshall json - template of ffjson
 | 
			
		||||
func (j *Layer) UnmarshalJSON(input []byte) error {
 | 
			
		||||
	fs := fflib.NewFFLexer(input)
 | 
			
		||||
| 
						 | 
				
			
			@ -486,6 +535,14 @@ mainparse:
 | 
			
		|||
						goto mainparse
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				case 'g':
 | 
			
		||||
 | 
			
		||||
					if bytes.Equal(ffjKeyLayerGIDMap, kn) {
 | 
			
		||||
						currentKey = ffjtLayerGIDMap
 | 
			
		||||
						state = fflib.FFParse_want_colon
 | 
			
		||||
						goto mainparse
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				case 'i':
 | 
			
		||||
 | 
			
		||||
					if bytes.Equal(ffjKeyLayerID, kn) {
 | 
			
		||||
| 
						 | 
				
			
			@ -523,6 +580,26 @@ mainparse:
 | 
			
		|||
						goto mainparse
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				case 'u':
 | 
			
		||||
 | 
			
		||||
					if bytes.Equal(ffjKeyLayerUIDMap, kn) {
 | 
			
		||||
						currentKey = ffjtLayerUIDMap
 | 
			
		||||
						state = fflib.FFParse_want_colon
 | 
			
		||||
						goto mainparse
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if fflib.SimpleLetterEqualFold(ffjKeyLayerGIDMap, kn) {
 | 
			
		||||
					currentKey = ffjtLayerGIDMap
 | 
			
		||||
					state = fflib.FFParse_want_colon
 | 
			
		||||
					goto mainparse
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if fflib.SimpleLetterEqualFold(ffjKeyLayerUIDMap, kn) {
 | 
			
		||||
					currentKey = ffjtLayerUIDMap
 | 
			
		||||
					state = fflib.FFParse_want_colon
 | 
			
		||||
					goto mainparse
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if fflib.EqualFoldRight(ffjKeyLayerFlags, kn) {
 | 
			
		||||
| 
						 | 
				
			
			@ -650,6 +727,12 @@ mainparse:
 | 
			
		|||
				case ffjtLayerFlags:
 | 
			
		||||
					goto handle_Flags
 | 
			
		||||
 | 
			
		||||
				case ffjtLayerUIDMap:
 | 
			
		||||
					goto handle_UIDMap
 | 
			
		||||
 | 
			
		||||
				case ffjtLayerGIDMap:
 | 
			
		||||
					goto handle_GIDMap
 | 
			
		||||
 | 
			
		||||
				case ffjtLayernosuchkey:
 | 
			
		||||
					err = fs.SkipField(tok)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -1108,6 +1191,142 @@ handle_Flags:
 | 
			
		|||
	state = fflib.FFParse_after_value
 | 
			
		||||
	goto mainparse
 | 
			
		||||
 | 
			
		||||
handle_UIDMap:
 | 
			
		||||
 | 
			
		||||
	/* handler: j.UIDMap type=[]idtools.IDMap kind=slice quoted=false*/
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			if tok != fflib.FFTok_left_brace && tok != fflib.FFTok_null {
 | 
			
		||||
				return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if tok == fflib.FFTok_null {
 | 
			
		||||
			j.UIDMap = nil
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			j.UIDMap = []idtools.IDMap{}
 | 
			
		||||
 | 
			
		||||
			wantVal := true
 | 
			
		||||
 | 
			
		||||
			for {
 | 
			
		||||
 | 
			
		||||
				var tmpJUIDMap idtools.IDMap
 | 
			
		||||
 | 
			
		||||
				tok = fs.Scan()
 | 
			
		||||
				if tok == fflib.FFTok_error {
 | 
			
		||||
					goto tokerror
 | 
			
		||||
				}
 | 
			
		||||
				if tok == fflib.FFTok_right_brace {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if tok == fflib.FFTok_comma {
 | 
			
		||||
					if wantVal == true {
 | 
			
		||||
						// TODO(pquerna): this isn't an ideal error message, this handles
 | 
			
		||||
						// things like [,,,] as an array value.
 | 
			
		||||
						return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
 | 
			
		||||
					}
 | 
			
		||||
					continue
 | 
			
		||||
				} else {
 | 
			
		||||
					wantVal = true
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				/* handler: tmpJUIDMap type=idtools.IDMap kind=struct quoted=false*/
 | 
			
		||||
 | 
			
		||||
				{
 | 
			
		||||
					/* Falling back. type=idtools.IDMap kind=struct */
 | 
			
		||||
					tbuf, err := fs.CaptureField(tok)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fs.WrapErr(err)
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					err = json.Unmarshal(tbuf, &tmpJUIDMap)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fs.WrapErr(err)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				j.UIDMap = append(j.UIDMap, tmpJUIDMap)
 | 
			
		||||
 | 
			
		||||
				wantVal = false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state = fflib.FFParse_after_value
 | 
			
		||||
	goto mainparse
 | 
			
		||||
 | 
			
		||||
handle_GIDMap:
 | 
			
		||||
 | 
			
		||||
	/* handler: j.GIDMap type=[]idtools.IDMap kind=slice quoted=false*/
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			if tok != fflib.FFTok_left_brace && tok != fflib.FFTok_null {
 | 
			
		||||
				return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if tok == fflib.FFTok_null {
 | 
			
		||||
			j.GIDMap = nil
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			j.GIDMap = []idtools.IDMap{}
 | 
			
		||||
 | 
			
		||||
			wantVal := true
 | 
			
		||||
 | 
			
		||||
			for {
 | 
			
		||||
 | 
			
		||||
				var tmpJGIDMap idtools.IDMap
 | 
			
		||||
 | 
			
		||||
				tok = fs.Scan()
 | 
			
		||||
				if tok == fflib.FFTok_error {
 | 
			
		||||
					goto tokerror
 | 
			
		||||
				}
 | 
			
		||||
				if tok == fflib.FFTok_right_brace {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if tok == fflib.FFTok_comma {
 | 
			
		||||
					if wantVal == true {
 | 
			
		||||
						// TODO(pquerna): this isn't an ideal error message, this handles
 | 
			
		||||
						// things like [,,,] as an array value.
 | 
			
		||||
						return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
 | 
			
		||||
					}
 | 
			
		||||
					continue
 | 
			
		||||
				} else {
 | 
			
		||||
					wantVal = true
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				/* handler: tmpJGIDMap type=idtools.IDMap kind=struct quoted=false*/
 | 
			
		||||
 | 
			
		||||
				{
 | 
			
		||||
					/* Falling back. type=idtools.IDMap kind=struct */
 | 
			
		||||
					tbuf, err := fs.CaptureField(tok)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fs.WrapErr(err)
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					err = json.Unmarshal(tbuf, &tmpJGIDMap)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fs.WrapErr(err)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				j.GIDMap = append(j.GIDMap, tmpJGIDMap)
 | 
			
		||||
 | 
			
		||||
				wantVal = false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state = fflib.FFParse_after_value
 | 
			
		||||
	goto mainparse
 | 
			
		||||
 | 
			
		||||
wantedvalue:
 | 
			
		||||
	return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
 | 
			
		||||
wrongtokenerror:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,18 +59,21 @@ type (
 | 
			
		|||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Archiver allows the reuse of most utility functions of this package
 | 
			
		||||
// with a pluggable Untar function. Also, to facilitate the passing of
 | 
			
		||||
// specific id mappings for untar, an archiver can be created with maps
 | 
			
		||||
// which will then be passed to Untar operations
 | 
			
		||||
// Archiver allows the reuse of most utility functions of this package with a
 | 
			
		||||
// pluggable Untar function.  To facilitate the passing of specific id mappings
 | 
			
		||||
// for untar, an archiver can be created with maps which will then be passed to
 | 
			
		||||
// Untar operations.  If ChownOpts is set, its values are mapped using
 | 
			
		||||
// UntarIDMappings before being used to create files and directories on disk.
 | 
			
		||||
type Archiver struct {
 | 
			
		||||
	Untar      func(io.Reader, string, *TarOptions) error
 | 
			
		||||
	IDMappings *idtools.IDMappings
 | 
			
		||||
	Untar           func(io.Reader, string, *TarOptions) error
 | 
			
		||||
	TarIDMappings   *idtools.IDMappings
 | 
			
		||||
	ChownOpts       *idtools.IDPair
 | 
			
		||||
	UntarIDMappings *idtools.IDMappings
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewDefaultArchiver returns a new Archiver without any IDMappings
 | 
			
		||||
func NewDefaultArchiver() *Archiver {
 | 
			
		||||
	return &Archiver{Untar: Untar, IDMappings: &idtools.IDMappings{}}
 | 
			
		||||
	return &Archiver{Untar: Untar, TarIDMappings: &idtools.IDMappings{}, UntarIDMappings: &idtools.IDMappings{}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// breakoutError is used to differentiate errors related to breaking out
 | 
			
		||||
| 
						 | 
				
			
			@ -942,7 +945,7 @@ loop:
 | 
			
		|||
		}
 | 
			
		||||
		trBuf.Reset(tr)
 | 
			
		||||
 | 
			
		||||
		if err := remapIDs(idMappings, hdr); err != nil {
 | 
			
		||||
		if err := remapIDs(nil, idMappings, options.ChownOpts, hdr); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1023,14 +1026,28 @@ func untarHandler(tarArchive io.Reader, dest string, options *TarOptions, decomp
 | 
			
		|||
// If either Tar or Untar fails, TarUntar aborts and returns the error.
 | 
			
		||||
func (archiver *Archiver) TarUntar(src, dst string) error {
 | 
			
		||||
	logrus.Debugf("TarUntar(%s %s)", src, dst)
 | 
			
		||||
	archive, err := TarWithOptions(src, &TarOptions{Compression: Uncompressed})
 | 
			
		||||
	tarMappings := archiver.TarIDMappings
 | 
			
		||||
	if tarMappings == nil {
 | 
			
		||||
		tarMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	options := &TarOptions{
 | 
			
		||||
		UIDMaps:     tarMappings.UIDs(),
 | 
			
		||||
		GIDMaps:     tarMappings.GIDs(),
 | 
			
		||||
		Compression: Uncompressed,
 | 
			
		||||
	}
 | 
			
		||||
	archive, err := TarWithOptions(src, options)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer archive.Close()
 | 
			
		||||
	options := &TarOptions{
 | 
			
		||||
		UIDMaps: archiver.IDMappings.UIDs(),
 | 
			
		||||
		GIDMaps: archiver.IDMappings.GIDs(),
 | 
			
		||||
	untarMappings := archiver.UntarIDMappings
 | 
			
		||||
	if untarMappings == nil {
 | 
			
		||||
		untarMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	options = &TarOptions{
 | 
			
		||||
		UIDMaps:   untarMappings.UIDs(),
 | 
			
		||||
		GIDMaps:   untarMappings.GIDs(),
 | 
			
		||||
		ChownOpts: archiver.ChownOpts,
 | 
			
		||||
	}
 | 
			
		||||
	return archiver.Untar(archive, dst, options)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1042,9 +1059,14 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
 | 
			
		|||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer archive.Close()
 | 
			
		||||
	untarMappings := archiver.UntarIDMappings
 | 
			
		||||
	if untarMappings == nil {
 | 
			
		||||
		untarMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	options := &TarOptions{
 | 
			
		||||
		UIDMaps: archiver.IDMappings.UIDs(),
 | 
			
		||||
		GIDMaps: archiver.IDMappings.GIDs(),
 | 
			
		||||
		UIDMaps:   untarMappings.UIDs(),
 | 
			
		||||
		GIDMaps:   untarMappings.GIDs(),
 | 
			
		||||
		ChownOpts: archiver.ChownOpts,
 | 
			
		||||
	}
 | 
			
		||||
	return archiver.Untar(archive, dst, options)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1065,7 +1087,10 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
 | 
			
		|||
	// if this archiver is set up with ID mapping we need to create
 | 
			
		||||
	// the new destination directory with the remapped root UID/GID pair
 | 
			
		||||
	// as owner
 | 
			
		||||
	rootIDs := archiver.IDMappings.RootPair()
 | 
			
		||||
	rootIDs := archiver.UntarIDMappings.RootPair()
 | 
			
		||||
	if archiver.ChownOpts != nil {
 | 
			
		||||
		rootIDs = *archiver.ChownOpts
 | 
			
		||||
	}
 | 
			
		||||
	// Create dst, copy src's content into it
 | 
			
		||||
	logrus.Debugf("Creating dest directory: %s", dst)
 | 
			
		||||
	if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -1116,7 +1141,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
 | 
			
		|||
		hdr.Name = filepath.Base(dst)
 | 
			
		||||
		hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
 | 
			
		||||
 | 
			
		||||
		if err := remapIDs(archiver.IDMappings, hdr); err != nil {
 | 
			
		||||
		if err := remapIDs(archiver.TarIDMappings, archiver.UntarIDMappings, archiver.ChownOpts, hdr); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1143,10 +1168,29 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
 | 
			
		|||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
 | 
			
		||||
	ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
 | 
			
		||||
func remapIDs(readIDMappings, writeIDMappings *idtools.IDMappings, chownOpts *idtools.IDPair, hdr *tar.Header) (err error) {
 | 
			
		||||
	var uid, gid int
 | 
			
		||||
	if chownOpts != nil {
 | 
			
		||||
		uid, gid = chownOpts.UID, chownOpts.GID
 | 
			
		||||
	} else {
 | 
			
		||||
		if readIDMappings != nil && !readIDMappings.Empty() {
 | 
			
		||||
			uid, gid, err = readIDMappings.ToContainer(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			uid, gid = hdr.Uid, hdr.Gid
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	ids := idtools.IDPair{UID: uid, GID: gid}
 | 
			
		||||
	if writeIDMappings != nil && !writeIDMappings.Empty() {
 | 
			
		||||
		ids, err = writeIDMappings.ToHost(ids)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	hdr.Uid, hdr.Gid = ids.UID, ids.GID
 | 
			
		||||
	return err
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// cmdStream executes a command, and returns its stdout as a stream.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2230
									
								
								vendor/github.com/containers/storage/pkg/archive/archive_ffjson.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										2230
									
								
								vendor/github.com/containers/storage/pkg/archive/archive_ffjson.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -257,6 +257,7 @@ func changes(layers []string, rw string, dc deleteChange, sc skipChange, wc whit
 | 
			
		|||
// FileInfo describes the information of a file.
 | 
			
		||||
type FileInfo struct {
 | 
			
		||||
	parent     *FileInfo
 | 
			
		||||
	idMappings *idtools.IDMappings
 | 
			
		||||
	name       string
 | 
			
		||||
	stat       *system.StatT
 | 
			
		||||
	children   map[string]*FileInfo
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +330,7 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
 | 
			
		|||
			// be visible when actually comparing the stat fields. The only time this
 | 
			
		||||
			// breaks down is if some code intentionally hides a change by setting
 | 
			
		||||
			// back mtime
 | 
			
		||||
			if statDifferent(oldStat, newStat) ||
 | 
			
		||||
			if statDifferent(oldStat, oldInfo, newStat, info) ||
 | 
			
		||||
				!bytes.Equal(oldChild.capability, newChild.capability) {
 | 
			
		||||
				change := Change{
 | 
			
		||||
					Path: newChild.path(),
 | 
			
		||||
| 
						 | 
				
			
			@ -379,18 +380,19 @@ func (info *FileInfo) Changes(oldInfo *FileInfo) []Change {
 | 
			
		|||
	return changes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newRootFileInfo() *FileInfo {
 | 
			
		||||
func newRootFileInfo(idMappings *idtools.IDMappings) *FileInfo {
 | 
			
		||||
	// As this runs on the daemon side, file paths are OS specific.
 | 
			
		||||
	root := &FileInfo{
 | 
			
		||||
		name:     string(os.PathSeparator),
 | 
			
		||||
		children: make(map[string]*FileInfo),
 | 
			
		||||
		name:       string(os.PathSeparator),
 | 
			
		||||
		idMappings: idMappings,
 | 
			
		||||
		children:   make(map[string]*FileInfo),
 | 
			
		||||
	}
 | 
			
		||||
	return root
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChangesDirs compares two directories and generates an array of Change objects describing the changes.
 | 
			
		||||
// If oldDir is "", then all files in newDir will be Add-Changes.
 | 
			
		||||
func ChangesDirs(newDir, oldDir string) ([]Change, error) {
 | 
			
		||||
func ChangesDirs(newDir string, newMappings *idtools.IDMappings, oldDir string, oldMappings *idtools.IDMappings) ([]Change, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		oldRoot, newRoot *FileInfo
 | 
			
		||||
	)
 | 
			
		||||
| 
						 | 
				
			
			@ -402,7 +404,7 @@ func ChangesDirs(newDir, oldDir string) ([]Change, error) {
 | 
			
		|||
		defer os.Remove(emptyDir)
 | 
			
		||||
		oldDir = emptyDir
 | 
			
		||||
	}
 | 
			
		||||
	oldRoot, newRoot, err := collectFileInfoForChanges(oldDir, newDir)
 | 
			
		||||
	oldRoot, newRoot, err := collectFileInfoForChanges(oldDir, newDir, oldMappings, newMappings)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ import (
 | 
			
		|||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/storage/pkg/idtools"
 | 
			
		||||
	"github.com/containers/storage/pkg/system"
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -22,10 +23,12 @@ import (
 | 
			
		|||
// directly. Eliminating stat calls in this way can save up to seconds on large
 | 
			
		||||
// images.
 | 
			
		||||
type walker struct {
 | 
			
		||||
	dir1  string
 | 
			
		||||
	dir2  string
 | 
			
		||||
	root1 *FileInfo
 | 
			
		||||
	root2 *FileInfo
 | 
			
		||||
	dir1   string
 | 
			
		||||
	dir2   string
 | 
			
		||||
	root1  *FileInfo
 | 
			
		||||
	root2  *FileInfo
 | 
			
		||||
	idmap1 *idtools.IDMappings
 | 
			
		||||
	idmap2 *idtools.IDMappings
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// collectFileInfoForChanges returns a complete representation of the trees
 | 
			
		||||
| 
						 | 
				
			
			@ -34,12 +37,12 @@ type walker struct {
 | 
			
		|||
// and dir2 will be pruned from the results. This method is *only* to be used
 | 
			
		||||
// to generating a list of changes between the two directories, as it does not
 | 
			
		||||
// reflect the full contents.
 | 
			
		||||
func collectFileInfoForChanges(dir1, dir2 string) (*FileInfo, *FileInfo, error) {
 | 
			
		||||
func collectFileInfoForChanges(dir1, dir2 string, idmap1, idmap2 *idtools.IDMappings) (*FileInfo, *FileInfo, error) {
 | 
			
		||||
	w := &walker{
 | 
			
		||||
		dir1:  dir1,
 | 
			
		||||
		dir2:  dir2,
 | 
			
		||||
		root1: newRootFileInfo(),
 | 
			
		||||
		root2: newRootFileInfo(),
 | 
			
		||||
		root1: newRootFileInfo(idmap1),
 | 
			
		||||
		root2: newRootFileInfo(idmap2),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i1, err := os.Lstat(w.dir1)
 | 
			
		||||
| 
						 | 
				
			
			@ -69,9 +72,10 @@ func walkchunk(path string, fi os.FileInfo, dir string, root *FileInfo) error {
 | 
			
		|||
		return fmt.Errorf("walkchunk: Unexpectedly no parent for %s", path)
 | 
			
		||||
	}
 | 
			
		||||
	info := &FileInfo{
 | 
			
		||||
		name:     filepath.Base(path),
 | 
			
		||||
		children: make(map[string]*FileInfo),
 | 
			
		||||
		parent:   parent,
 | 
			
		||||
		name:       filepath.Base(path),
 | 
			
		||||
		children:   make(map[string]*FileInfo),
 | 
			
		||||
		parent:     parent,
 | 
			
		||||
		idMappings: root.idMappings,
 | 
			
		||||
	}
 | 
			
		||||
	cpath := filepath.Join(dir, path)
 | 
			
		||||
	stat, err := system.FromStatT(fi.Sys().(*syscall.Stat_t))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,21 +9,22 @@ import (
 | 
			
		|||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/storage/pkg/idtools"
 | 
			
		||||
	"github.com/containers/storage/pkg/system"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func collectFileInfoForChanges(oldDir, newDir string) (*FileInfo, *FileInfo, error) {
 | 
			
		||||
func collectFileInfoForChanges(oldDir, newDir string, oldIDMap, newIDMap *idtools.IDMappings) (*FileInfo, *FileInfo, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		oldRoot, newRoot *FileInfo
 | 
			
		||||
		err1, err2       error
 | 
			
		||||
		errs             = make(chan error, 2)
 | 
			
		||||
	)
 | 
			
		||||
	go func() {
 | 
			
		||||
		oldRoot, err1 = collectFileInfo(oldDir)
 | 
			
		||||
		oldRoot, err1 = collectFileInfo(oldDir, oldIDMap)
 | 
			
		||||
		errs <- err1
 | 
			
		||||
	}()
 | 
			
		||||
	go func() {
 | 
			
		||||
		newRoot, err2 = collectFileInfo(newDir)
 | 
			
		||||
		newRoot, err2 = collectFileInfo(newDir, newIDMap)
 | 
			
		||||
		errs <- err2
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -37,8 +38,8 @@ func collectFileInfoForChanges(oldDir, newDir string) (*FileInfo, *FileInfo, err
 | 
			
		|||
	return oldRoot, newRoot, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func collectFileInfo(sourceDir string) (*FileInfo, error) {
 | 
			
		||||
	root := newRootFileInfo()
 | 
			
		||||
func collectFileInfo(sourceDir string, idMappings *idtools.IDMappings) (*FileInfo, error) {
 | 
			
		||||
	root := newRootFileInfo(idMappings)
 | 
			
		||||
 | 
			
		||||
	err := filepath.Walk(sourceDir, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -73,9 +74,10 @@ func collectFileInfo(sourceDir string) (*FileInfo, error) {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		info := &FileInfo{
 | 
			
		||||
			name:     filepath.Base(relPath),
 | 
			
		||||
			children: make(map[string]*FileInfo),
 | 
			
		||||
			parent:   parent,
 | 
			
		||||
			name:       filepath.Base(relPath),
 | 
			
		||||
			children:   make(map[string]*FileInfo),
 | 
			
		||||
			parent:     parent,
 | 
			
		||||
			idMappings: idMappings,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		s, err := system.Lstat(path)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,15 +6,26 @@ import (
 | 
			
		|||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/storage/pkg/idtools"
 | 
			
		||||
	"github.com/containers/storage/pkg/system"
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool {
 | 
			
		||||
func statDifferent(oldStat *system.StatT, oldInfo *FileInfo, newStat *system.StatT, newInfo *FileInfo) bool {
 | 
			
		||||
	// Don't look at size for dirs, its not a good measure of change
 | 
			
		||||
	oldUid, oldGid := oldStat.UID(), oldStat.GID()
 | 
			
		||||
	uid, gid := newStat.UID(), newStat.GID()
 | 
			
		||||
	if cuid, cgid, err := newInfo.idMappings.ToContainer(idtools.IDPair{UID: int(uid), GID: int(gid)}); err == nil {
 | 
			
		||||
		uid = uint32(cuid)
 | 
			
		||||
		gid = uint32(cgid)
 | 
			
		||||
		if oldcuid, oldcgid, err := oldInfo.idMappings.ToContainer(idtools.IDPair{UID: int(oldUid), GID: int(oldGid)}); err == nil {
 | 
			
		||||
			oldUid = uint32(oldcuid)
 | 
			
		||||
			oldGid = uint32(oldcgid)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	ownerChanged := uid != oldUid || gid != oldGid
 | 
			
		||||
	if oldStat.Mode() != newStat.Mode() ||
 | 
			
		||||
		oldStat.UID() != newStat.UID() ||
 | 
			
		||||
		oldStat.GID() != newStat.GID() ||
 | 
			
		||||
		ownerChanged ||
 | 
			
		||||
		oldStat.Rdev() != newStat.Rdev() ||
 | 
			
		||||
		// Don't look at size for dirs, its not a good measure of change
 | 
			
		||||
		(oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR &&
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ import (
 | 
			
		|||
	"github.com/containers/storage/pkg/system"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool {
 | 
			
		||||
func statDifferent(oldStat *system.StatT, oldInfo *FileInfo, newStat *system.StatT, newInfo *FileInfo) bool {
 | 
			
		||||
 | 
			
		||||
	// Don't look at size for dirs, its not a good measure of change
 | 
			
		||||
	if oldStat.Mtim() != newStat.Mtim() ||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -192,7 +192,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
 | 
			
		|||
				srcData = tmpFile
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err := remapIDs(idMappings, srcHdr); err != nil {
 | 
			
		||||
			if err := remapIDs(nil, idMappings, options.ChownOpts, srcHdr); err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,18 @@ func NewArchiver(idMappings *idtools.IDMappings) *archive.Archiver {
 | 
			
		|||
	if idMappings == nil {
 | 
			
		||||
		idMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	return &archive.Archiver{Untar: Untar, IDMappings: idMappings}
 | 
			
		||||
	return &archive.Archiver{Untar: Untar, TarIDMappings: idMappings, UntarIDMappings: idMappings}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewArchiverWithChown returns a new Archiver which uses chrootarchive.Untar and the provided ID mapping configuration on both ends
 | 
			
		||||
func NewArchiverWithChown(tarIDMappings *idtools.IDMappings, chownOpts *idtools.IDPair, untarIDMappings *idtools.IDMappings) *archive.Archiver {
 | 
			
		||||
	if tarIDMappings == nil {
 | 
			
		||||
		tarIDMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	if untarIDMappings == nil {
 | 
			
		||||
		untarIDMappings = &idtools.IDMappings{}
 | 
			
		||||
	}
 | 
			
		||||
	return &archive.Archiver{Untar: Untar, TarIDMappings: tarIDMappings, ChownOpts: chownOpts, UntarIDMappings: untarIDMappings}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Untar reads a stream of bytes from `archive`, parses it as a tar archive,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ import (
 | 
			
		|||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
| 
						 | 
				
			
			@ -136,9 +137,8 @@ type StoreOptions struct {
 | 
			
		|||
	GraphDriverName string `json:"driver,omitempty"`
 | 
			
		||||
	// GraphDriverOptions are driver-specific options.
 | 
			
		||||
	GraphDriverOptions []string `json:"driver-options,omitempty"`
 | 
			
		||||
	// UIDMap and GIDMap are used mainly for deciding on the ownership of
 | 
			
		||||
	// files in layers as they're stored on disk, which is often necessary
 | 
			
		||||
	// when user namespaces are being used.
 | 
			
		||||
	// UIDMap and GIDMap are used for setting up a container's root filesystem
 | 
			
		||||
	// for use inside of a user namespace where UID mapping is being used.
 | 
			
		||||
	UIDMap []idtools.IDMap `json:"uidmap,omitempty"`
 | 
			
		||||
	GIDMap []idtools.IDMap `json:"gidmap,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -152,6 +152,8 @@ type Store interface {
 | 
			
		|||
	GraphRoot() string
 | 
			
		||||
	GraphDriverName() string
 | 
			
		||||
	GraphOptions() []string
 | 
			
		||||
	UIDMap() []idtools.IDMap
 | 
			
		||||
	GIDMap() []idtools.IDMap
 | 
			
		||||
 | 
			
		||||
	// GraphDriver obtains and returns a handle to the graph Driver object used
 | 
			
		||||
	// by the Store.
 | 
			
		||||
| 
						 | 
				
			
			@ -161,7 +163,7 @@ type Store interface {
 | 
			
		|||
	// optionally having the specified ID (one will be assigned if none is
 | 
			
		||||
	// specified), with the specified layer (or no layer) as its parent,
 | 
			
		||||
	// and with optional names.  (The writeable flag is ignored.)
 | 
			
		||||
	CreateLayer(id, parent string, names []string, mountLabel string, writeable bool) (*Layer, error)
 | 
			
		||||
	CreateLayer(id, parent string, names []string, mountLabel string, writeable bool, options *LayerOptions) (*Layer, error)
 | 
			
		||||
 | 
			
		||||
	// PutLayer combines the functions of CreateLayer and ApplyDiff,
 | 
			
		||||
	// marking the layer for automatic removal if applying the diff fails
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +176,7 @@ type Store interface {
 | 
			
		|||
	//   if reexec.Init {
 | 
			
		||||
	//       return
 | 
			
		||||
	//   }
 | 
			
		||||
	PutLayer(id, parent string, names []string, mountLabel string, writeable bool, diff io.Reader) (*Layer, int64, error)
 | 
			
		||||
	PutLayer(id, parent string, names []string, mountLabel string, writeable bool, options *LayerOptions, diff io.Reader) (*Layer, int64, error)
 | 
			
		||||
 | 
			
		||||
	// CreateImage creates a new image, optionally with the specified ID
 | 
			
		||||
	// (one will be assigned if none is specified), with optional names,
 | 
			
		||||
| 
						 | 
				
			
			@ -303,6 +305,11 @@ type Store interface {
 | 
			
		|||
	// if we don't have a value on hand.
 | 
			
		||||
	LayerSize(id string) (int64, error)
 | 
			
		||||
 | 
			
		||||
	// LayerParentOwners returns the UIDs and GIDs of owners of parents of
 | 
			
		||||
	// the layer's mountpoint for which the layer's UID and GID maps (if
 | 
			
		||||
	// any are defined) don't contain corresponding IDs.
 | 
			
		||||
	LayerParentOwners(id string) ([]int, []int, error)
 | 
			
		||||
 | 
			
		||||
	// Layers returns a list of the currently known layers.
 | 
			
		||||
	Layers() ([]Layer, error)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -413,6 +420,11 @@ type Store interface {
 | 
			
		|||
	// directory.
 | 
			
		||||
	FromContainerRunDirectory(id, file string) ([]byte, error)
 | 
			
		||||
 | 
			
		||||
	// ContainerParentOwners returns the UIDs and GIDs of owners of parents
 | 
			
		||||
	// of the container's layer's mountpoint for which the layer's UID and
 | 
			
		||||
	// GID maps (if any are defined) don't contain corresponding IDs.
 | 
			
		||||
	ContainerParentOwners(id string) ([]int, []int, error)
 | 
			
		||||
 | 
			
		||||
	// Lookup returns the ID of a layer, image, or container with the specified
 | 
			
		||||
	// name or ID.
 | 
			
		||||
	Lookup(name string) (string, error)
 | 
			
		||||
| 
						 | 
				
			
			@ -429,6 +441,33 @@ type Store interface {
 | 
			
		|||
	Version() ([][2]string, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IDMappingOptions are used for specifying how ID mapping should be set up for
 | 
			
		||||
// a layer or container.
 | 
			
		||||
type IDMappingOptions struct {
 | 
			
		||||
	// UIDMap and GIDMap are used for setting up a layer's root filesystem
 | 
			
		||||
	// for use inside of a user namespace where ID mapping is being used.
 | 
			
		||||
	// If HostUIDMapping/HostGIDMapping is true, no mapping of the
 | 
			
		||||
	// respective type will be used.  Otherwise, if UIDMap and/or GIDMap
 | 
			
		||||
	// contain at least one mapping, one or both will be used.  By default,
 | 
			
		||||
	// if neither of those conditions apply, if the layer has a parent
 | 
			
		||||
	// layer, the parent layer's mapping will be used, and if it does not
 | 
			
		||||
	// have a parent layer, the mapping which was passed to the Store
 | 
			
		||||
	// object when it was initialized will be used.
 | 
			
		||||
	HostUIDMapping bool
 | 
			
		||||
	HostGIDMapping bool
 | 
			
		||||
	UIDMap         []idtools.IDMap
 | 
			
		||||
	GIDMap         []idtools.IDMap
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LayerOptions is used for passing options to a Store's CreateLayer() and PutLayer() methods.
 | 
			
		||||
type LayerOptions struct {
 | 
			
		||||
	// IDMappingOptions specifies the type of ID mapping which should be
 | 
			
		||||
	// used for this layer.  If nothing is specified, the layer will
 | 
			
		||||
	// inherit settings from its parent layer or, if it has no parent
 | 
			
		||||
	// layer, the Store object.
 | 
			
		||||
	IDMappingOptions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ImageOptions is used for passing options to a Store's CreateImage() method.
 | 
			
		||||
type ImageOptions struct {
 | 
			
		||||
	// CreationDate, if not zero, will override the default behavior of marking the image as having been
 | 
			
		||||
| 
						 | 
				
			
			@ -440,6 +479,11 @@ type ImageOptions struct {
 | 
			
		|||
 | 
			
		||||
// ContainerOptions is used for passing options to a Store's CreateContainer() method.
 | 
			
		||||
type ContainerOptions struct {
 | 
			
		||||
	// IDMappingOptions specifies the type of ID mapping which should be
 | 
			
		||||
	// used for this container's layer.  If nothing is specified, the
 | 
			
		||||
	// container's layer will inherit settings from the image's top layer
 | 
			
		||||
	// or, if it is not being created based on an image, the Store object.
 | 
			
		||||
	IDMappingOptions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type store struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -558,6 +602,14 @@ func (s *store) GraphOptions() []string {
 | 
			
		|||
	return s.graphOptions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *store) UIDMap() []idtools.IDMap {
 | 
			
		||||
	return copyIDMap(s.uidMap)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *store) GIDMap() []idtools.IDMap {
 | 
			
		||||
	return copyIDMap(s.gidMap)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *store) load() error {
 | 
			
		||||
	driver, err := s.GraphDriver()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -662,7 +714,7 @@ func (s *store) LayerStore() (LayerStore, error) {
 | 
			
		|||
	if err := os.MkdirAll(glpath, 0700); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	rls, err := newLayerStore(rlpath, glpath, driver)
 | 
			
		||||
	rls, err := newLayerStore(rlpath, glpath, driver, s.uidMap, s.gidMap)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -742,7 +794,8 @@ func (s *store) ContainerStore() (ContainerStore, error) {
 | 
			
		|||
	return nil, ErrLoadError
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *store) PutLayer(id, parent string, names []string, mountLabel string, writeable bool, diff io.Reader) (*Layer, int64, error) {
 | 
			
		||||
func (s *store) PutLayer(id, parent string, names []string, mountLabel string, writeable bool, options *LayerOptions, diff io.Reader) (*Layer, int64, error) {
 | 
			
		||||
	var parentLayer *Layer
 | 
			
		||||
	rlstore, err := s.LayerStore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, -1, err
 | 
			
		||||
| 
						 | 
				
			
			@ -768,9 +821,27 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
 | 
			
		|||
	if id == "" {
 | 
			
		||||
		id = stringid.GenerateRandomID()
 | 
			
		||||
	}
 | 
			
		||||
	if options == nil {
 | 
			
		||||
		options = &LayerOptions{}
 | 
			
		||||
	}
 | 
			
		||||
	if options.HostUIDMapping {
 | 
			
		||||
		options.UIDMap = nil
 | 
			
		||||
	}
 | 
			
		||||
	if options.HostGIDMapping {
 | 
			
		||||
		options.GIDMap = nil
 | 
			
		||||
	}
 | 
			
		||||
	uidMap := options.UIDMap
 | 
			
		||||
	gidMap := options.GIDMap
 | 
			
		||||
	if parent != "" {
 | 
			
		||||
		var ilayer *Layer
 | 
			
		||||
		for _, lstore := range append([]ROLayerStore{rlstore}, rlstores...) {
 | 
			
		||||
			if lstore != rlstore {
 | 
			
		||||
				lstore.Lock()
 | 
			
		||||
				defer lstore.Unlock()
 | 
			
		||||
				if modified, err := lstore.Modified(); modified || err != nil {
 | 
			
		||||
					lstore.Load()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if l, err := lstore.Get(parent); err == nil && l != nil {
 | 
			
		||||
				ilayer = l
 | 
			
		||||
				parent = ilayer.ID
 | 
			
		||||
| 
						 | 
				
			
			@ -780,6 +851,7 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
 | 
			
		|||
		if ilayer == nil {
 | 
			
		||||
			return nil, -1, ErrLayerUnknown
 | 
			
		||||
		}
 | 
			
		||||
		parentLayer = ilayer
 | 
			
		||||
		containers, err := rcstore.Containers()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, -1, err
 | 
			
		||||
| 
						 | 
				
			
			@ -789,12 +861,33 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
 | 
			
		|||
				return nil, -1, ErrParentIsContainer
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if !options.HostUIDMapping && len(options.UIDMap) == 0 {
 | 
			
		||||
			uidMap = ilayer.UIDMap
 | 
			
		||||
		}
 | 
			
		||||
		if !options.HostGIDMapping && len(options.GIDMap) == 0 {
 | 
			
		||||
			gidMap = ilayer.GIDMap
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if !options.HostUIDMapping && len(options.UIDMap) == 0 {
 | 
			
		||||
			uidMap = s.uidMap
 | 
			
		||||
		}
 | 
			
		||||
		if !options.HostGIDMapping && len(options.GIDMap) == 0 {
 | 
			
		||||
			gidMap = s.gidMap
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return rlstore.Put(id, parent, names, mountLabel, nil, writeable, nil, diff)
 | 
			
		||||
	layerOptions := &LayerOptions{
 | 
			
		||||
		IDMappingOptions: IDMappingOptions{
 | 
			
		||||
			HostUIDMapping: options.HostUIDMapping,
 | 
			
		||||
			HostGIDMapping: options.HostGIDMapping,
 | 
			
		||||
			UIDMap:         copyIDMap(uidMap),
 | 
			
		||||
			GIDMap:         copyIDMap(gidMap),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return rlstore.Put(id, parentLayer, names, mountLabel, nil, layerOptions, writeable, nil, diff)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *store) CreateLayer(id, parent string, names []string, mountLabel string, writeable bool) (*Layer, error) {
 | 
			
		||||
	layer, _, err := s.PutLayer(id, parent, names, mountLabel, writeable, nil)
 | 
			
		||||
func (s *store) CreateLayer(id, parent string, names []string, mountLabel string, writeable bool, options *LayerOptions) (*Layer, error) {
 | 
			
		||||
	layer, _, err := s.PutLayer(id, parent, names, mountLabel, writeable, options, nil)
 | 
			
		||||
	return layer, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -849,6 +942,15 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (s *store) CreateContainer(id string, names []string, image, layer, metadata string, options *ContainerOptions) (*Container, error) {
 | 
			
		||||
	if options == nil {
 | 
			
		||||
		options = &ContainerOptions{}
 | 
			
		||||
	}
 | 
			
		||||
	if options.HostUIDMapping {
 | 
			
		||||
		options.UIDMap = nil
 | 
			
		||||
	}
 | 
			
		||||
	if options.HostGIDMapping {
 | 
			
		||||
		options.GIDMap = nil
 | 
			
		||||
	}
 | 
			
		||||
	rlstore, err := s.LayerStore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -862,8 +964,10 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
 | 
			
		|||
		id = stringid.GenerateRandomID()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	imageTopLayer := ""
 | 
			
		||||
	var imageTopLayer *Layer
 | 
			
		||||
	imageID := ""
 | 
			
		||||
	uidMap := options.UIDMap
 | 
			
		||||
	gidMap := options.GIDMap
 | 
			
		||||
	if image != "" {
 | 
			
		||||
		istore, err := s.ImageStore()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -888,10 +992,53 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
 | 
			
		|||
		if cimage == nil {
 | 
			
		||||
			return nil, ErrImageUnknown
 | 
			
		||||
		}
 | 
			
		||||
		imageTopLayer = cimage.TopLayer
 | 
			
		||||
		imageID = cimage.ID
 | 
			
		||||
 | 
			
		||||
		lstores, err := s.ROLayerStores()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		var ilayer *Layer
 | 
			
		||||
		for _, store := range append([]ROLayerStore{rlstore}, lstores...) {
 | 
			
		||||
			if store != rlstore {
 | 
			
		||||
				store.Lock()
 | 
			
		||||
				defer store.Unlock()
 | 
			
		||||
				if modified, err := store.Modified(); modified || err != nil {
 | 
			
		||||
					store.Load()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ilayer, err = store.Get(cimage.TopLayer)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if ilayer == nil {
 | 
			
		||||
			return nil, ErrLayerUnknown
 | 
			
		||||
		}
 | 
			
		||||
		imageTopLayer = ilayer
 | 
			
		||||
		if !options.HostUIDMapping && len(options.UIDMap) == 0 {
 | 
			
		||||
			uidMap = ilayer.UIDMap
 | 
			
		||||
		}
 | 
			
		||||
		if !options.HostGIDMapping && len(options.GIDMap) == 0 {
 | 
			
		||||
			gidMap = ilayer.GIDMap
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if !options.HostUIDMapping && len(options.UIDMap) == 0 {
 | 
			
		||||
			uidMap = s.uidMap
 | 
			
		||||
		}
 | 
			
		||||
		if !options.HostGIDMapping && len(options.GIDMap) == 0 {
 | 
			
		||||
			gidMap = s.gidMap
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	clayer, err := rlstore.Create(layer, imageTopLayer, nil, "", nil, true)
 | 
			
		||||
	layerOptions := &LayerOptions{
 | 
			
		||||
		IDMappingOptions: IDMappingOptions{
 | 
			
		||||
			HostUIDMapping: options.HostUIDMapping,
 | 
			
		||||
			HostGIDMapping: options.HostGIDMapping,
 | 
			
		||||
			UIDMap:         copyIDMap(uidMap),
 | 
			
		||||
			GIDMap:         copyIDMap(gidMap),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	clayer, err := rlstore.Create(layer, imageTopLayer, nil, "", nil, layerOptions, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -905,7 +1052,15 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
 | 
			
		|||
	if modified, err := rcstore.Modified(); modified || err != nil {
 | 
			
		||||
		rcstore.Load()
 | 
			
		||||
	}
 | 
			
		||||
	container, err := rcstore.Create(id, names, imageID, layer, metadata)
 | 
			
		||||
	options = &ContainerOptions{
 | 
			
		||||
		IDMappingOptions: IDMappingOptions{
 | 
			
		||||
			HostUIDMapping: len(clayer.UIDMap) == 0,
 | 
			
		||||
			HostGIDMapping: len(clayer.GIDMap) == 0,
 | 
			
		||||
			UIDMap:         copyIDMap(clayer.UIDMap),
 | 
			
		||||
			GIDMap:         copyIDMap(clayer.GIDMap),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	container, err := rcstore.Create(id, names, imageID, layer, metadata, options)
 | 
			
		||||
	if err != nil || container == nil {
 | 
			
		||||
		rlstore.Delete(layer)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1944,6 +2099,51 @@ func (s *store) LayerSize(id string) (int64, error) {
 | 
			
		|||
	return -1, ErrLayerUnknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *store) LayerParentOwners(id string) ([]int, []int, error) {
 | 
			
		||||
	rlstore, err := s.LayerStore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	rlstore.Lock()
 | 
			
		||||
	defer rlstore.Unlock()
 | 
			
		||||
	if modified, err := rlstore.Modified(); modified || err != nil {
 | 
			
		||||
		rlstore.Load()
 | 
			
		||||
	}
 | 
			
		||||
	if rlstore.Exists(id) {
 | 
			
		||||
		return rlstore.ParentOwners(id)
 | 
			
		||||
	}
 | 
			
		||||
	return nil, nil, ErrLayerUnknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *store) ContainerParentOwners(id string) ([]int, []int, error) {
 | 
			
		||||
	rlstore, err := s.LayerStore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	rcstore, err := s.ContainerStore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	rlstore.Lock()
 | 
			
		||||
	defer rlstore.Unlock()
 | 
			
		||||
	if modified, err := rlstore.Modified(); modified || err != nil {
 | 
			
		||||
		rlstore.Load()
 | 
			
		||||
	}
 | 
			
		||||
	rcstore.Lock()
 | 
			
		||||
	defer rcstore.Unlock()
 | 
			
		||||
	if modified, err := rcstore.Modified(); modified || err != nil {
 | 
			
		||||
		rcstore.Load()
 | 
			
		||||
	}
 | 
			
		||||
	container, err := rcstore.Get(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if rlstore.Exists(container.LayerID) {
 | 
			
		||||
		return rlstore.ParentOwners(container.LayerID)
 | 
			
		||||
	}
 | 
			
		||||
	return nil, nil, ErrLayerUnknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *store) Layers() ([]Layer, error) {
 | 
			
		||||
	var layers []Layer
 | 
			
		||||
	lstore, err := s.LayerStore()
 | 
			
		||||
| 
						 | 
				
			
			@ -2399,6 +2599,18 @@ type OptionsConfig struct {
 | 
			
		|||
 | 
			
		||||
	// OverrideKernelCheck
 | 
			
		||||
	OverrideKernelCheck string `toml:"override_kernel_check"`
 | 
			
		||||
 | 
			
		||||
	// RemapUIDs is a list of default UID mappings to use for layers.
 | 
			
		||||
	RemapUIDs string `toml:"remap-uids"`
 | 
			
		||||
	// RemapGIDs is a list of default GID mappings to use for layers.
 | 
			
		||||
	RemapGIDs string `toml:"remap-gids"`
 | 
			
		||||
 | 
			
		||||
	// RemapUser is the name of one or more entries in /etc/subuid which
 | 
			
		||||
	// should be used to set up default UID mappings.
 | 
			
		||||
	RemapUser string `toml:"remap-user"`
 | 
			
		||||
	// RemapGroup is the name of one or more entries in /etc/subgid which
 | 
			
		||||
	// should be used to set up default GID mappings.
 | 
			
		||||
	RemapGroup string `toml:"remap-group"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TOML-friendly explicit tables used for conversions.
 | 
			
		||||
| 
						 | 
				
			
			@ -2448,6 +2660,71 @@ func init() {
 | 
			
		|||
	if config.Storage.Options.OverrideKernelCheck != "" {
 | 
			
		||||
		DefaultStoreOptions.GraphDriverOptions = append(DefaultStoreOptions.GraphDriverOptions, fmt.Sprintf("%s.override_kernel_check=%s", config.Storage.Driver, config.Storage.Options.OverrideKernelCheck))
 | 
			
		||||
	}
 | 
			
		||||
	if config.Storage.Options.RemapUser != "" && config.Storage.Options.RemapGroup == "" {
 | 
			
		||||
		config.Storage.Options.RemapGroup = config.Storage.Options.RemapUser
 | 
			
		||||
	}
 | 
			
		||||
	if config.Storage.Options.RemapGroup != "" && config.Storage.Options.RemapUser == "" {
 | 
			
		||||
		config.Storage.Options.RemapUser = config.Storage.Options.RemapGroup
 | 
			
		||||
	}
 | 
			
		||||
	if config.Storage.Options.RemapUser != "" && config.Storage.Options.RemapGroup != "" {
 | 
			
		||||
		mappings, err := idtools.NewIDMappings(config.Storage.Options.RemapUser, config.Storage.Options.RemapGroup)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Printf("Error initializing ID mappings for %s:%s %v\n", config.Storage.Options.RemapUser, config.Storage.Options.RemapGroup, err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		DefaultStoreOptions.UIDMap = mappings.UIDs()
 | 
			
		||||
		DefaultStoreOptions.GIDMap = mappings.GIDs()
 | 
			
		||||
	}
 | 
			
		||||
	nonDigitsToWhitespace := func(r rune) rune {
 | 
			
		||||
		if strings.IndexRune("0123456789", r) == -1 {
 | 
			
		||||
			return ' '
 | 
			
		||||
		} else {
 | 
			
		||||
			return r
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	parseTriple := func(spec []string) (container, host, size uint32, err error) {
 | 
			
		||||
		cid, err := strconv.ParseUint(spec[0], 10, 32)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, 0, 0, fmt.Errorf("error parsing id map value %q: %v", spec[0], err)
 | 
			
		||||
		}
 | 
			
		||||
		hid, err := strconv.ParseUint(spec[1], 10, 32)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, 0, 0, fmt.Errorf("error parsing id map value %q: %v", spec[1], err)
 | 
			
		||||
		}
 | 
			
		||||
		sz, err := strconv.ParseUint(spec[2], 10, 32)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, 0, 0, fmt.Errorf("error parsing id map value %q: %v", spec[2], err)
 | 
			
		||||
		}
 | 
			
		||||
		return uint32(cid), uint32(hid), uint32(sz), nil
 | 
			
		||||
	}
 | 
			
		||||
	parseIDMap := func(idMapSpec, mapSetting string) (idmap []idtools.IDMap) {
 | 
			
		||||
		if len(idMapSpec) > 0 {
 | 
			
		||||
			idSpec := strings.Fields(strings.Map(nonDigitsToWhitespace, idMapSpec))
 | 
			
		||||
			if len(idSpec)%3 != 0 {
 | 
			
		||||
				fmt.Printf("Error initializing ID mappings: %s setting is malformed.\n", mapSetting)
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			for i := range idSpec {
 | 
			
		||||
				if i%3 != 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				cid, hid, size, err := parseTriple(idSpec[i : i+3])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					fmt.Printf("Error initializing ID mappings: %s setting is malformed.\n", mapSetting)
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
				mapping := idtools.IDMap{
 | 
			
		||||
					ContainerID: int(cid),
 | 
			
		||||
					HostID:      int(hid),
 | 
			
		||||
					Size:        int(size),
 | 
			
		||||
				}
 | 
			
		||||
				idmap = append(idmap, mapping)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return idmap
 | 
			
		||||
	}
 | 
			
		||||
	DefaultStoreOptions.UIDMap = append(DefaultStoreOptions.UIDMap, parseIDMap(config.Storage.Options.RemapUIDs, "remap-uids")...)
 | 
			
		||||
	DefaultStoreOptions.GIDMap = append(DefaultStoreOptions.GIDMap, parseIDMap(config.Storage.Options.RemapGIDs, "remap-gids")...)
 | 
			
		||||
	if os.Getenv("STORAGE_DRIVER") != "" {
 | 
			
		||||
		DefaultStoreOptions.GraphDriverName = os.Getenv("STORAGE_DRIVER")
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue