mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	
							
								
								
									
										25
									
								
								vendor/github.com/containerd/continuity/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/containerd/continuity/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
 | 
			
		||||
*.o
 | 
			
		||||
*.a
 | 
			
		||||
*.so
 | 
			
		||||
 | 
			
		||||
# Folders
 | 
			
		||||
_obj
 | 
			
		||||
_test
 | 
			
		||||
bin
 | 
			
		||||
 | 
			
		||||
# Architecture specific extensions/prefixes
 | 
			
		||||
*.[568vq]
 | 
			
		||||
[568vq].out
 | 
			
		||||
 | 
			
		||||
*.cgo1.go
 | 
			
		||||
*.cgo2.c
 | 
			
		||||
_cgo_defun.c
 | 
			
		||||
_cgo_gotypes.go
 | 
			
		||||
_cgo_export.*
 | 
			
		||||
 | 
			
		||||
_testmain.go
 | 
			
		||||
 | 
			
		||||
*.exe
 | 
			
		||||
*.test
 | 
			
		||||
*.prof
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/containerd/continuity/.mailmap
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/containerd/continuity/.mailmap
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
Stephen J Day <stephen.day@docker.com>  Stephen Day <stevvooe@users.noreply.github.com>
 | 
			
		||||
							
								
								
									
										33
									
								
								vendor/github.com/containerd/continuity/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/containerd/continuity/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
language: go
 | 
			
		||||
sudo: required
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - 1.9.x
 | 
			
		||||
  - 1.10.x
 | 
			
		||||
  - 1.11.x
 | 
			
		||||
  - tip
 | 
			
		||||
 | 
			
		||||
go_import_path: github.com/containerd/continuity
 | 
			
		||||
 | 
			
		||||
env:
 | 
			
		||||
# NOTE: we cannot set GOOS directly (because gimme overrides the value)
 | 
			
		||||
  - TRAVIS_GOOS=windows
 | 
			
		||||
  - TRAVIS_GOOS=linux
 | 
			
		||||
  - TRAVIS_GOOS=darwin
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  - go get -u github.com/vbatts/git-validation
 | 
			
		||||
  - go get -u github.com/kunalkushwaha/ltag
 | 
			
		||||
  - go get -u github.com/LK4D4/vndr
 | 
			
		||||
 | 
			
		||||
before_script:
 | 
			
		||||
  - pushd ..; git clone https://github.com/containerd/project; popd
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - export GOOS=${TRAVIS_GOOS}
 | 
			
		||||
  - DCO_VERBOSITY=-q ../project/script/validate/dco
 | 
			
		||||
  - ../project/script/validate/fileheader ../project/
 | 
			
		||||
  - ../project/script/validate/vendor
 | 
			
		||||
  - make build binaries
 | 
			
		||||
  - if [ "$GOOS" = "linux" ]; then make vet test; fi
 | 
			
		||||
  - if [ "$GOOS" != "linux" ]; then make test-compile; fi
 | 
			
		||||
							
								
								
									
										82
									
								
								vendor/github.com/containerd/continuity/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/containerd/continuity/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
#   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
#   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
#   you may not use this file except in compliance with the License.
 | 
			
		||||
#   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
#       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
#   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
#   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
#   See the License for the specific language governing permissions and
 | 
			
		||||
#   limitations under the License.
 | 
			
		||||
 | 
			
		||||
# Set an output prefix, which is the local directory if not specified
 | 
			
		||||
PREFIX?=$(shell pwd)
 | 
			
		||||
 | 
			
		||||
# Used to populate version variable in main package.
 | 
			
		||||
VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always)
 | 
			
		||||
 | 
			
		||||
GO_LDFLAGS=-ldflags "-X `go list ./version`.Version=$(VERSION)"
 | 
			
		||||
 | 
			
		||||
PACKAGES=$(shell go list ./... | grep -v /vendor/)
 | 
			
		||||
 | 
			
		||||
.PHONY: clean all fmt vet lint build test binaries setup
 | 
			
		||||
.DEFAULT: default
 | 
			
		||||
# skip lint at the moment
 | 
			
		||||
all: AUTHORS clean fmt vet fmt build test binaries
 | 
			
		||||
 | 
			
		||||
AUTHORS: .mailmap .git/HEAD
 | 
			
		||||
	 git log --format='%aN <%aE>' | sort -fu > $@
 | 
			
		||||
 | 
			
		||||
# This only needs to be generated by hand when cutting full releases.
 | 
			
		||||
version/version.go:
 | 
			
		||||
	./version/version.sh > $@
 | 
			
		||||
 | 
			
		||||
${PREFIX}/bin/continuity: version/version.go $(shell find . -type f -name '*.go')
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@go build  -o $@ ${GO_LDFLAGS}  ${GO_GCFLAGS} ./cmd/continuity
 | 
			
		||||
 | 
			
		||||
setup:
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@go get -u github.com/golang/lint/golint
 | 
			
		||||
 | 
			
		||||
generate:
 | 
			
		||||
	go generate $(PACKAGES)
 | 
			
		||||
 | 
			
		||||
# Depends on binaries because vet will silently fail if it can't load compiled
 | 
			
		||||
# imports
 | 
			
		||||
vet: binaries
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@go vet $(PACKAGES)
 | 
			
		||||
 | 
			
		||||
fmt:
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@test -z "$$(gofmt -s -l . | grep -v Godeps/_workspace/src/ | grep -v vendor/ | tee /dev/stderr)" || \
 | 
			
		||||
		echo "+ please format Go code with 'gofmt -s'"
 | 
			
		||||
 | 
			
		||||
lint:
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@test -z "$$(golint $(PACKAGES) | grep -v Godeps/_workspace/src/ | grep -v vendor/ |tee /dev/stderr)"
 | 
			
		||||
 | 
			
		||||
build:
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@go build -v ${GO_LDFLAGS} $(PACKAGES)
 | 
			
		||||
 | 
			
		||||
test:
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@go test $(PACKAGES)
 | 
			
		||||
 | 
			
		||||
test-compile:
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@for pkg in $(PACKAGES); do go test -c $$pkg; done
 | 
			
		||||
 | 
			
		||||
binaries: ${PREFIX}/bin/continuity
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@if [ x$$GOOS = xwindows ]; then echo "+ continuity -> continuity.exe"; mv ${PREFIX}/bin/continuity ${PREFIX}/bin/continuity.exe; fi
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	@echo "+ $@"
 | 
			
		||||
	@rm -rf "${PREFIX}/bin/continuity" "${PREFIX}/bin/continuity.exe"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										84
									
								
								vendor/github.com/containerd/continuity/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								vendor/github.com/containerd/continuity/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
# continuity
 | 
			
		||||
 | 
			
		||||
