diff --git a/vendor.conf b/vendor.conf index 5d42448d..4851bded 100644 --- a/vendor.conf +++ b/vendor.conf @@ -8,7 +8,7 @@ github.com/mattn/go-isatty v0.0.4 github.com/VividCortex/ewma v1.1.1 golang.org/x/sync 42b317875d0fa942474b76e1b46a6060d720ae6e github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7 -github.com/containers/storage v1.12.1 +github.com/containers/storage v1.12.2 github.com/sirupsen/logrus v1.0.0 github.com/go-check/check v1 github.com/stretchr/testify v1.1.3 diff --git a/vendor/github.com/containers/storage/containers_ffjson.go b/vendor/github.com/containers/storage/containers_ffjson.go index 40b912bb..aef6becf 100644 --- a/vendor/github.com/containers/storage/containers_ffjson.go +++ b/vendor/github.com/containers/storage/containers_ffjson.go @@ -1,5 +1,5 @@ // Code generated by ffjson . DO NOT EDIT. -// source: ./containers.go +// source: containers.go package storage diff --git a/vendor/github.com/containers/storage/drivers/copy/copy.go b/vendor/github.com/containers/storage/drivers/copy/copy_linux.go similarity index 95% rename from vendor/github.com/containers/storage/drivers/copy/copy.go rename to vendor/github.com/containers/storage/drivers/copy/copy_linux.go index bcbc6128..d614b78f 100644 --- a/vendor/github.com/containers/storage/drivers/copy/copy.go +++ b/vendor/github.com/containers/storage/drivers/copy/copy_linux.go @@ -1,4 +1,4 @@ -// +build linux +// +build cgo package copy @@ -153,8 +153,8 @@ func DirCopy(srcDir, dstDir string, copyMode Mode, copyXattrs bool) error { isHardlink := false - switch f.Mode() & os.ModeType { - case 0: // Regular file + switch mode := f.Mode(); { + case mode.IsRegular(): id := fileID{dev: stat.Dev, ino: stat.Ino} if copyMode == Hardlink { isHardlink = true @@ -172,12 +172,12 @@ func DirCopy(srcDir, dstDir string, copyMode Mode, copyXattrs bool) error { copiedFiles[id] = dstPath } - case os.ModeDir: + case mode.IsDir(): if err := os.Mkdir(dstPath, f.Mode()); err != nil && !os.IsExist(err) { return err } - case os.ModeSymlink: + case mode&os.ModeSymlink != 0: link, err := os.Readlink(srcPath) if err != nil { return err @@ -187,14 +187,15 @@ func DirCopy(srcDir, dstDir string, copyMode Mode, copyXattrs bool) error { return err } - case os.ModeNamedPipe: + case mode&os.ModeNamedPipe != 0: fallthrough - case os.ModeSocket: + + case mode&os.ModeSocket != 0: if err := unix.Mkfifo(dstPath, stat.Mode); err != nil { return err } - case os.ModeDevice: + case mode&os.ModeDevice != 0: if rsystem.RunningInUserNS() { // cannot create a device if running in user namespace return nil @@ -204,7 +205,7 @@ func DirCopy(srcDir, dstDir string, copyMode Mode, copyXattrs bool) error { } default: - return fmt.Errorf("unknown file type for %s", srcPath) + return fmt.Errorf("unknown file type with mode %v for %s", mode, srcPath) } // Everything below is copying metadata from src to dst. All this metadata diff --git a/vendor/github.com/containers/storage/drivers/copy/copy_unsupported.go b/vendor/github.com/containers/storage/drivers/copy/copy_unsupported.go new file mode 100644 index 00000000..4d44f2f3 --- /dev/null +++ b/vendor/github.com/containers/storage/drivers/copy/copy_unsupported.go @@ -0,0 +1,19 @@ +// +build !linux !cgo + +package copy + +import "github.com/containers/storage/pkg/chrootarchive" + +// Mode indicates whether to use hardlink or copy content +type Mode int + +const ( + // Content creates a new file, and copies the content of the file + Content Mode = iota +) + +// DirCopy copies or hardlinks the contents of one directory to another, +// properly handling soft links +func DirCopy(srcDir, dstDir string, _ Mode, _ bool) error { + return chrootarchive.NewArchiver(nil).CopyWithTar(srcDir, dstDir) +} diff --git a/vendor/github.com/containers/storage/images_ffjson.go b/vendor/github.com/containers/storage/images_ffjson.go index 539acfe9..6b40ebd5 100644 --- a/vendor/github.com/containers/storage/images_ffjson.go +++ b/vendor/github.com/containers/storage/images_ffjson.go @@ -1,5 +1,5 @@ // Code generated by ffjson . DO NOT EDIT. -// source: ./images.go +// source: images.go package storage diff --git a/vendor/github.com/containers/storage/lockfile.go b/vendor/github.com/containers/storage/lockfile.go index 3a1befcb..ed875333 100644 --- a/vendor/github.com/containers/storage/lockfile.go +++ b/vendor/github.com/containers/storage/lockfile.go @@ -58,8 +58,17 @@ func GetROLockfile(path string) (Locker, error) { return getLockfile(path, true) } -// getLockfile is a helper for GetLockfile and GetROLockfile and returns Locker -// based on the path and read-only property. +// getLockfile returns a Locker object, possibly (depending on the platform) +// working inter-process, and associated with the specified path. +// +// If ro, the lock is a read-write lock and the returned Locker should correspond to the +// “lock for reading” (shared) operation; otherwise, the lock is either an exclusive lock, +// or a read-write lock and Locker should correspond to the “lock for writing” (exclusive) operation. +// +// WARNING: +// - The lock may or MAY NOT be inter-process. +// - There may or MAY NOT be an actual object on the filesystem created for the specified path. +// - Even if ro, the lock MAY be exclusive. func getLockfile(path string, ro bool) (Locker, error) { lockfilesLock.Lock() defer lockfilesLock.Unlock() @@ -79,7 +88,7 @@ func getLockfile(path string, ro bool) (Locker, error) { } return locker, nil } - locker, err := getLockFile(path, ro) // platform dependent locker + locker, err := createLockerForPath(path, ro) // platform-dependent locker if err != nil { return nil, err } diff --git a/vendor/github.com/containers/storage/lockfile_unix.go b/vendor/github.com/containers/storage/lockfile_unix.go index a9dc6412..8e0f22cb 100644 --- a/vendor/github.com/containers/storage/lockfile_unix.go +++ b/vendor/github.com/containers/storage/lockfile_unix.go @@ -13,34 +13,6 @@ import ( "golang.org/x/sys/unix" ) -func getLockFile(path string, ro bool) (Locker, error) { - var fd int - var err error - if ro { - fd, err = unix.Open(path, os.O_RDONLY, 0) - } else { - fd, err = unix.Open(path, os.O_RDWR|os.O_CREATE, unix.S_IRUSR|unix.S_IWUSR) - } - if err != nil { - return nil, errors.Wrapf(err, "error opening %q", path) - } - unix.CloseOnExec(fd) - - locktype := unix.F_WRLCK - if ro { - locktype = unix.F_RDLCK - } - return &lockfile{ - stateMutex: &sync.Mutex{}, - rwMutex: &sync.RWMutex{}, - file: path, - fd: uintptr(fd), - lw: stringid.GenerateRandomID(), - locktype: int16(locktype), - locked: false, - ro: ro}, nil -} - type lockfile struct { // rwMutex serializes concurrent reader-writer acquisitions in the same process space rwMutex *sync.RWMutex @@ -55,6 +27,52 @@ type lockfile struct { ro bool } +// openLock opens the file at path and returns the corresponding file +// descriptor. Note that the path is opened read-only when ro is set. If ro +// is unset, openLock will open the path read-write and create the file if +// necessary. +func openLock(path string, ro bool) (int, error) { + if ro { + return unix.Open(path, os.O_RDONLY, 0) + } + return unix.Open(path, os.O_RDWR|os.O_CREATE, unix.S_IRUSR|unix.S_IWUSR) +} + +// createLockerForPath returns a Locker object, possibly (depending on the platform) +// working inter-process and associated with the specified path. +// +// This function will be called at most once for each path value within a single process. +// +// If ro, the lock is a read-write lock and the returned Locker should correspond to the +// “lock for reading” (shared) operation; otherwise, the lock is either an exclusive lock, +// or a read-write lock and Locker should correspond to the “lock for writing” (exclusive) operation. +// +// WARNING: +// - The lock may or MAY NOT be inter-process. +// - There may or MAY NOT be an actual object on the filesystem created for the specified path. +// - Even if ro, the lock MAY be exclusive. +func createLockerForPath(path string, ro bool) (Locker, error) { + // Check if we can open the lock. + fd, err := openLock(path, ro) + if err != nil { + return nil, errors.Wrapf(err, "error opening %q", path) + } + unix.Close(fd) + + locktype := unix.F_WRLCK + if ro { + locktype = unix.F_RDLCK + } + return &lockfile{ + stateMutex: &sync.Mutex{}, + rwMutex: &sync.RWMutex{}, + file: path, + lw: stringid.GenerateRandomID(), + locktype: int16(locktype), + locked: false, + ro: ro}, nil +} + // lock locks the lockfile via FCTNL(2) based on the specified type and // command. func (l *lockfile) lock(l_type int16) { @@ -63,7 +81,6 @@ func (l *lockfile) lock(l_type int16) { Whence: int16(os.SEEK_SET), Start: 0, Len: 0, - Pid: int32(os.Getpid()), } switch l_type { case unix.F_RDLCK: @@ -74,7 +91,16 @@ func (l *lockfile) lock(l_type int16) { panic(fmt.Sprintf("attempted to acquire a file lock of unrecognized type %d", l_type)) } l.stateMutex.Lock() + defer l.stateMutex.Unlock() if l.counter == 0 { + // If we're the first reference on the lock, we need to open the file again. + fd, err := openLock(l.file, l.ro) + if err != nil { + panic(fmt.Sprintf("error opening %q", l.file)) + } + unix.CloseOnExec(fd) + l.fd = uintptr(fd) + // Optimization: only use the (expensive) fcntl syscall when // the counter is 0. In this case, we're either the first // reader lock or a writer lock. @@ -85,7 +111,6 @@ func (l *lockfile) lock(l_type int16) { l.locktype = l_type l.locked = true l.counter++ - l.stateMutex.Unlock() } // Lock locks the lockfile as a writer. Note that RLock() will be called if @@ -133,6 +158,8 @@ func (l *lockfile) Unlock() { for unix.FcntlFlock(l.fd, unix.F_SETLKW, &lk) != nil { time.Sleep(10 * time.Millisecond) } + // Close the file descriptor on the last unlock. + unix.Close(int(l.fd)) } if l.locktype == unix.F_RDLCK { l.rwMutex.RUnlock() diff --git a/vendor/github.com/containers/storage/lockfile_windows.go b/vendor/github.com/containers/storage/lockfile_windows.go index a3821bfe..c0206949 100644 --- a/vendor/github.com/containers/storage/lockfile_windows.go +++ b/vendor/github.com/containers/storage/lockfile_windows.go @@ -8,7 +8,20 @@ import ( "time" ) -func getLockFile(path string, ro bool) (Locker, error) { +// createLockerForPath returns a Locker object, possibly (depending on the platform) +// working inter-process and associated with the specified path. +// +// This function will be called at most once for each path value within a single process. +// +// If ro, the lock is a read-write lock and the returned Locker should correspond to the +// “lock for reading” (shared) operation; otherwise, the lock is either an exclusive lock, +// or a read-write lock and Locker should correspond to the “lock for writing” (exclusive) operation. +// +// WARNING: +// - The lock may or MAY NOT be inter-process. +// - There may or MAY NOT be an actual object on the filesystem created for the specified path. +// - Even if ro, the lock MAY be exclusive. +func createLockerForPath(path string, ro bool) (Locker, error) { return &lockfile{locked: false}, nil } diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go index 7e39e395..34df10ba 100644 --- a/vendor/github.com/containers/storage/store.go +++ b/vendor/github.com/containers/storage/store.go @@ -460,6 +460,9 @@ type Store interface { // Version returns version information, in the form of key-value pairs, from // the storage package. Version() ([][2]string, error) + + // GetDigestLock returns digest-specific Locker. + GetDigestLock(digest.Digest) (Locker, error) } // IDMappingOptions are used for specifying how ID mapping should be set up for @@ -529,6 +532,7 @@ type store struct { imageStore ImageStore roImageStores []ROImageStore containerStore ContainerStore + digestLockRoot string } // GetStore attempts to find an already-created Store object matching the @@ -698,9 +702,20 @@ func (s *store) load() error { return err } s.containerStore = rcs + + s.digestLockRoot = filepath.Join(s.runRoot, driverPrefix+"locks") + if err := os.MkdirAll(s.digestLockRoot, 0700); err != nil { + return err + } + return nil } +// GetDigestLock returns a digest-specific Locker. +func (s *store) GetDigestLock(d digest.Digest) (Locker, error) { + return GetLockfile(filepath.Join(s.digestLockRoot, d.String())) +} + func (s *store) getGraphDriver() (drivers.Driver, error) { if s.graphDriver != nil { return s.graphDriver, nil diff --git a/vendor/github.com/containers/storage/utils.go b/vendor/github.com/containers/storage/utils.go index e74956c9..f36833c3 100644 --- a/vendor/github.com/containers/storage/utils.go +++ b/vendor/github.com/containers/storage/utils.go @@ -6,6 +6,7 @@ import ( "os/exec" "os/user" "path/filepath" + "strconv" "strings" "github.com/BurntSushi/toml" @@ -158,6 +159,21 @@ func getTomlStorage(storeOptions *StoreOptions) *tomlConfig { return config } +func getRootlessUID() int { + uidEnv := os.Getenv("_CONTAINERS_ROOTLESS_UID") + if uidEnv != "" { + u, _ := strconv.Atoi(uidEnv) + return u + } + return os.Geteuid() +} + +// DefaultStoreOptionsAutoDetectUID returns the default storage ops for containers +func DefaultStoreOptionsAutoDetectUID() (StoreOptions, error) { + uid := getRootlessUID() + return DefaultStoreOptions(uid != 0, uid) +} + // DefaultStoreOptions returns the default storage ops for containers func DefaultStoreOptions(rootless bool, rootlessUid int) (StoreOptions, error) { var (