github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/pkg/fileutil/fileutil_linux.go (about) 1 // Copyright 2014 Red Hat, Inc 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build linux 16 17 package fileutil 18 19 import ( 20 "fmt" 21 "os" 22 "syscall" 23 "unsafe" 24 ) 25 26 func hasHardLinks(fi os.FileInfo) bool { 27 // On directories, Nlink doesn't make sense when checking for hard links 28 return !fi.IsDir() && fi.Sys().(*syscall.Stat_t).Nlink > 1 29 } 30 31 func getInode(fi os.FileInfo) uint64 { 32 return fi.Sys().(*syscall.Stat_t).Ino 33 } 34 35 // These functions are from github.com/docker/docker/pkg/system 36 37 // TODO(sgotti) waiting for a utimensat functions accepting flags and a 38 // LUtimesNano using it in https://github.com/golang/sys/ 39 func LUtimesNano(path string, ts []syscall.Timespec) error { 40 // These are not currently available in syscall 41 AT_FDCWD := -100 42 AT_SYMLINK_NOFOLLOW := 0x100 43 44 var _path *byte 45 _path, err := syscall.BytePtrFromString(path) 46 if err != nil { 47 return err 48 } 49 50 if _, _, err := syscall.Syscall6(syscall.SYS_UTIMENSAT, uintptr(AT_FDCWD), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), uintptr(AT_SYMLINK_NOFOLLOW), 0, 0); err != 0 && err != syscall.ENOSYS { 51 return err 52 } 53 54 return nil 55 } 56 57 // Returns a nil slice and nil error if the xattr is not set 58 func Lgetxattr(path string, attr string) ([]byte, error) { 59 pathBytes, err := syscall.BytePtrFromString(path) 60 if err != nil { 61 return nil, err 62 } 63 attrBytes, err := syscall.BytePtrFromString(attr) 64 if err != nil { 65 return nil, err 66 } 67 68 dest := make([]byte, 128) 69 destBytes := unsafe.Pointer(&dest[0]) 70 sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) 71 if errno == syscall.ENODATA { 72 return nil, nil 73 } 74 if errno == syscall.ERANGE { 75 dest = make([]byte, sz) 76 destBytes := unsafe.Pointer(&dest[0]) 77 sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) 78 } 79 if errno != 0 { 80 return nil, errno 81 } 82 83 return dest[:sz], nil 84 } 85 86 var _zero uintptr 87 88 func Lsetxattr(path string, attr string, data []byte, flags int) error { 89 pathBytes, err := syscall.BytePtrFromString(path) 90 if err != nil { 91 return err 92 } 93 attrBytes, err := syscall.BytePtrFromString(attr) 94 if err != nil { 95 return err 96 } 97 var dataBytes unsafe.Pointer 98 if len(data) > 0 { 99 dataBytes = unsafe.Pointer(&data[0]) 100 } else { 101 dataBytes = unsafe.Pointer(&_zero) 102 } 103 _, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0) 104 if errno != 0 { 105 return errno 106 } 107 return nil 108 } 109 110 // GetDeviceInfo returns the type, major, and minor numbers of a device. 111 // Kind is 'b' or 'c' for block and character devices, respectively. 112 // This does not follow symlinks. 113 func GetDeviceInfo(path string) (kind rune, major uint64, minor uint64, err error) { 114 d, err := os.Lstat(path) 115 if err != nil { 116 return 117 } 118 mode := d.Mode() 119 120 if mode&os.ModeDevice == 0 { 121 err = fmt.Errorf("not a device: %s", path) 122 return 123 } 124 stat_t, ok := d.Sys().(*syscall.Stat_t) 125 if !ok { 126 err = fmt.Errorf("cannot determine device number") 127 return 128 } 129 return getDeviceInfo(mode, stat_t.Rdev) 130 } 131 132 // Parse the device info out of the mode bits. Separate for testability. 133 func getDeviceInfo(mode os.FileMode, rdev uint64) (kind rune, major uint64, minor uint64, err error) { 134 kind = 'b' 135 136 if mode&os.ModeCharDevice != 0 { 137 kind = 'c' 138 } 139 140 major = (rdev >> 8) & 0xfff 141 minor = (rdev & 0xff) | ((rdev >> 12) & 0xfff00) 142 143 return 144 }