[](https://godoc.org/github.com/containerd/continuity)
 | 
			
		||||
[](https://travis-ci.org/containerd/continuity)
 | 
			
		||||
 | 
			
		||||
A transport-agnostic, filesystem metadata manifest system
 | 
			
		||||
 | 
			
		||||
This project is a staging area for experiments in providing transport agnostic
 | 
			
		||||
metadata storage.
 | 
			
		||||
 | 
			
		||||
Please see https://github.com/opencontainers/specs/issues/11 for more details.
 | 
			
		||||
 | 
			
		||||
## Manifest Format
 | 
			
		||||
 | 
			
		||||
A continuity manifest encodes filesystem metadata in Protocol Buffers.
 | 
			
		||||
Please refer to [proto/manifest.proto](proto/manifest.proto).
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
Build:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ make
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Create a manifest (of this repo itself):
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ ./bin/continuity build . > /tmp/a.pb
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Dump a manifest:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ ./bin/continuity ls /tmp/a.pb
 | 
			
		||||
...
 | 
			
		||||
-rw-rw-r--      270 B   /.gitignore
 | 
			
		||||
-rw-rw-r--      88 B    /.mailmap
 | 
			
		||||
-rw-rw-r--      187 B   /.travis.yml
 | 
			
		||||
-rw-rw-r--      359 B   /AUTHORS
 | 
			
		||||
-rw-rw-r--      11 kB   /LICENSE
 | 
			
		||||
-rw-rw-r--      1.5 kB  /Makefile
 | 
			
		||||
...
 | 
			
		||||
-rw-rw-r--      986 B   /testutil_test.go
 | 
			
		||||
drwxrwxr-x      0 B     /version
 | 
			
		||||
-rw-rw-r--      478 B   /version/version.go
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Verify a manifest:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ ./bin/continuity verify . /tmp/a.pb
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Break the directory and restore using the manifest:
 | 
			
		||||
```console
 | 
			
		||||
$ chmod 777 Makefile
 | 
			
		||||
$ ./bin/continuity verify . /tmp/a.pb
 | 
			
		||||
2017/06/23 08:00:34 error verifying manifest: resource "/Makefile" has incorrect mode: -rwxrwxrwx != -rw-rw-r--
 | 
			
		||||
$ ./bin/continuity apply . /tmp/a.pb
 | 
			
		||||
$ stat -c %a Makefile
 | 
			
		||||
664
 | 
			
		||||
$ ./bin/continuity verify . /tmp/a.pb
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Contribution Guide
 | 
			
		||||
### Building Proto Package
 | 
			
		||||
 | 
			
		||||
If you change the proto file you will need to rebuild the generated Go with `go generate`.
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ go generate ./proto
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Project details
 | 
			
		||||
 | 
			
		||||
continuity is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
 | 
			
		||||
As a containerd sub-project, you will find the:
 | 
			
		||||
 * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
 | 
			
		||||
 * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
 | 
			
		||||
 * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
 | 
			
		||||
 | 
			
		||||
information in our [`containerd/project`](https://github.com/containerd/project) repository.
 | 
			
		||||
							
								
								
									
										673
									
								
								vendor/github.com/containerd/continuity/context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										673
									
								
								vendor/github.com/containerd/continuity/context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,673 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/devices"
 | 
			
		||||
	driverpkg "github.com/containerd/continuity/driver"
 | 
			
		||||
	"github.com/containerd/continuity/pathdriver"
 | 
			
		||||
 | 
			
		||||
	"github.com/opencontainers/go-digest"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// ErrNotFound represents the resource not found
 | 
			
		||||
	ErrNotFound = fmt.Errorf("not found")
 | 
			
		||||
	// ErrNotSupported represents the resource not supported
 | 
			
		||||
	ErrNotSupported = fmt.Errorf("not supported")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Context represents a file system context for accessing resources. The
 | 
			
		||||
// responsibility of the context is to convert system specific resources to
 | 
			
		||||
// generic Resource objects. Most of this is safe path manipulation, as well
 | 
			
		||||
// as extraction of resource details.
 | 
			
		||||
type Context interface {
 | 
			
		||||
	Apply(Resource) error
 | 
			
		||||
	Verify(Resource) error
 | 
			
		||||
	Resource(string, os.FileInfo) (Resource, error)
 | 
			
		||||
	Walk(filepath.WalkFunc) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SymlinkPath is intended to give the symlink target value
 | 
			
		||||
// in a root context. Target and linkname are absolute paths
 | 
			
		||||
// not under the given root.
 | 
			
		||||
type SymlinkPath func(root, linkname, target string) (string, error)
 | 
			
		||||
 | 
			
		||||
// ContextOptions represents options to create a new context.
 | 
			
		||||
type ContextOptions struct {
 | 
			
		||||
	Digester   Digester
 | 
			
		||||
	Driver     driverpkg.Driver
 | 
			
		||||
	PathDriver pathdriver.PathDriver
 | 
			
		||||
	Provider   ContentProvider
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// context represents a file system context for accessing resources.
 | 
			
		||||
// Generally, all path qualified access and system considerations should land
 | 
			
		||||
// here.
 | 
			
		||||
type context struct {
 | 
			
		||||
	driver     driverpkg.Driver
 | 
			
		||||
	pathDriver pathdriver.PathDriver
 | 
			
		||||
	root       string
 | 
			
		||||
	digester   Digester
 | 
			
		||||
	provider   ContentProvider
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewContext returns a Context associated with root. The default driver will
 | 
			
		||||
// be used, as returned by NewDriver.
 | 
			
		||||
func NewContext(root string) (Context, error) {
 | 
			
		||||
	return NewContextWithOptions(root, ContextOptions{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewContextWithOptions returns a Context associate with the root.
 | 
			
		||||
func NewContextWithOptions(root string, options ContextOptions) (Context, error) {
 | 
			
		||||
	// normalize to absolute path
 | 
			
		||||
	pathDriver := options.PathDriver
 | 
			
		||||
	if pathDriver == nil {
 | 
			
		||||
		pathDriver = pathdriver.LocalPathDriver
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	root = pathDriver.FromSlash(root)
 | 
			
		||||
	root, err := pathDriver.Abs(pathDriver.Clean(root))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	driver := options.Driver
 | 
			
		||||
	if driver == nil {
 | 
			
		||||
		driver, err = driverpkg.NewSystemDriver()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	digester := options.Digester
 | 
			
		||||
	if digester == nil {
 | 
			
		||||
		digester = simpleDigester{digest.Canonical}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check the root directory. Need to be a little careful here. We are
 | 
			
		||||
	// allowing a link for now, but this may have odd behavior when
 | 
			
		||||
	// canonicalizing paths. As long as all files are opened through the link
 | 
			
		||||
	// path, this should be okay.
 | 
			
		||||
	fi, err := driver.Stat(root)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !fi.IsDir() {
 | 
			
		||||
		return nil, &os.PathError{Op: "NewContext", Path: root, Err: os.ErrInvalid}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &context{
 | 
			
		||||
		root:       root,
 | 
			
		||||
		driver:     driver,
 | 
			
		||||
		pathDriver: pathDriver,
 | 
			
		||||
		digester:   digester,
 | 
			
		||||
		provider:   options.Provider,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Resource returns the resource as path p, populating the entry with info
 | 
			
		||||
// from fi. The path p should be the path of the resource in the context,
 | 
			
		||||
// typically obtained through Walk or from the value of Resource.Path(). If fi
 | 
			
		||||
// is nil, it will be resolved.
 | 
			
		||||
func (c *context) Resource(p string, fi os.FileInfo) (Resource, error) {
 | 
			
		||||
	fp, err := c.fullpath(p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fi == nil {
 | 
			
		||||
		fi, err = c.driver.Lstat(fp)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base, err := newBaseResource(p, fi)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base.xattrs, err = c.resolveXAttrs(fp, fi, base)
 | 
			
		||||
	if err == ErrNotSupported {
 | 
			
		||||
		log.Printf("resolving xattrs on %s not supported", fp)
 | 
			
		||||
	} else if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO(stevvooe): Handle windows alternate data streams.
 | 
			
		||||
 | 
			
		||||
	if fi.Mode().IsRegular() {
 | 
			
		||||
		dgst, err := c.digest(p)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return newRegularFile(*base, base.paths, fi.Size(), dgst)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fi.Mode().IsDir() {
 | 
			
		||||
		return newDirectory(*base)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fi.Mode()&os.ModeSymlink != 0 {
 | 
			
		||||
		// We handle relative links vs absolute links by including a
 | 
			
		||||
		// beginning slash for absolute links. Effectively, the bundle's
 | 
			
		||||
		// root is treated as the absolute link anchor.
 | 
			
		||||
		target, err := c.driver.Readlink(fp)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return newSymLink(*base, target)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fi.Mode()&os.ModeNamedPipe != 0 {
 | 
			
		||||
		return newNamedPipe(*base, base.paths)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fi.Mode()&os.ModeDevice != 0 {
 | 
			
		||||
		deviceDriver, ok := c.driver.(driverpkg.DeviceInfoDriver)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			log.Printf("device extraction not supported %s", fp)
 | 
			
		||||
			return nil, ErrNotSupported
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// character and block devices merely need to recover the
 | 
			
		||||
		// major/minor device number.
 | 
			
		||||
		major, minor, err := deviceDriver.DeviceInfo(fi)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return newDevice(*base, base.paths, major, minor)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Printf("%q (%v) is not supported", fp, fi.Mode())
 | 
			
		||||
	return nil, ErrNotFound
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *context) verifyMetadata(resource, target Resource) error {
 | 
			
		||||
	if target.Mode() != resource.Mode() {
 | 
			
		||||
		return fmt.Errorf("resource %q has incorrect mode: %v != %v", target.Path(), target.Mode(), resource.Mode())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if target.UID() != resource.UID() {
 | 
			
		||||
		return fmt.Errorf("unexpected uid for %q: %v != %v", target.Path(), target.UID(), resource.GID())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if target.GID() != resource.GID() {
 | 
			
		||||
		return fmt.Errorf("unexpected gid for %q: %v != %v", target.Path(), target.GID(), target.GID())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if xattrer, ok := resource.(XAttrer); ok {
 | 
			
		||||
		txattrer, tok := target.(XAttrer)
 | 
			
		||||
		if !tok {
 | 
			
		||||
			return fmt.Errorf("resource %q has xattrs but target does not support them", resource.Path())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// For xattrs, only ensure that we have those defined in the resource
 | 
			
		||||
		// and their values match. We can ignore other xattrs. In other words,
 | 
			
		||||
		// we only verify that target has the subset defined by resource.
 | 
			
		||||
		txattrs := txattrer.XAttrs()
 | 
			
		||||
		for attr, value := range xattrer.XAttrs() {
 | 
			
		||||
			tvalue, ok := txattrs[attr]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return fmt.Errorf("resource %q target missing xattr %q", resource.Path(), attr)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if !bytes.Equal(value, tvalue) {
 | 
			
		||||
				return fmt.Errorf("xattr %q value differs for resource %q", attr, resource.Path())
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch r := resource.(type) {
 | 
			
		||||
	case RegularFile:
 | 
			
		||||
		// TODO(stevvooe): Another reason to use a record-based approach. We
 | 
			
		||||
		// have to do another type switch to get this to work. This could be
 | 
			
		||||
		// fixed with an Equal function, but let's study this a little more to
 | 
			
		||||
		// be sure.
 | 
			
		||||
		t, ok := target.(RegularFile)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return fmt.Errorf("resource %q target not a regular file", r.Path())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if t.Size() != r.Size() {
 | 
			
		||||
			return fmt.Errorf("resource %q target has incorrect size: %v != %v", t.Path(), t.Size(), r.Size())
 | 
			
		||||
		}
 | 
			
		||||
	case Directory:
 | 
			
		||||
		t, ok := target.(Directory)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return fmt.Errorf("resource %q target not a directory", t.Path())
 | 
			
		||||
		}
 | 
			
		||||
	case SymLink:
 | 
			
		||||
		t, ok := target.(SymLink)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return fmt.Errorf("resource %q target not a symlink", t.Path())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if t.Target() != r.Target() {
 | 
			
		||||
			return fmt.Errorf("resource %q target has mismatched target: %q != %q", t.Path(), t.Target(), r.Target())
 | 
			
		||||
		}
 | 
			
		||||
	case Device:
 | 
			
		||||
		t, ok := target.(Device)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return fmt.Errorf("resource %q is not a device", t.Path())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if t.Major() != r.Major() || t.Minor() != r.Minor() {
 | 
			
		||||
			return fmt.Errorf("resource %q has mismatched major/minor numbers: %d,%d != %d,%d", t.Path(), t.Major(), t.Minor(), r.Major(), r.Minor())
 | 
			
		||||
		}
 | 
			
		||||
	case NamedPipe:
 | 
			
		||||
		t, ok := target.(NamedPipe)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return fmt.Errorf("resource %q is not a named pipe", t.Path())
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("cannot verify resource: %v", resource)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Verify the resource in the context. An error will be returned a discrepancy
 | 
			
		||||
// is found.
 | 
			
		||||
func (c *context) Verify(resource Resource) error {
 | 
			
		||||
	fp, err := c.fullpath(resource.Path())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fi, err := c.driver.Lstat(fp)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	target, err := c.Resource(resource.Path(), fi)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if target.Path() != resource.Path() {
 | 
			
		||||
		return fmt.Errorf("resource paths do not match: %q != %q", target.Path(), resource.Path())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := c.verifyMetadata(resource, target); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if h, isHardlinkable := resource.(Hardlinkable); isHardlinkable {
 | 
			
		||||
		hardlinkKey, err := newHardlinkKey(fi)
 | 
			
		||||
		if err == errNotAHardLink {
 | 
			
		||||
			if len(h.Paths()) > 1 {
 | 
			
		||||
				return fmt.Errorf("%q is not a hardlink to %q", h.Paths()[1], resource.Path())
 | 
			
		||||
			}
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, path := range h.Paths()[1:] {
 | 
			
		||||
			fpLink, err := c.fullpath(path)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			fiLink, err := c.driver.Lstat(fpLink)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			targetLink, err := c.Resource(path, fiLink)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			hardlinkKeyLink, err := newHardlinkKey(fiLink)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if hardlinkKeyLink != hardlinkKey {
 | 
			
		||||
				return fmt.Errorf("%q is not a hardlink to %q", path, resource.Path())
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err := c.verifyMetadata(resource, targetLink); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch r := resource.(type) {
 | 
			
		||||
	case RegularFile:
 | 
			
		||||
		t, ok := target.(RegularFile)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return fmt.Errorf("resource %q target not a regular file", r.Path())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO(stevvooe): This may need to get a little more sophisticated
 | 
			
		||||
		// for digest comparison. We may want to actually calculate the
 | 
			
		||||
		// provided digests, rather than the implementations having an
 | 
			
		||||
		// overlap.
 | 
			
		||||
		if !digestsMatch(t.Digests(), r.Digests()) {
 | 
			
		||||
			return fmt.Errorf("digests for resource %q do not match: %v != %v", t.Path(), t.Digests(), r.Digests())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *context) checkoutFile(fp string, rf RegularFile) error {
 | 
			
		||||
	if c.provider == nil {
 | 
			
		||||
		return fmt.Errorf("no file provider")
 | 
			
		||||
	}
 | 
			
		||||
	var (
 | 
			
		||||
		r   io.ReadCloser
 | 
			
		||||
		err error
 | 
			
		||||
	)
 | 
			
		||||
	for _, dgst := range rf.Digests() {
 | 
			
		||||
		r, err = c.provider.Reader(dgst)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("file content could not be provided: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer r.Close()
 | 
			
		||||
 | 
			
		||||
	return atomicWriteFile(fp, r, rf.Size(), rf.Mode())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Apply the resource to the contexts. An error will be returned if the
 | 
			
		||||
// operation fails. Depending on the resource type, the resource may be
 | 
			
		||||
// created. For resource that cannot be resolved, an error will be returned.
 | 
			
		||||
func (c *context) Apply(resource Resource) error {
 | 
			
		||||
	fp, err := c.fullpath(resource.Path())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !strings.HasPrefix(fp, c.root) {
 | 
			
		||||
		return fmt.Errorf("resource %v escapes root", resource)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var chmod = true
 | 
			
		||||
	fi, err := c.driver.Lstat(fp)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if !os.IsNotExist(err) {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch r := resource.(type) {
 | 
			
		||||
	case RegularFile:
 | 
			
		||||
		if fi == nil {
 | 
			
		||||
			if err := c.checkoutFile(fp, r); err != nil {
 | 
			
		||||
				return fmt.Errorf("error checking out file %q: %v", resource.Path(), err)
 | 
			
		||||
			}
 | 
			
		||||
			chmod = false
 | 
			
		||||
		} else {
 | 
			
		||||
			if !fi.Mode().IsRegular() {
 | 
			
		||||
				return fmt.Errorf("file %q should be a regular file, but is not", resource.Path())
 | 
			
		||||
			}
 | 
			
		||||
			if fi.Size() != r.Size() {
 | 
			
		||||
				if err := c.checkoutFile(fp, r); err != nil {
 | 
			
		||||
					return fmt.Errorf("error checking out file %q: %v", resource.Path(), err)
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				for _, dgst := range r.Digests() {
 | 
			
		||||
					f, err := os.Open(fp)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fmt.Errorf("failure opening file for read %q: %v", resource.Path(), err)
 | 
			
		||||
					}
 | 
			
		||||
					compared, err := dgst.Algorithm().FromReader(f)
 | 
			
		||||
					if err == nil && dgst != compared {
 | 
			
		||||
						if err := c.checkoutFile(fp, r); err != nil {
 | 
			
		||||
							return fmt.Errorf("error checking out file %q: %v", resource.Path(), err)
 | 
			
		||||
						}
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
					if err1 := f.Close(); err == nil {
 | 
			
		||||
						err = err1
 | 
			
		||||
					}
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fmt.Errorf("error checking digest for %q: %v", resource.Path(), err)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case Directory:
 | 
			
		||||
		if fi == nil {
 | 
			
		||||
			if err := c.driver.Mkdir(fp, resource.Mode()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else if !fi.Mode().IsDir() {
 | 
			
		||||
			return fmt.Errorf("%q should be a directory, but is not", resource.Path())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case SymLink:
 | 
			
		||||
		var target string // only possibly set if target resource is a symlink
 | 
			
		||||
 | 
			
		||||
		if fi != nil {
 | 
			
		||||
			if fi.Mode()&os.ModeSymlink != 0 {
 | 
			
		||||
				target, err = c.driver.Readlink(fp)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if target != r.Target() {
 | 
			
		||||
			if fi != nil {
 | 
			
		||||
				if err := c.driver.Remove(fp); err != nil { // RemoveAll in case of directory?
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err := c.driver.Symlink(r.Target(), fp); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case Device:
 | 
			
		||||
		if fi == nil {
 | 
			
		||||
			if err := c.driver.Mknod(fp, resource.Mode(), int(r.Major()), int(r.Minor())); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else if (fi.Mode() & os.ModeDevice) == 0 {
 | 
			
		||||
			return fmt.Errorf("%q should be a device, but is not", resource.Path())
 | 
			
		||||
		} else {
 | 
			
		||||
			major, minor, err := devices.DeviceInfo(fi)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if major != r.Major() || minor != r.Minor() {
 | 
			
		||||
				if err := c.driver.Remove(fp); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if err := c.driver.Mknod(fp, resource.Mode(), int(r.Major()), int(r.Minor())); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case NamedPipe:
 | 
			
		||||
		if fi == nil {
 | 
			
		||||
			if err := c.driver.Mkfifo(fp, resource.Mode()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else if (fi.Mode() & os.ModeNamedPipe) == 0 {
 | 
			
		||||
			return fmt.Errorf("%q should be a named pipe, but is not", resource.Path())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if h, isHardlinkable := resource.(Hardlinkable); isHardlinkable {
 | 
			
		||||
		for _, path := range h.Paths() {
 | 
			
		||||
			if path == resource.Path() {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			lp, err := c.fullpath(path)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if _, fi := c.driver.Lstat(lp); fi == nil {
 | 
			
		||||
				c.driver.Remove(lp)
 | 
			
		||||
			}
 | 
			
		||||
			if err := c.driver.Link(fp, lp); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Update filemode if file was not created
 | 
			
		||||
	if chmod {
 | 
			
		||||
		if err := c.driver.Lchmod(fp, resource.Mode()); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := c.driver.Lchown(fp, resource.UID(), resource.GID()); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if xattrer, ok := resource.(XAttrer); ok {
 | 
			
		||||
		// For xattrs, only ensure that we have those defined in the resource
 | 
			
		||||
		// and their values are set. We can ignore other xattrs. In other words,
 | 
			
		||||
		// we only set xattres defined by resource but never remove.
 | 
			
		||||
 | 
			
		||||
		if _, ok := resource.(SymLink); ok {
 | 
			
		||||
			lxattrDriver, ok := c.driver.(driverpkg.LXAttrDriver)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return fmt.Errorf("unsupported symlink xattr for resource %q", resource.Path())
 | 
			
		||||
			}
 | 
			
		||||
			if err := lxattrDriver.LSetxattr(fp, xattrer.XAttrs()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			xattrDriver, ok := c.driver.(driverpkg.XAttrDriver)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return fmt.Errorf("unsupported xattr for resource %q", resource.Path())
 | 
			
		||||
			}
 | 
			
		||||
			if err := xattrDriver.Setxattr(fp, xattrer.XAttrs()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Walk provides a convenience function to call filepath.Walk correctly for
 | 
			
		||||
// the context. Otherwise identical to filepath.Walk, the path argument is
 | 
			
		||||
// corrected to be contained within the context.
 | 
			
		||||
func (c *context) Walk(fn filepath.WalkFunc) error {
 | 
			
		||||
	root := c.root
 | 
			
		||||
	fi, err := c.driver.Lstat(c.root)
 | 
			
		||||
	if err == nil && fi.Mode()&os.ModeSymlink != 0 {
 | 
			
		||||
		root, err = c.driver.Readlink(c.root)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return c.pathDriver.Walk(root, func(p string, fi os.FileInfo, err error) error {
 | 
			
		||||
		contained, err := c.containWithRoot(p, root)
 | 
			
		||||
		return fn(contained, fi, err)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// fullpath returns the system path for the resource, joined with the context
 | 
			
		||||
// root. The path p must be a part of the context.
 | 
			
		||||
func (c *context) fullpath(p string) (string, error) {
 | 
			
		||||
	p = c.pathDriver.Join(c.root, p)
 | 
			
		||||
	if !strings.HasPrefix(p, c.root) {
 | 
			
		||||
		return "", fmt.Errorf("invalid context path")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return p, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// contain cleans and santizes the filesystem path p to be an absolute path,
 | 
			
		||||
// effectively relative to the context root.
 | 
			
		||||
func (c *context) contain(p string) (string, error) {
 | 
			
		||||
	return c.containWithRoot(p, c.root)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// containWithRoot cleans and santizes the filesystem path p to be an absolute path,
 | 
			
		||||
// effectively relative to the passed root. Extra care should be used when calling this
 | 
			
		||||
// instead of contain. This is needed for Walk, as if context root is a symlink,
 | 
			
		||||
// it must be evaluated prior to the Walk
 | 
			
		||||
func (c *context) containWithRoot(p string, root string) (string, error) {
 | 
			
		||||
	sanitized, err := c.pathDriver.Rel(root, p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// ZOMBIES(stevvooe): In certain cases, we may want to remap these to a
 | 
			
		||||
	// "containment error", so the caller can decide what to do.
 | 
			
		||||
	return c.pathDriver.Join("/", c.pathDriver.Clean(sanitized)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// digest returns the digest of the file at path p, relative to the root.
 | 
			
		||||
func (c *context) digest(p string) (digest.Digest, error) {
 | 
			
		||||
	f, err := c.driver.Open(c.pathDriver.Join(c.root, p))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	return c.digester.Digest(f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// resolveXAttrs attempts to resolve the extended attributes for the resource
 | 
			
		||||
// at the path fp, which is the full path to the resource. If the resource
 | 
			
		||||
// cannot have xattrs, nil will be returned.
 | 
			
		||||
func (c *context) resolveXAttrs(fp string, fi os.FileInfo, base *resource) (map[string][]byte, error) {
 | 
			
		||||
	if fi.Mode().IsRegular() || fi.Mode().IsDir() {
 | 
			
		||||
		xattrDriver, ok := c.driver.(driverpkg.XAttrDriver)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			log.Println("xattr extraction not supported")
 | 
			
		||||
			return nil, ErrNotSupported
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return xattrDriver.Getxattr(fp)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fi.Mode()&os.ModeSymlink != 0 {
 | 
			
		||||
		lxattrDriver, ok := c.driver.(driverpkg.LXAttrDriver)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			log.Println("xattr extraction for symlinks not supported")
 | 
			
		||||
			return nil, ErrNotSupported
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return lxattrDriver.LGetxattr(fp)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/containerd/continuity/devices/devices.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/containerd/continuity/devices/devices.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package devices
 | 
			
		||||
 | 
			
		||||
import "fmt"
 | 
			
		||||
 | 
			
		||||
var ErrNotSupported = fmt.Errorf("not supported")
 | 
			
		||||
							
								
								
									
										74
									
								
								vendor/github.com/containerd/continuity/devices/devices_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/containerd/continuity/devices/devices_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
// +build linux darwin freebsd solaris
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package devices
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func DeviceInfo(fi os.FileInfo) (uint64, uint64, error) {
 | 
			
		||||
	sys, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return 0, 0, fmt.Errorf("cannot extract device from os.FileInfo")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev := uint64(sys.Rdev)
 | 
			
		||||
	return uint64(unix.Major(dev)), uint64(unix.Minor(dev)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// mknod provides a shortcut for syscall.Mknod
 | 
			
		||||
func Mknod(p string, mode os.FileMode, maj, min int) error {
 | 
			
		||||
	var (
 | 
			
		||||
		m   = syscallMode(mode.Perm())
 | 
			
		||||
		dev uint64
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if mode&os.ModeDevice != 0 {
 | 
			
		||||
		dev = unix.Mkdev(uint32(maj), uint32(min))
 | 
			
		||||
 | 
			
		||||
		if mode&os.ModeCharDevice != 0 {
 | 
			
		||||
			m |= unix.S_IFCHR
 | 
			
		||||
		} else {
 | 
			
		||||
			m |= unix.S_IFBLK
 | 
			
		||||
		}
 | 
			
		||||
	} else if mode&os.ModeNamedPipe != 0 {
 | 
			
		||||
		m |= unix.S_IFIFO
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return unix.Mknod(p, m, int(dev))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
 | 
			
		||||
func syscallMode(i os.FileMode) (o uint32) {
 | 
			
		||||
	o |= uint32(i.Perm())
 | 
			
		||||
	if i&os.ModeSetuid != 0 {
 | 
			
		||||
		o |= unix.S_ISUID
 | 
			
		||||
	}
 | 
			
		||||
	if i&os.ModeSetgid != 0 {
 | 
			
		||||
		o |= unix.S_ISGID
 | 
			
		||||
	}
 | 
			
		||||
	if i&os.ModeSticky != 0 {
 | 
			
		||||
		o |= unix.S_ISVTX
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/github.com/containerd/continuity/devices/devices_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/containerd/continuity/devices/devices_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package devices
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func DeviceInfo(fi os.FileInfo) (uint64, uint64, error) {
 | 
			
		||||
	return 0, 0, errors.Wrap(ErrNotSupported, "cannot get device info on windows")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								vendor/github.com/containerd/continuity/digests.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								vendor/github.com/containerd/continuity/digests.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"sort"
 | 
			
		||||
 | 
			
		||||
	"github.com/opencontainers/go-digest"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Digester produces a digest for a given read stream
 | 
			
		||||
type Digester interface {
 | 
			
		||||
	Digest(io.Reader) (digest.Digest, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContentProvider produces a read stream for a given digest
 | 
			
		||||
type ContentProvider interface {
 | 
			
		||||
	Reader(digest.Digest) (io.ReadCloser, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type simpleDigester struct {
 | 
			
		||||
	algorithm digest.Algorithm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sd simpleDigester) Digest(r io.Reader) (digest.Digest, error) {
 | 
			
		||||
	digester := sd.algorithm.Digester()
 | 
			
		||||
 | 
			
		||||
	if _, err := io.Copy(digester.Hash(), r); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return digester.Digest(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// uniqifyDigests sorts and uniqifies the provided digest, ensuring that the
 | 
			
		||||
// digests are not repeated and no two digests with the same algorithm have
 | 
			
		||||
// different values. Because a stable sort is used, this has the effect of
 | 
			
		||||
// "zipping" digest collections from multiple resources.
 | 
			
		||||
func uniqifyDigests(digests ...digest.Digest) ([]digest.Digest, error) {
 | 
			
		||||
	sort.Stable(digestSlice(digests)) // stable sort is important for the behavior here.
 | 
			
		||||
	seen := map[digest.Digest]struct{}{}
 | 
			
		||||
	algs := map[digest.Algorithm][]digest.Digest{} // detect different digests.
 | 
			
		||||
 | 
			
		||||
	var out []digest.Digest
 | 
			
		||||
	// uniqify the digests
 | 
			
		||||
	for _, d := range digests {
 | 
			
		||||
		if _, ok := seen[d]; ok {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		seen[d] = struct{}{}
 | 
			
		||||
		algs[d.Algorithm()] = append(algs[d.Algorithm()], d)
 | 
			
		||||
 | 
			
		||||
		if len(algs[d.Algorithm()]) > 1 {
 | 
			
		||||
			return nil, fmt.Errorf("conflicting digests for %v found", d.Algorithm())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		out = append(out, d)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return out, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// digestsMatch compares the two sets of digests to see if they match.
 | 
			
		||||
func digestsMatch(as, bs []digest.Digest) bool {
 | 
			
		||||
	all := append(as, bs...)
 | 
			
		||||
 | 
			
		||||
	uniqified, err := uniqifyDigests(all...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// the only error uniqifyDigests returns is when the digests disagree.
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disjoint := len(as) + len(bs)
 | 
			
		||||
	if len(uniqified) == disjoint {
 | 
			
		||||
		// if these two sets have the same cardinality, we know both sides
 | 
			
		||||
		// didn't share any digests.
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type digestSlice []digest.Digest
 | 
			
		||||
 | 
			
		||||
func (p digestSlice) Len() int           { return len(p) }
 | 
			
		||||
func (p digestSlice) Less(i, j int) bool { return p[i] < p[j] }
 | 
			
		||||
func (p digestSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 | 
			
		||||
							
								
								
									
										174
									
								
								vendor/github.com/containerd/continuity/driver/driver.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								vendor/github.com/containerd/continuity/driver/driver.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package driver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var ErrNotSupported = fmt.Errorf("not supported")
 | 
			
		||||
 | 
			
		||||
// Driver provides all of the system-level functions in a common interface.
 | 
			
		||||
// The context should call these with full paths and should never use the `os`
 | 
			
		||||
// package or any other package to access resources on the filesystem. This
 | 
			
		||||
// mechanism let's us carefully control access to the context and maintain
 | 
			
		||||
// path and resource integrity. It also gives us an interface to reason about
 | 
			
		||||
// direct resource access.
 | 
			
		||||
//
 | 
			
		||||
// Implementations don't need to do much other than meet the interface. For
 | 
			
		||||
// example, it is not required to wrap os.FileInfo to return correct paths for
 | 
			
		||||
// the call to Name().
 | 
			
		||||
type Driver interface {
 | 
			
		||||
	// Note that Open() returns a File interface instead of *os.File. This
 | 
			
		||||
	// is because os.File is a struct, so if Open was to return *os.File,
 | 
			
		||||
	// the only way to fulfill the interface would be to call os.Open()
 | 
			
		||||
	Open(path string) (File, error)
 | 
			
		||||
	OpenFile(path string, flag int, perm os.FileMode) (File, error)
 | 
			
		||||
 | 
			
		||||
	Stat(path string) (os.FileInfo, error)
 | 
			
		||||
	Lstat(path string) (os.FileInfo, error)
 | 
			
		||||
	Readlink(p string) (string, error)
 | 
			
		||||
	Mkdir(path string, mode os.FileMode) error
 | 
			
		||||
	Remove(path string) error
 | 
			
		||||
 | 
			
		||||
	Link(oldname, newname string) error
 | 
			
		||||
	Lchmod(path string, mode os.FileMode) error
 | 
			
		||||
	Lchown(path string, uid, gid int64) error
 | 
			
		||||
	Symlink(oldname, newname string) error
 | 
			
		||||
 | 
			
		||||
	MkdirAll(path string, perm os.FileMode) error
 | 
			
		||||
	RemoveAll(path string) error
 | 
			
		||||
 | 
			
		||||
	// TODO(aaronl): These methods might move outside the main Driver
 | 
			
		||||
	// interface in the future as more platforms are added.
 | 
			
		||||
	Mknod(path string, mode os.FileMode, major int, minor int) error
 | 
			
		||||
	Mkfifo(path string, mode os.FileMode) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// File is the interface for interacting with files returned by continuity's Open
 | 
			
		||||
// This is needed since os.File is a struct, instead of an interface, so it can't
 | 
			
		||||
// be used.
 | 
			
		||||
type File interface {
 | 
			
		||||
	io.ReadWriteCloser
 | 
			
		||||
	io.Seeker
 | 
			
		||||
	Readdir(n int) ([]os.FileInfo, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewSystemDriver() (Driver, error) {
 | 
			
		||||
	// TODO(stevvooe): Consider having this take a "hint" path argument, which
 | 
			
		||||
	// would be the context root. The hint could be used to resolve required
 | 
			
		||||
	// filesystem support when assembling the driver to use.
 | 
			
		||||
	return &driver{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// XAttrDriver should be implemented on operation systems and filesystems that
 | 
			
		||||
// have xattr support for regular files and directories.
 | 
			
		||||
type XAttrDriver interface {
 | 
			
		||||
	// Getxattr returns all of the extended attributes for the file at path.
 | 
			
		||||
	// Typically, this takes a syscall call to Listxattr and Getxattr.
 | 
			
		||||
	Getxattr(path string) (map[string][]byte, error)
 | 
			
		||||
 | 
			
		||||
	// Setxattr sets all of the extended attributes on file at path, following
 | 
			
		||||
	// any symbolic links, if necessary. All attributes on the target are
 | 
			
		||||
	// replaced by the values from attr. If the operation fails to set any
 | 
			
		||||
	// attribute, those already applied will not be rolled back.
 | 
			
		||||
	Setxattr(path string, attr map[string][]byte) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LXAttrDriver should be implemented by drivers on operating systems and
 | 
			
		||||
// filesystems that support setting and getting extended attributes on
 | 
			
		||||
// symbolic links. If this is not implemented, extended attributes will be
 | 
			
		||||
// ignored on symbolic links.
 | 
			
		||||
type LXAttrDriver interface {
 | 
			
		||||
	// LGetxattr returns all of the extended attributes for the file at path
 | 
			
		||||
	// and does not follow symlinks. Typically, this takes a syscall call to
 | 
			
		||||
	// Llistxattr and Lgetxattr.
 | 
			
		||||
	LGetxattr(path string) (map[string][]byte, error)
 | 
			
		||||
 | 
			
		||||
	// LSetxattr sets all of the extended attributes on file at path, without
 | 
			
		||||
	// following symbolic links. All attributes on the target are replaced by
 | 
			
		||||
	// the values from attr. If the operation fails to set any attribute,
 | 
			
		||||
	// those already applied will not be rolled back.
 | 
			
		||||
	LSetxattr(path string, attr map[string][]byte) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DeviceInfoDriver interface {
 | 
			
		||||
	DeviceInfo(fi os.FileInfo) (maj uint64, min uint64, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// driver is a simple default implementation that sends calls out to the "os"
 | 
			
		||||
// package. Extend the "driver" type in system-specific files to add support,
 | 
			
		||||
// such as xattrs, which can add support at compile time.
 | 
			
		||||
type driver struct{}
 | 
			
		||||
 | 
			
		||||
var _ File = &os.File{}
 | 
			
		||||
 | 
			
		||||
// LocalDriver is the exported Driver struct for convenience.
 | 
			
		||||
var LocalDriver Driver = &driver{}
 | 
			
		||||
 | 
			
		||||
func (d *driver) Open(p string) (File, error) {
 | 
			
		||||
	return os.Open(p)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) OpenFile(path string, flag int, perm os.FileMode) (File, error) {
 | 
			
		||||
	return os.OpenFile(path, flag, perm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) Stat(p string) (os.FileInfo, error) {
 | 
			
		||||
	return os.Stat(p)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) Lstat(p string) (os.FileInfo, error) {
 | 
			
		||||
	return os.Lstat(p)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) Mkdir(p string, mode os.FileMode) error {
 | 
			
		||||
	return os.Mkdir(p, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove is used to unlink files and remove directories.
 | 
			
		||||
// This is following the golang os package api which
 | 
			
		||||
// combines the operations into a higher level Remove
 | 
			
		||||
// function. If explicit unlinking or directory removal
 | 
			
		||||
// to mirror system call is required, they should be
 | 
			
		||||
// split up at that time.
 | 
			
		||||
func (d *driver) Remove(path string) error {
 | 
			
		||||
	return os.Remove(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) Link(oldname, newname string) error {
 | 
			
		||||
	return os.Link(oldname, newname)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) Lchown(name string, uid, gid int64) error {
 | 
			
		||||
	// TODO: error out if uid excesses int bit width?
 | 
			
		||||
	return os.Lchown(name, int(uid), int(gid))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) Symlink(oldname, newname string) error {
 | 
			
		||||
	return os.Symlink(oldname, newname)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) MkdirAll(path string, perm os.FileMode) error {
 | 
			
		||||
	return os.MkdirAll(path, perm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) RemoveAll(path string) error {
 | 
			
		||||
	return os.RemoveAll(path)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										138
									
								
								vendor/github.com/containerd/continuity/driver/driver_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								vendor/github.com/containerd/continuity/driver/driver_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,138 @@
 | 
			
		||||
// +build linux darwin freebsd solaris
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package driver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sort"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/devices"
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (d *driver) Mknod(path string, mode os.FileMode, major, minor int) error {
 | 
			
		||||
	err := devices.Mknod(path, mode, major, minor)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = &os.PathError{Op: "mknod", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) Mkfifo(path string, mode os.FileMode) error {
 | 
			
		||||
	if mode&os.ModeNamedPipe == 0 {
 | 
			
		||||
		return errors.New("mode passed to Mkfifo does not have the named pipe bit set")
 | 
			
		||||
	}
 | 
			
		||||
	// mknod with a mode that has ModeNamedPipe set creates a fifo, not a
 | 
			
		||||
	// device.
 | 
			
		||||
	err := devices.Mknod(path, mode, 0, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = &os.PathError{Op: "mkfifo", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Getxattr returns all of the extended attributes for the file at path p.
 | 
			
		||||
func (d *driver) Getxattr(p string) (map[string][]byte, error) {
 | 
			
		||||
	xattrs, err := sysx.Listxattr(p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("listing %s xattrs: %v", p, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sort.Strings(xattrs)
 | 
			
		||||
	m := make(map[string][]byte, len(xattrs))
 | 
			
		||||
 | 
			
		||||
	for _, attr := range xattrs {
 | 
			
		||||
		value, err := sysx.Getxattr(p, attr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("getting %q xattr on %s: %v", attr, p, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// NOTE(stevvooe): This append/copy tricky relies on unique
 | 
			
		||||
		// xattrs. Break this out into an alloc/copy if xattrs are no
 | 
			
		||||
		// longer unique.
 | 
			
		||||
		m[attr] = append(m[attr], value...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return m, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Setxattr sets all of the extended attributes on file at path, following
 | 
			
		||||
// any symbolic links, if necessary. All attributes on the target are
 | 
			
		||||
// replaced by the values from attr. If the operation fails to set any
 | 
			
		||||
// attribute, those already applied will not be rolled back.
 | 
			
		||||
func (d *driver) Setxattr(path string, attrMap map[string][]byte) error {
 | 
			
		||||
	for attr, value := range attrMap {
 | 
			
		||||
		if err := sysx.Setxattr(path, attr, value, 0); err != nil {
 | 
			
		||||
			return fmt.Errorf("error setting xattr %q on %s: %v", attr, path, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LGetxattr returns all of the extended attributes for the file at path p
 | 
			
		||||
// not following symbolic links.
 | 
			
		||||
func (d *driver) LGetxattr(p string) (map[string][]byte, error) {
 | 
			
		||||
	xattrs, err := sysx.LListxattr(p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("listing %s xattrs: %v", p, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sort.Strings(xattrs)
 | 
			
		||||
	m := make(map[string][]byte, len(xattrs))
 | 
			
		||||
 | 
			
		||||
	for _, attr := range xattrs {
 | 
			
		||||
		value, err := sysx.LGetxattr(p, attr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("getting %q xattr on %s: %v", attr, p, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// NOTE(stevvooe): This append/copy tricky relies on unique
 | 
			
		||||
		// xattrs. Break this out into an alloc/copy if xattrs are no
 | 
			
		||||
		// longer unique.
 | 
			
		||||
		m[attr] = append(m[attr], value...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return m, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LSetxattr sets all of the extended attributes on file at path, not
 | 
			
		||||
// following any symbolic links. All attributes on the target are
 | 
			
		||||
// replaced by the values from attr. If the operation fails to set any
 | 
			
		||||
// attribute, those already applied will not be rolled back.
 | 
			
		||||
func (d *driver) LSetxattr(path string, attrMap map[string][]byte) error {
 | 
			
		||||
	for attr, value := range attrMap {
 | 
			
		||||
		if err := sysx.LSetxattr(path, attr, value, 0); err != nil {
 | 
			
		||||
			return fmt.Errorf("error setting xattr %q on %s: %v", attr, path, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) DeviceInfo(fi os.FileInfo) (maj uint64, min uint64, err error) {
 | 
			
		||||
	return devices.DeviceInfo(fi)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Readlink was forked on Windows to fix a Golang bug, use the "os" package here
 | 
			
		||||
func (d *driver) Readlink(p string) (string, error) {
 | 
			
		||||
	return os.Readlink(p)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/github.com/containerd/continuity/driver/driver_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/containerd/continuity/driver/driver_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package driver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (d *driver) Mknod(path string, mode os.FileMode, major, minor int) error {
 | 
			
		||||
	return &os.PathError{Op: "mknod", Path: path, Err: ErrNotSupported}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *driver) Mkfifo(path string, mode os.FileMode) error {
 | 
			
		||||
	return &os.PathError{Op: "mkfifo", Path: path, Err: ErrNotSupported}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Lchmod changes the mode of an file not following symlinks.
 | 
			
		||||
func (d *driver) Lchmod(path string, mode os.FileMode) (err error) {
 | 
			
		||||
	// TODO: Use Window's equivalent
 | 
			
		||||
	return os.Chmod(path, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Readlink is forked in order to support Volume paths which are used
 | 
			
		||||
// in container layers.
 | 
			
		||||
func (d *driver) Readlink(p string) (string, error) {
 | 
			
		||||
	return sysx.Readlink(p)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/containerd/continuity/driver/lchmod_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/containerd/continuity/driver/lchmod_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package driver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Lchmod changes the mode of a file not following symlinks.
 | 
			
		||||
func (d *driver) Lchmod(path string, mode os.FileMode) error {
 | 
			
		||||
	// On Linux, file mode is not supported for symlinks,
 | 
			
		||||
	// and fchmodat() does not support AT_SYMLINK_NOFOLLOW,
 | 
			
		||||
	// so symlinks need to be skipped entirely.
 | 
			
		||||
	if st, err := os.Stat(path); err == nil && st.Mode()&os.ModeSymlink != 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := unix.Fchmodat(unix.AT_FDCWD, path, uint32(mode), 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = &os.PathError{Op: "lchmod", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								vendor/github.com/containerd/continuity/driver/lchmod_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/containerd/continuity/driver/lchmod_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
// +build darwin freebsd solaris
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package driver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Lchmod changes the mode of a file not following symlinks.
 | 
			
		||||
func (d *driver) Lchmod(path string, mode os.FileMode) error {
 | 
			
		||||
	err := unix.Fchmodat(unix.AT_FDCWD, path, uint32(mode), unix.AT_SYMLINK_NOFOLLOW)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = &os.PathError{Op: "lchmod", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								vendor/github.com/containerd/continuity/driver/utils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								vendor/github.com/containerd/continuity/driver/utils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package driver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ReadFile works the same as ioutil.ReadFile with the Driver abstraction
 | 
			
		||||
func ReadFile(r Driver, filename string) ([]byte, error) {
 | 
			
		||||
	f, err := r.Open(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	data, err := ioutil.ReadAll(f)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return data, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteFile works the same as ioutil.WriteFile with the Driver abstraction
 | 
			
		||||
func WriteFile(r Driver, filename string, data []byte, perm os.FileMode) error {
 | 
			
		||||
	f, err := r.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	n, err := f.Write(data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if n != len(data) {
 | 
			
		||||
		return io.ErrShortWrite
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadDir works the same as ioutil.ReadDir with the Driver abstraction
 | 
			
		||||
func ReadDir(r Driver, dirname string) ([]os.FileInfo, error) {
 | 
			
		||||
	f, err := r.Open(dirname)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	dirs, err := f.Readdir(-1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sort.Sort(fileInfos(dirs))
 | 
			
		||||
	return dirs, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Simple implementation of the sort.Interface for os.FileInfo
 | 
			
		||||
type fileInfos []os.FileInfo
 | 
			
		||||
 | 
			
		||||
func (fis fileInfos) Len() int {
 | 
			
		||||
	return len(fis)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fis fileInfos) Less(i, j int) bool {
 | 
			
		||||
	return fis[i].Name() < fis[j].Name()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fis fileInfos) Swap(i, j int) {
 | 
			
		||||
	fis[i], fis[j] = fis[j], fis[i]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										129
									
								
								vendor/github.com/containerd/continuity/groups_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								vendor/github.com/containerd/continuity/groups_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TODO(stevvooe): This needs a lot of work before we can call it useful.
 | 
			
		||||
 | 
			
		||||
type groupIndex struct {
 | 
			
		||||
	byName map[string]*group
 | 
			
		||||
	byGID  map[int]*group
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getGroupIndex() (*groupIndex, error) {
 | 
			
		||||
	f, err := os.Open("/etc/group")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	groups, err := parseGroups(f)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newGroupIndex(groups), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newGroupIndex(groups []group) *groupIndex {
 | 
			
		||||
	gi := &groupIndex{
 | 
			
		||||
		byName: make(map[string]*group),
 | 
			
		||||
		byGID:  make(map[int]*group),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, group := range groups {
 | 
			
		||||
		gi.byGID[group.gid] = &groups[i]
 | 
			
		||||
		gi.byName[group.name] = &groups[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return gi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type group struct {
 | 
			
		||||
	name    string
 | 
			
		||||
	gid     int
 | 
			
		||||
	members []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getGroupName(gid int) (string, error) {
 | 
			
		||||
	f, err := os.Open("/etc/group")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	groups, err := parseGroups(f)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, group := range groups {
 | 
			
		||||
		if group.gid == gid {
 | 
			
		||||
			return group.name, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "", fmt.Errorf("no group for gid")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseGroups parses an /etc/group file for group names, ids and membership.
 | 
			
		||||
// This is unix specific.
 | 
			
		||||
func parseGroups(rd io.Reader) ([]group, error) {
 | 
			
		||||
	var groups []group
 | 
			
		||||
	scanner := bufio.NewScanner(rd)
 | 
			
		||||
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		if strings.HasPrefix(scanner.Text(), "#") {
 | 
			
		||||
			continue // skip comment
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		parts := strings.SplitN(scanner.Text(), ":", 4)
 | 
			
		||||
 | 
			
		||||
		if len(parts) != 4 {
 | 
			
		||||
			return nil, fmt.Errorf("bad entry: %q", scanner.Text())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		name, _, sgid, smembers := parts[0], parts[1], parts[2], parts[3]
 | 
			
		||||
 | 
			
		||||
		gid, err := strconv.Atoi(sgid)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("bad gid: %q", gid)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		members := strings.Split(smembers, ",")
 | 
			
		||||
 | 
			
		||||
		groups = append(groups, group{
 | 
			
		||||
			name:    name,
 | 
			
		||||
			gid:     gid,
 | 
			
		||||
			members: members,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if scanner.Err() != nil {
 | 
			
		||||
		return nil, scanner.Err()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return groups, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								vendor/github.com/containerd/continuity/hardlinks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/containerd/continuity/hardlinks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	errNotAHardLink = fmt.Errorf("invalid hardlink")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type hardlinkManager struct {
 | 
			
		||||
	hardlinks map[hardlinkKey][]Resource
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newHardlinkManager() *hardlinkManager {
 | 
			
		||||
	return &hardlinkManager{
 | 
			
		||||
		hardlinks: map[hardlinkKey][]Resource{},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add attempts to add the resource to the hardlink manager. If the resource
 | 
			
		||||
// cannot be considered as a hardlink candidate, errNotAHardLink is returned.
 | 
			
		||||
func (hlm *hardlinkManager) Add(fi os.FileInfo, resource Resource) error {
 | 
			
		||||
	if _, ok := resource.(Hardlinkable); !ok {
 | 
			
		||||
		return errNotAHardLink
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key, err := newHardlinkKey(fi)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hlm.hardlinks[key] = append(hlm.hardlinks[key], resource)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Merge processes the current state of the hardlink manager and merges any
 | 
			
		||||
// shared nodes into hardlinked resources.
 | 
			
		||||
func (hlm *hardlinkManager) Merge() ([]Resource, error) {
 | 
			
		||||
	var resources []Resource
 | 
			
		||||
	for key, linked := range hlm.hardlinks {
 | 
			
		||||
		if len(linked) < 1 {
 | 
			
		||||
			return nil, fmt.Errorf("no hardlink entrys for dev, inode pair: %#v", key)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		merged, err := Merge(linked...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("error merging hardlink: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		resources = append(resources, merged)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resources, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								vendor/github.com/containerd/continuity/hardlinks_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/containerd/continuity/hardlinks_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
// +build linux darwin freebsd solaris
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// hardlinkKey provides a tuple-key for managing hardlinks. This is system-
 | 
			
		||||
// specific.
 | 
			
		||||
type hardlinkKey struct {
 | 
			
		||||
	dev   uint64
 | 
			
		||||
	inode uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newHardlinkKey returns a hardlink key for the provided file info. If the
 | 
			
		||||
// resource does not represent a possible hardlink, errNotAHardLink will be
 | 
			
		||||
// returned.
 | 
			
		||||
func newHardlinkKey(fi os.FileInfo) (hardlinkKey, error) {
 | 
			
		||||
	sys, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return hardlinkKey{}, fmt.Errorf("cannot resolve (*syscall.Stat_t) from os.FileInfo")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sys.Nlink < 2 {
 | 
			
		||||
		// NOTE(stevvooe): This is not always true for all filesystems. We
 | 
			
		||||
		// should somehow detect this and provided a slow "polyfill" that
 | 
			
		||||
		// leverages os.SameFile if we detect a filesystem where link counts
 | 
			
		||||
		// is not really supported.
 | 
			
		||||
		return hardlinkKey{}, errNotAHardLink
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return hardlinkKey{dev: uint64(sys.Dev), inode: uint64(sys.Ino)}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/containerd/continuity/hardlinks_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/containerd/continuity/hardlinks_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
type hardlinkKey struct{}
 | 
			
		||||
 | 
			
		||||
func newHardlinkKey(fi os.FileInfo) (hardlinkKey, error) {
 | 
			
		||||
	// NOTE(stevvooe): Obviously, this is not yet implemented. However, the
 | 
			
		||||
	// makings of an implementation are available in src/os/types_windows.go. More
 | 
			
		||||
	// investigation needs to be done to figure out exactly how to do this.
 | 
			
		||||
	return hardlinkKey{}, errNotAHardLink
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								vendor/github.com/containerd/continuity/ioutils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/containerd/continuity/ioutils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AtomicWriteFile atomically writes data to a file by first writing to a
 | 
			
		||||
// temp file and calling rename.
 | 
			
		||||
func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error {
 | 
			
		||||
	buf := bytes.NewBuffer(data)
 | 
			
		||||
	return atomicWriteFile(filename, buf, int64(len(data)), perm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// atomicWriteFile writes data to a file by first writing to a temp
 | 
			
		||||
// file and calling rename.
 | 
			
		||||
func atomicWriteFile(filename string, r io.Reader, dataSize int64, perm os.FileMode) error {
 | 
			
		||||
	f, err := ioutil.TempFile(filepath.Dir(filename), ".tmp-"+filepath.Base(filename))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = os.Chmod(f.Name(), perm)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		f.Close()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	n, err := io.Copy(f, r)
 | 
			
		||||
	if err == nil && n < dataSize {
 | 
			
		||||
		f.Close()
 | 
			
		||||
		return io.ErrShortWrite
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		f.Close()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := f.Sync(); err != nil {
 | 
			
		||||
		f.Close()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := f.Close(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return os.Rename(f.Name(), filename)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										160
									
								
								vendor/github.com/containerd/continuity/manifest.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								vendor/github.com/containerd/continuity/manifest.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sort"
 | 
			
		||||
 | 
			
		||||
	pb "github.com/containerd/continuity/proto"
 | 
			
		||||
	"github.com/golang/protobuf/proto"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Manifest provides the contents of a manifest. Users of this struct should
 | 
			
		||||
// not typically modify any fields directly.
 | 
			
		||||
type Manifest struct {
 | 
			
		||||
	// Resources specifies all the resources for a manifest in order by path.
 | 
			
		||||
	Resources []Resource
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Unmarshal(p []byte) (*Manifest, error) {
 | 
			
		||||
	var bm pb.Manifest
 | 
			
		||||
 | 
			
		||||
	if err := proto.Unmarshal(p, &bm); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var m Manifest
 | 
			
		||||
	for _, b := range bm.Resource {
 | 
			
		||||
		r, err := fromProto(b)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		m.Resources = append(m.Resources, r)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &m, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Marshal(m *Manifest) ([]byte, error) {
 | 
			
		||||
	var bm pb.Manifest
 | 
			
		||||
	for _, resource := range m.Resources {
 | 
			
		||||
		bm.Resource = append(bm.Resource, toProto(resource))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return proto.Marshal(&bm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func MarshalText(w io.Writer, m *Manifest) error {
 | 
			
		||||
	var bm pb.Manifest
 | 
			
		||||
	for _, resource := range m.Resources {
 | 
			
		||||
		bm.Resource = append(bm.Resource, toProto(resource))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return proto.MarshalText(w, &bm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BuildManifest creates the manifest for the given context
 | 
			
		||||
func BuildManifest(ctx Context) (*Manifest, error) {
 | 
			
		||||
	resourcesByPath := map[string]Resource{}
 | 
			
		||||
	hardlinks := newHardlinkManager()
 | 
			
		||||
 | 
			
		||||
	if err := ctx.Walk(func(p string, fi os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("error walking %s: %v", p, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if p == string(os.PathSeparator) {
 | 
			
		||||
			// skip root
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		resource, err := ctx.Resource(p, fi)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err == ErrNotFound {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			log.Printf("error getting resource %q: %v", p, err)
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// add to the hardlink manager
 | 
			
		||||
		if err := hardlinks.Add(fi, resource); err == nil {
 | 
			
		||||
			// Resource has been accepted by hardlink manager so we don't add
 | 
			
		||||
			// it to the resourcesByPath until we merge at the end.
 | 
			
		||||
			return nil
 | 
			
		||||
		} else if err != errNotAHardLink {
 | 
			
		||||
			// handle any other case where we have a proper error.
 | 
			
		||||
			return fmt.Errorf("adding hardlink %s: %v", p, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		resourcesByPath[p] = resource
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// merge and post-process the hardlinks.
 | 
			
		||||
	hardlinked, err := hardlinks.Merge()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, resource := range hardlinked {
 | 
			
		||||
		resourcesByPath[resource.Path()] = resource
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var resources []Resource
 | 
			
		||||
	for _, resource := range resourcesByPath {
 | 
			
		||||
		resources = append(resources, resource)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sort.Stable(ByPath(resources))
 | 
			
		||||
 | 
			
		||||
	return &Manifest{
 | 
			
		||||
		Resources: resources,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VerifyManifest verifies all the resources in a manifest
 | 
			
		||||
// against files from the given context.
 | 
			
		||||
func VerifyManifest(ctx Context, manifest *Manifest) error {
 | 
			
		||||
	for _, resource := range manifest.Resources {
 | 
			
		||||
		if err := ctx.Verify(resource); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplyManifest applies on the resources in a manifest to
 | 
			
		||||
// the given context.
 | 
			
		||||
func ApplyManifest(ctx Context, manifest *Manifest) error {
 | 
			
		||||
	for _, resource := range manifest.Resources {
 | 
			
		||||
		if err := ctx.Apply(resource); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/containerd/continuity/manifest_test_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/containerd/continuity/manifest_test_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
// +build ignore
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	devNullResource = resource{
 | 
			
		||||
		kind:  chardev,
 | 
			
		||||
		path:  "/dev/null",
 | 
			
		||||
		major: 3,
 | 
			
		||||
		minor: 2,
 | 
			
		||||
		mode:  0666 | os.ModeDevice | os.ModeCharDevice,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	devZeroResource = resource{
 | 
			
		||||
		kind:  chardev,
 | 
			
		||||
		path:  "/dev/zero",
 | 
			
		||||
		major: 3,
 | 
			
		||||
		minor: 3,
 | 
			
		||||
		mode:  0666 | os.ModeDevice | os.ModeCharDevice,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										19
									
								
								vendor/github.com/containerd/continuity/proto/gen.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/containerd/continuity/proto/gen.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package proto
 | 
			
		||||
 | 
			
		||||
//go:generate protoc --go_out=. manifest.proto
 | 
			
		||||
							
								
								
									
										181
									
								
								vendor/github.com/containerd/continuity/proto/manifest.pb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								vendor/github.com/containerd/continuity/proto/manifest.pb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,181 @@
 | 
			
		||||
// Code generated by protoc-gen-go.
 | 
			
		||||
// source: manifest.proto
 | 
			
		||||
// DO NOT EDIT!
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Package proto is a generated protocol buffer package.
 | 
			
		||||
 | 
			
		||||
It is generated from these files:
 | 
			
		||||
	manifest.proto
 | 
			
		||||
 | 
			
		||||
It has these top-level messages:
 | 
			
		||||
	Manifest
 | 
			
		||||
	Resource
 | 
			
		||||
	XAttr
 | 
			
		||||
	ADSEntry
 | 
			
		||||
*/
 | 
			
		||||
package proto
 | 
			
		||||
 | 
			
		||||
import proto1 "github.com/golang/protobuf/proto"
 | 
			
		||||
import fmt "fmt"
 | 
			
		||||
import math "math"
 | 
			
		||||
 | 
			
		||||
// Reference imports to suppress errors if they are not otherwise used.
 | 
			
		||||
var _ = proto1.Marshal
 | 
			
		||||
var _ = fmt.Errorf
 | 
			
		||||
var _ = math.Inf
 | 
			
		||||
 | 
			
		||||
// This is a compile-time assertion to ensure that this generated file
 | 
			
		||||
// is compatible with the proto package it is being compiled against.
 | 
			
		||||
// A compilation error at this line likely means your copy of the
 | 
			
		||||
// proto package needs to be updated.
 | 
			
		||||
const _ = proto1.ProtoPackageIsVersion2 // please upgrade the proto package
 | 
			
		||||
 | 
			
		||||
// Manifest specifies the entries in a container bundle, keyed and sorted by
 | 
			
		||||
// path.
 | 
			
		||||
type Manifest struct {
 | 
			
		||||
	Resource []*Resource `protobuf:"bytes,1,rep,name=resource" json:"resource,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Manifest) Reset()                    { *m = Manifest{} }
 | 
			
		||||
func (m *Manifest) String() string            { return proto1.CompactTextString(m) }
 | 
			
		||||
func (*Manifest) ProtoMessage()               {}
 | 
			
		||||
func (*Manifest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 | 
			
		||||
 | 
			
		||||
func (m *Manifest) GetResource() []*Resource {
 | 
			
		||||
	if m != nil {
 | 
			
		||||
		return m.Resource
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Resource struct {
 | 
			
		||||
	// Path specifies the path from the bundle root. If more than one
 | 
			
		||||
	// path is present, the entry may represent a hardlink, rather than using
 | 
			
		||||
	// a link target. The path format is operating system specific.
 | 
			
		||||
	Path []string `protobuf:"bytes,1,rep,name=path" json:"path,omitempty"`
 | 
			
		||||
	// Uid specifies the user id for the resource.
 | 
			
		||||
	Uid int64 `protobuf:"varint,2,opt,name=uid" json:"uid,omitempty"`
 | 
			
		||||
	// Gid specifies the group id for the resource.
 | 
			
		||||
	Gid int64 `protobuf:"varint,3,opt,name=gid" json:"gid,omitempty"`
 | 
			
		||||
	// user and group are not currently used but their field numbers have been
 | 
			
		||||
	// reserved for future use. As such, they are marked as deprecated.
 | 
			
		||||
	User  string `protobuf:"bytes,4,opt,name=user" json:"user,omitempty"`
 | 
			
		||||
	Group string `protobuf:"bytes,5,opt,name=group" json:"group,omitempty"`
 | 
			
		||||
	// Mode defines the file mode and permissions. We've used the same
 | 
			
		||||
	// bit-packing from Go's os package,
 | 
			
		||||
	// http://golang.org/pkg/os/#FileMode, since they've done the work of
 | 
			
		||||
	// creating a cross-platform layout.
 | 
			
		||||
	Mode uint32 `protobuf:"varint,6,opt,name=mode" json:"mode,omitempty"`
 | 
			
		||||
	// Size specifies the size in bytes of the resource. This is only valid
 | 
			
		||||
	// for regular files.
 | 
			
		||||
	Size uint64 `protobuf:"varint,7,opt,name=size" json:"size,omitempty"`
 | 
			
		||||
	// Digest specifies the content digest of the target file. Only valid for
 | 
			
		||||
	// regular files. The strings are formatted in OCI style, i.e. <alg>:<encoded>.
 | 
			
		||||
	// For detailed information about the format, please refer to OCI Image Spec:
 | 
			
		||||
	// https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests-and-verification
 | 
			
		||||
	// The digests are sorted in lexical order and implementations may choose
 | 
			
		||||
	// which algorithms they prefer.
 | 
			
		||||
	Digest []string `protobuf:"bytes,8,rep,name=digest" json:"digest,omitempty"`
 | 
			
		||||
	// Target defines the target of a hard or soft link. Absolute links start
 | 
			
		||||
	// with a slash and specify the resource relative to the bundle root.
 | 
			
		||||
	// Relative links do not start with a slash and are relative to the
 | 
			
		||||
	// resource path.
 | 
			
		||||
	Target string `protobuf:"bytes,9,opt,name=target" json:"target,omitempty"`
 | 
			
		||||
	// Major specifies the major device number for character and block devices.
 | 
			
		||||
	Major uint64 `protobuf:"varint,10,opt,name=major" json:"major,omitempty"`
 | 
			
		||||
	// Minor specifies the minor device number for character and block devices.
 | 
			
		||||
	Minor uint64 `protobuf:"varint,11,opt,name=minor" json:"minor,omitempty"`
 | 
			
		||||
	// Xattr provides storage for extended attributes for the target resource.
 | 
			
		||||
	Xattr []*XAttr `protobuf:"bytes,12,rep,name=xattr" json:"xattr,omitempty"`
 | 
			
		||||
	// Ads stores one or more alternate data streams for the target resource.
 | 
			
		||||
	Ads []*ADSEntry `protobuf:"bytes,13,rep,name=ads" json:"ads,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Resource) Reset()                    { *m = Resource{} }
 | 
			
		||||
func (m *Resource) String() string            { return proto1.CompactTextString(m) }
 | 
			
		||||
func (*Resource) ProtoMessage()               {}
 | 
			
		||||
func (*Resource) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 | 
			
		||||
 | 
			
		||||
func (m *Resource) GetXattr() []*XAttr {
 | 
			
		||||
	if m != nil {
 | 
			
		||||
		return m.Xattr
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Resource) GetAds() []*ADSEntry {
 | 
			
		||||
	if m != nil {
 | 
			
		||||
		return m.Ads
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// XAttr encodes extended attributes for a resource.
 | 
			
		||||
type XAttr struct {
 | 
			
		||||
	// Name specifies the attribute name.
 | 
			
		||||
	Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
 | 
			
		||||
	// Data specifies the associated data for the attribute.
 | 
			
		||||
	Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *XAttr) Reset()                    { *m = XAttr{} }
 | 
			
		||||
func (m *XAttr) String() string            { return proto1.CompactTextString(m) }
 | 
			
		||||
func (*XAttr) ProtoMessage()               {}
 | 
			
		||||
func (*XAttr) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
 | 
			
		||||
 | 
			
		||||
// ADSEntry encodes information for a Windows Alternate Data Stream.
 | 
			
		||||
type ADSEntry struct {
 | 
			
		||||
	// Name specifices the stream name.
 | 
			
		||||
	Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
 | 
			
		||||
	// Data specifies the stream data.
 | 
			
		||||
	// See also the description about the digest below.
 | 
			
		||||
	Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
 | 
			
		||||
	// Digest is a CAS representation of the stream data.
 | 
			
		||||
	//
 | 
			
		||||
	// At least one of data or digest MUST be specified, and either one of them
 | 
			
		||||
	// SHOULD be specified.
 | 
			
		||||
	//
 | 
			
		||||
	// How to access the actual data using the digest is implementation-specific,
 | 
			
		||||
	// and implementations can choose not to implement digest.
 | 
			
		||||
	// So, digest SHOULD be used only when the stream data is large.
 | 
			
		||||
	Digest string `protobuf:"bytes,3,opt,name=digest" json:"digest,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *ADSEntry) Reset()                    { *m = ADSEntry{} }
 | 
			
		||||
func (m *ADSEntry) String() string            { return proto1.CompactTextString(m) }
 | 
			
		||||
func (*ADSEntry) ProtoMessage()               {}
 | 
			
		||||
func (*ADSEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	proto1.RegisterType((*Manifest)(nil), "proto.Manifest")
 | 
			
		||||
	proto1.RegisterType((*Resource)(nil), "proto.Resource")
 | 
			
		||||
	proto1.RegisterType((*XAttr)(nil), "proto.XAttr")
 | 
			
		||||
	proto1.RegisterType((*ADSEntry)(nil), "proto.ADSEntry")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() { proto1.RegisterFile("manifest.proto", fileDescriptor0) }
 | 
			
		||||
 | 
			
		||||
var fileDescriptor0 = []byte{
 | 
			
		||||
	// 317 bytes of a gzipped FileDescriptorProto
 | 
			
		||||
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x90, 0x4f, 0x4b, 0xf3, 0x40,
 | 
			
		||||
	0x10, 0xc6, 0x49, 0x93, 0xf4, 0x4d, 0xa7, 0xed, 0xab, 0x2c, 0x52, 0xe6, 0x18, 0x73, 0x0a, 0x08,
 | 
			
		||||
	0x15, 0xf4, 0xe0, 0xb9, 0xa2, 0x17, 0xc1, 0xcb, 0x7a, 0xf1, 0xba, 0xba, 0x6b, 0x5c, 0x21, 0xd9,
 | 
			
		||||
	0xb0, 0xd9, 0x80, 0xfa, 0xe5, 0xfc, 0x6a, 0x32, 0xb3, 0x69, 0xd1, 0x9b, 0xa7, 0x3c, 0xcf, 0x6f,
 | 
			
		||||
	0xfe, 0x64, 0xf6, 0x81, 0xff, 0xad, 0xea, 0xec, 0x8b, 0x19, 0xc2, 0xb6, 0xf7, 0x2e, 0x38, 0x91,
 | 
			
		||||
	0xf3, 0xa7, 0xba, 0x82, 0xe2, 0x7e, 0x2a, 0x88, 0x33, 0x28, 0xbc, 0x19, 0xdc, 0xe8, 0x9f, 0x0d,
 | 
			
		||||
	0x26, 0x65, 0x5a, 0x2f, 0x2f, 0x8e, 0x62, 0xf3, 0x56, 0x4e, 0x58, 0x1e, 0x1a, 0xaa, 0xaf, 0x19,
 | 
			
		||||
	0x14, 0x7b, 0x2c, 0x04, 0x64, 0xbd, 0x0a, 0xaf, 0x3c, 0xb5, 0x90, 0xac, 0xc5, 0x31, 0xa4, 0xa3,
 | 
			
		||||
	0xd5, 0x38, 0x2b, 0x93, 0x3a, 0x95, 0x24, 0x89, 0x34, 0x56, 0x63, 0x1a, 0x49, 0x63, 0xb5, 0xd8,
 | 
			
		||||
	0x40, 0x36, 0x0e, 0xc6, 0x63, 0x56, 0x26, 0xf5, 0xe2, 0x7a, 0x86, 0x89, 0x64, 0x2f, 0x10, 0xf2,
 | 
			
		||||
	0xc6, 0xbb, 0xb1, 0xc7, 0xfc, 0x50, 0x88, 0x80, 0xfe, 0xd4, 0x3a, 0x6d, 0x70, 0x5e, 0x26, 0xf5,
 | 
			
		||||
	0x5a, 0xb2, 0x26, 0x36, 0xd8, 0x4f, 0x83, 0xff, 0xca, 0xa4, 0xce, 0x24, 0x6b, 0xb1, 0x81, 0xb9,
 | 
			
		||||
	0xb6, 0x8d, 0x19, 0x02, 0x16, 0x7c, 0xd3, 0xe4, 0x88, 0x07, 0xe5, 0x1b, 0x13, 0x70, 0x41, 0xab,
 | 
			
		||||
	0xe5, 0xe4, 0xc4, 0x09, 0xe4, 0xad, 0x7a, 0x73, 0x1e, 0x81, 0x97, 0x44, 0xc3, 0xd4, 0x76, 0xce,
 | 
			
		||||
	0xe3, 0x72, 0xa2, 0x64, 0x44, 0x05, 0xf9, 0xbb, 0x0a, 0xc1, 0xe3, 0x8a, 0x43, 0x5a, 0x4d, 0x21,
 | 
			
		||||
	0x3d, 0xee, 0x42, 0xf0, 0x32, 0x96, 0xc4, 0x29, 0xa4, 0x4a, 0x0f, 0xb8, 0xfe, 0x15, 0xe3, 0xee,
 | 
			
		||||
	0xe6, 0xe1, 0xb6, 0x0b, 0xfe, 0x43, 0x52, 0xad, 0x3a, 0x87, 0x9c, 0x47, 0xe8, 0xfe, 0x4e, 0xb5,
 | 
			
		||||
	0x94, 0x39, 0x5d, 0xc4, 0x9a, 0x98, 0x56, 0x41, 0x71, 0x7c, 0x2b, 0xc9, 0xba, 0xba, 0x83, 0x62,
 | 
			
		||||
	0xbf, 0xe1, 0xaf, 0x33, 0x3f, 0x72, 0x48, 0xe3, 0x7b, 0xa3, 0x7b, 0x9a, 0xf3, 0x45, 0x97, 0xdf,
 | 
			
		||||
	0x01, 0x00, 0x00, 0xff, 0xff, 0xef, 0x27, 0x99, 0xf7, 0x17, 0x02, 0x00, 0x00,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										97
									
								
								vendor/github.com/containerd/continuity/proto/manifest.proto
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								vendor/github.com/containerd/continuity/proto/manifest.proto
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package proto;
 | 
			
		||||
 | 
			
		||||
// Manifest specifies the entries in a container bundle, keyed and sorted by
 | 
			
		||||
// path.
 | 
			
		||||
message Manifest {
 | 
			
		||||
    repeated Resource resource = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Resource {
 | 
			
		||||
    // Path specifies the path from the bundle root. If more than one
 | 
			
		||||
    // path is present, the entry may represent a hardlink, rather than using
 | 
			
		||||
    // a link target. The path format is operating system specific.
 | 
			
		||||
    repeated string path = 1;
 | 
			
		||||
 | 
			
		||||
    // NOTE(stevvooe): Need to define clear precedence for user/group/uid/gid precedence.
 | 
			
		||||
 | 
			
		||||
    // Uid specifies the user id for the resource.
 | 
			
		||||
    int64 uid = 2;
 | 
			
		||||
 | 
			
		||||
    // Gid specifies the group id for the resource.
 | 
			
		||||
    int64 gid = 3;
 | 
			
		||||
 | 
			
		||||
    // user and group are not currently used but their field numbers have been
 | 
			
		||||
    // reserved for future use. As such, they are marked as deprecated.
 | 
			
		||||
    string user = 4 [deprecated=true]; // "deprecated" stands for "reserved" here
 | 
			
		||||
    string group = 5 [deprecated=true]; // "deprecated" stands for "reserved" here
 | 
			
		||||
 | 
			
		||||
    // Mode defines the file mode and permissions. We've used the same
 | 
			
		||||
    // bit-packing from Go's os package,
 | 
			
		||||
    // http://golang.org/pkg/os/#FileMode, since they've done the work of
 | 
			
		||||
    // creating a cross-platform layout.
 | 
			
		||||
    uint32 mode = 6;
 | 
			
		||||
 | 
			
		||||
    // NOTE(stevvooe): Beyond here, we start defining type specific fields.
 | 
			
		||||
 | 
			
		||||
    // Size specifies the size in bytes of the resource. This is only valid
 | 
			
		||||
    // for regular files.
 | 
			
		||||
    uint64 size = 7;
 | 
			
		||||
 | 
			
		||||
    // Digest specifies the content digest of the target file. Only valid for
 | 
			
		||||
    // regular files. The strings are formatted in OCI style, i.e. <alg>:<encoded>.
 | 
			
		||||
    // For detailed information about the format, please refer to OCI Image Spec:
 | 
			
		||||
    // https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests-and-verification
 | 
			
		||||
    // The digests are sorted in lexical order and implementations may choose
 | 
			
		||||
    // which algorithms they prefer.
 | 
			
		||||
    repeated string digest = 8;
 | 
			
		||||
 | 
			
		||||
    // Target defines the target of a hard or soft link. Absolute links start
 | 
			
		||||
    // with a slash and specify the resource relative to the bundle root.
 | 
			
		||||
    // Relative links do not start with a slash and are relative to the
 | 
			
		||||
    // resource path.
 | 
			
		||||
    string target = 9;
 | 
			
		||||
 | 
			
		||||
    // Major specifies the major device number for character and block devices.
 | 
			
		||||
    uint64 major = 10;
 | 
			
		||||
 | 
			
		||||
    // Minor specifies the minor device number for character and block devices.
 | 
			
		||||
    uint64 minor = 11;
 | 
			
		||||
 | 
			
		||||
    // Xattr provides storage for extended attributes for the target resource.
 | 
			
		||||
    repeated XAttr xattr = 12;
 | 
			
		||||
 | 
			
		||||
    // Ads stores one or more alternate data streams for the target resource.
 | 
			
		||||
    repeated ADSEntry ads = 13;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// XAttr encodes extended attributes for a resource.
 | 
			
		||||
message XAttr {
 | 
			
		||||
    // Name specifies the attribute name.
 | 
			
		||||
    string name = 1;
 | 
			
		||||
 | 
			
		||||
    // Data specifies the associated data for the attribute.
 | 
			
		||||
    bytes data = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ADSEntry encodes information for a Windows Alternate Data Stream.
 | 
			
		||||
message ADSEntry {
 | 
			
		||||
    // Name specifices the stream name.
 | 
			
		||||
    string name = 1;
 | 
			
		||||
 | 
			
		||||
    // Data specifies the stream data.
 | 
			
		||||
    // See also the description about the digest below.
 | 
			
		||||
    bytes data = 2;
 | 
			
		||||
 | 
			
		||||
    // Digest is a CAS representation of the stream data.
 | 
			
		||||
    //
 | 
			
		||||
    // At least one of data or digest MUST be specified, and either one of them
 | 
			
		||||
    // SHOULD be specified.
 | 
			
		||||
    //
 | 
			
		||||
    // How to access the actual data using the digest is implementation-specific,
 | 
			
		||||
    // and implementations can choose not to implement digest.
 | 
			
		||||
    // So, digest SHOULD be used only when the stream data is large.
 | 
			
		||||
    string digest = 3;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										590
									
								
								vendor/github.com/containerd/continuity/resource.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										590
									
								
								vendor/github.com/containerd/continuity/resource.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,590 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"sort"
 | 
			
		||||
 | 
			
		||||
	pb "github.com/containerd/continuity/proto"
 | 
			
		||||
	"github.com/opencontainers/go-digest"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TODO(stevvooe): A record based model, somewhat sketched out at the bottom
 | 
			
		||||
// of this file, will be more flexible. Another possibly is to tie the package
 | 
			
		||||
// interface directly to the protobuf type. This will have efficiency
 | 
			
		||||
// advantages at the cost coupling the nasty codegen types to the exported
 | 
			
		||||
// interface.
 | 
			
		||||
 | 
			
		||||
type Resource interface {
 | 
			
		||||
	// Path provides the primary resource path relative to the bundle root. In
 | 
			
		||||
	// cases where resources have more than one path, such as with hard links,
 | 
			
		||||
	// this will return the primary path, which is often just the first entry.
 | 
			
		||||
	Path() string
 | 
			
		||||
 | 
			
		||||
	// Mode returns the
 | 
			
		||||
	Mode() os.FileMode
 | 
			
		||||
 | 
			
		||||
	UID() int64
 | 
			
		||||
	GID() int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ByPath provides the canonical sort order for a set of resources. Use with
 | 
			
		||||
// sort.Stable for deterministic sorting.
 | 
			
		||||
type ByPath []Resource
 | 
			
		||||
 | 
			
		||||
func (bp ByPath) Len() int           { return len(bp) }
 | 
			
		||||
func (bp ByPath) Swap(i, j int)      { bp[i], bp[j] = bp[j], bp[i] }
 | 
			
		||||
func (bp ByPath) Less(i, j int) bool { return bp[i].Path() < bp[j].Path() }
 | 
			
		||||
 | 
			
		||||
type XAttrer interface {
 | 
			
		||||
	XAttrs() map[string][]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hardlinkable is an interface that a resource type satisfies if it can be a
 | 
			
		||||
// hardlink target.
 | 
			
		||||
type Hardlinkable interface {
 | 
			
		||||
	// Paths returns all paths of the resource, including the primary path
 | 
			
		||||
	// returned by Resource.Path. If len(Paths()) > 1, the resource is a hard
 | 
			
		||||
	// link.
 | 
			
		||||
	Paths() []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RegularFile interface {
 | 
			
		||||
	Resource
 | 
			
		||||
	XAttrer
 | 
			
		||||
	Hardlinkable
 | 
			
		||||
 | 
			
		||||
	Size() int64
 | 
			
		||||
	Digests() []digest.Digest
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Merge two or more Resources into new file. Typically, this should be
 | 
			
		||||
// used to merge regular files as hardlinks. If the files are not identical,
 | 
			
		||||
// other than Paths and Digests, the merge will fail and an error will be
 | 
			
		||||
// returned.
 | 
			
		||||
func Merge(fs ...Resource) (Resource, error) {
 | 
			
		||||
	if len(fs) < 1 {
 | 
			
		||||
		return nil, fmt.Errorf("please provide a resource to merge")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(fs) == 1 {
 | 
			
		||||
		return fs[0], nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var paths []string
 | 
			
		||||
	var digests []digest.Digest
 | 
			
		||||
	bypath := map[string][]Resource{}
 | 
			
		||||
 | 
			
		||||
	// The attributes are all compared against the first to make sure they
 | 
			
		||||
	// agree before adding to the above collections. If any of these don't
 | 
			
		||||
	// correctly validate, the merge fails.
 | 
			
		||||
	prototype := fs[0]
 | 
			
		||||
	xattrs := make(map[string][]byte)
 | 
			
		||||
 | 
			
		||||
	// initialize xattrs for use below. All files must have same xattrs.
 | 
			
		||||
	if prototypeXAttrer, ok := prototype.(XAttrer); ok {
 | 
			
		||||
		for attr, value := range prototypeXAttrer.XAttrs() {
 | 
			
		||||
			xattrs[attr] = value
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, f := range fs {
 | 
			
		||||
		h, isHardlinkable := f.(Hardlinkable)
 | 
			
		||||
		if !isHardlinkable {
 | 
			
		||||
			return nil, errNotAHardLink
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if f.Mode() != prototype.Mode() {
 | 
			
		||||
			return nil, fmt.Errorf("modes do not match: %v != %v", f.Mode(), prototype.Mode())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if f.UID() != prototype.UID() {
 | 
			
		||||
			return nil, fmt.Errorf("uid does not match: %v != %v", f.UID(), prototype.UID())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if f.GID() != prototype.GID() {
 | 
			
		||||
			return nil, fmt.Errorf("gid does not match: %v != %v", f.GID(), prototype.GID())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if xattrer, ok := f.(XAttrer); ok {
 | 
			
		||||
			fxattrs := xattrer.XAttrs()
 | 
			
		||||
			if !reflect.DeepEqual(fxattrs, xattrs) {
 | 
			
		||||
				return nil, fmt.Errorf("resource %q xattrs do not match: %v != %v", f, fxattrs, xattrs)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, p := range h.Paths() {
 | 
			
		||||
			pfs, ok := bypath[p]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				// ensure paths are unique by only appending on a new path.
 | 
			
		||||
				paths = append(paths, p)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bypath[p] = append(pfs, f)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if regFile, isRegFile := f.(RegularFile); isRegFile {
 | 
			
		||||
			prototypeRegFile, prototypeIsRegFile := prototype.(RegularFile)
 | 
			
		||||
			if !prototypeIsRegFile {
 | 
			
		||||
				return nil, errors.New("prototype is not a regular file")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if regFile.Size() != prototypeRegFile.Size() {
 | 
			
		||||
				return nil, fmt.Errorf("size does not match: %v != %v", regFile.Size(), prototypeRegFile.Size())
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			digests = append(digests, regFile.Digests()...)
 | 
			
		||||
		} else if device, isDevice := f.(Device); isDevice {
 | 
			
		||||
			prototypeDevice, prototypeIsDevice := prototype.(Device)
 | 
			
		||||
			if !prototypeIsDevice {
 | 
			
		||||
				return nil, errors.New("prototype is not a device")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if device.Major() != prototypeDevice.Major() {
 | 
			
		||||
				return nil, fmt.Errorf("major number does not match: %v != %v", device.Major(), prototypeDevice.Major())
 | 
			
		||||
			}
 | 
			
		||||
			if device.Minor() != prototypeDevice.Minor() {
 | 
			
		||||
				return nil, fmt.Errorf("minor number does not match: %v != %v", device.Minor(), prototypeDevice.Minor())
 | 
			
		||||
			}
 | 
			
		||||
		} else if _, isNamedPipe := f.(NamedPipe); isNamedPipe {
 | 
			
		||||
			_, prototypeIsNamedPipe := prototype.(NamedPipe)
 | 
			
		||||
			if !prototypeIsNamedPipe {
 | 
			
		||||
				return nil, errors.New("prototype is not a named pipe")
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, errNotAHardLink
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sort.Stable(sort.StringSlice(paths))
 | 
			
		||||
 | 
			
		||||
	// Choose a "canonical" file. Really, it is just the first file to sort
 | 
			
		||||
	// against. We also effectively select the very first digest as the
 | 
			
		||||
	// "canonical" one for this file.
 | 
			
		||||
	first := bypath[paths[0]][0]
 | 
			
		||||
 | 
			
		||||
	resource := resource{
 | 
			
		||||
		paths:  paths,
 | 
			
		||||
		mode:   first.Mode(),
 | 
			
		||||
		uid:    first.UID(),
 | 
			
		||||
		gid:    first.GID(),
 | 
			
		||||
		xattrs: xattrs,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch typedF := first.(type) {
 | 
			
		||||
	case RegularFile:
 | 
			
		||||
		var err error
 | 
			
		||||
		digests, err = uniqifyDigests(digests...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return ®ularFile{
 | 
			
		||||
			resource: resource,
 | 
			
		||||
			size:     typedF.Size(),
 | 
			
		||||
			digests:  digests,
 | 
			
		||||
		}, nil
 | 
			
		||||
	case Device:
 | 
			
		||||
		return &device{
 | 
			
		||||
			resource: resource,
 | 
			
		||||
			major:    typedF.Major(),
 | 
			
		||||
			minor:    typedF.Minor(),
 | 
			
		||||
		}, nil
 | 
			
		||||
 | 
			
		||||
	case NamedPipe:
 | 
			
		||||
		return &namedPipe{
 | 
			
		||||
			resource: resource,
 | 
			
		||||
		}, nil
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, errNotAHardLink
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Directory interface {
 | 
			
		||||
	Resource
 | 
			
		||||
	XAttrer
 | 
			
		||||
 | 
			
		||||
	// Directory is a no-op method to identify directory objects by interface.
 | 
			
		||||
	Directory()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SymLink interface {
 | 
			
		||||
	Resource
 | 
			
		||||
 | 
			
		||||
	// Target returns the target of the symlink contained in the .
 | 
			
		||||
	Target() string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NamedPipe interface {
 | 
			
		||||
	Resource
 | 
			
		||||
	Hardlinkable
 | 
			
		||||
	XAttrer
 | 
			
		||||
 | 
			
		||||
	// Pipe is a no-op method to allow consistent resolution of NamedPipe
 | 
			
		||||
	// interface.
 | 
			
		||||
	Pipe()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Device interface {
 | 
			
		||||
	Resource
 | 
			
		||||
	Hardlinkable
 | 
			
		||||
	XAttrer
 | 
			
		||||
 | 
			
		||||
	Major() uint64
 | 
			
		||||
	Minor() uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type resource struct {
 | 
			
		||||
	paths    []string
 | 
			
		||||
	mode     os.FileMode
 | 
			
		||||
	uid, gid int64
 | 
			
		||||
	xattrs   map[string][]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ Resource = &resource{}
 | 
			
		||||
 | 
			
		||||
func (r *resource) Path() string {
 | 
			
		||||
	if len(r.paths) < 1 {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r.paths[0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *resource) Mode() os.FileMode {
 | 
			
		||||
	return r.mode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *resource) UID() int64 {
 | 
			
		||||
	return r.uid
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *resource) GID() int64 {
 | 
			
		||||
	return r.gid
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type regularFile struct {
 | 
			
		||||
	resource
 | 
			
		||||
	size    int64
 | 
			
		||||
	digests []digest.Digest
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ RegularFile = ®ularFile{}
 | 
			
		||||
 | 
			
		||||
// newRegularFile returns the RegularFile, using the populated base resource
 | 
			
		||||
// and one or more digests of the content.
 | 
			
		||||
func newRegularFile(base resource, paths []string, size int64, dgsts ...digest.Digest) (RegularFile, error) {
 | 
			
		||||
	if !base.Mode().IsRegular() {
 | 
			
		||||
		return nil, fmt.Errorf("not a regular file")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base.paths = make([]string, len(paths))
 | 
			
		||||
	copy(base.paths, paths)
 | 
			
		||||
 | 
			
		||||
	// make our own copy of digests
 | 
			
		||||
	ds := make([]digest.Digest, len(dgsts))
 | 
			
		||||
	copy(ds, dgsts)
 | 
			
		||||
 | 
			
		||||
	return ®ularFile{
 | 
			
		||||
		resource: base,
 | 
			
		||||
		size:     size,
 | 
			
		||||
		digests:  ds,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rf *regularFile) Paths() []string {
 | 
			
		||||
	paths := make([]string, len(rf.paths))
 | 
			
		||||
	copy(paths, rf.paths)
 | 
			
		||||
	return paths
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rf *regularFile) Size() int64 {
 | 
			
		||||
	return rf.size
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rf *regularFile) Digests() []digest.Digest {
 | 
			
		||||
	digests := make([]digest.Digest, len(rf.digests))
 | 
			
		||||
	copy(digests, rf.digests)
 | 
			
		||||
	return digests
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rf *regularFile) XAttrs() map[string][]byte {
 | 
			
		||||
	xattrs := make(map[string][]byte, len(rf.xattrs))
 | 
			
		||||
 | 
			
		||||
	for attr, value := range rf.xattrs {
 | 
			
		||||
		xattrs[attr] = append(xattrs[attr], value...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return xattrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type directory struct {
 | 
			
		||||
	resource
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ Directory = &directory{}
 | 
			
		||||
 | 
			
		||||
func newDirectory(base resource) (Directory, error) {
 | 
			
		||||
	if !base.Mode().IsDir() {
 | 
			
		||||
		return nil, fmt.Errorf("not a directory")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &directory{
 | 
			
		||||
		resource: base,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *directory) Directory() {}
 | 
			
		||||
 | 
			
		||||
func (d *directory) XAttrs() map[string][]byte {
 | 
			
		||||
	xattrs := make(map[string][]byte, len(d.xattrs))
 | 
			
		||||
 | 
			
		||||
	for attr, value := range d.xattrs {
 | 
			
		||||
		xattrs[attr] = append(xattrs[attr], value...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return xattrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type symLink struct {
 | 
			
		||||
	resource
 | 
			
		||||
	target string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ SymLink = &symLink{}
 | 
			
		||||
 | 
			
		||||
func newSymLink(base resource, target string) (SymLink, error) {
 | 
			
		||||
	if base.Mode()&os.ModeSymlink == 0 {
 | 
			
		||||
		return nil, fmt.Errorf("not a symlink")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &symLink{
 | 
			
		||||
		resource: base,
 | 
			
		||||
		target:   target,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *symLink) Target() string {
 | 
			
		||||
	return l.target
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type namedPipe struct {
 | 
			
		||||
	resource
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ NamedPipe = &namedPipe{}
 | 
			
		||||
 | 
			
		||||
func newNamedPipe(base resource, paths []string) (NamedPipe, error) {
 | 
			
		||||
	if base.Mode()&os.ModeNamedPipe == 0 {
 | 
			
		||||
		return nil, fmt.Errorf("not a namedpipe")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base.paths = make([]string, len(paths))
 | 
			
		||||
	copy(base.paths, paths)
 | 
			
		||||
 | 
			
		||||
	return &namedPipe{
 | 
			
		||||
		resource: base,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (np *namedPipe) Pipe() {}
 | 
			
		||||
 | 
			
		||||
func (np *namedPipe) Paths() []string {
 | 
			
		||||
	paths := make([]string, len(np.paths))
 | 
			
		||||
	copy(paths, np.paths)
 | 
			
		||||
	return paths
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (np *namedPipe) XAttrs() map[string][]byte {
 | 
			
		||||
	xattrs := make(map[string][]byte, len(np.xattrs))
 | 
			
		||||
 | 
			
		||||
	for attr, value := range np.xattrs {
 | 
			
		||||
		xattrs[attr] = append(xattrs[attr], value...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return xattrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type device struct {
 | 
			
		||||
	resource
 | 
			
		||||
	major, minor uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ Device = &device{}
 | 
			
		||||
 | 
			
		||||
func newDevice(base resource, paths []string, major, minor uint64) (Device, error) {
 | 
			
		||||
	if base.Mode()&os.ModeDevice == 0 {
 | 
			
		||||
		return nil, fmt.Errorf("not a device")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base.paths = make([]string, len(paths))
 | 
			
		||||
	copy(base.paths, paths)
 | 
			
		||||
 | 
			
		||||
	return &device{
 | 
			
		||||
		resource: base,
 | 
			
		||||
		major:    major,
 | 
			
		||||
		minor:    minor,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *device) Paths() []string {
 | 
			
		||||
	paths := make([]string, len(d.paths))
 | 
			
		||||
	copy(paths, d.paths)
 | 
			
		||||
	return paths
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *device) XAttrs() map[string][]byte {
 | 
			
		||||
	xattrs := make(map[string][]byte, len(d.xattrs))
 | 
			
		||||
 | 
			
		||||
	for attr, value := range d.xattrs {
 | 
			
		||||
		xattrs[attr] = append(xattrs[attr], value...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return xattrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d device) Major() uint64 {
 | 
			
		||||
	return d.major
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d device) Minor() uint64 {
 | 
			
		||||
	return d.minor
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// toProto converts a resource to a protobuf record. We'd like to push this
 | 
			
		||||
// the individual types but we want to keep this all together during
 | 
			
		||||
// prototyping.
 | 
			
		||||
func toProto(resource Resource) *pb.Resource {
 | 
			
		||||
	b := &pb.Resource{
 | 
			
		||||
		Path: []string{resource.Path()},
 | 
			
		||||
		Mode: uint32(resource.Mode()),
 | 
			
		||||
		Uid:  resource.UID(),
 | 
			
		||||
		Gid:  resource.GID(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if xattrer, ok := resource.(XAttrer); ok {
 | 
			
		||||
		// Sorts the XAttrs by name for consistent ordering.
 | 
			
		||||
		keys := []string{}
 | 
			
		||||
		xattrs := xattrer.XAttrs()
 | 
			
		||||
		for k := range xattrs {
 | 
			
		||||
			keys = append(keys, k)
 | 
			
		||||
		}
 | 
			
		||||
		sort.Strings(keys)
 | 
			
		||||
 | 
			
		||||
		for _, k := range keys {
 | 
			
		||||
			b.Xattr = append(b.Xattr, &pb.XAttr{Name: k, Data: xattrs[k]})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch r := resource.(type) {
 | 
			
		||||
	case RegularFile:
 | 
			
		||||
		b.Path = r.Paths()
 | 
			
		||||
		b.Size = uint64(r.Size())
 | 
			
		||||
 | 
			
		||||
		for _, dgst := range r.Digests() {
 | 
			
		||||
			b.Digest = append(b.Digest, dgst.String())
 | 
			
		||||
		}
 | 
			
		||||
	case SymLink:
 | 
			
		||||
		b.Target = r.Target()
 | 
			
		||||
	case Device:
 | 
			
		||||
		b.Major, b.Minor = r.Major(), r.Minor()
 | 
			
		||||
		b.Path = r.Paths()
 | 
			
		||||
	case NamedPipe:
 | 
			
		||||
		b.Path = r.Paths()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// enforce a few stability guarantees that may not be provided by the
 | 
			
		||||
	// resource implementation.
 | 
			
		||||
	sort.Strings(b.Path)
 | 
			
		||||
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// fromProto converts from a protobuf Resource to a Resource interface.
 | 
			
		||||
func fromProto(b *pb.Resource) (Resource, error) {
 | 
			
		||||
	base := &resource{
 | 
			
		||||
		paths: b.Path,
 | 
			
		||||
		mode:  os.FileMode(b.Mode),
 | 
			
		||||
		uid:   b.Uid,
 | 
			
		||||
		gid:   b.Gid,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base.xattrs = make(map[string][]byte, len(b.Xattr))
 | 
			
		||||
 | 
			
		||||
	for _, attr := range b.Xattr {
 | 
			
		||||
		base.xattrs[attr.Name] = attr.Data
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case base.Mode().IsRegular():
 | 
			
		||||
		dgsts := make([]digest.Digest, len(b.Digest))
 | 
			
		||||
		for i, dgst := range b.Digest {
 | 
			
		||||
			// TODO(stevvooe): Should we be validating at this point?
 | 
			
		||||
			dgsts[i] = digest.Digest(dgst)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return newRegularFile(*base, b.Path, int64(b.Size), dgsts...)
 | 
			
		||||
	case base.Mode().IsDir():
 | 
			
		||||
		return newDirectory(*base)
 | 
			
		||||
	case base.Mode()&os.ModeSymlink != 0:
 | 
			
		||||
		return newSymLink(*base, b.Target)
 | 
			
		||||
	case base.Mode()&os.ModeNamedPipe != 0:
 | 
			
		||||
		return newNamedPipe(*base, b.Path)
 | 
			
		||||
	case base.Mode()&os.ModeDevice != 0:
 | 
			
		||||
		return newDevice(*base, b.Path, b.Major, b.Minor)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, fmt.Errorf("unknown resource record (%#v): %s", b, base.Mode())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NOTE(stevvooe): An alternative model that supports inline declaration.
 | 
			
		||||
// Convenient for unit testing where inline declarations may be desirable but
 | 
			
		||||
// creates an awkward API for the standard use case.
 | 
			
		||||
 | 
			
		||||
// type ResourceKind int
 | 
			
		||||
 | 
			
		||||
// const (
 | 
			
		||||
// 	ResourceRegularFile = iota + 1
 | 
			
		||||
// 	ResourceDirectory
 | 
			
		||||
// 	ResourceSymLink
 | 
			
		||||
// 	Resource
 | 
			
		||||
// )
 | 
			
		||||
 | 
			
		||||
// type Resource struct {
 | 
			
		||||
// 	Kind         ResourceKind
 | 
			
		||||
// 	Paths        []string
 | 
			
		||||
// 	Mode         os.FileMode
 | 
			
		||||
// 	UID          string
 | 
			
		||||
// 	GID          string
 | 
			
		||||
// 	Size         int64
 | 
			
		||||
// 	Digests      []digest.Digest
 | 
			
		||||
// 	Target       string
 | 
			
		||||
// 	Major, Minor int
 | 
			
		||||
// 	XAttrs       map[string][]byte
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// type RegularFile struct {
 | 
			
		||||
// 	Paths   []string
 | 
			
		||||
//  Size 	int64
 | 
			
		||||
// 	Digests []digest.Digest
 | 
			
		||||
// 	Perm    os.FileMode // os.ModePerm + sticky, setuid, setgid
 | 
			
		||||
// }
 | 
			
		||||
							
								
								
									
										53
									
								
								vendor/github.com/containerd/continuity/resource_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								vendor/github.com/containerd/continuity/resource_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
// +build linux darwin freebsd solaris
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// newBaseResource returns a *resource, populated with data from p and fi,
 | 
			
		||||
// where p will be populated directly.
 | 
			
		||||
func newBaseResource(p string, fi os.FileInfo) (*resource, error) {
 | 
			
		||||
	// TODO(stevvooe): This need to be resolved for the container's root,
 | 
			
		||||
	// where here we are really getting the host OS's value. We need to allow
 | 
			
		||||
	// this be passed in and fixed up to make these uid/gid mappings portable.
 | 
			
		||||
	// Either this can be part of the driver or we can achieve it through some
 | 
			
		||||
	// other mechanism.
 | 
			
		||||
	sys, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		// TODO(stevvooe): This may not be a hard error for all platforms. We
 | 
			
		||||
		// may want to move this to the driver.
 | 
			
		||||
		return nil, fmt.Errorf("unable to resolve syscall.Stat_t from (os.FileInfo).Sys(): %#v", fi)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &resource{
 | 
			
		||||
		paths: []string{p},
 | 
			
		||||
		mode:  fi.Mode(),
 | 
			
		||||
 | 
			
		||||
		uid: int64(sys.Uid),
 | 
			
		||||
		gid: int64(sys.Gid),
 | 
			
		||||
 | 
			
		||||
		// NOTE(stevvooe): Population of shared xattrs field is deferred to
 | 
			
		||||
		// the resource types that populate it. Since they are a property of
 | 
			
		||||
		// the context, they must set there.
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/containerd/continuity/resource_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/containerd/continuity/resource_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package continuity
 | 
			
		||||
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
// newBaseResource returns a *resource, populated with data from p and fi,
 | 
			
		||||
// where p will be populated directly.
 | 
			
		||||
func newBaseResource(p string, fi os.FileInfo) (*resource, error) {
 | 
			
		||||
	return &resource{
 | 
			
		||||
		paths: []string{p},
 | 
			
		||||
		mode:  fi.Mode(),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/containerd/continuity/vendor.conf
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/containerd/continuity/vendor.conf
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
bazil.org/fuse 371fbbdaa8987b715bdd21d6adc4c9b20155f748
 | 
			
		||||
github.com/dustin/go-humanize bb3d318650d48840a39aa21a027c6630e198e626
 | 
			
		||||
github.com/golang/protobuf 1e59b77b52bf8e4b449a57e6f79f21226d571845
 | 
			
		||||
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
 | 
			
		||||
github.com/opencontainers/go-digest 279bed98673dd5bef374d3b6e4b09e2af76183bf
 | 
			
		||||
github.com/pkg/errors f15c970de5b76fac0b59abb32d62c17cc7bed265
 | 
			
		||||
github.com/sirupsen/logrus 89742aefa4b206dcf400792f3bd35b542998eb3b
 | 
			
		||||
github.com/spf13/cobra 2da4a54c5ceefcee7ca5dd0eea1e18a3b6366489
 | 
			
		||||
github.com/spf13/pflag 4c012f6dcd9546820e378d0bdda4d8fc772cdfea
 | 
			
		||||
golang.org/x/crypto 9f005a07e0d31d45e6656d241bb5c0f2efd4bc94
 | 
			
		||||
golang.org/x/net a337091b0525af65de94df2eb7e98bd9962dcbe2
 | 
			
		||||
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
 | 
			
		||||
golang.org/x/sys 77b0e4315053a57ed2962443614bdb28db152054
 | 
			
		||||
		Reference in New Issue
	
	Block a user