summaryrefslogtreecommitdiff
path: root/vendor
diff options
context:
space:
mode:
Diffstat (limited to 'vendor')
-rw-r--r--vendor/github.com/containers/image/docker/daemon/client.go24
-rw-r--r--vendor/github.com/containers/image/storage/storage_image.go2
-rw-r--r--vendor/github.com/containers/storage/containers.go17
-rw-r--r--vendor/github.com/containers/storage/containers_ffjson.go221
-rw-r--r--vendor/github.com/containers/storage/drivers/aufs/aufs.go64
-rw-r--r--vendor/github.com/containers/storage/drivers/btrfs/btrfs.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/chown.go167
-rw-r--r--vendor/github.com/containers/storage/drivers/chroot_unix.go21
-rw-r--r--vendor/github.com/containers/storage/drivers/chroot_windows.go15
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/driver.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/driver.go22
-rw-r--r--vendor/github.com/containers/storage/drivers/fsdiff.go71
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go174
-rw-r--r--vendor/github.com/containers/storage/drivers/vfs/driver.go10
-rw-r--r--vendor/github.com/containers/storage/drivers/windows/windows.go21
-rw-r--r--vendor/github.com/containers/storage/drivers/zfs/zfs.go2
-rw-r--r--vendor/github.com/containers/storage/errors.go2
-rw-r--r--vendor/github.com/containers/storage/images_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/layers.go155
-rw-r--r--vendor/github.com/containers/storage/layers_ffjson.go221
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive.go82
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive_ffjson.go2230
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes.go14
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes_linux.go24
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes_other.go18
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes_unix.go17
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes_windows.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/diff.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/chrootarchive/archive.go13
-rw-r--r--vendor/github.com/containers/storage/store.go305
30 files changed, 3740 insertions, 182 deletions
diff --git a/vendor/github.com/containers/image/docker/daemon/client.go b/vendor/github.com/containers/image/docker/daemon/client.go
index 82fab4b19..11f8f6420 100644
--- a/vendor/github.com/containers/image/docker/daemon/client.go
+++ b/vendor/github.com/containers/image/docker/daemon/client.go
@@ -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,
+ }
+}
diff --git a/vendor/github.com/containers/image/storage/storage_image.go b/vendor/github.com/containers/image/storage/storage_image.go
index cc99027a5..0823b7ed9 100644
--- a/vendor/github.com/containers/image/storage/storage_image.go
+++ b/vendor/github.com/containers/image/storage/storage_image.go
@@ -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)
}
diff --git a/vendor/github.com/containers/storage/containers.go b/vendor/github.com/containers/storage/containers.go
index 1d8b4d3f6..bf73054bc 100644
--- a/vendor/github.com/containers/storage/containers.go
+++ b/vendor/github.com/containers/storage/containers.go
@@ -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
diff --git a/vendor/github.com/containers/storage/containers_ffjson.go b/vendor/github.com/containers/storage/containers_ffjson.go
index a0fb69eb2..aef6becfe 100644
--- a/vendor/github.com/containers/storage/containers_ffjson.go
+++ b/vendor/github.com/containers/storage/containers_ffjson.go
@@ -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*/
diff --git a/vendor/github.com/containers/storage/drivers/aufs/aufs.go b/vendor/github.com/containers/storage/drivers/aufs/aufs.go
index c1cfabee9..bbbe9e4af 100644
--- a/vendor/github.com/containers/storage/drivers/aufs/aufs.go
+++ b/vendor/github.com/containers/storage/drivers/aufs/aufs.go
@@ -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")
+}
diff --git a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
index abc856c83..4b9699fdb 100644
--- a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
+++ b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
@@ -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) {
diff --git a/vendor/github.com/containers/storage/drivers/chown.go b/vendor/github.com/containers/storage/drivers/chown.go
new file mode 100644
index 000000000..c12e73b3b
--- /dev/null
+++ b/vendor/github.com/containers/storage/drivers/chown.go
@@ -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)
+}
diff --git a/vendor/github.com/containers/storage/drivers/chroot_unix.go b/vendor/github.com/containers/storage/drivers/chroot_unix.go
new file mode 100644
index 000000000..c8c4905bf
--- /dev/null
+++ b/vendor/github.com/containers/storage/drivers/chroot_unix.go
@@ -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
+}
diff --git a/vendor/github.com/containers/storage/drivers/chroot_windows.go b/vendor/github.com/containers/storage/drivers/chroot_windows.go
new file mode 100644
index 000000000..1df031789
--- /dev/null
+++ b/vendor/github.com/containers/storage/drivers/chroot_windows.go
@@ -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
+}
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/driver.go b/vendor/github.com/containers/storage/drivers/devmapper/driver.go
index d68fb66cc..a4ec6ebfd 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/driver.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/driver.go
@@ -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 {
diff --git a/vendor/github.com/containers/storage/drivers/driver.go b/vendor/github.com/containers/storage/drivers/driver.go
index 615d93be5..1b4ad336d 100644
--- a/vendor/github.com/containers/storage/drivers/driver.go
+++ b/vendor/github.com/containers/storage/drivers/driver.go
@@ -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.
diff --git a/vendor/github.com/containers/storage/drivers/fsdiff.go b/vendor/github.com/containers/storage/drivers/fsdiff.go
index f74239cb9..35869d906 100644
--- a/vendor/github.com/containers/storage/drivers/fsdiff.go
+++ b/vendor/github.com/containers/storage/drivers/fsdiff.go
@@ -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
}
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index de6ee6da5..6b5f6912f 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -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)
+}
diff --git a/vendor/github.com/containers/storage/drivers/vfs/driver.go b/vendor/github.com/containers/storage/drivers/vfs/driver.go
index ae62207d1..cee55f8d1 100644
--- a/vendor/github.com/containers/storage/drivers/vfs/driver.go
+++ b/vendor/github.com/containers/storage/drivers/vfs/driver.go
@@ -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
}
diff --git a/vendor/github.com/containers/storage/drivers/windows/windows.go b/vendor/github.com/containers/storage/drivers/windows/windows.go
index e9e9f5c65..b750715bf 100644
--- a/vendor/github.com/containers/storage/drivers/windows/windows.go
+++ b/vendor/github.com/containers/storage/drivers/windows/windows.go
@@ -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
}
diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs.go b/vendor/github.com/containers/storage/drivers/zfs/zfs.go
index 8c8e7d671..886ebc8bd 100644
--- a/vendor/github.com/containers/storage/drivers/zfs/zfs.go
+++ b/vendor/github.com/containers/storage/drivers/zfs/zfs.go
@@ -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) {
diff --git a/vendor/github.com/containers/storage/errors.go b/vendor/github.com/containers/storage/errors.go
index bed6f8cdc..562415c09 100644
--- a/vendor/github.com/containers/storage/errors.go
+++ b/vendor/github.com/containers/storage/errors.go
@@ -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")
)
diff --git a/vendor/github.com/containers/storage/images_ffjson.go b/vendor/github.com/containers/storage/images_ffjson.go
index f91ee6d4f..f6a8b0650 100644
--- a/vendor/github.com/containers/storage/images_ffjson.go
+++ b/vendor/github.com/containers/storage/images_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: ./images.go
+// source: images.go
package storage
diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go
index 91117a4f2..9a060e684 100644
--- a/vendor/github.com/containers/storage/layers.go
+++ b/vendor/github.com/containers/storage/layers.go
@@ -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
}
diff --git a/vendor/github.com/containers/storage/layers_ffjson.go b/vendor/github.com/containers/storage/layers_ffjson.go
index 608fe1863..125b5d8c9 100644
--- a/vendor/github.com/containers/storage/layers_ffjson.go
+++ b/vendor/github.com/containers/storage/layers_ffjson.go
@@ -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:
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go
index e74cddd70..1002296f2 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive.go
@@ -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.
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive_ffjson.go b/vendor/github.com/containers/storage/pkg/archive/archive_ffjson.go
new file mode 100644
index 000000000..6f0f4524e
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/archive/archive_ffjson.go
@@ -0,0 +1,2230 @@
+// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
+// source: pkg/archive/archive.go
+
+package archive
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "github.com/containers/storage/pkg/idtools"
+ fflib "github.com/pquerna/ffjson/fflib/v1"
+)
+
+// MarshalJSON marshal bytes to json - template
+func (j *Archiver) MarshalJSON() ([]byte, error) {
+ var buf fflib.Buffer
+ if j == nil {
+ buf.WriteString("null")
+ return buf.Bytes(), nil
+ }
+ err := j.MarshalJSONBuf(&buf)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalJSONBuf marshal buff to json - template
+func (j *Archiver) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
+ if j == nil {
+ buf.WriteString("null")
+ return nil
+ }
+ var err error
+ var obj []byte
+ _ = obj
+ _ = err
+ buf.WriteString(`{"Untar":`)
+ /* Falling back. type=func(io.Reader, string, *archive.TarOptions) error kind=func */
+ err = buf.Encode(j.Untar)
+ if err != nil {
+ return err
+ }
+ if j.TarIDMappings != nil {
+ /* Struct fall back. type=idtools.IDMappings kind=struct */
+ buf.WriteString(`,"TarIDMappings":`)
+ err = buf.Encode(j.TarIDMappings)
+ if err != nil {
+ return err
+ }
+ } else {
+ buf.WriteString(`,"TarIDMappings":null`)
+ }
+ if j.ChownOpts != nil {
+ /* Struct fall back. type=idtools.IDPair kind=struct */
+ buf.WriteString(`,"ChownOpts":`)
+ err = buf.Encode(j.ChownOpts)
+ if err != nil {
+ return err
+ }
+ } else {
+ buf.WriteString(`,"ChownOpts":null`)
+ }
+ if j.UntarIDMappings != nil {
+ /* Struct fall back. type=idtools.IDMappings kind=struct */
+ buf.WriteString(`,"UntarIDMappings":`)
+ err = buf.Encode(j.UntarIDMappings)
+ if err != nil {
+ return err
+ }
+ } else {
+ buf.WriteString(`,"UntarIDMappings":null`)
+ }
+ buf.WriteByte('}')
+ return nil
+}
+
+const (
+ ffjtArchiverbase = iota
+ ffjtArchivernosuchkey
+
+ ffjtArchiverUntar
+
+ ffjtArchiverTarIDMappings
+
+ ffjtArchiverChownOpts
+
+ ffjtArchiverUntarIDMappings
+)
+
+var ffjKeyArchiverUntar = []byte("Untar")
+
+var ffjKeyArchiverTarIDMappings = []byte("TarIDMappings")
+
+var ffjKeyArchiverChownOpts = []byte("ChownOpts")
+
+var ffjKeyArchiverUntarIDMappings = []byte("UntarIDMappings")
+
+// UnmarshalJSON umarshall json - template of ffjson
+func (j *Archiver) UnmarshalJSON(input []byte) error {
+ fs := fflib.NewFFLexer(input)
+ return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)
+}
+
+// UnmarshalJSONFFLexer fast json unmarshall - template ffjson
+func (j *Archiver) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {
+ var err error
+ currentKey := ffjtArchiverbase
+ _ = currentKey
+ tok := fflib.FFTok_init
+ wantedTok := fflib.FFTok_init
+
+mainparse:
+ for {
+ tok = fs.Scan()
+ // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state))
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+
+ switch state {
+
+ case fflib.FFParse_map_start:
+ if tok != fflib.FFTok_left_bracket {
+ wantedTok = fflib.FFTok_left_bracket
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_key
+ continue
+
+ case fflib.FFParse_after_value:
+ if tok == fflib.FFTok_comma {
+ state = fflib.FFParse_want_key
+ } else if tok == fflib.FFTok_right_bracket {
+ goto done
+ } else {
+ wantedTok = fflib.FFTok_comma
+ goto wrongtokenerror
+ }
+
+ case fflib.FFParse_want_key:
+ // json {} ended. goto exit. woo.
+ if tok == fflib.FFTok_right_bracket {
+ goto done
+ }
+ if tok != fflib.FFTok_string {
+ wantedTok = fflib.FFTok_string
+ goto wrongtokenerror
+ }
+
+ kn := fs.Output.Bytes()
+ if len(kn) <= 0 {
+ // "" case. hrm.
+ currentKey = ffjtArchivernosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ } else {
+ switch kn[0] {
+
+ case 'C':
+
+ if bytes.Equal(ffjKeyArchiverChownOpts, kn) {
+ currentKey = ffjtArchiverChownOpts
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'T':
+
+ if bytes.Equal(ffjKeyArchiverTarIDMappings, kn) {
+ currentKey = ffjtArchiverTarIDMappings
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'U':
+
+ if bytes.Equal(ffjKeyArchiverUntar, kn) {
+ currentKey = ffjtArchiverUntar
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyArchiverUntarIDMappings, kn) {
+ currentKey = ffjtArchiverUntarIDMappings
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ }
+
+ if fflib.EqualFoldRight(ffjKeyArchiverUntarIDMappings, kn) {
+ currentKey = ffjtArchiverUntarIDMappings
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyArchiverChownOpts, kn) {
+ currentKey = ffjtArchiverChownOpts
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyArchiverTarIDMappings, kn) {
+ currentKey = ffjtArchiverTarIDMappings
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.SimpleLetterEqualFold(ffjKeyArchiverUntar, kn) {
+ currentKey = ffjtArchiverUntar
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ currentKey = ffjtArchivernosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case fflib.FFParse_want_colon:
+ if tok != fflib.FFTok_colon {
+ wantedTok = fflib.FFTok_colon
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_value
+ continue
+ case fflib.FFParse_want_value:
+
+ if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null {
+ switch currentKey {
+
+ case ffjtArchiverUntar:
+ goto handle_Untar
+
+ case ffjtArchiverTarIDMappings:
+ goto handle_TarIDMappings
+
+ case ffjtArchiverChownOpts:
+ goto handle_ChownOpts
+
+ case ffjtArchiverUntarIDMappings:
+ goto handle_UntarIDMappings
+
+ case ffjtArchivernosuchkey:
+ err = fs.SkipField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ state = fflib.FFParse_after_value
+ goto mainparse
+ }
+ } else {
+ goto wantedvalue
+ }
+ }
+ }
+
+handle_Untar:
+
+ /* handler: j.Untar type=func(io.Reader, string, *archive.TarOptions) error kind=func quoted=false*/
+
+ {
+ /* Falling back. type=func(io.Reader, string, *archive.TarOptions) error kind=func */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.Untar)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_TarIDMappings:
+
+ /* handler: j.TarIDMappings type=idtools.IDMappings kind=struct quoted=false*/
+
+ {
+ /* Falling back. type=idtools.IDMappings kind=struct */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.TarIDMappings)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_ChownOpts:
+
+ /* handler: j.ChownOpts type=idtools.IDPair kind=struct quoted=false*/
+
+ {
+ /* Falling back. type=idtools.IDPair kind=struct */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.ChownOpts)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UntarIDMappings:
+
+ /* handler: j.UntarIDMappings type=idtools.IDMappings kind=struct quoted=false*/
+
+ {
+ /* Falling back. type=idtools.IDMappings kind=struct */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.UntarIDMappings)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+wantedvalue:
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+wrongtokenerror:
+ return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String()))
+tokerror:
+ if fs.BigError != nil {
+ return fs.WrapErr(fs.BigError)
+ }
+ err = fs.Error.ToError()
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ panic("ffjson-generated: unreachable, please report bug.")
+done:
+
+ return nil
+}
+
+// MarshalJSON marshal bytes to json - template
+func (j *TarOptions) MarshalJSON() ([]byte, error) {
+ var buf fflib.Buffer
+ if j == nil {
+ buf.WriteString("null")
+ return buf.Bytes(), nil
+ }
+ err := j.MarshalJSONBuf(&buf)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalJSONBuf marshal buff to json - template
+func (j *TarOptions) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
+ if j == nil {
+ buf.WriteString("null")
+ return nil
+ }
+ var err error
+ var obj []byte
+ _ = obj
+ _ = err
+ buf.WriteString(`{"IncludeFiles":`)
+ if j.IncludeFiles != nil {
+ buf.WriteString(`[`)
+ for i, v := range j.IncludeFiles {
+ if i != 0 {
+ buf.WriteString(`,`)
+ }
+ fflib.WriteJsonString(buf, string(v))
+ }
+ buf.WriteString(`]`)
+ } else {
+ buf.WriteString(`null`)
+ }
+ buf.WriteString(`,"ExcludePatterns":`)
+ if j.ExcludePatterns != nil {
+ buf.WriteString(`[`)
+ for i, v := range j.ExcludePatterns {
+ if i != 0 {
+ buf.WriteString(`,`)
+ }
+ fflib.WriteJsonString(buf, string(v))
+ }
+ buf.WriteString(`]`)
+ } else {
+ buf.WriteString(`null`)
+ }
+ buf.WriteString(`,"Compression":`)
+ fflib.FormatBits2(buf, uint64(j.Compression), 10, j.Compression < 0)
+ if j.NoLchown {
+ buf.WriteString(`,"NoLchown":true`)
+ } else {
+ buf.WriteString(`,"NoLchown":false`)
+ }
+ buf.WriteString(`,"UIDMaps":`)
+ if j.UIDMaps != nil {
+ buf.WriteString(`[`)
+ for i, v := range j.UIDMaps {
+ 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.WriteString(`,"GIDMaps":`)
+ if j.GIDMaps != nil {
+ buf.WriteString(`[`)
+ for i, v := range j.GIDMaps {
+ 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`)
+ }
+ if j.ChownOpts != nil {
+ /* Struct fall back. type=idtools.IDPair kind=struct */
+ buf.WriteString(`,"ChownOpts":`)
+ err = buf.Encode(j.ChownOpts)
+ if err != nil {
+ return err
+ }
+ } else {
+ buf.WriteString(`,"ChownOpts":null`)
+ }
+ if j.IncludeSourceDir {
+ buf.WriteString(`,"IncludeSourceDir":true`)
+ } else {
+ buf.WriteString(`,"IncludeSourceDir":false`)
+ }
+ buf.WriteString(`,"WhiteoutFormat":`)
+ fflib.FormatBits2(buf, uint64(j.WhiteoutFormat), 10, j.WhiteoutFormat < 0)
+ buf.WriteString(`,"WhiteoutData":`)
+ /* Interface types must use runtime reflection. type=interface {} kind=interface */
+ err = buf.Encode(j.WhiteoutData)
+ if err != nil {
+ return err
+ }
+ if j.NoOverwriteDirNonDir {
+ buf.WriteString(`,"NoOverwriteDirNonDir":true`)
+ } else {
+ buf.WriteString(`,"NoOverwriteDirNonDir":false`)
+ }
+ if j.RebaseNames == nil {
+ buf.WriteString(`,"RebaseNames":null`)
+ } else {
+ buf.WriteString(`,"RebaseNames":{ `)
+ for key, value := range j.RebaseNames {
+ fflib.WriteJsonString(buf, key)
+ buf.WriteString(`:`)
+ fflib.WriteJsonString(buf, string(value))
+ buf.WriteByte(',')
+ }
+ buf.Rewind(1)
+ buf.WriteByte('}')
+ }
+ if j.InUserNS {
+ buf.WriteString(`,"InUserNS":true`)
+ } else {
+ buf.WriteString(`,"InUserNS":false`)
+ }
+ buf.WriteByte('}')
+ return nil
+}
+
+const (
+ ffjtTarOptionsbase = iota
+ ffjtTarOptionsnosuchkey
+
+ ffjtTarOptionsIncludeFiles
+
+ ffjtTarOptionsExcludePatterns
+
+ ffjtTarOptionsCompression
+
+ ffjtTarOptionsNoLchown
+
+ ffjtTarOptionsUIDMaps
+
+ ffjtTarOptionsGIDMaps
+
+ ffjtTarOptionsChownOpts
+
+ ffjtTarOptionsIncludeSourceDir
+
+ ffjtTarOptionsWhiteoutFormat
+
+ ffjtTarOptionsWhiteoutData
+
+ ffjtTarOptionsNoOverwriteDirNonDir
+
+ ffjtTarOptionsRebaseNames
+
+ ffjtTarOptionsInUserNS
+)
+
+var ffjKeyTarOptionsIncludeFiles = []byte("IncludeFiles")
+
+var ffjKeyTarOptionsExcludePatterns = []byte("ExcludePatterns")
+
+var ffjKeyTarOptionsCompression = []byte("Compression")
+
+var ffjKeyTarOptionsNoLchown = []byte("NoLchown")
+
+var ffjKeyTarOptionsUIDMaps = []byte("UIDMaps")
+
+var ffjKeyTarOptionsGIDMaps = []byte("GIDMaps")
+
+var ffjKeyTarOptionsChownOpts = []byte("ChownOpts")
+
+var ffjKeyTarOptionsIncludeSourceDir = []byte("IncludeSourceDir")
+
+var ffjKeyTarOptionsWhiteoutFormat = []byte("WhiteoutFormat")
+
+var ffjKeyTarOptionsWhiteoutData = []byte("WhiteoutData")
+
+var ffjKeyTarOptionsNoOverwriteDirNonDir = []byte("NoOverwriteDirNonDir")
+
+var ffjKeyTarOptionsRebaseNames = []byte("RebaseNames")
+
+var ffjKeyTarOptionsInUserNS = []byte("InUserNS")
+
+// UnmarshalJSON umarshall json - template of ffjson
+func (j *TarOptions) UnmarshalJSON(input []byte) error {
+ fs := fflib.NewFFLexer(input)
+ return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)
+}
+
+// UnmarshalJSONFFLexer fast json unmarshall - template ffjson
+func (j *TarOptions) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {
+ var err error
+ currentKey := ffjtTarOptionsbase
+ _ = currentKey
+ tok := fflib.FFTok_init
+ wantedTok := fflib.FFTok_init
+
+mainparse:
+ for {
+ tok = fs.Scan()
+ // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state))
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+
+ switch state {
+
+ case fflib.FFParse_map_start:
+ if tok != fflib.FFTok_left_bracket {
+ wantedTok = fflib.FFTok_left_bracket
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_key
+ continue
+
+ case fflib.FFParse_after_value:
+ if tok == fflib.FFTok_comma {
+ state = fflib.FFParse_want_key
+ } else if tok == fflib.FFTok_right_bracket {
+ goto done
+ } else {
+ wantedTok = fflib.FFTok_comma
+ goto wrongtokenerror
+ }
+
+ case fflib.FFParse_want_key:
+ // json {} ended. goto exit. woo.
+ if tok == fflib.FFTok_right_bracket {
+ goto done
+ }
+ if tok != fflib.FFTok_string {
+ wantedTok = fflib.FFTok_string
+ goto wrongtokenerror
+ }
+
+ kn := fs.Output.Bytes()
+ if len(kn) <= 0 {
+ // "" case. hrm.
+ currentKey = ffjtTarOptionsnosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ } else {
+ switch kn[0] {
+
+ case 'C':
+
+ if bytes.Equal(ffjKeyTarOptionsCompression, kn) {
+ currentKey = ffjtTarOptionsCompression
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyTarOptionsChownOpts, kn) {
+ currentKey = ffjtTarOptionsChownOpts
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'E':
+
+ if bytes.Equal(ffjKeyTarOptionsExcludePatterns, kn) {
+ currentKey = ffjtTarOptionsExcludePatterns
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'G':
+
+ if bytes.Equal(ffjKeyTarOptionsGIDMaps, kn) {
+ currentKey = ffjtTarOptionsGIDMaps
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'I':
+
+ if bytes.Equal(ffjKeyTarOptionsIncludeFiles, kn) {
+ currentKey = ffjtTarOptionsIncludeFiles
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyTarOptionsIncludeSourceDir, kn) {
+ currentKey = ffjtTarOptionsIncludeSourceDir
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyTarOptionsInUserNS, kn) {
+ currentKey = ffjtTarOptionsInUserNS
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'N':
+
+ if bytes.Equal(ffjKeyTarOptionsNoLchown, kn) {
+ currentKey = ffjtTarOptionsNoLchown
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyTarOptionsNoOverwriteDirNonDir, kn) {
+ currentKey = ffjtTarOptionsNoOverwriteDirNonDir
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'R':
+
+ if bytes.Equal(ffjKeyTarOptionsRebaseNames, kn) {
+ currentKey = ffjtTarOptionsRebaseNames
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'U':
+
+ if bytes.Equal(ffjKeyTarOptionsUIDMaps, kn) {
+ currentKey = ffjtTarOptionsUIDMaps
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'W':
+
+ if bytes.Equal(ffjKeyTarOptionsWhiteoutFormat, kn) {
+ currentKey = ffjtTarOptionsWhiteoutFormat
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyTarOptionsWhiteoutData, kn) {
+ currentKey = ffjtTarOptionsWhiteoutData
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTarOptionsInUserNS, kn) {
+ currentKey = ffjtTarOptionsInUserNS
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTarOptionsRebaseNames, kn) {
+ currentKey = ffjtTarOptionsRebaseNames
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.SimpleLetterEqualFold(ffjKeyTarOptionsNoOverwriteDirNonDir, kn) {
+ currentKey = ffjtTarOptionsNoOverwriteDirNonDir
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.SimpleLetterEqualFold(ffjKeyTarOptionsWhiteoutData, kn) {
+ currentKey = ffjtTarOptionsWhiteoutData
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.SimpleLetterEqualFold(ffjKeyTarOptionsWhiteoutFormat, kn) {
+ currentKey = ffjtTarOptionsWhiteoutFormat
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTarOptionsIncludeSourceDir, kn) {
+ currentKey = ffjtTarOptionsIncludeSourceDir
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTarOptionsChownOpts, kn) {
+ currentKey = ffjtTarOptionsChownOpts
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTarOptionsGIDMaps, kn) {
+ currentKey = ffjtTarOptionsGIDMaps
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTarOptionsUIDMaps, kn) {
+ currentKey = ffjtTarOptionsUIDMaps
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.SimpleLetterEqualFold(ffjKeyTarOptionsNoLchown, kn) {
+ currentKey = ffjtTarOptionsNoLchown
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTarOptionsCompression, kn) {
+ currentKey = ffjtTarOptionsCompression
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTarOptionsExcludePatterns, kn) {
+ currentKey = ffjtTarOptionsExcludePatterns
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTarOptionsIncludeFiles, kn) {
+ currentKey = ffjtTarOptionsIncludeFiles
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ currentKey = ffjtTarOptionsnosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case fflib.FFParse_want_colon:
+ if tok != fflib.FFTok_colon {
+ wantedTok = fflib.FFTok_colon
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_value
+ continue
+ case fflib.FFParse_want_value:
+
+ if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null {
+ switch currentKey {
+
+ case ffjtTarOptionsIncludeFiles:
+ goto handle_IncludeFiles
+
+ case ffjtTarOptionsExcludePatterns:
+ goto handle_ExcludePatterns
+
+ case ffjtTarOptionsCompression:
+ goto handle_Compression
+
+ case ffjtTarOptionsNoLchown:
+ goto handle_NoLchown
+
+ case ffjtTarOptionsUIDMaps:
+ goto handle_UIDMaps
+
+ case ffjtTarOptionsGIDMaps:
+ goto handle_GIDMaps
+
+ case ffjtTarOptionsChownOpts:
+ goto handle_ChownOpts
+
+ case ffjtTarOptionsIncludeSourceDir:
+ goto handle_IncludeSourceDir
+
+ case ffjtTarOptionsWhiteoutFormat:
+ goto handle_WhiteoutFormat
+
+ case ffjtTarOptionsWhiteoutData:
+ goto handle_WhiteoutData
+
+ case ffjtTarOptionsNoOverwriteDirNonDir:
+ goto handle_NoOverwriteDirNonDir
+
+ case ffjtTarOptionsRebaseNames:
+ goto handle_RebaseNames
+
+ case ffjtTarOptionsInUserNS:
+ goto handle_InUserNS
+
+ case ffjtTarOptionsnosuchkey:
+ err = fs.SkipField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ state = fflib.FFParse_after_value
+ goto mainparse
+ }
+ } else {
+ goto wantedvalue
+ }
+ }
+ }
+
+handle_IncludeFiles:
+
+ /* handler: j.IncludeFiles type=[]string 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.IncludeFiles = nil
+ } else {
+
+ j.IncludeFiles = []string{}
+
+ wantVal := true
+
+ for {
+
+ var tmpJIncludeFiles string
+
+ 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: tmpJIncludeFiles type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ tmpJIncludeFiles = string(string(outBuf))
+
+ }
+ }
+
+ j.IncludeFiles = append(j.IncludeFiles, tmpJIncludeFiles)
+
+ wantVal = false
+ }
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_ExcludePatterns:
+
+ /* handler: j.ExcludePatterns type=[]string 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.ExcludePatterns = nil
+ } else {
+
+ j.ExcludePatterns = []string{}
+
+ wantVal := true
+
+ for {
+
+ var tmpJExcludePatterns string
+
+ 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: tmpJExcludePatterns type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ tmpJExcludePatterns = string(string(outBuf))
+
+ }
+ }
+
+ j.ExcludePatterns = append(j.ExcludePatterns, tmpJExcludePatterns)
+
+ wantVal = false
+ }
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_Compression:
+
+ /* handler: j.Compression type=archive.Compression kind=int quoted=false*/
+
+ {
+ if tok != fflib.FFTok_integer && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for Compression", tok))
+ }
+ }
+
+ {
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64)
+
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ j.Compression = Compression(tval)
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_NoLchown:
+
+ /* handler: j.NoLchown type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.NoLchown = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.NoLchown = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UIDMaps:
+
+ /* handler: j.UIDMaps 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.UIDMaps = nil
+ } else {
+
+ j.UIDMaps = []idtools.IDMap{}
+
+ wantVal := true
+
+ for {
+
+ var tmpJUIDMaps 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: tmpJUIDMaps 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, &tmpJUIDMaps)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ j.UIDMaps = append(j.UIDMaps, tmpJUIDMaps)
+
+ wantVal = false
+ }
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_GIDMaps:
+
+ /* handler: j.GIDMaps 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.GIDMaps = nil
+ } else {
+
+ j.GIDMaps = []idtools.IDMap{}
+
+ wantVal := true
+
+ for {
+
+ var tmpJGIDMaps 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: tmpJGIDMaps 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, &tmpJGIDMaps)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ j.GIDMaps = append(j.GIDMaps, tmpJGIDMaps)
+
+ wantVal = false
+ }
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_ChownOpts:
+
+ /* handler: j.ChownOpts type=idtools.IDPair kind=struct quoted=false*/
+
+ {
+ /* Falling back. type=idtools.IDPair kind=struct */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.ChownOpts)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_IncludeSourceDir:
+
+ /* handler: j.IncludeSourceDir type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.IncludeSourceDir = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.IncludeSourceDir = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_WhiteoutFormat:
+
+ /* handler: j.WhiteoutFormat type=archive.WhiteoutFormat kind=int quoted=false*/
+
+ {
+ if tok != fflib.FFTok_integer && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for WhiteoutFormat", tok))
+ }
+ }
+
+ {
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64)
+
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ j.WhiteoutFormat = WhiteoutFormat(tval)
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_WhiteoutData:
+
+ /* handler: j.WhiteoutData type=interface {} kind=interface quoted=false*/
+
+ {
+ /* Falling back. type=interface {} kind=interface */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.WhiteoutData)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_NoOverwriteDirNonDir:
+
+ /* handler: j.NoOverwriteDirNonDir type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.NoOverwriteDirNonDir = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.NoOverwriteDirNonDir = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_RebaseNames:
+
+ /* handler: j.RebaseNames type=map[string]string kind=map quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_left_bracket && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+ j.RebaseNames = nil
+ } else {
+
+ j.RebaseNames = make(map[string]string, 0)
+
+ wantVal := true
+
+ for {
+
+ var k string
+
+ var tmpJRebaseNames string
+
+ tok = fs.Scan()
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+ if tok == fflib.FFTok_right_bracket {
+ 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: k type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ k = string(string(outBuf))
+
+ }
+ }
+
+ // Expect ':' after key
+ tok = fs.Scan()
+ if tok != fflib.FFTok_colon {
+ return fs.WrapErr(fmt.Errorf("wanted colon token, but got token: %v", tok))
+ }
+
+ tok = fs.Scan()
+ /* handler: tmpJRebaseNames type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ tmpJRebaseNames = string(string(outBuf))
+
+ }
+ }
+
+ j.RebaseNames[k] = tmpJRebaseNames
+
+ wantVal = false
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_InUserNS:
+
+ /* handler: j.InUserNS type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.InUserNS = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.InUserNS = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+wantedvalue:
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+wrongtokenerror:
+ return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String()))
+tokerror:
+ if fs.BigError != nil {
+ return fs.WrapErr(fs.BigError)
+ }
+ err = fs.Error.ToError()
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ panic("ffjson-generated: unreachable, please report bug.")
+done:
+
+ return nil
+}
+
+// MarshalJSON marshal bytes to json - template
+func (j *TempArchive) MarshalJSON() ([]byte, error) {
+ var buf fflib.Buffer
+ if j == nil {
+ buf.WriteString("null")
+ return buf.Bytes(), nil
+ }
+ err := j.MarshalJSONBuf(&buf)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalJSONBuf marshal buff to json - template
+func (j *TempArchive) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
+ if j == nil {
+ buf.WriteString("null")
+ return nil
+ }
+ var err error
+ var obj []byte
+ _ = obj
+ _ = err
+ buf.WriteString(`{"Size":`)
+ fflib.FormatBits2(buf, uint64(j.Size), 10, j.Size < 0)
+ buf.WriteByte('}')
+ return nil
+}
+
+const (
+ ffjtTempArchivebase = iota
+ ffjtTempArchivenosuchkey
+
+ ffjtTempArchiveSize
+)
+
+var ffjKeyTempArchiveSize = []byte("Size")
+
+// UnmarshalJSON umarshall json - template of ffjson
+func (j *TempArchive) UnmarshalJSON(input []byte) error {
+ fs := fflib.NewFFLexer(input)
+ return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)
+}
+
+// UnmarshalJSONFFLexer fast json unmarshall - template ffjson
+func (j *TempArchive) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {
+ var err error
+ currentKey := ffjtTempArchivebase
+ _ = currentKey
+ tok := fflib.FFTok_init
+ wantedTok := fflib.FFTok_init
+
+mainparse:
+ for {
+ tok = fs.Scan()
+ // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state))
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+
+ switch state {
+
+ case fflib.FFParse_map_start:
+ if tok != fflib.FFTok_left_bracket {
+ wantedTok = fflib.FFTok_left_bracket
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_key
+ continue
+
+ case fflib.FFParse_after_value:
+ if tok == fflib.FFTok_comma {
+ state = fflib.FFParse_want_key
+ } else if tok == fflib.FFTok_right_bracket {
+ goto done
+ } else {
+ wantedTok = fflib.FFTok_comma
+ goto wrongtokenerror
+ }
+
+ case fflib.FFParse_want_key:
+ // json {} ended. goto exit. woo.
+ if tok == fflib.FFTok_right_bracket {
+ goto done
+ }
+ if tok != fflib.FFTok_string {
+ wantedTok = fflib.FFTok_string
+ goto wrongtokenerror
+ }
+
+ kn := fs.Output.Bytes()
+ if len(kn) <= 0 {
+ // "" case. hrm.
+ currentKey = ffjtTempArchivenosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ } else {
+ switch kn[0] {
+
+ case 'S':
+
+ if bytes.Equal(ffjKeyTempArchiveSize, kn) {
+ currentKey = ffjtTempArchiveSize
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ }
+
+ if fflib.EqualFoldRight(ffjKeyTempArchiveSize, kn) {
+ currentKey = ffjtTempArchiveSize
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ currentKey = ffjtTempArchivenosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case fflib.FFParse_want_colon:
+ if tok != fflib.FFTok_colon {
+ wantedTok = fflib.FFTok_colon
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_value
+ continue
+ case fflib.FFParse_want_value:
+
+ if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null {
+ switch currentKey {
+
+ case ffjtTempArchiveSize:
+ goto handle_Size
+
+ case ffjtTempArchivenosuchkey:
+ err = fs.SkipField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ state = fflib.FFParse_after_value
+ goto mainparse
+ }
+ } else {
+ goto wantedvalue
+ }
+ }
+ }
+
+handle_Size:
+
+ /* handler: j.Size type=int64 kind=int64 quoted=false*/
+
+ {
+ if tok != fflib.FFTok_integer && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int64", tok))
+ }
+ }
+
+ {
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64)
+
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ j.Size = int64(tval)
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+wantedvalue:
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+wrongtokenerror:
+ return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String()))
+tokerror:
+ if fs.BigError != nil {
+ return fs.WrapErr(fs.BigError)
+ }
+ err = fs.Error.ToError()
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ panic("ffjson-generated: unreachable, please report bug.")
+done:
+
+ return nil
+}
+
+// MarshalJSON marshal bytes to json - template
+func (j *tarAppender) MarshalJSON() ([]byte, error) {
+ var buf fflib.Buffer
+ if j == nil {
+ buf.WriteString("null")
+ return buf.Bytes(), nil
+ }
+ err := j.MarshalJSONBuf(&buf)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalJSONBuf marshal buff to json - template
+func (j *tarAppender) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
+ if j == nil {
+ buf.WriteString("null")
+ return nil
+ }
+ var err error
+ var obj []byte
+ _ = obj
+ _ = err
+ if j.TarWriter != nil {
+ /* Struct fall back. type=tar.Writer kind=struct */
+ buf.WriteString(`{"TarWriter":`)
+ err = buf.Encode(j.TarWriter)
+ if err != nil {
+ return err
+ }
+ } else {
+ buf.WriteString(`{"TarWriter":null`)
+ }
+ if j.Buffer != nil {
+ /* Struct fall back. type=bufio.Writer kind=struct */
+ buf.WriteString(`,"Buffer":`)
+ err = buf.Encode(j.Buffer)
+ if err != nil {
+ return err
+ }
+ } else {
+ buf.WriteString(`,"Buffer":null`)
+ }
+ /* Falling back. type=map[uint64]string kind=map */
+ buf.WriteString(`,"SeenFiles":`)
+ err = buf.Encode(j.SeenFiles)
+ if err != nil {
+ return err
+ }
+ if j.IDMappings != nil {
+ /* Struct fall back. type=idtools.IDMappings kind=struct */
+ buf.WriteString(`,"IDMappings":`)
+ err = buf.Encode(j.IDMappings)
+ if err != nil {
+ return err
+ }
+ } else {
+ buf.WriteString(`,"IDMappings":null`)
+ }
+ if j.ChownOpts != nil {
+ /* Struct fall back. type=idtools.IDPair kind=struct */
+ buf.WriteString(`,"ChownOpts":`)
+ err = buf.Encode(j.ChownOpts)
+ if err != nil {
+ return err
+ }
+ } else {
+ buf.WriteString(`,"ChownOpts":null`)
+ }
+ buf.WriteString(`,"WhiteoutConverter":`)
+ /* Interface types must use runtime reflection. type=archive.tarWhiteoutConverter kind=interface */
+ err = buf.Encode(j.WhiteoutConverter)
+ if err != nil {
+ return err
+ }
+ buf.WriteByte('}')
+ return nil
+}
+
+const (
+ ffjttarAppenderbase = iota
+ ffjttarAppendernosuchkey
+
+ ffjttarAppenderTarWriter
+
+ ffjttarAppenderBuffer
+
+ ffjttarAppenderSeenFiles
+
+ ffjttarAppenderIDMappings
+
+ ffjttarAppenderChownOpts
+
+ ffjttarAppenderWhiteoutConverter
+)
+
+var ffjKeytarAppenderTarWriter = []byte("TarWriter")
+
+var ffjKeytarAppenderBuffer = []byte("Buffer")
+
+var ffjKeytarAppenderSeenFiles = []byte("SeenFiles")
+
+var ffjKeytarAppenderIDMappings = []byte("IDMappings")
+
+var ffjKeytarAppenderChownOpts = []byte("ChownOpts")
+
+var ffjKeytarAppenderWhiteoutConverter = []byte("WhiteoutConverter")
+
+// UnmarshalJSON umarshall json - template of ffjson
+func (j *tarAppender) UnmarshalJSON(input []byte) error {
+ fs := fflib.NewFFLexer(input)
+ return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)
+}
+
+// UnmarshalJSONFFLexer fast json unmarshall - template ffjson
+func (j *tarAppender) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {
+ var err error
+ currentKey := ffjttarAppenderbase
+ _ = currentKey
+ tok := fflib.FFTok_init
+ wantedTok := fflib.FFTok_init
+
+mainparse:
+ for {
+ tok = fs.Scan()
+ // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state))
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+
+ switch state {
+
+ case fflib.FFParse_map_start:
+ if tok != fflib.FFTok_left_bracket {
+ wantedTok = fflib.FFTok_left_bracket
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_key
+ continue
+
+ case fflib.FFParse_after_value:
+ if tok == fflib.FFTok_comma {
+ state = fflib.FFParse_want_key
+ } else if tok == fflib.FFTok_right_bracket {
+ goto done
+ } else {
+ wantedTok = fflib.FFTok_comma
+ goto wrongtokenerror
+ }
+
+ case fflib.FFParse_want_key:
+ // json {} ended. goto exit. woo.
+ if tok == fflib.FFTok_right_bracket {
+ goto done
+ }
+ if tok != fflib.FFTok_string {
+ wantedTok = fflib.FFTok_string
+ goto wrongtokenerror
+ }
+
+ kn := fs.Output.Bytes()
+ if len(kn) <= 0 {
+ // "" case. hrm.
+ currentKey = ffjttarAppendernosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ } else {
+ switch kn[0] {
+
+ case 'B':
+
+ if bytes.Equal(ffjKeytarAppenderBuffer, kn) {
+ currentKey = ffjttarAppenderBuffer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'C':
+
+ if bytes.Equal(ffjKeytarAppenderChownOpts, kn) {
+ currentKey = ffjttarAppenderChownOpts
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'I':
+
+ if bytes.Equal(ffjKeytarAppenderIDMappings, kn) {
+ currentKey = ffjttarAppenderIDMappings
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'S':
+
+ if bytes.Equal(ffjKeytarAppenderSeenFiles, kn) {
+ currentKey = ffjttarAppenderSeenFiles
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'T':
+
+ if bytes.Equal(ffjKeytarAppenderTarWriter, kn) {
+ currentKey = ffjttarAppenderTarWriter
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 'W':
+
+ if bytes.Equal(ffjKeytarAppenderWhiteoutConverter, kn) {
+ currentKey = ffjttarAppenderWhiteoutConverter
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ }
+
+ if fflib.SimpleLetterEqualFold(ffjKeytarAppenderWhiteoutConverter, kn) {
+ currentKey = ffjttarAppenderWhiteoutConverter
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeytarAppenderChownOpts, kn) {
+ currentKey = ffjttarAppenderChownOpts
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeytarAppenderIDMappings, kn) {
+ currentKey = ffjttarAppenderIDMappings
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeytarAppenderSeenFiles, kn) {
+ currentKey = ffjttarAppenderSeenFiles
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.SimpleLetterEqualFold(ffjKeytarAppenderBuffer, kn) {
+ currentKey = ffjttarAppenderBuffer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.SimpleLetterEqualFold(ffjKeytarAppenderTarWriter, kn) {
+ currentKey = ffjttarAppenderTarWriter
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ currentKey = ffjttarAppendernosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case fflib.FFParse_want_colon:
+ if tok != fflib.FFTok_colon {
+ wantedTok = fflib.FFTok_colon
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_value
+ continue
+ case fflib.FFParse_want_value:
+
+ if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null {
+ switch currentKey {
+
+ case ffjttarAppenderTarWriter:
+ goto handle_TarWriter
+
+ case ffjttarAppenderBuffer:
+ goto handle_Buffer
+
+ case ffjttarAppenderSeenFiles:
+ goto handle_SeenFiles
+
+ case ffjttarAppenderIDMappings:
+ goto handle_IDMappings
+
+ case ffjttarAppenderChownOpts:
+ goto handle_ChownOpts
+
+ case ffjttarAppenderWhiteoutConverter:
+ goto handle_WhiteoutConverter
+
+ case ffjttarAppendernosuchkey:
+ err = fs.SkipField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ state = fflib.FFParse_after_value
+ goto mainparse
+ }
+ } else {
+ goto wantedvalue
+ }
+ }
+ }
+
+handle_TarWriter:
+
+ /* handler: j.TarWriter type=tar.Writer kind=struct quoted=false*/
+
+ {
+ /* Falling back. type=tar.Writer kind=struct */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.TarWriter)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_Buffer:
+
+ /* handler: j.Buffer type=bufio.Writer kind=struct quoted=false*/
+
+ {
+ /* Falling back. type=bufio.Writer kind=struct */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.Buffer)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_SeenFiles:
+
+ /* handler: j.SeenFiles type=map[uint64]string kind=map quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_left_bracket && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+ j.SeenFiles = nil
+ } else {
+
+ j.SeenFiles = make(map[uint64]string, 0)
+
+ wantVal := true
+
+ for {
+
+ var k uint64
+
+ var tmpJSeenFiles string
+
+ tok = fs.Scan()
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+ if tok == fflib.FFTok_right_bracket {
+ 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: k type=uint64 kind=uint64 quoted=false*/
+
+ {
+ if tok != fflib.FFTok_integer && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for uint64", tok))
+ }
+ }
+
+ {
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ tval, err := fflib.ParseUint(fs.Output.Bytes(), 10, 64)
+
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ k = uint64(tval)
+
+ }
+ }
+
+ // Expect ':' after key
+ tok = fs.Scan()
+ if tok != fflib.FFTok_colon {
+ return fs.WrapErr(fmt.Errorf("wanted colon token, but got token: %v", tok))
+ }
+
+ tok = fs.Scan()
+ /* handler: tmpJSeenFiles type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ tmpJSeenFiles = string(string(outBuf))
+
+ }
+ }
+
+ j.SeenFiles[k] = tmpJSeenFiles
+
+ wantVal = false
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_IDMappings:
+
+ /* handler: j.IDMappings type=idtools.IDMappings kind=struct quoted=false*/
+
+ {
+ /* Falling back. type=idtools.IDMappings kind=struct */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.IDMappings)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_ChownOpts:
+
+ /* handler: j.ChownOpts type=idtools.IDPair kind=struct quoted=false*/
+
+ {
+ /* Falling back. type=idtools.IDPair kind=struct */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.ChownOpts)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_WhiteoutConverter:
+
+ /* handler: j.WhiteoutConverter type=archive.tarWhiteoutConverter kind=interface quoted=false*/
+
+ {
+ /* Falling back. type=archive.tarWhiteoutConverter kind=interface */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &j.WhiteoutConverter)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+wantedvalue:
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+wrongtokenerror:
+ return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String()))
+tokerror:
+ if fs.BigError != nil {
+ return fs.WrapErr(fs.BigError)
+ }
+ err = fs.Error.ToError()
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ panic("ffjson-generated: unreachable, please report bug.")
+done:
+
+ return nil
+}
diff --git a/vendor/github.com/containers/storage/pkg/archive/changes.go b/vendor/github.com/containers/storage/pkg/archive/changes.go
index 8ab6b83f5..d3d6c8f74 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes.go
@@ -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
}
diff --git a/vendor/github.com/containers/storage/pkg/archive/changes_linux.go b/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
index 8a82e857d..b12309361 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
@@ -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))
diff --git a/vendor/github.com/containers/storage/pkg/archive/changes_other.go b/vendor/github.com/containers/storage/pkg/archive/changes_other.go
index e1d1e7a91..bbbd8c9de 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes_other.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes_other.go
@@ -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)
diff --git a/vendor/github.com/containers/storage/pkg/archive/changes_unix.go b/vendor/github.com/containers/storage/pkg/archive/changes_unix.go
index d669c01b4..031ec341b 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes_unix.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes_unix.go
@@ -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 &&
diff --git a/vendor/github.com/containers/storage/pkg/archive/changes_windows.go b/vendor/github.com/containers/storage/pkg/archive/changes_windows.go
index 5ad3d7e38..966400e59 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes_windows.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes_windows.go
@@ -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() ||
diff --git a/vendor/github.com/containers/storage/pkg/archive/diff.go b/vendor/github.com/containers/storage/pkg/archive/diff.go
index f93f4cb17..eb1f2b4c8 100644
--- a/vendor/github.com/containers/storage/pkg/archive/diff.go
+++ b/vendor/github.com/containers/storage/pkg/archive/diff.go
@@ -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
}
diff --git a/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go b/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go
index 2735f1400..b9fa228e6 100644
--- a/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go
@@ -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,
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index c7de67ec5..407dda872 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -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
+ }
+ }
+ layerOptions := &LayerOptions{
+ IDMappingOptions: IDMappingOptions{
+ HostUIDMapping: options.HostUIDMapping,
+ HostGIDMapping: options.HostGIDMapping,
+ UIDMap: copyIDMap(uidMap),
+ GIDMap: copyIDMap(gidMap),
+ },
}
- return rlstore.Put(id, parent, names, mountLabel, nil, writeable, nil, diff)
+ 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
+ }
+ }
+ layerOptions := &LayerOptions{
+ IDMappingOptions: IDMappingOptions{
+ HostUIDMapping: options.HostUIDMapping,
+ HostGIDMapping: options.HostGIDMapping,
+ UIDMap: copyIDMap(uidMap),
+ GIDMap: copyIDMap(gidMap),
+ },
}
- clayer, err := rlstore.Create(layer, imageTopLayer, nil, "", nil, true)
+ 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")
}