github.com/cdoern/storage@v1.12.13/pkg/archive/archive_unix.go (about) 1 // +build !windows 2 3 package archive 4 5 import ( 6 "archive/tar" 7 "errors" 8 "os" 9 "path/filepath" 10 "syscall" 11 12 "github.com/containers/storage/pkg/idtools" 13 "github.com/containers/storage/pkg/system" 14 rsystem "github.com/opencontainers/runc/libcontainer/system" 15 "golang.org/x/sys/unix" 16 ) 17 18 // fixVolumePathPrefix does platform specific processing to ensure that if 19 // the path being passed in is not in a volume path format, convert it to one. 20 func fixVolumePathPrefix(srcPath string) string { 21 return srcPath 22 } 23 24 // getWalkRoot calculates the root path when performing a TarWithOptions. 25 // We use a separate function as this is platform specific. On Linux, we 26 // can't use filepath.Join(srcPath,include) because this will clean away 27 // a trailing "." or "/" which may be important. 28 func getWalkRoot(srcPath string, include string) string { 29 return srcPath + string(filepath.Separator) + include 30 } 31 32 // CanonicalTarNameForPath returns platform-specific filepath 33 // to canonical posix-style path for tar archival. p is relative 34 // path. 35 func CanonicalTarNameForPath(p string) (string, error) { 36 return p, nil // already unix-style 37 } 38 39 // chmodTarEntry is used to adjust the file permissions used in tar header based 40 // on the platform the archival is done. 41 42 func chmodTarEntry(perm os.FileMode) os.FileMode { 43 return perm // noop for unix as golang APIs provide perm bits correctly 44 } 45 46 func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (err error) { 47 s, ok := stat.(*syscall.Stat_t) 48 49 if ok { 50 // Currently go does not fill in the major/minors 51 if s.Mode&unix.S_IFBLK != 0 || 52 s.Mode&unix.S_IFCHR != 0 { 53 hdr.Devmajor = int64(major(uint64(s.Rdev))) // nolint: unconvert 54 hdr.Devminor = int64(minor(uint64(s.Rdev))) // nolint: unconvert 55 } 56 } 57 58 return 59 } 60 61 func getInodeFromStat(stat interface{}) (inode uint64, err error) { 62 s, ok := stat.(*syscall.Stat_t) 63 64 if ok { 65 inode = s.Ino 66 } 67 68 return 69 } 70 71 func getFileUIDGID(stat interface{}) (idtools.IDPair, error) { 72 s, ok := stat.(*syscall.Stat_t) 73 74 if !ok { 75 return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t") 76 } 77 return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil 78 } 79 80 func major(device uint64) uint64 { 81 return (device >> 8) & 0xfff 82 } 83 84 func minor(device uint64) uint64 { 85 return (device & 0xff) | ((device >> 12) & 0xfff00) 86 } 87 88 // handleTarTypeBlockCharFifo is an OS-specific helper function used by 89 // createTarFile to handle the following types of header: Block; Char; Fifo 90 func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error { 91 if rsystem.RunningInUserNS() { 92 // cannot create a device if running in user namespace 93 return nil 94 } 95 96 mode := uint32(hdr.Mode & 07777) 97 switch hdr.Typeflag { 98 case tar.TypeBlock: 99 mode |= unix.S_IFBLK 100 case tar.TypeChar: 101 mode |= unix.S_IFCHR 102 case tar.TypeFifo: 103 mode |= unix.S_IFIFO 104 } 105 106 return system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor))) 107 } 108 109 func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { 110 if hdr.Typeflag == tar.TypeLink { 111 if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) { 112 if err := os.Chmod(path, hdrInfo.Mode()); err != nil { 113 return err 114 } 115 } 116 } else if hdr.Typeflag != tar.TypeSymlink { 117 if err := os.Chmod(path, hdrInfo.Mode()); err != nil { 118 return err 119 } 120 } 121 return nil 122 }