parent
326f0cfa2f
commit
5c292c61c6
1437 changed files with 208886 additions and 87131 deletions
105
vendor/github.com/containers/storage/pkg/archive/archive.go
generated
vendored
105
vendor/github.com/containers/storage/pkg/archive/archive.go
generated
vendored
|
|
@ -9,7 +9,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
|
@ -25,7 +24,6 @@ import (
|
|||
"github.com/containers/storage/pkg/system"
|
||||
"github.com/containers/storage/pkg/unshare"
|
||||
gzip "github.com/klauspost/pgzip"
|
||||
"github.com/opencontainers/runc/libcontainer/userns"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/ulikunitz/xz"
|
||||
)
|
||||
|
|
@ -77,6 +75,7 @@ const (
|
|||
solaris = "solaris"
|
||||
windows = "windows"
|
||||
darwin = "darwin"
|
||||
freebsd = "freebsd"
|
||||
)
|
||||
|
||||
var xattrsToIgnore = map[string]interface{}{
|
||||
|
|
@ -132,16 +131,6 @@ const (
|
|||
OverlayWhiteoutFormat
|
||||
)
|
||||
|
||||
const (
|
||||
modeISDIR = 040000 // Directory
|
||||
modeISFIFO = 010000 // FIFO
|
||||
modeISREG = 0100000 // Regular file
|
||||
modeISLNK = 0120000 // Symbolic link
|
||||
modeISBLK = 060000 // Block special file
|
||||
modeISCHR = 020000 // Character special file
|
||||
modeISSOCK = 0140000 // Socket
|
||||
)
|
||||
|
||||
// IsArchivePath checks if the (possibly compressed) file at the given path
|
||||
// starts with a tar file header.
|
||||
func IsArchivePath(path string) bool {
|
||||
|
|
@ -329,7 +318,6 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
|
|||
}
|
||||
|
||||
pipeWriter.Close()
|
||||
|
||||
}()
|
||||
return pipeReader
|
||||
}
|
||||
|
|
@ -360,7 +348,7 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr.Mode = fillGo18FileTypeBits(int64(chmodTarEntry(os.FileMode(hdr.Mode))), fi)
|
||||
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
|
||||
name, err = canonicalTarName(name, fi.IsDir())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tar: cannot canonicalize path: %w", err)
|
||||
|
|
@ -372,31 +360,6 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro
|
|||
return hdr, nil
|
||||
}
|
||||
|
||||
// fillGo18FileTypeBits fills type bits which have been removed on Go 1.9 archive/tar
|
||||
// https://github.com/golang/go/commit/66b5a2f
|
||||
func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 {
|
||||
fm := fi.Mode()
|
||||
switch {
|
||||
case fm.IsRegular():
|
||||
mode |= modeISREG
|
||||
case fi.IsDir():
|
||||
mode |= modeISDIR
|
||||
case fm&os.ModeSymlink != 0:
|
||||
mode |= modeISLNK
|
||||
case fm&os.ModeDevice != 0:
|
||||
if fm&os.ModeCharDevice != 0 {
|
||||
mode |= modeISCHR
|
||||
} else {
|
||||
mode |= modeISBLK
|
||||
}
|
||||
case fm&os.ModeNamedPipe != 0:
|
||||
mode |= modeISFIFO
|
||||
case fm&os.ModeSocket != 0:
|
||||
mode |= modeISSOCK
|
||||
}
|
||||
return mode
|
||||
}
|
||||
|
||||
// ReadSecurityXattrToTarHeader reads security.capability, security,image
|
||||
// xattrs from filesystem to a tar header
|
||||
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
|
||||
|
|
@ -484,7 +447,7 @@ func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *
|
|||
}
|
||||
|
||||
// canonicalTarName provides a platform-independent and consistent posix-style
|
||||
//path for files and directories to be archived regardless of the platform.
|
||||
// path for files and directories to be archived regardless of the platform.
|
||||
func canonicalTarName(name string, isDir bool) (string, error) {
|
||||
name, err := CanonicalTarNameForPath(name)
|
||||
if err != nil {
|
||||
|
|
@ -528,6 +491,9 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
|||
if err := ReadUserXattrToTarHeader(path, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ReadFileFlagsToTarHeader(path, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
if ta.CopyPass {
|
||||
copyPassHeader(hdr)
|
||||
}
|
||||
|
|
@ -550,9 +516,9 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
|||
}
|
||||
}
|
||||
|
||||
//handle re-mapping container ID mappings back to host ID mappings before
|
||||
//writing tar headers/files. We skip whiteout files because they were written
|
||||
//by the kernel and already have proper ownership relative to the host
|
||||
// handle re-mapping container ID mappings back to host ID mappings before
|
||||
// writing tar headers/files. We skip whiteout files because they were written
|
||||
// by the kernel and already have proper ownership relative to the host
|
||||
if !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IDMappings.Empty() {
|
||||
fileIDPair, err := getFileUIDGID(fi.Sys())
|
||||
if err != nil {
|
||||
|
|
@ -673,7 +639,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||
if !strings.HasPrefix(targetPath, extractDir) {
|
||||
return breakoutError(fmt.Errorf("invalid hardlink %q -> %q", targetPath, hdr.Linkname))
|
||||
}
|
||||
if err := os.Link(targetPath, path); err != nil {
|
||||
if err := handleLLink(targetPath, path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -700,7 +666,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||
}
|
||||
|
||||
if forceMask != nil && (hdr.Typeflag != tar.TypeSymlink || runtime.GOOS == "darwin") {
|
||||
value := fmt.Sprintf("%d:%d:0%o", hdr.Uid, hdr.Gid, hdrInfo.Mode()&07777)
|
||||
value := fmt.Sprintf("%d:%d:0%o", hdr.Uid, hdr.Gid, hdrInfo.Mode()&0o7777)
|
||||
if err := system.Lsetxattr(path, idtools.ContainersOverrideXattr, []byte(value), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -771,6 +737,15 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||
|
||||
}
|
||||
|
||||
// We defer setting flags on directories until the end of
|
||||
// Unpack or UnpackLayer in case setting them makes the
|
||||
// directory immutable.
|
||||
if hdr.Typeflag != tar.TypeDir {
|
||||
if err := WriteFileFlagsFromTarHeader(path, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"errors": errs,
|
||||
|
|
@ -789,7 +764,6 @@ func Tar(path string, compression Compression) (io.ReadCloser, error) {
|
|||
// TarWithOptions creates an archive from the directory at `path`, only including files whose relative
|
||||
// paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`.
|
||||
func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
|
||||
|
||||
// Fix the source path to work with long path names. This is a no-op
|
||||
// on platforms other than Windows.
|
||||
srcPath = fixVolumePathPrefix(srcPath)
|
||||
|
|
@ -865,7 +839,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
|||
rebaseName := options.RebaseNames[include]
|
||||
|
||||
walkRoot := getWalkRoot(srcPath, include)
|
||||
filepath.WalkDir(walkRoot, func(filePath string, d fs.DirEntry, err error) error {
|
||||
if err := filepath.WalkDir(walkRoot, func(filePath string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
logrus.Errorf("Tar: Can't stat file %s to tar: %s", srcPath, err)
|
||||
return nil
|
||||
|
|
@ -875,7 +849,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
|||
if err != nil || (!options.IncludeSourceDir && relFilePath == "." && d.IsDir()) {
|
||||
// Error getting relative path OR we are looking
|
||||
// at the source directory path. Skip in both situations.
|
||||
return nil
|
||||
return nil //nolint: nilerr
|
||||
}
|
||||
|
||||
if options.IncludeSourceDir && include == "." && relFilePath != "." {
|
||||
|
|
@ -892,8 +866,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
|||
if include != relFilePath {
|
||||
matches, err := pm.IsMatch(relFilePath)
|
||||
if err != nil {
|
||||
logrus.Errorf("Matching %s: %v", relFilePath, err)
|
||||
return err
|
||||
return fmt.Errorf("matching %s: %w", relFilePath, err)
|
||||
}
|
||||
skip = matches
|
||||
}
|
||||
|
|
@ -956,7 +929,10 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
|||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
logrus.Errorf("%s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
@ -1019,7 +995,7 @@ loop:
|
|||
parent := filepath.Dir(hdr.Name)
|
||||
parentPath := filepath.Join(dest, parent)
|
||||
if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
|
||||
err = idtools.MkdirAllAndChownNew(parentPath, 0777, rootIDs)
|
||||
err = idtools.MkdirAllAndChownNew(parentPath, 0o777, rootIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1100,6 +1076,9 @@ loop:
|
|||
if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := WriteFileFlagsFromTarHeader(path, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1107,7 +1086,9 @@ loop:
|
|||
// Untar reads a stream of bytes from `archive`, parses it as a tar archive,
|
||||
// and unpacks it into the directory at `dest`.
|
||||
// The archive may be compressed with one of the following algorithms:
|
||||
// identity (uncompressed), gzip, bzip2, xz.
|
||||
//
|
||||
// identity (uncompressed), gzip, bzip2, xz.
|
||||
//
|
||||
// FIXME: specify behavior when target path exists vs. doesn't exist.
|
||||
func Untar(tarArchive io.Reader, dest string, options *TarOptions) error {
|
||||
return untarHandler(tarArchive, dest, options, true)
|
||||
|
|
@ -1159,7 +1140,7 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
|
|||
GIDMaps: tarMappings.GIDs(),
|
||||
Compression: Uncompressed,
|
||||
CopyPass: true,
|
||||
InUserNS: userns.RunningInUserNS(),
|
||||
InUserNS: unshare.IsRootless(),
|
||||
}
|
||||
archive, err := TarWithOptions(src, options)
|
||||
if err != nil {
|
||||
|
|
@ -1174,7 +1155,7 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
|
|||
UIDMaps: untarMappings.UIDs(),
|
||||
GIDMaps: untarMappings.GIDs(),
|
||||
ChownOpts: archiver.ChownOpts,
|
||||
InUserNS: userns.RunningInUserNS(),
|
||||
InUserNS: unshare.IsRootless(),
|
||||
}
|
||||
return archiver.Untar(archive, dst, options)
|
||||
}
|
||||
|
|
@ -1194,7 +1175,7 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
|
|||
UIDMaps: untarMappings.UIDs(),
|
||||
GIDMaps: untarMappings.GIDs(),
|
||||
ChownOpts: archiver.ChownOpts,
|
||||
InUserNS: userns.RunningInUserNS(),
|
||||
InUserNS: unshare.IsRootless(),
|
||||
}
|
||||
return archiver.Untar(archive, dst, options)
|
||||
}
|
||||
|
|
@ -1221,7 +1202,7 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
|
|||
}
|
||||
// Create dst, copy src's content into it
|
||||
logrus.Debugf("Creating dest directory: %s", dst)
|
||||
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
|
||||
if err := idtools.MkdirAllAndChownNew(dst, 0o755, rootIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
|
||||
|
|
@ -1248,7 +1229,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
|||
dst = filepath.Join(dst, filepath.Base(src))
|
||||
}
|
||||
// Create the holding directory if necessary
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0700); err != nil {
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0o700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -1294,7 +1275,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
|||
UIDMaps: archiver.UntarIDMappings.UIDs(),
|
||||
GIDMaps: archiver.UntarIDMappings.GIDs(),
|
||||
ChownOpts: archiver.ChownOpts,
|
||||
InUserNS: userns.RunningInUserNS(),
|
||||
InUserNS: unshare.IsRootless(),
|
||||
NoOverwriteDirNonDir: true,
|
||||
}
|
||||
err = archiver.Untar(r, filepath.Dir(dst), options)
|
||||
|
|
@ -1348,7 +1329,7 @@ func remapIDs(readIDMappings, writeIDMappings *idtools.IDMappings, chownOpts *id
|
|||
// of that file as an archive. The archive can only be read once - as soon as reading completes,
|
||||
// the file will be deleted.
|
||||
func NewTempArchive(src io.Reader, dir string) (*TempArchive, error) {
|
||||
f, err := ioutil.TempFile(dir, "")
|
||||
f, err := os.CreateTemp(dir, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1404,7 +1385,7 @@ func IsArchive(header []byte) bool {
|
|||
if compression != Uncompressed {
|
||||
return true
|
||||
}
|
||||
r := tar.NewReader(bytes.NewBuffer(header))
|
||||
r := tar.NewReader(bytes.NewReader(header))
|
||||
_, err := r.Next()
|
||||
return err == nil
|
||||
}
|
||||
|
|
@ -1472,7 +1453,7 @@ func CopyFileWithTarAndChown(chownOpts *idtools.IDPair, hasher io.Writer, uidmap
|
|||
err = fmt.Errorf("extracting data to %q while copying: %w", dest, err)
|
||||
}
|
||||
hashWorker.Wait()
|
||||
if err == nil {
|
||||
if err == nil && hashError != nil {
|
||||
err = fmt.Errorf("calculating digest of data for %q while copying: %w", dest, hashError)
|
||||
}
|
||||
return err
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/archive/archive_110.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/archive/archive_110.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build go1.10
|
||||
// +build go1.10
|
||||
|
||||
package archive
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/archive/archive_19.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/archive/archive_19.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !go1.10
|
||||
// +build !go1.10
|
||||
|
||||
package archive
|
||||
|
|
|
|||
19
vendor/github.com/containers/storage/pkg/archive/archive_bsd.go
generated
vendored
Normal file
19
vendor/github.com/containers/storage/pkg/archive/archive_bsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//go:build freebsd || darwin
|
||||
// +build freebsd darwin
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo, forceMask *os.FileMode) error {
|
||||
permissionsMask := hdrInfo.Mode()
|
||||
if forceMask != nil {
|
||||
permissionsMask = *forceMask
|
||||
}
|
||||
return unix.Fchmodat(unix.AT_FDCWD, path, uint32(permissionsMask), unix.AT_SYMLINK_NOFOLLOW)
|
||||
}
|
||||
125
vendor/github.com/containers/storage/pkg/archive/archive_freebsd.go
generated
vendored
125
vendor/github.com/containers/storage/pkg/archive/archive_freebsd.go
generated
vendored
|
|
@ -1,125 +0,0 @@
|
|||
// +build freebsd
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/containers/storage/pkg/system"
|
||||
"github.com/opencontainers/runc/libcontainer/userns"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// fixVolumePathPrefix does platform specific processing to ensure that if
|
||||
// the path being passed in is not in a volume path format, convert it to one.
|
||||
func fixVolumePathPrefix(srcPath string) string {
|
||||
return srcPath
|
||||
}
|
||||
|
||||
// getWalkRoot calculates the root path when performing a TarWithOptions.
|
||||
// We use a separate function as this is platform specific. On Linux, we
|
||||
// can't use filepath.Join(srcPath,include) because this will clean away
|
||||
// a trailing "." or "/" which may be important.
|
||||
func getWalkRoot(srcPath string, include string) string {
|
||||
return srcPath + string(filepath.Separator) + include
|
||||
}
|
||||
|
||||
// CanonicalTarNameForPath returns platform-specific filepath
|
||||
// to canonical posix-style path for tar archival. p is relative
|
||||
// path.
|
||||
func CanonicalTarNameForPath(p string) (string, error) {
|
||||
return p, nil // already unix-style
|
||||
}
|
||||
|
||||
// chmodTarEntry is used to adjust the file permissions used in tar header based
|
||||
// on the platform the archival is done.
|
||||
func chmodTarEntry(perm os.FileMode) os.FileMode {
|
||||
return perm // noop for unix as golang APIs provide perm bits correctly
|
||||
}
|
||||
|
||||
func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (err error) {
|
||||
s, ok := stat.(*syscall.Stat_t)
|
||||
|
||||
if ok {
|
||||
// Currently go does not fill in the major/minors
|
||||
if s.Mode&unix.S_IFBLK != 0 ||
|
||||
s.Mode&unix.S_IFCHR != 0 {
|
||||
hdr.Devmajor = int64(major(uint64(s.Rdev))) // nolint: unconvert
|
||||
hdr.Devminor = int64(minor(uint64(s.Rdev))) // nolint: unconvert
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getInodeFromStat(stat interface{}) (inode uint64, err error) {
|
||||
s, ok := stat.(*syscall.Stat_t)
|
||||
|
||||
if ok {
|
||||
inode = s.Ino
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
||||
s, ok := stat.(*syscall.Stat_t)
|
||||
|
||||
if !ok {
|
||||
return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t")
|
||||
}
|
||||
return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil
|
||||
}
|
||||
|
||||
func major(device uint64) uint64 {
|
||||
return (device >> 8) & 0xfff
|
||||
}
|
||||
|
||||
func minor(device uint64) uint64 {
|
||||
return (device & 0xff) | ((device >> 12) & 0xfff00)
|
||||
}
|
||||
|
||||
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
|
||||
// createTarFile to handle the following types of header: Block; Char; Fifo
|
||||
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
|
||||
if userns.RunningInUserNS() {
|
||||
// cannot create a device if running in user namespace
|
||||
return nil
|
||||
}
|
||||
|
||||
mode := uint32(hdr.Mode & 07777)
|
||||
switch hdr.Typeflag {
|
||||
case tar.TypeBlock:
|
||||
mode |= unix.S_IFBLK
|
||||
case tar.TypeChar:
|
||||
mode |= unix.S_IFCHR
|
||||
case tar.TypeFifo:
|
||||
mode |= unix.S_IFIFO
|
||||
}
|
||||
|
||||
return system.Mknod(path, mode, uint64(system.Mkdev(hdr.Devmajor, hdr.Devminor)))
|
||||
}
|
||||
|
||||
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo, forceMask *os.FileMode) error {
|
||||
permissionsMask := hdrInfo.Mode()
|
||||
if forceMask != nil {
|
||||
permissionsMask = *forceMask
|
||||
}
|
||||
if hdr.Typeflag == tar.TypeLink {
|
||||
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
|
||||
if err := os.Chmod(path, permissionsMask); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if hdr.Typeflag != tar.TypeSymlink {
|
||||
if err := os.Chmod(path, permissionsMask); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
30
vendor/github.com/containers/storage/pkg/archive/archive_linux.go
generated
vendored
30
vendor/github.com/containers/storage/pkg/archive/archive_linux.go
generated
vendored
|
|
@ -53,7 +53,7 @@ func (o overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi
|
|||
}
|
||||
// If there are no lower layers, then it can't have been deleted in this layer.
|
||||
if len(o.rolayers) == 0 {
|
||||
return nil, nil
|
||||
return nil, nil //nolint: nilnil
|
||||
}
|
||||
// At this point, we have a directory that's opaque. If it appears in one of the lower
|
||||
// layers, then it was newly-created here, so it wasn't also deleted here.
|
||||
|
|
@ -66,7 +66,7 @@ func (o overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi
|
|||
if statErr == nil {
|
||||
if stat.Mode()&os.ModeCharDevice != 0 {
|
||||
if isWhiteOut(stat) {
|
||||
return nil, nil
|
||||
return nil, nil //nolint: nilnil
|
||||
}
|
||||
}
|
||||
// It's not whiteout, so it was there in the older layer, so we need to
|
||||
|
|
@ -100,7 +100,7 @@ func (o overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi
|
|||
// original directory wasn't inherited into this layer,
|
||||
// so we don't need to emit whiteout for it.
|
||||
if isWhiteOut(stat) {
|
||||
return nil, nil
|
||||
return nil, nil //nolint: nilnil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -153,8 +153,7 @@ func (overlayWhiteoutConverter) ConvertReadWithHandler(hdr *tar.Header, path str
|
|||
return true, nil
|
||||
}
|
||||
|
||||
type directHandler struct {
|
||||
}
|
||||
type directHandler struct{}
|
||||
|
||||
func (d directHandler) Setxattr(path, name string, value []byte) error {
|
||||
return unix.Setxattr(path, name, value, 0)
|
||||
|
|
@ -185,7 +184,26 @@ func GetFileOwner(path string) (uint32, uint32, uint32, error) {
|
|||
}
|
||||
s, ok := f.Sys().(*syscall.Stat_t)
|
||||
if ok {
|
||||
return s.Uid, s.Gid, s.Mode & 07777, nil
|
||||
return s.Uid, s.Gid, s.Mode & 0o7777, nil
|
||||
}
|
||||
return 0, 0, uint32(f.Mode()), nil
|
||||
}
|
||||
|
||||
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo, forceMask *os.FileMode) error {
|
||||
permissionsMask := hdrInfo.Mode()
|
||||
if forceMask != nil {
|
||||
permissionsMask = *forceMask
|
||||
}
|
||||
if hdr.Typeflag == tar.TypeLink {
|
||||
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
|
||||
if err := os.Chmod(path, permissionsMask); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if hdr.Typeflag != tar.TypeSymlink {
|
||||
if err := os.Chmod(path, permissionsMask); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/archive/archive_other.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/archive/archive_other.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package archive
|
||||
|
|
|
|||
36
vendor/github.com/containers/storage/pkg/archive/archive_unix.go
generated
vendored
36
vendor/github.com/containers/storage/pkg/archive/archive_unix.go
generated
vendored
|
|
@ -1,4 +1,5 @@
|
|||
// +build !windows,!freebsd
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package archive
|
||||
|
||||
|
|
@ -49,8 +50,8 @@ func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (
|
|||
// Currently go does not fill in the major/minors
|
||||
if s.Mode&unix.S_IFBLK != 0 ||
|
||||
s.Mode&unix.S_IFCHR != 0 {
|
||||
hdr.Devmajor = int64(major(uint64(s.Rdev))) // nolint: unconvert
|
||||
hdr.Devminor = int64(minor(uint64(s.Rdev))) // nolint: unconvert
|
||||
hdr.Devmajor = int64(major(uint64(s.Rdev))) //nolint: unconvert
|
||||
hdr.Devminor = int64(minor(uint64(s.Rdev))) //nolint: unconvert
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +88,7 @@ func minor(device uint64) uint64 {
|
|||
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
|
||||
// createTarFile to handle the following types of header: Block; Char; Fifo
|
||||
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
|
||||
mode := uint32(hdr.Mode & 07777)
|
||||
mode := uint32(hdr.Mode & 0o7777)
|
||||
switch hdr.Typeflag {
|
||||
case tar.TypeBlock:
|
||||
mode |= unix.S_IFBLK
|
||||
|
|
@ -97,24 +98,15 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
|
|||
mode |= unix.S_IFIFO
|
||||
}
|
||||
|
||||
return system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor)))
|
||||
return system.Mknod(path, mode, system.Mkdev(hdr.Devmajor, hdr.Devminor))
|
||||
}
|
||||
|
||||
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo, forceMask *os.FileMode) error {
|
||||
permissionsMask := hdrInfo.Mode()
|
||||
if forceMask != nil {
|
||||
permissionsMask = *forceMask
|
||||
}
|
||||
if hdr.Typeflag == tar.TypeLink {
|
||||
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
|
||||
if err := os.Chmod(path, permissionsMask); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if hdr.Typeflag != tar.TypeSymlink {
|
||||
if err := os.Chmod(path, permissionsMask); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
// Hardlink without symlinks
|
||||
func handleLLink(targetPath, path string) error {
|
||||
// Note: on Linux, the link syscall will not follow symlinks.
|
||||
// This behavior is implementation-dependent since
|
||||
// POSIX.1-2008 so to make it clear that we need non-symlink
|
||||
// following here we use the linkat syscall which has a flags
|
||||
// field to select symlink following or not.
|
||||
return unix.Linkat(unix.AT_FDCWD, targetPath, unix.AT_FDCWD, path, 0)
|
||||
}
|
||||
|
|
|
|||
12
vendor/github.com/containers/storage/pkg/archive/archive_windows.go
generated
vendored
12
vendor/github.com/containers/storage/pkg/archive/archive_windows.go
generated
vendored
|
|
@ -38,18 +38,17 @@ func CanonicalTarNameForPath(p string) (string, error) {
|
|||
return "", fmt.Errorf("windows path contains forward slash: %s", p)
|
||||
}
|
||||
return strings.Replace(p, string(os.PathSeparator), "/", -1), nil
|
||||
|
||||
}
|
||||
|
||||
// chmodTarEntry is used to adjust the file permissions used in tar header based
|
||||
// on the platform the archival is done.
|
||||
func chmodTarEntry(perm os.FileMode) os.FileMode {
|
||||
//perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.)
|
||||
// perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.)
|
||||
permPart := perm & os.ModePerm
|
||||
noPermPart := perm &^ os.ModePerm
|
||||
// Add the x bit: make everything +x from windows
|
||||
permPart |= 0111
|
||||
permPart &= 0755
|
||||
permPart |= 0o111
|
||||
permPart &= 0o755
|
||||
|
||||
return noPermPart | permPart
|
||||
}
|
||||
|
|
@ -78,3 +77,8 @@ func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
|||
// no notion of file ownership mapping yet on Windows
|
||||
return idtools.IDPair{0, 0}, nil
|
||||
}
|
||||
|
||||
// Hardlink without following symlinks
|
||||
func handleLLink(targetPath string, path string) error {
|
||||
return os.Link(targetPath, path)
|
||||
}
|
||||
|
|
|
|||
19
vendor/github.com/containers/storage/pkg/archive/changes.go
generated
vendored
19
vendor/github.com/containers/storage/pkg/archive/changes.go
generated
vendored
|
|
@ -5,7 +5,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
|
|
@ -57,7 +56,7 @@ func (change *Change) String() string {
|
|||
return fmt.Sprintf("%s %s", change.Kind, change.Path)
|
||||
}
|
||||
|
||||
// for sort.Sort
|
||||
// changesByPath implements sort.Interface.
|
||||
type changesByPath []Change
|
||||
|
||||
func (c changesByPath) Less(i, j int) bool { return c[i].Path < c[j].Path }
|
||||
|
|
@ -132,9 +131,11 @@ func isENOTDIR(err error) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
type skipChange func(string) (bool, error)
|
||||
type deleteChange func(string, string, os.FileInfo) (string, error)
|
||||
type whiteoutChange func(string, string) (bool, error)
|
||||
type (
|
||||
skipChange func(string) (bool, error)
|
||||
deleteChange func(string, string, os.FileInfo) (string, error)
|
||||
whiteoutChange func(string, string) (bool, error)
|
||||
)
|
||||
|
||||
func changes(layers []string, rw string, dc deleteChange, sc skipChange, wc whiteoutChange) ([]Change, error) {
|
||||
var (
|
||||
|
|
@ -300,7 +301,6 @@ func (info *FileInfo) path() string {
|
|||
}
|
||||
|
||||
func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
|
||||
|
||||
sizeAtEntry := len(*changes)
|
||||
|
||||
if oldInfo == nil {
|
||||
|
|
@ -374,7 +374,6 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
|
|||
copy((*changes)[sizeAtEntry+1:], (*changes)[sizeAtEntry:])
|
||||
(*changes)[sizeAtEntry] = change
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Changes add changes to file information.
|
||||
|
|
@ -399,11 +398,9 @@ func newRootFileInfo(idMappings *idtools.IDMappings) *FileInfo {
|
|||
// ChangesDirs compares two directories and generates an array of Change objects describing the changes.
|
||||
// If oldDir is "", then all files in newDir will be Add-Changes.
|
||||
func ChangesDirs(newDir string, newMappings *idtools.IDMappings, oldDir string, oldMappings *idtools.IDMappings) ([]Change, error) {
|
||||
var (
|
||||
oldRoot, newRoot *FileInfo
|
||||
)
|
||||
var oldRoot, newRoot *FileInfo
|
||||
if oldDir == "" {
|
||||
emptyDir, err := ioutil.TempDir("", "empty")
|
||||
emptyDir, err := os.MkdirTemp("", "empty")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
5
vendor/github.com/containers/storage/pkg/archive/changes_linux.go
generated
vendored
5
vendor/github.com/containers/storage/pkg/archive/changes_linux.go
generated
vendored
|
|
@ -30,8 +30,8 @@ type walker struct {
|
|||
dir2 string
|
||||
root1 *FileInfo
|
||||
root2 *FileInfo
|
||||
idmap1 *idtools.IDMappings
|
||||
idmap2 *idtools.IDMappings
|
||||
idmap1 *idtools.IDMappings //nolint:unused
|
||||
idmap2 *idtools.IDMappings //nolint:unused
|
||||
}
|
||||
|
||||
// collectFileInfoForChanges returns a complete representation of the trees
|
||||
|
|
@ -397,5 +397,4 @@ func overlayDeletedFile(layers []string, root, path string, fi os.FileInfo) (str
|
|||
|
||||
// We didn't find the same path in any older layers, so it was new in this one.
|
||||
return "", nil
|
||||
|
||||
}
|
||||
|
|
|
|||
13
vendor/github.com/containers/storage/pkg/archive/changes_other.go
generated
vendored
13
vendor/github.com/containers/storage/pkg/archive/changes_other.go
generated
vendored
|
|
@ -43,7 +43,12 @@ func collectFileInfoForChanges(oldDir, newDir string, oldIDMap, newIDMap *idtool
|
|||
func collectFileInfo(sourceDir string, idMappings *idtools.IDMappings) (*FileInfo, error) {
|
||||
root := newRootFileInfo(idMappings)
|
||||
|
||||
err := filepath.WalkDir(sourceDir, func(path string, d fs.DirEntry, err error) error {
|
||||
sourceStat, err := system.Lstat(sourceDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = filepath.WalkDir(sourceDir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -86,8 +91,12 @@ func collectFileInfo(sourceDir string, idMappings *idtools.IDMappings) (*FileInf
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.stat = s
|
||||
|
||||
if s.Dev() != sourceStat.Dev() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
info.stat = s
|
||||
info.capability, _ = system.Lgetxattr(path, "security.capability")
|
||||
|
||||
parent.children[info.name] = info
|
||||
|
|
|
|||
2
vendor/github.com/containers/storage/pkg/archive/changes_unix.go
generated
vendored
2
vendor/github.com/containers/storage/pkg/archive/changes_unix.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package archive
|
||||
|
|
@ -29,6 +30,7 @@ func statDifferent(oldStat *system.StatT, oldInfo *FileInfo, newStat *system.Sta
|
|||
if oldStat.Mode() != newStat.Mode() ||
|
||||
ownerChanged ||
|
||||
oldStat.Rdev() != newStat.Rdev() ||
|
||||
oldStat.Flags() != newStat.Flags() ||
|
||||
// Don't look at size for dirs, its not a good measure of change
|
||||
(oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR &&
|
||||
(!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) {
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/archive/changes_windows.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/archive/changes_windows.go
generated
vendored
|
|
@ -7,7 +7,6 @@ import (
|
|||
)
|
||||
|
||||
func statDifferent(oldStat *system.StatT, oldInfo *FileInfo, newStat *system.StatT, newInfo *FileInfo) bool {
|
||||
|
||||
// Don't look at size for dirs, its not a good measure of change
|
||||
if oldStat.Mtim() != newStat.Mtim() ||
|
||||
oldStat.Mode() != newStat.Mode() ||
|
||||
|
|
|
|||
4
vendor/github.com/containers/storage/pkg/archive/copy.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/archive/copy.go
generated
vendored
|
|
@ -4,7 +4,6 @@ import (
|
|||
"archive/tar"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
|
@ -255,7 +254,7 @@ func PrepareArchiveCopy(srcContent io.Reader, srcInfo, dstInfo CopyInfo) (dstDir
|
|||
// The destination exists as a directory. No alteration
|
||||
// to srcContent is needed as its contents can be
|
||||
// simply extracted to the destination directory.
|
||||
return dstInfo.Path, ioutil.NopCloser(srcContent), nil
|
||||
return dstInfo.Path, io.NopCloser(srcContent), nil
|
||||
case dstInfo.Exists && srcInfo.IsDir:
|
||||
// The destination exists as some type of file and the source
|
||||
// content is a directory. This is an error condition since
|
||||
|
|
@ -298,7 +297,6 @@ func PrepareArchiveCopy(srcContent io.Reader, srcInfo, dstInfo CopyInfo) (dstDir
|
|||
}
|
||||
return dstDir, RebaseArchiveEntries(srcContent, srcBase, dstBase), nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RebaseArchiveEntries rewrites the given srcContent archive replacing
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/archive/copy_unix.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/archive/copy_unix.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package archive
|
||||
|
|
|
|||
26
vendor/github.com/containers/storage/pkg/archive/diff.go
generated
vendored
26
vendor/github.com/containers/storage/pkg/archive/diff.go
generated
vendored
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
|
@ -86,7 +85,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
parentPath := filepath.Join(dest, parent)
|
||||
|
||||
if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
|
||||
err = os.MkdirAll(parentPath, 0755)
|
||||
err = os.MkdirAll(parentPath, 0o755)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -102,7 +101,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
basename := filepath.Base(hdr.Name)
|
||||
aufsHardlinks[basename] = hdr
|
||||
if aufsTempdir == "" {
|
||||
if aufsTempdir, err = ioutil.TempDir("", "storageplnk"); err != nil {
|
||||
if aufsTempdir, err = os.MkdirTemp("", "storageplnk"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer os.RemoveAll(aufsTempdir)
|
||||
|
|
@ -146,6 +145,9 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
return nil
|
||||
}
|
||||
if _, exists := unpackedPaths[path]; !exists {
|
||||
if err := resetImmutable(path, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
err := os.RemoveAll(path)
|
||||
return err
|
||||
}
|
||||
|
|
@ -157,6 +159,9 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
} else {
|
||||
originalBase := base[len(WhiteoutPrefix):]
|
||||
originalPath := filepath.Join(dir, originalBase)
|
||||
if err := resetImmutable(originalPath, nil); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := os.RemoveAll(originalPath); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -166,7 +171,15 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
// The only exception is when it is a directory *and* the file from
|
||||
// the layer is also a directory. Then we want to merge them (i.e.
|
||||
// just apply the metadata from the layer).
|
||||
//
|
||||
// We always reset the immutable flag (if present) to allow metadata
|
||||
// changes and to allow directory modification. The flag will be
|
||||
// re-applied based on the contents of hdr either at the end for
|
||||
// directories or in createTarFile otherwise.
|
||||
if fi, err := os.Lstat(path); err == nil {
|
||||
if err := resetImmutable(path, &fi); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !(fi.IsDir() && hdr.Typeflag == tar.TypeDir) {
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return 0, err
|
||||
|
|
@ -216,6 +229,9 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := WriteFileFlagsFromTarHeader(path, hdr); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return size, nil
|
||||
|
|
@ -246,7 +262,9 @@ func applyLayerHandler(dest string, layer io.Reader, options *TarOptions, decomp
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer system.Umask(oldmask) // ignore err, ErrNotSupportedPlatform
|
||||
defer func() {
|
||||
_, _ = system.Umask(oldmask) // Ignore err. This can only fail with ErrNotSupportedPlatform, in which case we would have failed above.
|
||||
}()
|
||||
|
||||
if decompress {
|
||||
layer, err = DecompressStream(layer)
|
||||
|
|
|
|||
167
vendor/github.com/containers/storage/pkg/archive/fflags_bsd.go
generated
vendored
Normal file
167
vendor/github.com/containers/storage/pkg/archive/fflags_bsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
//go:build freebsd
|
||||
// +build freebsd
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"fmt"
|
||||
"math/bits"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/containers/storage/pkg/system"
|
||||
)
|
||||
|
||||
const (
|
||||
paxSCHILYFflags = "SCHILY.fflags"
|
||||
)
|
||||
|
||||
var (
|
||||
flagNameToValue = map[string]uint32{
|
||||
"sappnd": system.SF_APPEND,
|
||||
"sappend": system.SF_APPEND,
|
||||
"arch": system.SF_ARCHIVED,
|
||||
"archived": system.SF_ARCHIVED,
|
||||
"schg": system.SF_IMMUTABLE,
|
||||
"schange": system.SF_IMMUTABLE,
|
||||
"simmutable": system.SF_IMMUTABLE,
|
||||
"sunlnk": system.SF_NOUNLINK,
|
||||
"sunlink": system.SF_NOUNLINK,
|
||||
"snapshot": system.SF_SNAPSHOT,
|
||||
"uappnd": system.UF_APPEND,
|
||||
"uappend": system.UF_APPEND,
|
||||
"uarch": system.UF_ARCHIVE,
|
||||
"uarchive": system.UF_ARCHIVE,
|
||||
"hidden": system.UF_HIDDEN,
|
||||
"uhidden": system.UF_HIDDEN,
|
||||
"uchg": system.UF_IMMUTABLE,
|
||||
"uchange": system.UF_IMMUTABLE,
|
||||
"uimmutable": system.UF_IMMUTABLE,
|
||||
"uunlnk": system.UF_NOUNLINK,
|
||||
"uunlink": system.UF_NOUNLINK,
|
||||
"offline": system.UF_OFFLINE,
|
||||
"uoffline": system.UF_OFFLINE,
|
||||
"opaque": system.UF_OPAQUE,
|
||||
"rdonly": system.UF_READONLY,
|
||||
"urdonly": system.UF_READONLY,
|
||||
"readonly": system.UF_READONLY,
|
||||
"ureadonly": system.UF_READONLY,
|
||||
"reparse": system.UF_REPARSE,
|
||||
"ureparse": system.UF_REPARSE,
|
||||
"sparse": system.UF_SPARSE,
|
||||
"usparse": system.UF_SPARSE,
|
||||
"system": system.UF_SYSTEM,
|
||||
"usystem": system.UF_SYSTEM,
|
||||
}
|
||||
// Only include the short names for the reverse map
|
||||
flagValueToName = map[uint32]string{
|
||||
system.SF_APPEND: "sappnd",
|
||||
system.SF_ARCHIVED: "arch",
|
||||
system.SF_IMMUTABLE: "schg",
|
||||
system.SF_NOUNLINK: "sunlnk",
|
||||
system.SF_SNAPSHOT: "snapshot",
|
||||
system.UF_APPEND: "uappnd",
|
||||
system.UF_ARCHIVE: "uarch",
|
||||
system.UF_HIDDEN: "hidden",
|
||||
system.UF_IMMUTABLE: "uchg",
|
||||
system.UF_NOUNLINK: "uunlnk",
|
||||
system.UF_OFFLINE: "offline",
|
||||
system.UF_OPAQUE: "opaque",
|
||||
system.UF_READONLY: "rdonly",
|
||||
system.UF_REPARSE: "reparse",
|
||||
system.UF_SPARSE: "sparse",
|
||||
system.UF_SYSTEM: "system",
|
||||
}
|
||||
)
|
||||
|
||||
func parseFileFlags(fflags string) (uint32, uint32, error) {
|
||||
var set, clear uint32 = 0, 0
|
||||
for _, fflag := range strings.Split(fflags, ",") {
|
||||
isClear := false
|
||||
if strings.HasPrefix(fflag, "no") {
|
||||
isClear = true
|
||||
fflag = strings.TrimPrefix(fflag, "no")
|
||||
}
|
||||
if value, ok := flagNameToValue[fflag]; ok {
|
||||
if isClear {
|
||||
clear |= value
|
||||
} else {
|
||||
set |= value
|
||||
}
|
||||
} else {
|
||||
return 0, 0, fmt.Errorf("parsing file flags, unrecognised token: %s", fflag)
|
||||
}
|
||||
}
|
||||
return set, clear, nil
|
||||
}
|
||||
|
||||
func formatFileFlags(fflags uint32) (string, error) {
|
||||
res := []string{}
|
||||
for fflags != 0 {
|
||||
// Extract lowest set bit
|
||||
fflag := uint32(1) << bits.TrailingZeros32(fflags)
|
||||
if name, ok := flagValueToName[fflag]; ok {
|
||||
res = append(res, name)
|
||||
} else {
|
||||
return "", fmt.Errorf("formatting file flags, unrecognised flag: %x", fflag)
|
||||
}
|
||||
fflags &= ^fflag
|
||||
}
|
||||
return strings.Join(res, ","), nil
|
||||
}
|
||||
|
||||
func ReadFileFlagsToTarHeader(path string, hdr *tar.Header) error {
|
||||
st, err := system.Lstat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fflags, err := formatFileFlags(st.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fflags != "" {
|
||||
if hdr.PAXRecords == nil {
|
||||
hdr.PAXRecords = map[string]string{}
|
||||
}
|
||||
hdr.PAXRecords[paxSCHILYFflags] = fflags
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteFileFlagsFromTarHeader(path string, hdr *tar.Header) error {
|
||||
if fflags, ok := hdr.PAXRecords[paxSCHILYFflags]; ok {
|
||||
var set, clear uint32
|
||||
set, clear, err := parseFileFlags(fflags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Apply the delta to the existing file flags
|
||||
st, err := system.Lstat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return system.Lchflags(path, (st.Flags() & ^clear)|set)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resetImmutable(path string, fi *os.FileInfo) error {
|
||||
var flags uint32
|
||||
if fi != nil {
|
||||
flags = (*fi).Sys().(*syscall.Stat_t).Flags
|
||||
} else {
|
||||
st, err := system.Lstat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
flags = st.Flags()
|
||||
}
|
||||
if flags&(system.SF_IMMUTABLE|system.UF_IMMUTABLE) != 0 {
|
||||
flags &= ^(system.SF_IMMUTABLE | system.UF_IMMUTABLE)
|
||||
return system.Lchflags(path, flags)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
21
vendor/github.com/containers/storage/pkg/archive/fflags_unsupported.go
generated
vendored
Normal file
21
vendor/github.com/containers/storage/pkg/archive/fflags_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//go:build !freebsd
|
||||
// +build !freebsd
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ReadFileFlagsToTarHeader(path string, hdr *tar.Header) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteFileFlagsFromTarHeader(path string, hdr *tar.Header) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func resetImmutable(path string, fi *os.FileInfo) error {
|
||||
return nil
|
||||
}
|
||||
1
vendor/github.com/containers/storage/pkg/archive/time_unsupported.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/archive/time_unsupported.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package archive
|
||||
|
|
|
|||
4
vendor/github.com/containers/storage/pkg/archive/wrap.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/archive/wrap.go
generated
vendored
|
|
@ -17,8 +17,8 @@ import (
|
|||
// Generate("foo.txt", "hello world", "emptyfile")
|
||||
//
|
||||
// The above call will return an archive with 2 files:
|
||||
// * ./foo.txt with content "hello world"
|
||||
// * ./empty with empty content
|
||||
// - ./foo.txt with content "hello world"
|
||||
// - ./empty with empty content
|
||||
//
|
||||
// FIXME: stream content instead of buffering
|
||||
// FIXME: specify permissions and other archive metadata
|
||||
|
|
|
|||
93
vendor/github.com/containers/storage/pkg/chunked/compressor/compressor.go
generated
vendored
93
vendor/github.com/containers/storage/pkg/chunked/compressor/compressor.go
generated
vendored
|
|
@ -6,24 +6,27 @@ package compressor
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containers/storage/pkg/chunked/internal"
|
||||
"github.com/containers/storage/pkg/ioutils"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/vbatts/tar-split/archive/tar"
|
||||
"github.com/vbatts/tar-split/tar/asm"
|
||||
"github.com/vbatts/tar-split/tar/storage"
|
||||
)
|
||||
|
||||
const RollsumBits = 16
|
||||
const holesThreshold = int64(1 << 10)
|
||||
const (
|
||||
RollsumBits = 16
|
||||
holesThreshold = int64(1 << 10)
|
||||
)
|
||||
|
||||
type holesFinder struct {
|
||||
reader *bufio.Reader
|
||||
fileOff int64
|
||||
zeros int64
|
||||
from int64
|
||||
threshold int64
|
||||
|
||||
state int
|
||||
|
|
@ -36,11 +39,11 @@ const (
|
|||
holesFinderStateEOF
|
||||
)
|
||||
|
||||
// ReadByte reads a single byte from the underlying reader.
|
||||
// readByte reads a single byte from the underlying reader.
|
||||
// If a single byte is read, the return value is (0, RAW-BYTE-VALUE, nil).
|
||||
// If there are at least f.THRESHOLD consecutive zeros, then the
|
||||
// return value is (N_CONSECUTIVE_ZEROS, '\x00').
|
||||
func (f *holesFinder) ReadByte() (int64, byte, error) {
|
||||
func (f *holesFinder) readByte() (int64, byte, error) {
|
||||
for {
|
||||
switch f.state {
|
||||
// reading the file stream
|
||||
|
|
@ -81,7 +84,7 @@ func (f *holesFinder) ReadByte() (int64, byte, error) {
|
|||
f.state = holesFinderStateFound
|
||||
}
|
||||
} else {
|
||||
if f.reader.UnreadByte(); err != nil {
|
||||
if err := f.reader.UnreadByte(); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
f.state = holesFinderStateRead
|
||||
|
|
@ -98,7 +101,7 @@ func (f *holesFinder) ReadByte() (int64, byte, error) {
|
|||
return holeLen, 0, nil
|
||||
}
|
||||
if b != 0 {
|
||||
if f.reader.UnreadByte(); err != nil {
|
||||
if err := f.reader.UnreadByte(); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
f.state = holesFinderStateRead
|
||||
|
|
@ -162,7 +165,7 @@ func (rc *rollingChecksumReader) Read(b []byte) (bool, int, error) {
|
|||
}
|
||||
|
||||
for i := 0; i < len(b); i++ {
|
||||
holeLen, n, err := rc.reader.ReadByte()
|
||||
holeLen, n, err := rc.reader.readByte()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
rc.closed = true
|
||||
|
|
@ -199,11 +202,55 @@ type chunk struct {
|
|||
ChunkType string
|
||||
}
|
||||
|
||||
type tarSplitData struct {
|
||||
compressed *bytes.Buffer
|
||||
digester digest.Digester
|
||||
uncompressedCounter *ioutils.WriteCounter
|
||||
zstd *zstd.Encoder
|
||||
packer storage.Packer
|
||||
}
|
||||
|
||||
func newTarSplitData(level int) (*tarSplitData, error) {
|
||||
compressed := bytes.NewBuffer(nil)
|
||||
digester := digest.Canonical.Digester()
|
||||
|
||||
zstdWriter, err := internal.ZstdWriterWithLevel(io.MultiWriter(compressed, digester.Hash()), level)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uncompressedCounter := ioutils.NewWriteCounter(zstdWriter)
|
||||
metaPacker := storage.NewJSONPacker(uncompressedCounter)
|
||||
|
||||
return &tarSplitData{
|
||||
compressed: compressed,
|
||||
digester: digester,
|
||||
uncompressedCounter: uncompressedCounter,
|
||||
zstd: zstdWriter,
|
||||
packer: metaPacker,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func writeZstdChunkedStream(destFile io.Writer, outMetadata map[string]string, reader io.Reader, level int) error {
|
||||
// total written so far. Used to retrieve partial offsets in the file
|
||||
dest := ioutils.NewWriteCounter(destFile)
|
||||
|
||||
tr := tar.NewReader(reader)
|
||||
tarSplitData, err := newTarSplitData(level)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if tarSplitData.zstd != nil {
|
||||
tarSplitData.zstd.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
its, err := asm.NewInputTarStream(reader, tarSplitData.packer, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tr := tar.NewReader(its)
|
||||
tr.RawAccounting = true
|
||||
|
||||
buf := make([]byte, 4096)
|
||||
|
|
@ -215,7 +262,6 @@ func writeZstdChunkedStream(destFile io.Writer, outMetadata map[string]string, r
|
|||
defer func() {
|
||||
if zstdWriter != nil {
|
||||
zstdWriter.Close()
|
||||
zstdWriter.Flush()
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
@ -225,9 +271,6 @@ func writeZstdChunkedStream(destFile io.Writer, outMetadata map[string]string, r
|
|||
if err := zstdWriter.Close(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := zstdWriter.Flush(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
offset = dest.Count
|
||||
zstdWriter.Reset(dest)
|
||||
}
|
||||
|
|
@ -374,9 +417,11 @@ func writeZstdChunkedStream(destFile io.Writer, outMetadata map[string]string, r
|
|||
|
||||
rawBytes := tr.RawBytes()
|
||||
if _, err := zstdWriter.Write(rawBytes); err != nil {
|
||||
zstdWriter.Close()
|
||||
return err
|
||||
}
|
||||
if err := zstdWriter.Flush(); err != nil {
|
||||
zstdWriter.Close()
|
||||
return err
|
||||
}
|
||||
if err := zstdWriter.Close(); err != nil {
|
||||
|
|
@ -384,7 +429,21 @@ func writeZstdChunkedStream(destFile io.Writer, outMetadata map[string]string, r
|
|||
}
|
||||
zstdWriter = nil
|
||||
|
||||
return internal.WriteZstdChunkedManifest(dest, outMetadata, uint64(dest.Count), metadata, level)
|
||||
if err := tarSplitData.zstd.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tarSplitData.zstd.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
tarSplitData.zstd = nil
|
||||
|
||||
ts := internal.TarSplitData{
|
||||
Data: tarSplitData.compressed.Bytes(),
|
||||
Digest: tarSplitData.digester.Digest(),
|
||||
UncompressedSize: tarSplitData.uncompressedCounter.Count,
|
||||
}
|
||||
|
||||
return internal.WriteZstdChunkedManifest(dest, outMetadata, uint64(dest.Count), &ts, metadata, level)
|
||||
}
|
||||
|
||||
type zstdChunkedWriter struct {
|
||||
|
|
@ -432,7 +491,7 @@ func zstdChunkedWriterWithLevel(out io.Writer, metadata map[string]string, level
|
|||
|
||||
go func() {
|
||||
ch <- writeZstdChunkedStream(out, metadata, r, level)
|
||||
io.Copy(ioutil.Discard, r)
|
||||
_, _ = io.Copy(io.Discard, r) // Ordinarily writeZstdChunkedStream consumes all of r. If it fails, ensure the write end never blocks and eventually terminates.
|
||||
r.Close()
|
||||
close(ch)
|
||||
}()
|
||||
|
|
|
|||
12
vendor/github.com/containers/storage/pkg/chunked/compressor/rollsum.go
generated
vendored
12
vendor/github.com/containers/storage/pkg/chunked/compressor/rollsum.go
generated
vendored
|
|
@ -25,11 +25,15 @@ import (
|
|||
"math/bits"
|
||||
)
|
||||
|
||||
const windowSize = 64 // Roll assumes windowSize is a power of 2
|
||||
const charOffset = 31
|
||||
const (
|
||||
windowSize = 64 // Roll assumes windowSize is a power of 2
|
||||
charOffset = 31
|
||||
)
|
||||
|
||||
const blobBits = 13
|
||||
const blobSize = 1 << blobBits // 8k
|
||||
const (
|
||||
blobBits = 13
|
||||
blobSize = 1 << blobBits // 8k
|
||||
)
|
||||
|
||||
type RollSum struct {
|
||||
s1, s2 uint32
|
||||
|
|
|
|||
40
vendor/github.com/containers/storage/pkg/chunked/internal/compression.go
generated
vendored
40
vendor/github.com/containers/storage/pkg/chunked/internal/compression.go
generated
vendored
|
|
@ -88,8 +88,10 @@ func GetType(t byte) (string, error) {
|
|||
}
|
||||
|
||||
const (
|
||||
ManifestChecksumKey = "io.containers.zstd-chunked.manifest-checksum"
|
||||
ManifestInfoKey = "io.containers.zstd-chunked.manifest-position"
|
||||
ManifestChecksumKey = "io.github.containers.zstd-chunked.manifest-checksum"
|
||||
ManifestInfoKey = "io.github.containers.zstd-chunked.manifest-position"
|
||||
TarSplitChecksumKey = "io.github.containers.zstd-chunked.tarsplit-checksum"
|
||||
TarSplitInfoKey = "io.github.containers.zstd-chunked.tarsplit-position"
|
||||
|
||||
// ManifestTypeCRFS is a manifest file compatible with the CRFS TOC file.
|
||||
ManifestTypeCRFS = 1
|
||||
|
|
@ -97,7 +99,7 @@ const (
|
|||
// FooterSizeSupported is the footer size supported by this implementation.
|
||||
// Newer versions of the image format might increase this value, so reject
|
||||
// any version that is not supported.
|
||||
FooterSizeSupported = 40
|
||||
FooterSizeSupported = 56
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -114,7 +116,7 @@ func appendZstdSkippableFrame(dest io.Writer, data []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var size []byte = make([]byte, 4)
|
||||
size := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(size, uint32(len(data)))
|
||||
if _, err := dest.Write(size); err != nil {
|
||||
return err
|
||||
|
|
@ -125,16 +127,23 @@ func appendZstdSkippableFrame(dest io.Writer, data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func WriteZstdChunkedManifest(dest io.Writer, outMetadata map[string]string, offset uint64, metadata []FileMetadata, level int) error {
|
||||
type TarSplitData struct {
|
||||
Data []byte
|
||||
Digest digest.Digest
|
||||
UncompressedSize int64
|
||||
}
|
||||
|
||||
func WriteZstdChunkedManifest(dest io.Writer, outMetadata map[string]string, offset uint64, tarSplitData *TarSplitData, metadata []FileMetadata, level int) error {
|
||||
// 8 is the size of the zstd skippable frame header + the frame size
|
||||
manifestOffset := offset + 8
|
||||
const zstdSkippableFrameHeader = 8
|
||||
manifestOffset := offset + zstdSkippableFrameHeader
|
||||
|
||||
toc := TOC{
|
||||
Version: 1,
|
||||
Entries: metadata,
|
||||
}
|
||||
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
// Generate the manifest
|
||||
manifest, err := json.Marshal(toc)
|
||||
if err != nil {
|
||||
|
|
@ -167,13 +176,20 @@ func WriteZstdChunkedManifest(dest io.Writer, outMetadata map[string]string, off
|
|||
return err
|
||||
}
|
||||
|
||||
outMetadata[TarSplitChecksumKey] = tarSplitData.Digest.String()
|
||||
tarSplitOffset := manifestOffset + uint64(len(compressedManifest)) + zstdSkippableFrameHeader
|
||||
outMetadata[TarSplitInfoKey] = fmt.Sprintf("%d:%d:%d", tarSplitOffset, len(tarSplitData.Data), tarSplitData.UncompressedSize)
|
||||
if err := appendZstdSkippableFrame(dest, tarSplitData.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Store the offset to the manifest and its size in LE order
|
||||
var manifestDataLE []byte = make([]byte, FooterSizeSupported)
|
||||
manifestDataLE := make([]byte, FooterSizeSupported)
|
||||
binary.LittleEndian.PutUint64(manifestDataLE, manifestOffset)
|
||||
binary.LittleEndian.PutUint64(manifestDataLE[8:], uint64(len(compressedManifest)))
|
||||
binary.LittleEndian.PutUint64(manifestDataLE[16:], uint64(len(manifest)))
|
||||
binary.LittleEndian.PutUint64(manifestDataLE[24:], uint64(ManifestTypeCRFS))
|
||||
copy(manifestDataLE[32:], ZstdChunkedFrameMagic)
|
||||
binary.LittleEndian.PutUint64(manifestDataLE[8*1:], uint64(len(compressedManifest)))
|
||||
binary.LittleEndian.PutUint64(manifestDataLE[8*2:], uint64(len(manifest)))
|
||||
binary.LittleEndian.PutUint64(manifestDataLE[8*3:], uint64(ManifestTypeCRFS))
|
||||
copy(manifestDataLE[8*4:], ZstdChunkedFrameMagic)
|
||||
|
||||
return appendZstdSkippableFrame(dest, manifestDataLE)
|
||||
}
|
||||
|
|
|
|||
15
vendor/github.com/containers/storage/pkg/fileutils/fileutils.go
generated
vendored
15
vendor/github.com/containers/storage/pkg/fileutils/fileutils.go
generated
vendored
|
|
@ -165,7 +165,7 @@ func (pm *PatternMatcher) Patterns() []*Pattern {
|
|||
return pm.patterns
|
||||
}
|
||||
|
||||
// Pattern defines a single regexp used used to filter file paths.
|
||||
// Pattern defines a single regexp used to filter file paths.
|
||||
type Pattern struct {
|
||||
cleanedPattern string
|
||||
dirs []string
|
||||
|
|
@ -183,7 +183,6 @@ func (p *Pattern) Exclusion() bool {
|
|||
}
|
||||
|
||||
func (p *Pattern) match(path string) (bool, error) {
|
||||
|
||||
if p.regexp == nil {
|
||||
if err := p.compile(); err != nil {
|
||||
return false, filepath.ErrBadPattern
|
||||
|
|
@ -321,14 +320,14 @@ func ReadSymlinkedDirectory(path string) (string, error) {
|
|||
var realPath string
|
||||
var err error
|
||||
if realPath, err = filepath.Abs(path); err != nil {
|
||||
return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err)
|
||||
return "", fmt.Errorf("unable to get absolute path for %s: %w", path, err)
|
||||
}
|
||||
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
|
||||
return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
|
||||
return "", fmt.Errorf("failed to canonicalise path for %s: %w", path, err)
|
||||
}
|
||||
realPathInfo, err := os.Stat(realPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err)
|
||||
return "", fmt.Errorf("failed to stat target '%s' of '%s': %w", realPath, path, err)
|
||||
}
|
||||
if !realPathInfo.Mode().IsDir() {
|
||||
return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
|
||||
|
|
@ -356,12 +355,12 @@ func CreateIfNotExists(path string, isDir bool) error {
|
|||
if _, err := os.Stat(path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if isDir {
|
||||
return os.MkdirAll(path, 0755)
|
||||
return os.MkdirAll(path, 0o755)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.OpenFile(path, os.O_CREATE, 0755)
|
||||
f, err := os.OpenFile(path, os.O_CREATE, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
4
vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go
generated
vendored
|
|
@ -1,10 +1,10 @@
|
|||
//go:build linux || freebsd
|
||||
// +build linux freebsd
|
||||
|
||||
package fileutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
// GetTotalUsedFds Returns the number of used File Descriptors by
|
||||
// reading it via /proc filesystem.
|
||||
func GetTotalUsedFds() int {
|
||||
if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
|
||||
if fds, err := os.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
} else {
|
||||
return len(fds)
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/homedir/homedir_others.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/homedir/homedir_others.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !linux && !darwin && !freebsd
|
||||
// +build !linux,!darwin,!freebsd
|
||||
|
||||
package homedir
|
||||
|
|
|
|||
5
vendor/github.com/containers/storage/pkg/homedir/homedir_unix.go
generated
vendored
5
vendor/github.com/containers/storage/pkg/homedir/homedir_unix.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package homedir
|
||||
|
|
@ -46,7 +47,7 @@ func GetShortcutString() string {
|
|||
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
|
||||
func GetRuntimeDir() (string, error) {
|
||||
if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" {
|
||||
return xdgRuntimeDir, nil
|
||||
return filepath.EvalSymlinks(xdgRuntimeDir)
|
||||
}
|
||||
return "", errors.New("could not get XDG_RUNTIME_DIR")
|
||||
}
|
||||
|
|
@ -62,7 +63,7 @@ func StickRuntimeDirContents(files []string) ([]string, error) {
|
|||
runtimeDir, err := GetRuntimeDir()
|
||||
if err != nil {
|
||||
// ignore error if runtimeDir is empty
|
||||
return nil, nil
|
||||
return nil, nil //nolint: nilerr
|
||||
}
|
||||
runtimeDir, err = filepath.Abs(runtimeDir)
|
||||
if err != nil {
|
||||
|
|
|
|||
11
vendor/github.com/containers/storage/pkg/idtools/idtools.go
generated
vendored
11
vendor/github.com/containers/storage/pkg/idtools/idtools.go
generated
vendored
|
|
@ -2,8 +2,8 @@ package idtools
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
|
|
@ -219,7 +219,7 @@ func getOverflowUID() int {
|
|||
overflowUIDOnce.Do(func() {
|
||||
// 65534 is the value on older kernels where /proc/sys/kernel/overflowuid is not present
|
||||
overflowUID = 65534
|
||||
if content, err := ioutil.ReadFile("/proc/sys/kernel/overflowuid"); err == nil {
|
||||
if content, err := os.ReadFile("/proc/sys/kernel/overflowuid"); err == nil {
|
||||
if tmp, err := strconv.Atoi(string(content)); err == nil {
|
||||
overflowUID = tmp
|
||||
}
|
||||
|
|
@ -233,7 +233,7 @@ func getOverflowGID() int {
|
|||
overflowGIDOnce.Do(func() {
|
||||
// 65534 is the value on older kernels where /proc/sys/kernel/overflowgid is not present
|
||||
overflowGID = 65534
|
||||
if content, err := ioutil.ReadFile("/proc/sys/kernel/overflowgid"); err == nil {
|
||||
if content, err := os.ReadFile("/proc/sys/kernel/overflowgid"); err == nil {
|
||||
if tmp, err := strconv.Atoi(string(content)); err == nil {
|
||||
overflowGID = tmp
|
||||
}
|
||||
|
|
@ -360,8 +360,9 @@ func parseSubidFile(path, username string) (ranges, error) {
|
|||
}
|
||||
|
||||
func checkChownErr(err error, name string, uid, gid int) error {
|
||||
if e, ok := err.(*os.PathError); ok && e.Err == syscall.EINVAL {
|
||||
return fmt.Errorf("potentially insufficient UIDs or GIDs available in user namespace (requested %d:%d for %s): Check /etc/subuid and /etc/subgid if configured locally and run podman-system-migrate: %w", uid, gid, name, err)
|
||||
var e *os.PathError
|
||||
if errors.As(err, &e) && e.Err == syscall.EINVAL {
|
||||
return fmt.Errorf(`potentially insufficient UIDs or GIDs available in user namespace (requested %d:%d for %s): Check /etc/subuid and /etc/subgid if configured locally and run "podman system migrate": %w`, uid, gid, name, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/containers/storage/pkg/idtools/idtools_unix.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/idtools/idtools_unix.go
generated
vendored
|
|
@ -91,13 +91,13 @@ func CanAccess(path string, pair IDPair) bool {
|
|||
}
|
||||
|
||||
func accessible(isOwner, isGroup bool, perms os.FileMode) bool {
|
||||
if isOwner && (perms&0100 == 0100) {
|
||||
if isOwner && (perms&0o100 == 0o100) {
|
||||
return true
|
||||
}
|
||||
if isGroup && (perms&0010 == 0010) {
|
||||
if isGroup && (perms&0o010 == 0o010) {
|
||||
return true
|
||||
}
|
||||
if perms&0001 == 0001 {
|
||||
if perms&0o001 == 0o001 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/idtools/idtools_unsupported.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/idtools/idtools_unsupported.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !linux || !libsubid || !cgo
|
||||
// +build !linux !libsubid !cgo
|
||||
|
||||
package idtools
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/idtools/idtools_windows.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/idtools/idtools_windows.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package idtools
|
||||
|
|
|
|||
6
vendor/github.com/containers/storage/pkg/idtools/usergroupadd_linux.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/idtools/usergroupadd_linux.go
generated
vendored
|
|
@ -2,11 +2,12 @@ package idtools
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/containers/storage/pkg/regexp"
|
||||
)
|
||||
|
||||
// add a user and/or group to Linux /etc/passwd, /etc/group using standard
|
||||
|
|
@ -24,7 +25,7 @@ var (
|
|||
"usermod": "-%s %d-%d %s",
|
||||
}
|
||||
|
||||
idOutRegexp = regexp.MustCompile(`uid=([0-9]+).*gid=([0-9]+)`)
|
||||
idOutRegexp = regexp.Delayed(`uid=([0-9]+).*gid=([0-9]+)`)
|
||||
// default length for a UID/GID subordinate range
|
||||
defaultRangeLen = 65536
|
||||
defaultRangeStart = 100000
|
||||
|
|
@ -88,7 +89,6 @@ func addUser(userName string) error {
|
|||
}
|
||||
|
||||
func createSubordinateRanges(name string) error {
|
||||
|
||||
// first, we should verify that ranges weren't automatically created
|
||||
// by the distro tooling
|
||||
ranges, err := readSubuid(name)
|
||||
|
|
|
|||
4
vendor/github.com/containers/storage/pkg/idtools/utils_unix.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/idtools/utils_unix.go
generated
vendored
|
|
@ -19,8 +19,8 @@ func resolveBinary(binname string) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
//only return no error if the final resolved binary basename
|
||||
//matches what was searched for
|
||||
// only return no error if the final resolved binary basename
|
||||
// matches what was searched for
|
||||
if filepath.Base(resolvedPath) == binname {
|
||||
return resolvedPath, nil
|
||||
}
|
||||
|
|
|
|||
152
vendor/github.com/containers/storage/pkg/ioutils/fswriters.go
generated
vendored
152
vendor/github.com/containers/storage/pkg/ioutils/fswriters.go
generated
vendored
|
|
@ -2,9 +2,9 @@ package ioutils
|
|||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AtomicFileWriterOptions specifies options for creating the atomic file writer.
|
||||
|
|
@ -14,9 +14,26 @@ type AtomicFileWriterOptions struct {
|
|||
// storage after it has been written and before it is moved to
|
||||
// the specified path.
|
||||
NoSync bool
|
||||
// On successful return from Close() this is set to the mtime of the
|
||||
// newly written file.
|
||||
ModTime time.Time
|
||||
// Specifies whether Commit() must be explicitly called to write state
|
||||
// to the destination. This allows an application to preserve the original
|
||||
// file when an error occurs during processing (and not just during write)
|
||||
// The default is false, which will auto-commit on Close
|
||||
ExplicitCommit bool
|
||||
}
|
||||
|
||||
var defaultWriterOptions AtomicFileWriterOptions = AtomicFileWriterOptions{}
|
||||
type CommittableWriter interface {
|
||||
io.WriteCloser
|
||||
|
||||
// Commit closes the temporary file associated with this writer, and
|
||||
// provided no errors (during commit or previously during write operations),
|
||||
// will publish the completed file under the intended destination.
|
||||
Commit() error
|
||||
}
|
||||
|
||||
var defaultWriterOptions = AtomicFileWriterOptions{}
|
||||
|
||||
// SetDefaultOptions overrides the default options used when creating an
|
||||
// atomic file writer.
|
||||
|
|
@ -24,11 +41,21 @@ func SetDefaultOptions(opts AtomicFileWriterOptions) {
|
|||
defaultWriterOptions = opts
|
||||
}
|
||||
|
||||
// NewAtomicFileWriterWithOpts returns WriteCloser so that writing to it writes to a
|
||||
// temporary file and closing it atomically changes the temporary file to
|
||||
// destination path. Writing and closing concurrently is not allowed.
|
||||
func NewAtomicFileWriterWithOpts(filename string, perm os.FileMode, opts *AtomicFileWriterOptions) (io.WriteCloser, error) {
|
||||
f, err := ioutil.TempFile(filepath.Dir(filename), ".tmp-"+filepath.Base(filename))
|
||||
// NewAtomicFileWriterWithOpts returns a CommittableWriter so that writing to it
|
||||
// writes to a temporary file, which can later be committed to a destination path,
|
||||
// either by Closing in the case of auto-commit, or manually calling commit if the
|
||||
// ExplicitCommit option is enabled. Writing and closing concurrently is not
|
||||
// allowed.
|
||||
func NewAtomicFileWriterWithOpts(filename string, perm os.FileMode, opts *AtomicFileWriterOptions) (CommittableWriter, error) {
|
||||
return newAtomicFileWriter(filename, perm, opts)
|
||||
}
|
||||
|
||||
// newAtomicFileWriter returns a CommittableWriter so that writing to it writes to
|
||||
// a temporary file, which can later be committed to a destination path, either by
|
||||
// Closing in the case of auto-commit, or manually calling commit if the
|
||||
// ExplicitCommit option is enabled. Writing and closing concurrently is not allowed.
|
||||
func newAtomicFileWriter(filename string, perm os.FileMode, opts *AtomicFileWriterOptions) (*atomicFileWriter, error) {
|
||||
f, err := os.CreateTemp(filepath.Dir(filename), ".tmp-"+filepath.Base(filename))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -40,43 +67,56 @@ func NewAtomicFileWriterWithOpts(filename string, perm os.FileMode, opts *Atomic
|
|||
return nil, err
|
||||
}
|
||||
return &atomicFileWriter{
|
||||
f: f,
|
||||
fn: abspath,
|
||||
perm: perm,
|
||||
noSync: opts.NoSync,
|
||||
f: f,
|
||||
fn: abspath,
|
||||
perm: perm,
|
||||
noSync: opts.NoSync,
|
||||
explicitCommit: opts.ExplicitCommit,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewAtomicFileWriter returns WriteCloser so that writing to it writes to a
|
||||
// temporary file and closing it atomically changes the temporary file to
|
||||
// destination path. Writing and closing concurrently is not allowed.
|
||||
func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, error) {
|
||||
// NewAtomicFileWriterWithOpts returns a CommittableWriter, with auto-commit enabled.
|
||||
// Writing to it writes to a temporary file and closing it atomically changes the
|
||||
// temporary file to destination path. Writing and closing concurrently is not allowed.
|
||||
func NewAtomicFileWriter(filename string, perm os.FileMode) (CommittableWriter, error) {
|
||||
return NewAtomicFileWriterWithOpts(filename, perm, nil)
|
||||
}
|
||||
|
||||
// AtomicWriteFile atomically writes data to a file named by filename.
|
||||
func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error {
|
||||
f, err := NewAtomicFileWriter(filename, perm)
|
||||
func AtomicWriteFileWithOpts(filename string, data []byte, perm os.FileMode, opts *AtomicFileWriterOptions) error {
|
||||
f, err := newAtomicFileWriter(filename, perm, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := f.Write(data)
|
||||
if err == nil && n < len(data) {
|
||||
err = io.ErrShortWrite
|
||||
f.(*atomicFileWriter).writeErr = err
|
||||
f.writeErr = err
|
||||
}
|
||||
if err1 := f.Close(); err == nil {
|
||||
err = err1
|
||||
}
|
||||
|
||||
if opts != nil {
|
||||
opts.ModTime = f.modTime
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error {
|
||||
return AtomicWriteFileWithOpts(filename, data, perm, nil)
|
||||
}
|
||||
|
||||
type atomicFileWriter struct {
|
||||
f *os.File
|
||||
fn string
|
||||
writeErr error
|
||||
perm os.FileMode
|
||||
noSync bool
|
||||
f *os.File
|
||||
fn string
|
||||
writeErr error
|
||||
perm os.FileMode
|
||||
noSync bool
|
||||
modTime time.Time
|
||||
closed bool
|
||||
explicitCommit bool
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) Write(dt []byte) (int, error) {
|
||||
|
|
@ -87,27 +127,73 @@ func (w *atomicFileWriter) Write(dt []byte) (int, error) {
|
|||
return n, err
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) Close() (retErr error) {
|
||||
func (w *atomicFileWriter) closeTempFile() error {
|
||||
if w.closed {
|
||||
return nil
|
||||
}
|
||||
|
||||
w.closed = true
|
||||
return w.f.Close()
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) Close() error {
|
||||
return w.complete(!w.explicitCommit)
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) Commit() error {
|
||||
return w.complete(true)
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) complete(commit bool) (retErr error) {
|
||||
if w == nil || w.closed {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer func() {
|
||||
w.closeTempFile()
|
||||
if retErr != nil || w.writeErr != nil {
|
||||
os.Remove(w.f.Name())
|
||||
}
|
||||
}()
|
||||
if !w.noSync {
|
||||
if err := fdatasync(w.f); err != nil {
|
||||
w.f.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
if commit {
|
||||
return w.commitState()
|
||||
}
|
||||
if err := w.f.Close(); err != nil {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) commitState() error {
|
||||
// Perform a data only sync (fdatasync()) if supported
|
||||
if err := w.postDataWrittenSync(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Chmod(w.f.Name(), w.perm); err != nil {
|
||||
|
||||
// Capture fstat before closing the fd
|
||||
info, err := w.f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.modTime = info.ModTime()
|
||||
|
||||
if err := w.f.Chmod(w.perm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform full sync on platforms that need it
|
||||
if err := w.preRenameSync(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Some platforms require closing before rename (Windows)
|
||||
if err := w.closeTempFile(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if w.writeErr == nil {
|
||||
return os.Rename(w.f.Name(), w.fn)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +210,7 @@ type AtomicWriteSet struct {
|
|||
// commit. If no temporary directory is given the system
|
||||
// default is used.
|
||||
func NewAtomicWriteSet(tmpDir string) (*AtomicWriteSet, error) {
|
||||
td, err := ioutil.TempDir(tmpDir, "write-set-")
|
||||
td, err := os.MkdirTemp(tmpDir, "write-set-")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -159,7 +245,7 @@ func (w syncFileCloser) Close() error {
|
|||
if !defaultWriterOptions.NoSync {
|
||||
return w.File.Close()
|
||||
}
|
||||
err := fdatasync(w.File)
|
||||
err := dataOrFullSync(w.File)
|
||||
if err1 := w.File.Close(); err == nil {
|
||||
err = err1
|
||||
}
|
||||
|
|
|
|||
14
vendor/github.com/containers/storage/pkg/ioutils/fswriters_linux.go
generated
vendored
14
vendor/github.com/containers/storage/pkg/ioutils/fswriters_linux.go
generated
vendored
|
|
@ -6,6 +6,18 @@ import (
|
|||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func fdatasync(f *os.File) error {
|
||||
func dataOrFullSync(f *os.File) error {
|
||||
return unix.Fdatasync(int(f.Fd()))
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) postDataWrittenSync() error {
|
||||
if w.noSync {
|
||||
return nil
|
||||
}
|
||||
return unix.Fdatasync(int(w.f.Fd()))
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) preRenameSync() error {
|
||||
// On Linux data can be reliably flushed to media without metadata, so defer
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
26
vendor/github.com/containers/storage/pkg/ioutils/fswriters_other.go
generated
vendored
Normal file
26
vendor/github.com/containers/storage/pkg/ioutils/fswriters_other.go
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package ioutils
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func dataOrFullSync(f *os.File) error {
|
||||
return f.Sync()
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) postDataWrittenSync() error {
|
||||
// many platforms (Mac, Windows) require a full sync to reliably flush to media
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) preRenameSync() error {
|
||||
if w.noSync {
|
||||
return nil
|
||||
}
|
||||
|
||||
// fsync() on Non-linux Unix, FlushFileBuffers (Windows), F_FULLFSYNC (Mac)
|
||||
return w.f.Sync()
|
||||
}
|
||||
11
vendor/github.com/containers/storage/pkg/ioutils/fswriters_unsupported.go
generated
vendored
11
vendor/github.com/containers/storage/pkg/ioutils/fswriters_unsupported.go
generated
vendored
|
|
@ -1,11 +0,0 @@
|
|||
// +build !linux
|
||||
|
||||
package ioutils
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func fdatasync(f *os.File) error {
|
||||
return f.Sync()
|
||||
}
|
||||
3
vendor/github.com/containers/storage/pkg/ioutils/readers.go
generated
vendored
3
vendor/github.com/containers/storage/pkg/ioutils/readers.go
generated
vendored
|
|
@ -1,11 +1,10 @@
|
|||
package ioutils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type readCloserWrapper struct {
|
||||
|
|
|
|||
7
vendor/github.com/containers/storage/pkg/ioutils/temp_unix.go
generated
vendored
7
vendor/github.com/containers/storage/pkg/ioutils/temp_unix.go
generated
vendored
|
|
@ -1,10 +1,11 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package ioutils
|
||||
|
||||
import "io/ioutil"
|
||||
import "os"
|
||||
|
||||
// TempDir on Unix systems is equivalent to ioutil.TempDir.
|
||||
// TempDir on Unix systems is equivalent to os.MkdirTemp.
|
||||
func TempDir(dir, prefix string) (string, error) {
|
||||
return ioutil.TempDir(dir, prefix)
|
||||
return os.MkdirTemp(dir, prefix)
|
||||
}
|
||||
|
|
|
|||
7
vendor/github.com/containers/storage/pkg/ioutils/temp_windows.go
generated
vendored
7
vendor/github.com/containers/storage/pkg/ioutils/temp_windows.go
generated
vendored
|
|
@ -1,16 +1,17 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package ioutils
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/containers/storage/pkg/longpath"
|
||||
)
|
||||
|
||||
// TempDir is the equivalent of ioutil.TempDir, except that the result is in Windows longpath format.
|
||||
// TempDir is the equivalent of os.MkdirTemp, except that the result is in Windows longpath format.
|
||||
func TempDir(dir, prefix string) (string, error) {
|
||||
tempDir, err := ioutil.TempDir(dir, prefix)
|
||||
tempDir, err := os.MkdirTemp(dir, prefix)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
|||
74
vendor/github.com/containers/storage/pkg/lockfile/lockfile.go
generated
vendored
74
vendor/github.com/containers/storage/pkg/lockfile/lockfile.go
generated
vendored
|
|
@ -10,6 +10,8 @@ import (
|
|||
// A Locker represents a file lock where the file is used to cache an
|
||||
// identifier of the last party that made changes to whatever's being protected
|
||||
// by the lock.
|
||||
//
|
||||
// Deprecated: Refer directly to *LockFile, the provided implementation, instead.
|
||||
type Locker interface {
|
||||
// Acquire a writer lock.
|
||||
// The default unix implementation panics if:
|
||||
|
|
@ -17,10 +19,6 @@ type Locker interface {
|
|||
// - tried to lock a read-only lock-file
|
||||
Lock()
|
||||
|
||||
// Acquire a writer lock recursively, allowing for recursive acquisitions
|
||||
// within the same process space.
|
||||
RecursiveLock()
|
||||
|
||||
// Unlock the lock.
|
||||
// The default unix implementation panics if:
|
||||
// - unlocking an unlocked lock
|
||||
|
|
@ -32,10 +30,13 @@ type Locker interface {
|
|||
|
||||
// Touch records, for others sharing the lock, that the caller was the
|
||||
// last writer. It should only be called with the lock held.
|
||||
//
|
||||
// Deprecated: Use *LockFile.RecordWrite.
|
||||
Touch() error
|
||||
|
||||
// Modified() checks if the most recent writer was a party other than the
|
||||
// last recorded writer. It should only be called with the lock held.
|
||||
// Deprecated: Use *LockFile.ModifiedSince.
|
||||
Modified() (bool, error)
|
||||
|
||||
// TouchedSince() checks if the most recent writer modified the file (likely using Touch()) after the specified time.
|
||||
|
|
@ -44,63 +45,86 @@ type Locker interface {
|
|||
// IsReadWrite() checks if the lock file is read-write
|
||||
IsReadWrite() bool
|
||||
|
||||
// Locked() checks if lock is locked for writing by a thread in this process
|
||||
Locked() bool
|
||||
// AssertLocked() can be used by callers that _know_ that they hold the lock (for reading or writing), for sanity checking.
|
||||
// It might do nothing at all, or it may panic if the caller is not the owner of this lock.
|
||||
AssertLocked()
|
||||
|
||||
// AssertLockedForWriting() can be used by callers that _know_ that they hold the lock locked for writing, for sanity checking.
|
||||
// It might do nothing at all, or it may panic if the caller is not the owner of this lock for writing.
|
||||
AssertLockedForWriting()
|
||||
}
|
||||
|
||||
var (
|
||||
lockfiles map[string]Locker
|
||||
lockfilesLock sync.Mutex
|
||||
lockFiles map[string]*LockFile
|
||||
lockFilesLock sync.Mutex
|
||||
)
|
||||
|
||||
// GetLockFile opens a read-write lock file, creating it if necessary. The
|
||||
// *LockFile object may already be locked if the path has already been requested
|
||||
// by the current process.
|
||||
func GetLockFile(path string) (*LockFile, error) {
|
||||
return getLockfile(path, false)
|
||||
}
|
||||
|
||||
// GetLockfile opens a read-write lock file, creating it if necessary. The
|
||||
// Locker object may already be locked if the path has already been requested
|
||||
// by the current process.
|
||||
//
|
||||
// Deprecated: Use GetLockFile
|
||||
func GetLockfile(path string) (Locker, error) {
|
||||
return getLockfile(path, false)
|
||||
return GetLockFile(path)
|
||||
}
|
||||
|
||||
// GetROLockFile opens a read-only lock file, creating it if necessary. The
|
||||
// *LockFile object may already be locked if the path has already been requested
|
||||
// by the current process.
|
||||
func GetROLockFile(path string) (*LockFile, error) {
|
||||
return getLockfile(path, true)
|
||||
}
|
||||
|
||||
// GetROLockfile opens a read-only lock file, creating it if necessary. The
|
||||
// Locker object may already be locked if the path has already been requested
|
||||
// by the current process.
|
||||
//
|
||||
// Deprecated: Use GetROLockFile
|
||||
func GetROLockfile(path string) (Locker, error) {
|
||||
return getLockfile(path, true)
|
||||
return GetROLockFile(path)
|
||||
}
|
||||
|
||||
// getLockfile returns a Locker object, possibly (depending on the platform)
|
||||
// getLockFile returns a *LockFile 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
|
||||
// If ro, the lock is a read-write lock and the returned *LockFile 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.
|
||||
// or a read-write lock and *LockFile 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()
|
||||
if lockfiles == nil {
|
||||
lockfiles = make(map[string]Locker)
|
||||
func getLockfile(path string, ro bool) (*LockFile, error) {
|
||||
lockFilesLock.Lock()
|
||||
defer lockFilesLock.Unlock()
|
||||
if lockFiles == nil {
|
||||
lockFiles = make(map[string]*LockFile)
|
||||
}
|
||||
cleanPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ensuring that path %q is an absolute path: %w", path, err)
|
||||
}
|
||||
if locker, ok := lockfiles[cleanPath]; ok {
|
||||
if ro && locker.IsReadWrite() {
|
||||
if lockFile, ok := lockFiles[cleanPath]; ok {
|
||||
if ro && lockFile.IsReadWrite() {
|
||||
return nil, fmt.Errorf("lock %q is not a read-only lock", cleanPath)
|
||||
}
|
||||
if !ro && !locker.IsReadWrite() {
|
||||
if !ro && !lockFile.IsReadWrite() {
|
||||
return nil, fmt.Errorf("lock %q is not a read-write lock", cleanPath)
|
||||
}
|
||||
return locker, nil
|
||||
return lockFile, nil
|
||||
}
|
||||
locker, err := createLockerForPath(cleanPath, ro) // platform-dependent locker
|
||||
lockFile, err := createLockFileForPath(cleanPath, ro) // platform-dependent LockFile
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lockfiles[cleanPath] = locker
|
||||
return locker, nil
|
||||
lockFiles[cleanPath] = lockFile
|
||||
return lockFile, nil
|
||||
}
|
||||
|
|
|
|||
303
vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
generated
vendored
303
vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
generated
vendored
|
|
@ -18,28 +18,48 @@ import (
|
|||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type lockfile struct {
|
||||
// *LockFile represents a file lock where the file is used to cache an
|
||||
// identifier of the last party that made changes to whatever's being protected
|
||||
// by the lock.
|
||||
//
|
||||
// It MUST NOT be created manually. Use GetLockFile or GetROLockFile instead.
|
||||
type LockFile struct {
|
||||
// The following fields are only set when constructing *LockFile, and must never be modified afterwards.
|
||||
// They are safe to access without any other locking.
|
||||
file string
|
||||
ro bool
|
||||
|
||||
// rwMutex serializes concurrent reader-writer acquisitions in the same process space
|
||||
rwMutex *sync.RWMutex
|
||||
// stateMutex is used to synchronize concurrent accesses to the state below
|
||||
stateMutex *sync.Mutex
|
||||
counter int64
|
||||
file string
|
||||
fd uintptr
|
||||
lw []byte // "last writer"-unique value valid as of the last .Touch() or .Modified(), generated by newLastWriterID()
|
||||
lw LastWrite // A global value valid as of the last .Touch() or .Modified()
|
||||
locktype int16
|
||||
locked bool
|
||||
ro bool
|
||||
recursive bool
|
||||
// The following fields are only modified on transitions between counter == 0 / counter != 0.
|
||||
// Thus, they can be safely accessed by users _that currently hold the LockFile_ without locking.
|
||||
// In other cases, they need to be protected using stateMutex.
|
||||
fd uintptr
|
||||
}
|
||||
|
||||
// LastWrite is an opaque identifier of the last write to some *LockFile.
|
||||
// It can be used by users of a *LockFile to determine if the lock indicates changes
|
||||
// since the last check.
|
||||
//
|
||||
// Never construct a LastWrite manually; only accept it from *LockFile methods, and pass it back.
|
||||
type LastWrite struct {
|
||||
// Never modify fields of a LastWrite object; it has value semantics.
|
||||
state []byte // Contents of the lock file.
|
||||
}
|
||||
|
||||
const lastWriterIDSize = 64 // This must be the same as len(stringid.GenerateRandomID)
|
||||
var lastWriterIDCounter uint64 // Private state for newLastWriterID
|
||||
|
||||
// newLastWriterID returns a new "last writer" ID.
|
||||
// newLastWrite returns a new "last write" ID.
|
||||
// The value must be different on every call, and also differ from values
|
||||
// generated by other processes.
|
||||
func newLastWriterID() []byte {
|
||||
func newLastWrite() LastWrite {
|
||||
// The ID is (PID, time, per-process counter, random)
|
||||
// PID + time represents both a unique process across reboots,
|
||||
// and a specific time within the process; the per-process counter
|
||||
|
|
@ -61,53 +81,84 @@ func newLastWriterID() []byte {
|
|||
panic(err) // This shouldn't happen
|
||||
}
|
||||
|
||||
return res
|
||||
return LastWrite{
|
||||
state: res,
|
||||
}
|
||||
}
|
||||
|
||||
// newLastWriteFromData returns a LastWrite corresponding to data that came from a previous LastWrite.serialize
|
||||
func newLastWriteFromData(serialized []byte) LastWrite {
|
||||
if serialized == nil {
|
||||
panic("newLastWriteFromData with nil data")
|
||||
}
|
||||
return LastWrite{
|
||||
state: serialized,
|
||||
}
|
||||
}
|
||||
|
||||
// serialize returns bytes to write to the lock file to represent the specified write.
|
||||
func (lw LastWrite) serialize() []byte {
|
||||
if lw.state == nil {
|
||||
panic("LastWrite.serialize on an uninitialized object")
|
||||
}
|
||||
return lw.state
|
||||
}
|
||||
|
||||
// Equals returns true if lw matches other
|
||||
func (lw LastWrite) equals(other LastWrite) bool {
|
||||
if lw.state == nil {
|
||||
panic("LastWrite.equals on an uninitialized object")
|
||||
}
|
||||
if other.state == nil {
|
||||
panic("LastWrite.equals with an uninitialized counterparty")
|
||||
}
|
||||
return bytes.Equal(lw.state, other.state)
|
||||
}
|
||||
|
||||
// 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.
|
||||
// descriptor. The path is opened either read-only or read-write,
|
||||
// depending on the value of ro argument.
|
||||
//
|
||||
// openLock will create the file and its parent directories,
|
||||
// if necessary.
|
||||
func openLock(path string, ro bool) (fd int, err error) {
|
||||
flags := unix.O_CLOEXEC | os.O_CREATE
|
||||
if ro {
|
||||
fd, err = unix.Open(path, os.O_RDONLY|unix.O_CLOEXEC|os.O_CREATE, 0)
|
||||
flags |= os.O_RDONLY
|
||||
} else {
|
||||
fd, err = unix.Open(path,
|
||||
os.O_RDWR|unix.O_CLOEXEC|os.O_CREATE,
|
||||
unix.S_IRUSR|unix.S_IWUSR|unix.S_IRGRP|unix.S_IROTH,
|
||||
)
|
||||
flags |= os.O_RDWR
|
||||
}
|
||||
|
||||
fd, err = unix.Open(path, flags, 0o644)
|
||||
if err == nil {
|
||||
return
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// the directory of the lockfile seems to be removed, try to create it
|
||||
if os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
|
||||
return fd, fmt.Errorf("creating locker directory: %w", err)
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
|
||||
return fd, fmt.Errorf("creating lock file directory: %w", err)
|
||||
}
|
||||
|
||||
return openLock(path, ro)
|
||||
}
|
||||
|
||||
return
|
||||
return fd, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
|
||||
// createLockerForPath returns a Locker object, possibly (depending on the platform)
|
||||
// createLockFileForPath returns new *LockFile 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
|
||||
// If ro, the lock is a read-write lock and the returned *LockFile 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.
|
||||
// or a read-write lock and *LockFile 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) {
|
||||
func createLockFileForPath(path string, ro bool) (*LockFile, error) {
|
||||
// Check if we can open the lock.
|
||||
fd, err := openLock(path, ro)
|
||||
if err != nil {
|
||||
|
|
@ -119,22 +170,24 @@ func createLockerForPath(path string, ro bool) (Locker, error) {
|
|||
if ro {
|
||||
locktype = unix.F_RDLCK
|
||||
}
|
||||
return &lockfile{
|
||||
stateMutex: &sync.Mutex{},
|
||||
return &LockFile{
|
||||
file: path,
|
||||
ro: ro,
|
||||
|
||||
rwMutex: &sync.RWMutex{},
|
||||
file: path,
|
||||
lw: newLastWriterID(),
|
||||
stateMutex: &sync.Mutex{},
|
||||
lw: newLastWrite(), // For compatibility, the first call of .Modified() will always report a change.
|
||||
locktype: int16(locktype),
|
||||
locked: false,
|
||||
ro: ro}, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
// lock locks the lockfile via FCTNL(2) based on the specified type and
|
||||
// command.
|
||||
func (l *lockfile) lock(lType int16, recursive bool) {
|
||||
func (l *LockFile) lock(lType int16) {
|
||||
lk := unix.Flock_t{
|
||||
Type: lType,
|
||||
Whence: int16(os.SEEK_SET),
|
||||
Whence: int16(unix.SEEK_SET),
|
||||
Start: 0,
|
||||
Len: 0,
|
||||
}
|
||||
|
|
@ -142,13 +195,7 @@ func (l *lockfile) lock(lType int16, recursive bool) {
|
|||
case unix.F_RDLCK:
|
||||
l.rwMutex.RLock()
|
||||
case unix.F_WRLCK:
|
||||
if recursive {
|
||||
// NOTE: that's okay as recursive is only set in RecursiveLock(), so
|
||||
// there's no need to protect against hypothetical RDLCK cases.
|
||||
l.rwMutex.RLock()
|
||||
} else {
|
||||
l.rwMutex.Lock()
|
||||
}
|
||||
l.rwMutex.Lock()
|
||||
default:
|
||||
panic(fmt.Sprintf("attempted to acquire a file lock of unrecognized type %d", lType))
|
||||
}
|
||||
|
|
@ -158,7 +205,7 @@ func (l *lockfile) lock(lType int16, recursive bool) {
|
|||
// 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: %v", l.file, err))
|
||||
panic(err)
|
||||
}
|
||||
l.fd = uintptr(fd)
|
||||
|
||||
|
|
@ -171,39 +218,27 @@ func (l *lockfile) lock(lType int16, recursive bool) {
|
|||
}
|
||||
l.locktype = lType
|
||||
l.locked = true
|
||||
l.recursive = recursive
|
||||
l.counter++
|
||||
}
|
||||
|
||||
// Lock locks the lockfile as a writer. Panic if the lock is a read-only one.
|
||||
func (l *lockfile) Lock() {
|
||||
func (l *LockFile) Lock() {
|
||||
if l.ro {
|
||||
panic("can't take write lock on read-only lock file")
|
||||
} else {
|
||||
l.lock(unix.F_WRLCK, false)
|
||||
}
|
||||
}
|
||||
|
||||
// RecursiveLock locks the lockfile as a writer but allows for recursive
|
||||
// acquisitions within the same process space. Note that RLock() will be called
|
||||
// if it's a lockTypReader lock.
|
||||
func (l *lockfile) RecursiveLock() {
|
||||
if l.ro {
|
||||
l.RLock()
|
||||
} else {
|
||||
l.lock(unix.F_WRLCK, true)
|
||||
l.lock(unix.F_WRLCK)
|
||||
}
|
||||
}
|
||||
|
||||
// LockRead locks the lockfile as a reader.
|
||||
func (l *lockfile) RLock() {
|
||||
l.lock(unix.F_RDLCK, false)
|
||||
func (l *LockFile) RLock() {
|
||||
l.lock(unix.F_RDLCK)
|
||||
}
|
||||
|
||||
// Unlock unlocks the lockfile.
|
||||
func (l *lockfile) Unlock() {
|
||||
func (l *LockFile) Unlock() {
|
||||
l.stateMutex.Lock()
|
||||
if l.locked == false {
|
||||
if !l.locked {
|
||||
// Panic when unlocking an unlocked lock. That's a violation
|
||||
// of the lock semantics and will reveal such.
|
||||
panic("calling Unlock on unlocked lock")
|
||||
|
|
@ -224,7 +259,7 @@ func (l *lockfile) Unlock() {
|
|||
// file lock.
|
||||
unix.Close(int(l.fd))
|
||||
}
|
||||
if l.locktype == unix.F_RDLCK || l.recursive {
|
||||
if l.locktype == unix.F_RDLCK {
|
||||
l.rwMutex.RUnlock()
|
||||
} else {
|
||||
l.rwMutex.Unlock()
|
||||
|
|
@ -232,59 +267,157 @@ func (l *lockfile) Unlock() {
|
|||
l.stateMutex.Unlock()
|
||||
}
|
||||
|
||||
// Locked checks if lockfile is locked for writing by a thread in this process.
|
||||
func (l *lockfile) Locked() bool {
|
||||
l.stateMutex.Lock()
|
||||
defer l.stateMutex.Unlock()
|
||||
return l.locked && (l.locktype == unix.F_WRLCK)
|
||||
func (l *LockFile) AssertLocked() {
|
||||
// DO NOT provide a variant that returns the value of l.locked.
|
||||
//
|
||||
// If the caller does not hold the lock, l.locked might nevertheless be true because another goroutine does hold it, and
|
||||
// we can’t tell the difference.
|
||||
//
|
||||
// Hence, this “AssertLocked” method, which exists only for sanity checks.
|
||||
|
||||
// Don’t even bother with l.stateMutex: The caller is expected to hold the lock, and in that case l.locked is constant true
|
||||
// with no possible writers.
|
||||
// If the caller does not hold the lock, we are violating the locking/memory model anyway, and accessing the data
|
||||
// without the lock is more efficient for callers, and potentially more visible to lock analysers for incorrect callers.
|
||||
if !l.locked {
|
||||
panic("internal error: lock is not held by the expected owner")
|
||||
}
|
||||
}
|
||||
|
||||
// Touch updates the lock file with the UID of the user.
|
||||
func (l *lockfile) Touch() error {
|
||||
func (l *LockFile) AssertLockedForWriting() {
|
||||
// DO NOT provide a variant that returns the current lock state.
|
||||
//
|
||||
// The same caveats as for AssertLocked apply equally.
|
||||
|
||||
l.AssertLocked()
|
||||
// Like AssertLocked, don’t even bother with l.stateMutex.
|
||||
if l.locktype != unix.F_WRLCK {
|
||||
panic("internal error: lock is not held for writing")
|
||||
}
|
||||
}
|
||||
|
||||
// GetLastWrite returns a LastWrite value corresponding to current state of the lock.
|
||||
// This is typically called before (_not after_) loading the state when initializing a consumer
|
||||
// of the data protected by the lock.
|
||||
// During the lifetime of the consumer, the consumer should usually call ModifiedSince instead.
|
||||
//
|
||||
// The caller must hold the lock (for reading or writing).
|
||||
func (l *LockFile) GetLastWrite() (LastWrite, error) {
|
||||
l.AssertLocked()
|
||||
contents := make([]byte, lastWriterIDSize)
|
||||
n, err := unix.Pread(int(l.fd), contents, 0)
|
||||
if err != nil {
|
||||
return LastWrite{}, err
|
||||
}
|
||||
// It is important to handle the partial read case, because
|
||||
// the initial size of the lock file is zero, which is a valid
|
||||
// state (no writes yet)
|
||||
contents = contents[:n]
|
||||
return newLastWriteFromData(contents), nil
|
||||
}
|
||||
|
||||
// RecordWrite updates the lock with a new LastWrite value, and returns the new value.
|
||||
//
|
||||
// If this function fails, the LastWriter value of the lock is indeterminate;
|
||||
// the caller should keep using the previously-recorded LastWrite value,
|
||||
// and possibly detecting its own modification as an external one:
|
||||
//
|
||||
// lw, err := state.lock.RecordWrite()
|
||||
// if err != nil { /* fail */ }
|
||||
// state.lastWrite = lw
|
||||
//
|
||||
// The caller must hold the lock for writing.
|
||||
func (l *LockFile) RecordWrite() (LastWrite, error) {
|
||||
l.AssertLockedForWriting()
|
||||
lw := newLastWrite()
|
||||
lockContents := lw.serialize()
|
||||
n, err := unix.Pwrite(int(l.fd), lockContents, 0)
|
||||
if err != nil {
|
||||
return LastWrite{}, err
|
||||
}
|
||||
if n != len(lockContents) {
|
||||
return LastWrite{}, unix.ENOSPC
|
||||
}
|
||||
return lw, nil
|
||||
}
|
||||
|
||||
// ModifiedSince checks if the lock has been changed since a provided LastWrite value,
|
||||
// and returns the one to record instead.
|
||||
//
|
||||
// If ModifiedSince reports no modification, the previous LastWrite value
|
||||
// is still valid and can continue to be used.
|
||||
//
|
||||
// If this function fails, the LastWriter value of the lock is indeterminate;
|
||||
// the caller should fail and keep using the previously-recorded LastWrite value,
|
||||
// so that it continues failing until the situation is resolved. Similarly,
|
||||
// it should only update the recorded LastWrite value after processing the update:
|
||||
//
|
||||
// lw2, modified, err := state.lock.ModifiedSince(state.lastWrite)
|
||||
// if err != nil { /* fail */ }
|
||||
// state.lastWrite = lw2
|
||||
// if modified {
|
||||
// if err := reload(); err != nil { /* fail */ }
|
||||
// state.lastWrite = lw2
|
||||
// }
|
||||
//
|
||||
// The caller must hold the lock (for reading or writing).
|
||||
func (l *LockFile) ModifiedSince(previous LastWrite) (LastWrite, bool, error) {
|
||||
l.AssertLocked()
|
||||
currentLW, err := l.GetLastWrite()
|
||||
if err != nil {
|
||||
return LastWrite{}, false, err
|
||||
}
|
||||
modified := !previous.equals(currentLW)
|
||||
return currentLW, modified, nil
|
||||
}
|
||||
|
||||
// Touch updates the lock file with to record that the current lock holder has modified the lock-protected data.
|
||||
//
|
||||
// Deprecated: Use *LockFile.RecordWrite.
|
||||
func (l *LockFile) Touch() error {
|
||||
lw, err := l.RecordWrite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.stateMutex.Lock()
|
||||
if !l.locked || (l.locktype != unix.F_WRLCK) {
|
||||
panic("attempted to update last-writer in lockfile without the write lock")
|
||||
}
|
||||
defer l.stateMutex.Unlock()
|
||||
l.lw = newLastWriterID()
|
||||
n, err := unix.Pwrite(int(l.fd), l.lw, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(l.lw) {
|
||||
return unix.ENOSPC
|
||||
}
|
||||
l.lw = lw
|
||||
return nil
|
||||
}
|
||||
|
||||
// Modified indicates if the lockfile has been updated since the last time it
|
||||
// was loaded.
|
||||
func (l *lockfile) Modified() (bool, error) {
|
||||
// NOTE: Unlike ModifiedSince, this returns true the first time it is called on a *LockFile.
|
||||
// Callers cannot, in general, rely on this, because that might have happened for some other
|
||||
// owner of the same *LockFile who created it previously.
|
||||
//
|
||||
// Deprecated: Use *LockFile.ModifiedSince.
|
||||
func (l *LockFile) Modified() (bool, error) {
|
||||
l.stateMutex.Lock()
|
||||
if !l.locked {
|
||||
panic("attempted to check last-writer in lockfile without locking it first")
|
||||
}
|
||||
defer l.stateMutex.Unlock()
|
||||
currentLW := make([]byte, len(l.lw))
|
||||
n, err := unix.Pread(int(l.fd), currentLW, 0)
|
||||
oldLW := l.lw
|
||||
// Note that this is called with stateMutex held; that’s fine because ModifiedSince doesn’t need to lock it.
|
||||
currentLW, modified, err := l.ModifiedSince(oldLW)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
if n != len(l.lw) {
|
||||
return true, nil
|
||||
}
|
||||
oldLW := l.lw
|
||||
l.lw = currentLW
|
||||
return !bytes.Equal(currentLW, oldLW), nil
|
||||
return modified, nil
|
||||
}
|
||||
|
||||
// IsReadWriteLock indicates if the lock file is a read-write lock.
|
||||
func (l *lockfile) IsReadWrite() bool {
|
||||
func (l *LockFile) IsReadWrite() bool {
|
||||
return !l.ro
|
||||
}
|
||||
|
||||
// TouchedSince indicates if the lock file has been touched since the specified time
|
||||
func (l *lockfile) TouchedSince(when time.Time) bool {
|
||||
func (l *LockFile) TouchedSince(when time.Time) bool {
|
||||
st, err := system.Fstat(int(l.fd))
|
||||
if err != nil {
|
||||
return true
|
||||
|
|
|
|||
119
vendor/github.com/containers/storage/pkg/lockfile/lockfile_windows.go
generated
vendored
119
vendor/github.com/containers/storage/pkg/lockfile/lockfile_windows.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package lockfile
|
||||
|
|
@ -8,65 +9,141 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// createLockerForPath returns a Locker object, possibly (depending on the platform)
|
||||
// createLockFileForPath returns a *LockFile 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
|
||||
// If ro, the lock is a read-write lock and the returned *LockFile 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.
|
||||
// or a read-write lock and *LockFile 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
|
||||
func createLockFileForPath(path string, ro bool) (*LockFile, error) {
|
||||
return &LockFile{locked: false}, nil
|
||||
}
|
||||
|
||||
type lockfile struct {
|
||||
// *LockFile represents a file lock where the file is used to cache an
|
||||
// identifier of the last party that made changes to whatever's being protected
|
||||
// by the lock.
|
||||
//
|
||||
// It MUST NOT be created manually. Use GetLockFile or GetROLockFile instead.
|
||||
type LockFile struct {
|
||||
mu sync.Mutex
|
||||
file string
|
||||
locked bool
|
||||
}
|
||||
|
||||
func (l *lockfile) Lock() {
|
||||
// LastWrite is an opaque identifier of the last write to some *LockFile.
|
||||
// It can be used by users of a *LockFile to determine if the lock indicates changes
|
||||
// since the last check.
|
||||
// A default-initialized LastWrite never matches any last write, i.e. it always indicates changes.
|
||||
type LastWrite struct {
|
||||
// Nothing: The Windows “implementation” does not actually track writes.
|
||||
}
|
||||
|
||||
func (l *LockFile) Lock() {
|
||||
l.mu.Lock()
|
||||
l.locked = true
|
||||
}
|
||||
|
||||
func (l *lockfile) RecursiveLock() {
|
||||
// We don't support Windows but a recursive writer-lock in one process-space
|
||||
// is really a writer lock, so just panic.
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
func (l *lockfile) RLock() {
|
||||
func (l *LockFile) RLock() {
|
||||
l.mu.Lock()
|
||||
l.locked = true
|
||||
}
|
||||
|
||||
func (l *lockfile) Unlock() {
|
||||
func (l *LockFile) Unlock() {
|
||||
l.locked = false
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
func (l *lockfile) Locked() bool {
|
||||
return l.locked
|
||||
func (l *LockFile) AssertLocked() {
|
||||
// DO NOT provide a variant that returns the value of l.locked.
|
||||
//
|
||||
// If the caller does not hold the lock, l.locked might nevertheless be true because another goroutine does hold it, and
|
||||
// we can’t tell the difference.
|
||||
//
|
||||
// Hence, this “AssertLocked” method, which exists only for sanity checks.
|
||||
if !l.locked {
|
||||
panic("internal error: lock is not held by the expected owner")
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lockfile) Modified() (bool, error) {
|
||||
func (l *LockFile) AssertLockedForWriting() {
|
||||
// DO NOT provide a variant that returns the current lock state.
|
||||
//
|
||||
// The same caveats as for AssertLocked apply equally.
|
||||
l.AssertLocked() // The current implementation does not distinguish between read and write locks.
|
||||
}
|
||||
|
||||
// GetLastWrite() returns a LastWrite value corresponding to current state of the lock.
|
||||
// This is typically called before (_not after_) loading the state when initializing a consumer
|
||||
// of the data protected by the lock.
|
||||
// During the lifetime of the consumer, the consumer should usually call ModifiedSince instead.
|
||||
//
|
||||
// The caller must hold the lock (for reading or writing) before this function is called.
|
||||
func (l *LockFile) GetLastWrite() (LastWrite, error) {
|
||||
l.AssertLocked()
|
||||
return LastWrite{}, nil
|
||||
}
|
||||
|
||||
// RecordWrite updates the lock with a new LastWrite value, and returns the new value.
|
||||
//
|
||||
// If this function fails, the LastWriter value of the lock is indeterminate;
|
||||
// the caller should keep using the previously-recorded LastWrite value,
|
||||
// and possibly detecting its own modification as an external one:
|
||||
//
|
||||
// lw, err := state.lock.RecordWrite()
|
||||
// if err != nil { /* fail */ }
|
||||
// state.lastWrite = lw
|
||||
//
|
||||
// The caller must hold the lock for writing.
|
||||
func (l *LockFile) RecordWrite() (LastWrite, error) {
|
||||
return LastWrite{}, nil
|
||||
}
|
||||
|
||||
// ModifiedSince checks if the lock has been changed since a provided LastWrite value,
|
||||
// and returns the one to record instead.
|
||||
//
|
||||
// If ModifiedSince reports no modification, the previous LastWrite value
|
||||
// is still valid and can continue to be used.
|
||||
//
|
||||
// If this function fails, the LastWriter value of the lock is indeterminate;
|
||||
// the caller should fail and keep using the previously-recorded LastWrite value,
|
||||
// so that it continues failing until the situation is resolved. Similarly,
|
||||
// it should only update the recorded LastWrite value after processing the update:
|
||||
//
|
||||
// lw2, modified, err := state.lock.ModifiedSince(state.lastWrite)
|
||||
// if err != nil { /* fail */ }
|
||||
// state.lastWrite = lw2
|
||||
// if modified {
|
||||
// if err := reload(); err != nil { /* fail */ }
|
||||
// state.lastWrite = lw2
|
||||
// }
|
||||
//
|
||||
// The caller must hold the lock (for reading or writing).
|
||||
func (l *LockFile) ModifiedSince(previous LastWrite) (LastWrite, bool, error) {
|
||||
return LastWrite{}, false, nil
|
||||
}
|
||||
|
||||
// Deprecated: Use *LockFile.ModifiedSince.
|
||||
func (l *LockFile) Modified() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (l *lockfile) Touch() error {
|
||||
|
||||
// Deprecated: Use *LockFile.RecordWrite.
|
||||
func (l *LockFile) Touch() error {
|
||||
return nil
|
||||
}
|
||||
func (l *lockfile) IsReadWrite() bool {
|
||||
|
||||
func (l *LockFile) IsReadWrite() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *lockfile) TouchedSince(when time.Time) bool {
|
||||
func (l *LockFile) TouchedSince(when time.Time) bool {
|
||||
stat, err := os.Stat(l.file)
|
||||
if err != nil {
|
||||
return true
|
||||
|
|
|
|||
27
vendor/github.com/containers/storage/pkg/mount/unmount_unix.go
generated
vendored
27
vendor/github.com/containers/storage/pkg/mount/unmount_unix.go
generated
vendored
|
|
@ -1,16 +1,29 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package mount
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func unmount(target string, flags int) error {
|
||||
err := unix.Unmount(target, flags)
|
||||
if err == nil || err == unix.EINVAL {
|
||||
// Ignore "not mounted" error here. Note the same error
|
||||
// can be returned if flags are invalid, so this code
|
||||
// assumes that the flags value is always correct.
|
||||
return nil
|
||||
var err error
|
||||
for i := 0; i < 50; i++ {
|
||||
err = unix.Unmount(target, flags)
|
||||
switch err {
|
||||
case unix.EBUSY:
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
continue
|
||||
case unix.EINVAL, nil:
|
||||
// Ignore "not mounted" error here. Note the same error
|
||||
// can be returned if flags are invalid, so this code
|
||||
// assumes that the flags value is always correct.
|
||||
return nil
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return &mountError{
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/mount/unmount_unsupported.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/mount/unmount_unsupported.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package mount
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/reexec/command_freebsd.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/reexec/command_freebsd.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build freebsd
|
||||
// +build freebsd
|
||||
|
||||
package reexec
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/reexec/command_linux.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/reexec/command_linux.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package reexec
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/reexec/command_unsupported.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/reexec/command_unsupported.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !linux && !windows && !freebsd && !solaris && !darwin
|
||||
// +build !linux,!windows,!freebsd,!solaris,!darwin
|
||||
|
||||
package reexec
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/reexec/command_windows.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/reexec/command_windows.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package reexec
|
||||
|
|
|
|||
2
vendor/github.com/containers/storage/pkg/reexec/reexec.go
generated
vendored
2
vendor/github.com/containers/storage/pkg/reexec/reexec.go
generated
vendored
|
|
@ -49,7 +49,7 @@ func panicIfNotInitialized() {
|
|||
}
|
||||
}
|
||||
|
||||
func naiveSelf() string {
|
||||
func naiveSelf() string { //nolint: unused
|
||||
name := os.Args[0]
|
||||
if filepath.Base(name) == name {
|
||||
if lp, err := exec.LookPath(name); err == nil {
|
||||
|
|
|
|||
234
vendor/github.com/containers/storage/pkg/regexp/regexp.go
generated
vendored
Normal file
234
vendor/github.com/containers/storage/pkg/regexp/regexp.go
generated
vendored
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
package regexp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"regexp"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Regexp is a wrapper struct used for wrapping MustCompile regex expressions
|
||||
// used as global variables. Using this structure helps speed the startup time
|
||||
// of apps that want to use global regex variables. This library initializes them on
|
||||
// first use as opposed to the start of the executable.
|
||||
type Regexp struct {
|
||||
*regexpStruct
|
||||
}
|
||||
|
||||
type regexpStruct struct {
|
||||
_ noCopy
|
||||
once sync.Once
|
||||
regexp *regexp.Regexp
|
||||
val string
|
||||
}
|
||||
|
||||
func Delayed(val string) Regexp {
|
||||
re := ®expStruct{
|
||||
val: val,
|
||||
}
|
||||
if precompile {
|
||||
re.regexp = regexp.MustCompile(re.val)
|
||||
}
|
||||
return Regexp{re}
|
||||
}
|
||||
|
||||
func (re *regexpStruct) compile() {
|
||||
if precompile {
|
||||
return
|
||||
}
|
||||
re.once.Do(func() {
|
||||
re.regexp = regexp.MustCompile(re.val)
|
||||
})
|
||||
}
|
||||
|
||||
func (re *regexpStruct) Expand(dst []byte, template []byte, src []byte, match []int) []byte {
|
||||
re.compile()
|
||||
return re.regexp.Expand(dst, template, src, match)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) ExpandString(dst []byte, template string, src string, match []int) []byte {
|
||||
re.compile()
|
||||
return re.regexp.ExpandString(dst, template, src, match)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) Find(b []byte) []byte {
|
||||
re.compile()
|
||||
return re.regexp.Find(b)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindAll(b []byte, n int) [][]byte {
|
||||
re.compile()
|
||||
return re.regexp.FindAll(b, n)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindAllIndex(b []byte, n int) [][]int {
|
||||
re.compile()
|
||||
return re.regexp.FindAllIndex(b, n)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindAllString(s string, n int) []string {
|
||||
re.compile()
|
||||
return re.regexp.FindAllString(s, n)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindAllStringIndex(s string, n int) [][]int {
|
||||
re.compile()
|
||||
return re.regexp.FindAllStringIndex(s, n)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindAllStringSubmatch(s string, n int) [][]string {
|
||||
re.compile()
|
||||
return re.regexp.FindAllStringSubmatch(s, n)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindAllStringSubmatchIndex(s string, n int) [][]int {
|
||||
re.compile()
|
||||
return re.regexp.FindAllStringSubmatchIndex(s, n)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindAllSubmatch(b []byte, n int) [][][]byte {
|
||||
re.compile()
|
||||
return re.regexp.FindAllSubmatch(b, n)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindAllSubmatchIndex(b []byte, n int) [][]int {
|
||||
re.compile()
|
||||
return re.regexp.FindAllSubmatchIndex(b, n)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindIndex(b []byte) (loc []int) {
|
||||
re.compile()
|
||||
return re.regexp.FindIndex(b)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindReaderIndex(r io.RuneReader) (loc []int) {
|
||||
re.compile()
|
||||
return re.regexp.FindReaderIndex(r)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindReaderSubmatchIndex(r io.RuneReader) []int {
|
||||
re.compile()
|
||||
return re.regexp.FindReaderSubmatchIndex(r)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindString(s string) string {
|
||||
re.compile()
|
||||
return re.regexp.FindString(s)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindStringIndex(s string) (loc []int) {
|
||||
re.compile()
|
||||
return re.regexp.FindStringIndex(s)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindStringSubmatch(s string) []string {
|
||||
re.compile()
|
||||
return re.regexp.FindStringSubmatch(s)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindStringSubmatchIndex(s string) []int {
|
||||
re.compile()
|
||||
return re.regexp.FindStringSubmatchIndex(s)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindSubmatch(b []byte) [][]byte {
|
||||
re.compile()
|
||||
return re.regexp.FindSubmatch(b)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) FindSubmatchIndex(b []byte) []int {
|
||||
re.compile()
|
||||
return re.regexp.FindSubmatchIndex(b)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) LiteralPrefix() (prefix string, complete bool) {
|
||||
re.compile()
|
||||
return re.regexp.LiteralPrefix()
|
||||
}
|
||||
|
||||
func (re *regexpStruct) Longest() {
|
||||
re.compile()
|
||||
re.regexp.Longest()
|
||||
}
|
||||
|
||||
func (re *regexpStruct) Match(b []byte) bool {
|
||||
re.compile()
|
||||
return re.regexp.Match(b)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) MatchReader(r io.RuneReader) bool {
|
||||
re.compile()
|
||||
return re.regexp.MatchReader(r)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) MatchString(s string) bool {
|
||||
re.compile()
|
||||
return re.regexp.MatchString(s)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) NumSubexp() int {
|
||||
re.compile()
|
||||
return re.regexp.NumSubexp()
|
||||
}
|
||||
|
||||
func (re *regexpStruct) ReplaceAll(src, repl []byte) []byte {
|
||||
re.compile()
|
||||
return re.regexp.ReplaceAll(src, repl)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
|
||||
re.compile()
|
||||
return re.regexp.ReplaceAllFunc(src, repl)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) ReplaceAllLiteral(src, repl []byte) []byte {
|
||||
re.compile()
|
||||
return re.regexp.ReplaceAllLiteral(src, repl)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) ReplaceAllLiteralString(src, repl string) string {
|
||||
re.compile()
|
||||
return re.regexp.ReplaceAllLiteralString(src, repl)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) ReplaceAllString(src, repl string) string {
|
||||
re.compile()
|
||||
return re.regexp.ReplaceAllString(src, repl)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) ReplaceAllStringFunc(src string, repl func(string) string) string {
|
||||
re.compile()
|
||||
return re.regexp.ReplaceAllStringFunc(src, repl)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) Split(s string, n int) []string {
|
||||
re.compile()
|
||||
return re.regexp.Split(s, n)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) String() string {
|
||||
re.compile()
|
||||
return re.regexp.String()
|
||||
}
|
||||
|
||||
func (re *regexpStruct) SubexpIndex(name string) int {
|
||||
re.compile()
|
||||
return re.regexp.SubexpIndex(name)
|
||||
}
|
||||
|
||||
func (re *regexpStruct) SubexpNames() []string {
|
||||
re.compile()
|
||||
return re.regexp.SubexpNames()
|
||||
}
|
||||
|
||||
// noCopy may be added to structs which must not be copied
|
||||
// after the first use.
|
||||
//
|
||||
// See https://golang.org/issues/8005#issuecomment-190753527
|
||||
// for details.
|
||||
//
|
||||
// Note that it must not be embedded, due to the Lock and Unlock methods.
|
||||
type noCopy struct{}
|
||||
|
||||
// Lock is a no-op used by -copylocks checker from `go vet`.
|
||||
func (*noCopy) Lock() {}
|
||||
func (*noCopy) Unlock() {}
|
||||
6
vendor/github.com/containers/storage/pkg/regexp/regexp_dontprecompile.go
generated
vendored
Normal file
6
vendor/github.com/containers/storage/pkg/regexp/regexp_dontprecompile.go
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
//go:build !regexp_precompile
|
||||
// +build !regexp_precompile
|
||||
|
||||
package regexp
|
||||
|
||||
const precompile = false
|
||||
6
vendor/github.com/containers/storage/pkg/regexp/regexp_precompile.go
generated
vendored
Normal file
6
vendor/github.com/containers/storage/pkg/regexp/regexp_precompile.go
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
//go:build regexp_precompile
|
||||
// +build regexp_precompile
|
||||
|
||||
package regexp
|
||||
|
||||
const precompile = true
|
||||
7
vendor/github.com/containers/storage/pkg/system/chtimes_unix.go
generated
vendored
7
vendor/github.com/containers/storage/pkg/system/chtimes_unix.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package system
|
||||
|
|
@ -6,9 +7,9 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
//setCTime will set the create time on a file. On Unix, the create
|
||||
//time is updated as a side effect of setting the modified time, so
|
||||
//no action is required.
|
||||
// setCTime will set the create time on a file. On Unix, the create
|
||||
// time is updated as a side effect of setting the modified time, so
|
||||
// no action is required.
|
||||
func setCTime(path string, ctime time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
5
vendor/github.com/containers/storage/pkg/system/chtimes_windows.go
generated
vendored
5
vendor/github.com/containers/storage/pkg/system/chtimes_windows.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package system
|
||||
|
|
@ -8,8 +9,8 @@ import (
|
|||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
//setCTime will set the create time on a file. On Windows, this requires
|
||||
//calling SetFileTime and explicitly including the create time.
|
||||
// setCTime will set the create time on a file. On Windows, this requires
|
||||
// calling SetFileTime and explicitly including the create time.
|
||||
func setCTime(path string, ctime time.Time) error {
|
||||
ctimespec := windows.NsecToTimespec(ctime.UnixNano())
|
||||
pathp, e := windows.UTF16PtrFromString(path)
|
||||
|
|
|
|||
6
vendor/github.com/containers/storage/pkg/system/errors.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/system/errors.go
generated
vendored
|
|
@ -4,7 +4,5 @@ import (
|
|||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotSupportedPlatform means the platform is not supported.
|
||||
ErrNotSupportedPlatform = errors.New("platform and architecture is not supported")
|
||||
)
|
||||
// ErrNotSupportedPlatform means the platform is not supported.
|
||||
var ErrNotSupportedPlatform = errors.New("platform and architecture is not supported")
|
||||
|
|
|
|||
2
vendor/github.com/containers/storage/pkg/system/init.go
generated
vendored
2
vendor/github.com/containers/storage/pkg/system/init.go
generated
vendored
|
|
@ -6,7 +6,7 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
// Used by chtimes
|
||||
// maxTime is used by chtimes.
|
||||
var maxTime time.Time
|
||||
|
||||
func init() {
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/system/init_windows.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/init_windows.go
generated
vendored
|
|
@ -13,5 +13,4 @@ func init() {
|
|||
if os.Getenv("LCOW_SUPPORTED") != "" {
|
||||
lcowSupported = true
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
56
vendor/github.com/containers/storage/pkg/system/lchflags_bsd.go
generated
vendored
Normal file
56
vendor/github.com/containers/storage/pkg/system/lchflags_bsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
//go:build freebsd
|
||||
// +build freebsd
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Flag values from <sys/stat.h>
|
||||
const (
|
||||
/*
|
||||
* Definitions of flags stored in file flags word.
|
||||
*
|
||||
* Super-user and owner changeable flags.
|
||||
*/
|
||||
UF_SETTABLE uint32 = 0x0000ffff /* mask of owner changeable flags */
|
||||
UF_NODUMP uint32 = 0x00000001 /* do not dump file */
|
||||
UF_IMMUTABLE uint32 = 0x00000002 /* file may not be changed */
|
||||
UF_APPEND uint32 = 0x00000004 /* writes to file may only append */
|
||||
UF_OPAQUE uint32 = 0x00000008 /* directory is opaque wrt. union */
|
||||
UF_NOUNLINK uint32 = 0x00000010 /* file may not be removed or renamed */
|
||||
|
||||
UF_SYSTEM uint32 = 0x00000080 /* Windows system file bit */
|
||||
UF_SPARSE uint32 = 0x00000100 /* sparse file */
|
||||
UF_OFFLINE uint32 = 0x00000200 /* file is offline */
|
||||
UF_REPARSE uint32 = 0x00000400 /* Windows reparse point file bit */
|
||||
UF_ARCHIVE uint32 = 0x00000800 /* file needs to be archived */
|
||||
UF_READONLY uint32 = 0x00001000 /* Windows readonly file bit */
|
||||
/* This is the same as the MacOS X definition of UF_HIDDEN. */
|
||||
UF_HIDDEN uint32 = 0x00008000 /* file is hidden */
|
||||
|
||||
/*
|
||||
* Super-user changeable flags.
|
||||
*/
|
||||
SF_SETTABLE uint32 = 0xffff0000 /* mask of superuser changeable flags */
|
||||
SF_ARCHIVED uint32 = 0x00010000 /* file is archived */
|
||||
SF_IMMUTABLE uint32 = 0x00020000 /* file may not be changed */
|
||||
SF_APPEND uint32 = 0x00040000 /* writes to file may only append */
|
||||
SF_NOUNLINK uint32 = 0x00100000 /* file may not be removed or renamed */
|
||||
SF_SNAPSHOT uint32 = 0x00200000 /* snapshot inode */
|
||||
)
|
||||
|
||||
func Lchflags(path string, flags uint32) error {
|
||||
p, err := unix.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, e1 := unix.Syscall(unix.SYS_LCHFLAGS, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
|
||||
if e1 != 0 {
|
||||
return e1
|
||||
}
|
||||
return nil
|
||||
}
|
||||
1
vendor/github.com/containers/storage/pkg/system/lcow_unix.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/lcow_unix.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package system
|
||||
|
|
|
|||
3
vendor/github.com/containers/storage/pkg/system/lstat_unix.go
generated
vendored
3
vendor/github.com/containers/storage/pkg/system/lstat_unix.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package system
|
||||
|
|
@ -14,7 +15,7 @@ import (
|
|||
func Lstat(path string) (*StatT, error) {
|
||||
s := &syscall.Stat_t{}
|
||||
if err := syscall.Lstat(path, s); err != nil {
|
||||
return nil, &os.PathError{"Lstat", path, err}
|
||||
return nil, &os.PathError{Op: "Lstat", Path: path, Err: err}
|
||||
}
|
||||
return fromStatT(s)
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/containers/storage/pkg/system/meminfo_freebsd.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/system/meminfo_freebsd.go
generated
vendored
|
|
@ -4,6 +4,7 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
|
|
@ -58,7 +59,8 @@ func getSwapInfo() (int64, int64, error) {
|
|||
}
|
||||
|
||||
// ReadMemInfo retrieves memory statistics of the host system and returns a
|
||||
// MemInfo type.
|
||||
//
|
||||
// MemInfo type.
|
||||
func ReadMemInfo() (*MemInfo, error) {
|
||||
MemTotal, MemFree, err := getMemInfo()
|
||||
if err != nil {
|
||||
|
|
@ -70,7 +72,7 @@ func ReadMemInfo() (*MemInfo, error) {
|
|||
}
|
||||
|
||||
if MemTotal < 0 || MemFree < 0 || SwapTotal < 0 || SwapFree < 0 {
|
||||
return nil, fmt.Errorf("getting system memory info %w", err)
|
||||
return nil, errors.New("getting system memory info")
|
||||
}
|
||||
|
||||
meminfo := &MemInfo{}
|
||||
|
|
|
|||
4
vendor/github.com/containers/storage/pkg/system/meminfo_solaris.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/system/meminfo_solaris.go
generated
vendored
|
|
@ -81,9 +81,9 @@ func getFreeMem() int64 {
|
|||
}
|
||||
|
||||
// ReadMemInfo retrieves memory statistics of the host system and returns a
|
||||
// MemInfo type.
|
||||
//
|
||||
// MemInfo type.
|
||||
func ReadMemInfo() (*MemInfo, error) {
|
||||
|
||||
ppKernel := C.getPpKernel()
|
||||
MemTotal := getTotalMem()
|
||||
MemFree := getFreeMem()
|
||||
|
|
|
|||
3
vendor/github.com/containers/storage/pkg/system/meminfo_windows.go
generated
vendored
3
vendor/github.com/containers/storage/pkg/system/meminfo_windows.go
generated
vendored
|
|
@ -27,7 +27,8 @@ type memorystatusex struct {
|
|||
}
|
||||
|
||||
// ReadMemInfo retrieves memory statistics of the host system and returns a
|
||||
// MemInfo type.
|
||||
//
|
||||
// MemInfo type.
|
||||
func ReadMemInfo() (*MemInfo, error) {
|
||||
msi := &memorystatusex{
|
||||
dwLength: 64,
|
||||
|
|
|
|||
5
vendor/github.com/containers/storage/pkg/system/mknod.go
generated
vendored
5
vendor/github.com/containers/storage/pkg/system/mknod.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows && !freebsd
|
||||
// +build !windows,!freebsd
|
||||
|
||||
package system
|
||||
|
|
@ -8,8 +9,8 @@ import (
|
|||
|
||||
// Mknod creates a filesystem node (file, device special file or named pipe) named path
|
||||
// with attributes specified by mode and dev.
|
||||
func Mknod(path string, mode uint32, dev int) error {
|
||||
return unix.Mknod(path, mode, dev)
|
||||
func Mknod(path string, mode uint32, dev uint32) error {
|
||||
return unix.Mknod(path, mode, int(dev))
|
||||
}
|
||||
|
||||
// Mkdev is used to build the value of linux devices (in /dev/) which specifies major
|
||||
|
|
|
|||
5
vendor/github.com/containers/storage/pkg/system/mknod_freebsd.go
generated
vendored
5
vendor/github.com/containers/storage/pkg/system/mknod_freebsd.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build freebsd
|
||||
// +build freebsd
|
||||
|
||||
package system
|
||||
|
|
@ -17,6 +18,6 @@ func Mknod(path string, mode uint32, dev uint64) error {
|
|||
// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes.
|
||||
// They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major,
|
||||
// then the top 12 bits of the minor.
|
||||
func Mkdev(major int64, minor int64) uint32 {
|
||||
return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
|
||||
func Mkdev(major int64, minor int64) uint64 {
|
||||
return uint64(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
|
||||
}
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/system/mknod_windows.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/mknod_windows.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package system
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/system/path.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/path.go
generated
vendored
|
|
@ -17,5 +17,4 @@ func DefaultPathEnv(platform string) string {
|
|||
return ""
|
||||
}
|
||||
return defaultUnixPathEnv
|
||||
|
||||
}
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/system/path_unix.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/path_unix.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package system
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/system/process_unix.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/process_unix.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build linux || freebsd || solaris || darwin
|
||||
// +build linux freebsd solaris darwin
|
||||
|
||||
package system
|
||||
|
|
|
|||
22
vendor/github.com/containers/storage/pkg/system/rm.go
generated
vendored
22
vendor/github.com/containers/storage/pkg/system/rm.go
generated
vendored
|
|
@ -1,6 +1,7 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
|
@ -29,6 +30,12 @@ func EnsureRemoveAll(dir string) error {
|
|||
exitOnErr := make(map[string]int)
|
||||
maxRetry := 100
|
||||
|
||||
// Attempt a simple remove all first, this avoids the more expensive
|
||||
// RecursiveUnmount call if not needed.
|
||||
if err := os.RemoveAll(dir); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Attempt to unmount anything beneath this dir first
|
||||
if err := mount.RecursiveUnmount(dir); err != nil {
|
||||
logrus.Debugf("RecusiveUnmount on %s failed: %v", dir, err)
|
||||
|
|
@ -40,6 +47,19 @@ func EnsureRemoveAll(dir string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// If the RemoveAll fails with a permission error, we
|
||||
// may have immutable files so try to remove the
|
||||
// immutable flag and redo the RemoveAll.
|
||||
if errors.Is(err, syscall.EPERM) {
|
||||
if err = resetFileFlags(dir); err != nil {
|
||||
return fmt.Errorf("resetting file flags: %w", err)
|
||||
}
|
||||
err = os.RemoveAll(dir)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
pe, ok := err.(*os.PathError)
|
||||
if !ok {
|
||||
return err
|
||||
|
|
@ -62,7 +82,7 @@ func EnsureRemoveAll(dir string) error {
|
|||
continue
|
||||
}
|
||||
|
||||
if pe.Err != syscall.EBUSY {
|
||||
if !IsEBUSY(pe.Err) {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
10
vendor/github.com/containers/storage/pkg/system/rm_common.go
generated
vendored
Normal file
10
vendor/github.com/containers/storage/pkg/system/rm_common.go
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
//go:build !freebsd
|
||||
// +build !freebsd
|
||||
|
||||
package system
|
||||
|
||||
// Reset file flags in a directory tree. This allows EnsureRemoveAll
|
||||
// to delete trees which have the immutable flag set.
|
||||
func resetFileFlags(dir string) error {
|
||||
return nil
|
||||
}
|
||||
17
vendor/github.com/containers/storage/pkg/system/rm_freebsd.go
generated
vendored
Normal file
17
vendor/github.com/containers/storage/pkg/system/rm_freebsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Reset file flags in a directory tree. This allows EnsureRemoveAll
|
||||
// to delete trees which have the immutable flag set.
|
||||
func resetFileFlags(dir string) error {
|
||||
return filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err := Lchflags(path, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
12
vendor/github.com/containers/storage/pkg/system/stat_common.go
generated
vendored
Normal file
12
vendor/github.com/containers/storage/pkg/system/stat_common.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
//go:build !freebsd
|
||||
// +build !freebsd
|
||||
|
||||
package system
|
||||
|
||||
type platformStatT struct{}
|
||||
|
||||
// Flags return file flags if supported or zero otherwise
|
||||
func (s StatT) Flags() uint32 {
|
||||
_ = s.platformStatT // Silence warnings that StatT.platformStatT is unused (on these platforms)
|
||||
return 0
|
||||
}
|
||||
6
vendor/github.com/containers/storage/pkg/system/stat_darwin.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/system/stat_darwin.go
generated
vendored
|
|
@ -4,10 +4,12 @@ import "syscall"
|
|||
|
||||
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
||||
return &StatT{size: s.Size,
|
||||
return &StatT{
|
||||
size: s.Size,
|
||||
mode: uint32(s.Mode),
|
||||
uid: s.Uid,
|
||||
gid: s.Gid,
|
||||
rdev: uint64(s.Rdev),
|
||||
mtim: s.Mtimespec}, nil
|
||||
mtim: s.Mtimespec,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
19
vendor/github.com/containers/storage/pkg/system/stat_freebsd.go
generated
vendored
19
vendor/github.com/containers/storage/pkg/system/stat_freebsd.go
generated
vendored
|
|
@ -2,12 +2,27 @@ package system
|
|||
|
||||
import "syscall"
|
||||
|
||||
type platformStatT struct {
|
||||
flags uint32
|
||||
}
|
||||
|
||||
// Flags return file flags if supported or zero otherwise
|
||||
func (s StatT) Flags() uint32 {
|
||||
return s.flags
|
||||
}
|
||||
|
||||
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
||||
return &StatT{size: s.Size,
|
||||
st := &StatT{
|
||||
size: s.Size,
|
||||
mode: uint32(s.Mode),
|
||||
uid: s.Uid,
|
||||
gid: s.Gid,
|
||||
rdev: uint64(s.Rdev),
|
||||
mtim: s.Mtimespec}, nil
|
||||
mtim: s.Mtimespec,
|
||||
dev: s.Dev,
|
||||
}
|
||||
st.flags = s.Flags
|
||||
st.dev = s.Dev
|
||||
return st, nil
|
||||
}
|
||||
|
|
|
|||
7
vendor/github.com/containers/storage/pkg/system/stat_linux.go
generated
vendored
7
vendor/github.com/containers/storage/pkg/system/stat_linux.go
generated
vendored
|
|
@ -4,12 +4,15 @@ import "syscall"
|
|||
|
||||
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
||||
return &StatT{size: s.Size,
|
||||
return &StatT{
|
||||
size: s.Size,
|
||||
mode: s.Mode,
|
||||
uid: s.Uid,
|
||||
gid: s.Gid,
|
||||
rdev: uint64(s.Rdev),
|
||||
mtim: s.Mtim}, nil
|
||||
mtim: s.Mtim,
|
||||
dev: uint64(s.Dev),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
||||
|
|
|
|||
6
vendor/github.com/containers/storage/pkg/system/stat_openbsd.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/system/stat_openbsd.go
generated
vendored
|
|
@ -4,10 +4,12 @@ import "syscall"
|
|||
|
||||
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
||||
return &StatT{size: s.Size,
|
||||
return &StatT{
|
||||
size: s.Size,
|
||||
mode: uint32(s.Mode),
|
||||
uid: s.Uid,
|
||||
gid: s.Gid,
|
||||
rdev: uint64(s.Rdev),
|
||||
mtim: s.Mtim}, nil
|
||||
mtim: s.Mtim,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/containers/storage/pkg/system/stat_solaris.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/system/stat_solaris.go
generated
vendored
|
|
@ -4,10 +4,12 @@ import "syscall"
|
|||
|
||||
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
||||
return &StatT{size: s.Size,
|
||||
return &StatT{
|
||||
size: s.Size,
|
||||
mode: uint32(s.Mode),
|
||||
uid: s.Uid,
|
||||
gid: s.Gid,
|
||||
rdev: uint64(s.Rdev),
|
||||
mtim: s.Mtim}, nil
|
||||
mtim: s.Mtim,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
8
vendor/github.com/containers/storage/pkg/system/stat_unix.go
generated
vendored
8
vendor/github.com/containers/storage/pkg/system/stat_unix.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package system
|
||||
|
|
@ -17,6 +18,8 @@ type StatT struct {
|
|||
rdev uint64
|
||||
size int64
|
||||
mtim syscall.Timespec
|
||||
dev uint64
|
||||
platformStatT
|
||||
}
|
||||
|
||||
// Mode returns file's permission mode.
|
||||
|
|
@ -49,6 +52,11 @@ func (s StatT) Mtim() syscall.Timespec {
|
|||
return s.mtim
|
||||
}
|
||||
|
||||
// Dev returns a unique identifier for owning filesystem
|
||||
func (s StatT) Dev() uint64 {
|
||||
return s.dev
|
||||
}
|
||||
|
||||
// Stat takes a path to a file and returns
|
||||
// a system.StatT type pertaining to that file.
|
||||
//
|
||||
|
|
|
|||
9
vendor/github.com/containers/storage/pkg/system/stat_windows.go
generated
vendored
9
vendor/github.com/containers/storage/pkg/system/stat_windows.go
generated
vendored
|
|
@ -11,6 +11,7 @@ type StatT struct {
|
|||
mode os.FileMode
|
||||
size int64
|
||||
mtim time.Time
|
||||
platformStatT
|
||||
}
|
||||
|
||||
// Size returns file's size.
|
||||
|
|
@ -42,6 +43,11 @@ func (s StatT) GID() uint32 {
|
|||
return 0
|
||||
}
|
||||
|
||||
// Dev returns a unique identifier for owning filesystem
|
||||
func (s StatT) Dev() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Stat takes a path to a file and returns
|
||||
// a system.StatT type pertaining to that file.
|
||||
//
|
||||
|
|
@ -59,5 +65,6 @@ func fromStatT(fi *os.FileInfo) (*StatT, error) {
|
|||
return &StatT{
|
||||
size: (*fi).Size(),
|
||||
mode: (*fi).Mode(),
|
||||
mtim: (*fi).ModTime()}, nil
|
||||
mtim: (*fi).ModTime(),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/system/umask.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/umask.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package system
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/system/umask_windows.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/umask_windows.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package system
|
||||
|
|
|
|||
5
vendor/github.com/containers/storage/pkg/system/utimes_freebsd.go
generated
vendored
5
vendor/github.com/containers/storage/pkg/system/utimes_freebsd.go
generated
vendored
|
|
@ -10,13 +10,14 @@ import (
|
|||
// LUtimesNano is used to change access and modification time of the specified path.
|
||||
// It's used for symbol link file because unix.UtimesNano doesn't support a NOFOLLOW flag atm.
|
||||
func LUtimesNano(path string, ts []syscall.Timespec) error {
|
||||
atFdCwd := unix.AT_FDCWD
|
||||
|
||||
var _path *byte
|
||||
_path, err := unix.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, _, err := unix.Syscall(unix.SYS_LUTIMES, uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), 0); err != 0 && err != unix.ENOSYS {
|
||||
if _, _, err := unix.Syscall6(unix.SYS_UTIMENSAT, uintptr(atFdCwd), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), unix.AT_SYMLINK_NOFOLLOW, 0, 0); err != 0 && err != unix.ENOSYS {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/system/utimes_unsupported.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/utimes_unsupported.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !linux && !freebsd
|
||||
// +build !linux,!freebsd
|
||||
|
||||
package system
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/system/xattrs_unsupported.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/system/xattrs_unsupported.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !linux && !darwin
|
||||
// +build !linux,!darwin
|
||||
|
||||
package system
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/unshare/getenv_linux_cgo.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/unshare/getenv_linux_cgo.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build linux && cgo
|
||||
// +build linux,cgo
|
||||
|
||||
package unshare
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/unshare/getenv_linux_nocgo.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/unshare/getenv_linux_nocgo.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build linux && !cgo
|
||||
// +build linux,!cgo
|
||||
|
||||
package unshare
|
||||
|
|
|
|||
17
vendor/github.com/containers/storage/pkg/unshare/unshare.go
generated
vendored
17
vendor/github.com/containers/storage/pkg/unshare/unshare.go
generated
vendored
|
|
@ -5,18 +5,12 @@ import (
|
|||
"os"
|
||||
"os/user"
|
||||
"sync"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
homeDirOnce sync.Once
|
||||
homeDirErr error
|
||||
homeDir string
|
||||
|
||||
hasCapSysAdminOnce sync.Once
|
||||
hasCapSysAdminRet bool
|
||||
hasCapSysAdminErr error
|
||||
)
|
||||
|
||||
// HomeDir returns the home directory for the current user.
|
||||
|
|
@ -36,14 +30,3 @@ func HomeDir() (string, error) {
|
|||
})
|
||||
return homeDir, homeDirErr
|
||||
}
|
||||
|
||||
func bailOnError(err error, format string, a ...interface{}) { // nolint: golint,goprintffuncname
|
||||
if err != nil {
|
||||
if format != "" {
|
||||
logrus.Errorf("%s: %v", fmt.Sprintf(format, a...), err)
|
||||
} else {
|
||||
logrus.Errorf("%v", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/containers/storage/pkg/unshare/unshare_cgo.go
generated
vendored
2
vendor/github.com/containers/storage/pkg/unshare/unshare_cgo.go
generated
vendored
|
|
@ -5,7 +5,7 @@ package unshare
|
|||
|
||||
// #cgo CFLAGS: -Wall
|
||||
// extern void _containers_unshare(void);
|
||||
// void __attribute__((constructor)) init(void) {
|
||||
// static void __attribute__((constructor)) init(void) {
|
||||
// _containers_unshare();
|
||||
// }
|
||||
import "C"
|
||||
|
|
|
|||
1
vendor/github.com/containers/storage/pkg/unshare/unshare_darwin.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/unshare/unshare_darwin.go
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package unshare
|
||||
|
|
|
|||
2
vendor/github.com/containers/storage/pkg/unshare/unshare_freebsd.go
generated
vendored
2
vendor/github.com/containers/storage/pkg/unshare/unshare_freebsd.go
generated
vendored
|
|
@ -59,7 +59,7 @@ func (c *Cmd) Start() error {
|
|||
if err != nil {
|
||||
pidRead.Close()
|
||||
pidWrite.Close()
|
||||
return fmt.Errorf("creating pid pipe: %w", err)
|
||||
return fmt.Errorf("creating continue read/write pipe: %w", err)
|
||||
}
|
||||
c.Env = append(c.Env, fmt.Sprintf("_Containers-continue-pipe=%d", len(c.ExtraFiles)+3))
|
||||
c.ExtraFiles = append(c.ExtraFiles, continueRead)
|
||||
|
|
|
|||
3
vendor/github.com/containers/storage/pkg/unshare/unshare_gccgo.go
generated
vendored
3
vendor/github.com/containers/storage/pkg/unshare/unshare_gccgo.go
generated
vendored
|
|
@ -1,10 +1,11 @@
|
|||
//go:build linux && cgo && gccgo
|
||||
// +build linux,cgo,gccgo
|
||||
|
||||
package unshare
|
||||
|
||||
// #cgo CFLAGS: -Wall -Wextra
|
||||
// extern void _containers_unshare(void);
|
||||
// void __attribute__((constructor)) init(void) {
|
||||
// static void __attribute__((constructor)) init(void) {
|
||||
// _containers_unshare();
|
||||
// }
|
||||
import "C"
|
||||
|
|
|
|||
59
vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go
generated
vendored
59
vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go
generated
vendored
|
|
@ -33,9 +33,9 @@ type Cmd struct {
|
|||
*exec.Cmd
|
||||
UnshareFlags int
|
||||
UseNewuidmap bool
|
||||
UidMappings []specs.LinuxIDMapping // nolint: golint
|
||||
UidMappings []specs.LinuxIDMapping // nolint: revive,golint
|
||||
UseNewgidmap bool
|
||||
GidMappings []specs.LinuxIDMapping // nolint: golint
|
||||
GidMappings []specs.LinuxIDMapping // nolint: revive,golint
|
||||
GidMappingsEnableSetgroups bool
|
||||
Setsid bool
|
||||
Setpgrp bool
|
||||
|
|
@ -129,7 +129,7 @@ func (c *Cmd) Start() error {
|
|||
if err != nil {
|
||||
pidRead.Close()
|
||||
pidWrite.Close()
|
||||
return fmt.Errorf("creating pid pipe: %w", err)
|
||||
return fmt.Errorf("creating continue read/write pipe: %w", err)
|
||||
}
|
||||
c.Env = append(c.Env, fmt.Sprintf("_Containers-continue-pipe=%d", len(c.ExtraFiles)+3))
|
||||
c.ExtraFiles = append(c.ExtraFiles, continueRead)
|
||||
|
|
@ -175,12 +175,11 @@ func (c *Cmd) Start() error {
|
|||
pidWrite = nil
|
||||
|
||||
// Read the child's PID from the pipe.
|
||||
pidString := ""
|
||||
b := new(bytes.Buffer)
|
||||
if _, err := io.Copy(b, pidRead); err != nil {
|
||||
return fmt.Errorf("reading child PID: %w", err)
|
||||
}
|
||||
pidString = b.String()
|
||||
pidString := b.String()
|
||||
pid, err := strconv.Atoi(pidString)
|
||||
if err != nil {
|
||||
fmt.Fprintf(continueWrite, "error parsing PID %q: %v", pidString, err)
|
||||
|
|
@ -387,10 +386,47 @@ const (
|
|||
UsernsEnvName = "_CONTAINERS_USERNS_CONFIGURED"
|
||||
)
|
||||
|
||||
// hasFullUsersMappings checks whether the current user namespace has all the IDs mapped.
|
||||
func hasFullUsersMappings() (bool, error) {
|
||||
content, err := os.ReadFile("/proc/self/uid_map")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// The kernel rejects attempts to create mappings where either starting
|
||||
// point is (u32)-1: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/user_namespace.c?id=af3e9579ecfb#n1006 .
|
||||
// So, if the uid_map contains 4294967295, the entire IDs space is available in the
|
||||
// user namespace, so it is likely the initial user namespace.
|
||||
return bytes.Contains(content, []byte("4294967295")), nil
|
||||
}
|
||||
|
||||
var (
|
||||
hasCapSysAdminOnce sync.Once
|
||||
hasCapSysAdminRet bool
|
||||
hasCapSysAdminErr error
|
||||
)
|
||||
|
||||
// IsRootless tells us if we are running in rootless mode
|
||||
func IsRootless() bool {
|
||||
isRootlessOnce.Do(func() {
|
||||
isRootless = getRootlessUID() != 0 || getenv(UsernsEnvName) != ""
|
||||
if !isRootless {
|
||||
hasCapSysAdmin, err := HasCapSysAdmin()
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to read CAP_SYS_ADMIN presence for the current process")
|
||||
}
|
||||
if err == nil && !hasCapSysAdmin {
|
||||
isRootless = true
|
||||
}
|
||||
}
|
||||
if !isRootless {
|
||||
hasMappings, err := hasFullUsersMappings()
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to read current user namespace mappings")
|
||||
}
|
||||
if err == nil && !hasMappings {
|
||||
isRootless = true
|
||||
}
|
||||
}
|
||||
})
|
||||
return isRootless
|
||||
}
|
||||
|
|
@ -414,10 +450,21 @@ type Runnable interface {
|
|||
Run() error
|
||||
}
|
||||
|
||||
func bailOnError(err error, format string, a ...interface{}) { // nolint: revive,goprintffuncname
|
||||
if err != nil {
|
||||
if format != "" {
|
||||
logrus.Errorf("%s: %v", fmt.Sprintf(format, a...), err)
|
||||
} else {
|
||||
logrus.Errorf("%v", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// MaybeReexecUsingUserNamespace re-exec the process in a new namespace
|
||||
func MaybeReexecUsingUserNamespace(evenForRoot bool) {
|
||||
// If we've already been through this once, no need to try again.
|
||||
if os.Geteuid() == 0 && IsRootless() {
|
||||
if os.Geteuid() == 0 && GetRootlessUID() > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue