github.com/lalkh/containerd@v1.4.3/archive/tar_unix.go (about) 1 // +build !windows 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package archive 20 21 import ( 22 "archive/tar" 23 "os" 24 "strings" 25 "syscall" 26 27 "github.com/containerd/containerd/sys" 28 "github.com/containerd/continuity/fs" 29 "github.com/containerd/continuity/sysx" 30 "github.com/pkg/errors" 31 "golang.org/x/sys/unix" 32 ) 33 34 func tarName(p string) (string, error) { 35 return p, nil 36 } 37 38 func chmodTarEntry(perm os.FileMode) os.FileMode { 39 return perm 40 } 41 42 func setHeaderForSpecialDevice(hdr *tar.Header, name string, fi os.FileInfo) error { 43 s, ok := fi.Sys().(*syscall.Stat_t) 44 if !ok { 45 return errors.New("unsupported stat type") 46 } 47 48 // Rdev is int32 on darwin/bsd, int64 on linux/solaris 49 rdev := uint64(s.Rdev) // nolint: unconvert 50 51 // Currently go does not fill in the major/minors 52 if s.Mode&syscall.S_IFBLK != 0 || 53 s.Mode&syscall.S_IFCHR != 0 { 54 hdr.Devmajor = int64(unix.Major(rdev)) 55 hdr.Devminor = int64(unix.Minor(rdev)) 56 } 57 58 return nil 59 } 60 61 func open(p string) (*os.File, error) { 62 return os.Open(p) 63 } 64 65 func openFile(name string, flag int, perm os.FileMode) (*os.File, error) { 66 f, err := os.OpenFile(name, flag, perm) 67 if err != nil { 68 return nil, err 69 } 70 // Call chmod to avoid permission mask 71 if err := os.Chmod(name, perm); err != nil { 72 return nil, err 73 } 74 return f, err 75 } 76 77 func mkdir(path string, perm os.FileMode) error { 78 if err := os.Mkdir(path, perm); err != nil { 79 return err 80 } 81 // Only final created directory gets explicit permission 82 // call to avoid permission mask 83 return os.Chmod(path, perm) 84 } 85 86 func skipFile(hdr *tar.Header) bool { 87 switch hdr.Typeflag { 88 case tar.TypeBlock, tar.TypeChar: 89 // cannot create a device if running in user namespace 90 return sys.RunningInUserNS() 91 default: 92 return false 93 } 94 } 95 96 // handleTarTypeBlockCharFifo is an OS-specific helper function used by 97 // createTarFile to handle the following types of header: Block; Char; Fifo. 98 // This function must not be called for Block and Char when running in userns. 99 // (skipFile() should return true for them.) 100 func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error { 101 mode := uint32(hdr.Mode & 07777) 102 switch hdr.Typeflag { 103 case tar.TypeBlock: 104 mode |= unix.S_IFBLK 105 case tar.TypeChar: 106 mode |= unix.S_IFCHR 107 case tar.TypeFifo: 108 mode |= unix.S_IFIFO 109 } 110 111 return unix.Mknod(path, mode, int(unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor)))) 112 } 113 114 func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { 115 if hdr.Typeflag == tar.TypeLink { 116 if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) { 117 if err := os.Chmod(path, hdrInfo.Mode()); err != nil && !os.IsNotExist(err) { 118 return err 119 } 120 } 121 } else if hdr.Typeflag != tar.TypeSymlink { 122 if err := os.Chmod(path, hdrInfo.Mode()); err != nil { 123 return err 124 } 125 } 126 return nil 127 } 128 129 func getxattr(path, attr string) ([]byte, error) { 130 b, err := sysx.LGetxattr(path, attr) 131 if err == unix.ENOTSUP || err == sysx.ENODATA { 132 return nil, nil 133 } 134 return b, err 135 } 136 137 func setxattr(path, key, value string) error { 138 // Do not set trusted attributes 139 if strings.HasPrefix(key, "trusted.") { 140 return errors.Wrap(unix.ENOTSUP, "admin attributes from archive not supported") 141 } 142 return unix.Lsetxattr(path, key, []byte(value), 0) 143 } 144 145 func copyDirInfo(fi os.FileInfo, path string) error { 146 st := fi.Sys().(*syscall.Stat_t) 147 if err := os.Lchown(path, int(st.Uid), int(st.Gid)); err != nil { 148 if os.IsPermission(err) { 149 // Normally if uid/gid are the same this would be a no-op, but some 150 // filesystems may still return EPERM... for instance NFS does this. 151 // In such a case, this is not an error. 152 if dstStat, err2 := os.Lstat(path); err2 == nil { 153 st2 := dstStat.Sys().(*syscall.Stat_t) 154 if st.Uid == st2.Uid && st.Gid == st2.Gid { 155 err = nil 156 } 157 } 158 } 159 if err != nil { 160 return errors.Wrapf(err, "failed to chown %s", path) 161 } 162 } 163 164 if err := os.Chmod(path, fi.Mode()); err != nil { 165 return errors.Wrapf(err, "failed to chmod %s", path) 166 } 167 168 timespec := []unix.Timespec{ 169 unix.NsecToTimespec(syscall.TimespecToNsec(fs.StatAtime(st))), 170 unix.NsecToTimespec(syscall.TimespecToNsec(fs.StatMtime(st))), 171 } 172 if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil { 173 return errors.Wrapf(err, "failed to utime %s", path) 174 } 175 176 return nil 177 } 178 179 func copyUpXAttrs(dst, src string) error { 180 xattrKeys, err := sysx.LListxattr(src) 181 if err != nil { 182 if err == unix.ENOTSUP || err == sysx.ENODATA { 183 return nil 184 } 185 return errors.Wrapf(err, "failed to list xattrs on %s", src) 186 } 187 for _, xattr := range xattrKeys { 188 // Do not copy up trusted attributes 189 if strings.HasPrefix(xattr, "trusted.") { 190 continue 191 } 192 data, err := sysx.LGetxattr(src, xattr) 193 if err != nil { 194 if err == unix.ENOTSUP || err == sysx.ENODATA { 195 continue 196 } 197 return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) 198 } 199 if err := unix.Lsetxattr(dst, xattr, data, unix.XATTR_CREATE); err != nil { 200 if err == unix.ENOTSUP || err == unix.ENODATA || err == unix.EEXIST { 201 continue 202 } 203 return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) 204 } 205 } 206 207 return nil 208 }