github.com/moby/docker@v26.1.3+incompatible/pkg/archive/archive_unix.go (about) 1 //go:build !windows 2 3 package archive // import "github.com/docker/docker/pkg/archive" 4 5 import ( 6 "archive/tar" 7 "errors" 8 "os" 9 "path/filepath" 10 "runtime" 11 "strings" 12 "syscall" 13 14 "github.com/containerd/containerd/pkg/userns" 15 "github.com/docker/docker/pkg/idtools" 16 "github.com/docker/docker/pkg/system" 17 "golang.org/x/sys/unix" 18 ) 19 20 func init() { 21 sysStat = statUnix 22 } 23 24 // fixVolumePathPrefix does platform specific processing to ensure that if 25 // the path being passed in is not in a volume path format, convert it to one. 26 func fixVolumePathPrefix(srcPath string) string { 27 return srcPath 28 } 29 30 // getWalkRoot calculates the root path when performing a TarWithOptions. 31 // We use a separate function as this is platform specific. On Linux, we 32 // can't use filepath.Join(srcPath,include) because this will clean away 33 // a trailing "." or "/" which may be important. 34 func getWalkRoot(srcPath string, include string) string { 35 return strings.TrimSuffix(srcPath, string(filepath.Separator)) + string(filepath.Separator) + include 36 } 37 38 // chmodTarEntry is used to adjust the file permissions used in tar header based 39 // on the platform the archival is done. 40 func chmodTarEntry(perm os.FileMode) os.FileMode { 41 return perm // noop for unix as golang APIs provide perm bits correctly 42 } 43 44 // statUnix populates hdr from system-dependent fields of fi without performing 45 // any OS lookups. 46 func statUnix(fi os.FileInfo, hdr *tar.Header) error { 47 // Devmajor and Devminor are only needed for special devices. 48 49 // In FreeBSD, RDev for regular files is -1 (unless overridden by FS): 50 // https://cgit.freebsd.org/src/tree/sys/kern/vfs_default.c?h=stable/13#n1531 51 // (NODEV is -1: https://cgit.freebsd.org/src/tree/sys/sys/param.h?h=stable/13#n241). 52 53 // ZFS in particular does not override the default: 54 // https://cgit.freebsd.org/src/tree/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c?h=stable/13#n2027 55 56 // Since `Stat_t.Rdev` is uint64, the cast turns -1 into (2^64 - 1). 57 // Such large values cannot be encoded in a tar header. 58 if runtime.GOOS == "freebsd" && hdr.Typeflag != tar.TypeBlock && hdr.Typeflag != tar.TypeChar { 59 return nil 60 } 61 s, ok := fi.Sys().(*syscall.Stat_t) 62 if !ok { 63 return nil 64 } 65 66 hdr.Uid = int(s.Uid) 67 hdr.Gid = int(s.Gid) 68 69 if s.Mode&unix.S_IFBLK != 0 || 70 s.Mode&unix.S_IFCHR != 0 { 71 hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) //nolint: unconvert 72 hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) //nolint: unconvert 73 } 74 75 return nil 76 } 77 78 func getInodeFromStat(stat interface{}) (inode uint64, err error) { 79 s, ok := stat.(*syscall.Stat_t) 80 81 if ok { 82 inode = s.Ino 83 } 84 85 return 86 } 87 88 func getFileUIDGID(stat interface{}) (idtools.Identity, error) { 89 s, ok := stat.(*syscall.Stat_t) 90 91 if !ok { 92 return idtools.Identity{}, errors.New("cannot convert stat value to syscall.Stat_t") 93 } 94 return idtools.Identity{UID: int(s.Uid), GID: int(s.Gid)}, nil 95 } 96 97 // handleTarTypeBlockCharFifo is an OS-specific helper function used by 98 // createTarFile to handle the following types of header: Block; Char; Fifo 99 func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error { 100 mode := uint32(hdr.Mode & 0o7777) 101 switch hdr.Typeflag { 102 case tar.TypeBlock: 103 mode |= unix.S_IFBLK 104 case tar.TypeChar: 105 mode |= unix.S_IFCHR 106 case tar.TypeFifo: 107 mode |= unix.S_IFIFO 108 } 109 110 err := system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor))) 111 if errors.Is(err, syscall.EPERM) && userns.RunningInUserNS() { 112 // In most cases, cannot create a device if running in user namespace 113 err = nil 114 } 115 return err 116 } 117 118 func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { 119 if hdr.Typeflag == tar.TypeLink { 120 if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) { 121 if err := os.Chmod(path, hdrInfo.Mode()); err != nil { 122 return err 123 } 124 } 125 } else if hdr.Typeflag != tar.TypeSymlink { 126 if err := os.Chmod(path, hdrInfo.Mode()); err != nil { 127 return err 128 } 129 } 130 return nil 131 }