github.com/dctrud/umoci@v0.4.3-0.20191016193643-05a1d37de015/pkg/system/xattr_linux.go (about) 1 /* 2 * umoci: Umoci Modifies Open Containers' Images 3 * Copyright (C) 2016, 2017, 2018 SUSE LLC. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package system 19 20 import ( 21 "bytes" 22 "os" 23 24 "github.com/pkg/errors" 25 "golang.org/x/sys/unix" 26 ) 27 28 // Llistxattr is a wrapper around unix.Llistattr, to abstract the NUL-splitting 29 // and resizing of the returned []string. 30 func Llistxattr(path string) ([]string, error) { 31 var buffer []byte 32 for { 33 // Find the size. 34 sz, err := unix.Llistxattr(path, nil) 35 if err != nil { 36 // Could not get the size. 37 return nil, err 38 } 39 buffer = make([]byte, sz) 40 41 // Get the buffer. 42 _, err = unix.Llistxattr(path, buffer) 43 if err != nil { 44 // If we got an ERANGE then we have to resize the buffer because 45 // someone raced with us getting the list. Don't you just love C 46 // interfaces. 47 if err == unix.ERANGE { 48 continue 49 } 50 return nil, err 51 } 52 53 break 54 } 55 56 // Split the buffer. 57 var xattrs []string 58 for _, name := range bytes.Split(buffer, []byte{'\x00'}) { 59 // "" is not a valid xattr (weirdly you get ERANGE -- not EINVAL -- if 60 // you try to touch it). So just skip it. 61 if len(name) == 0 { 62 continue 63 } 64 xattrs = append(xattrs, string(name)) 65 } 66 return xattrs, nil 67 } 68 69 // Lgetxattr is a wrapper around unix.Lgetattr, to abstract the resizing of the 70 // returned []string. 71 func Lgetxattr(path string, name string) ([]byte, error) { 72 var buffer []byte 73 for { 74 // Find the size. 75 sz, err := unix.Lgetxattr(path, name, nil) 76 if err != nil { 77 // Could not get the size. 78 return nil, err 79 } 80 buffer = make([]byte, sz) 81 82 // Get the buffer. 83 _, err = unix.Lgetxattr(path, name, buffer) 84 if err != nil { 85 // If we got an ERANGE then we have to resize the buffer because 86 // someone raced with us getting the list. Don't you just love C 87 // interfaces. 88 if err == unix.ERANGE { 89 continue 90 } 91 return nil, err 92 } 93 94 break 95 } 96 return buffer, nil 97 } 98 99 // Lclearxattrs is a wrapper around Llistxattr and Lremovexattr, which attempts 100 // to remove all xattrs from a given file. 101 func Lclearxattrs(path string, except map[string]struct{}) error { 102 names, err := Llistxattr(path) 103 if err != nil { 104 return errors.Wrap(err, "lclearxattrs: get list") 105 } 106 for _, name := range names { 107 if _, skip := except[name]; skip { 108 continue 109 } 110 if err := unix.Lremovexattr(path, name); err != nil { 111 // Ignore permission errors, because hitting a permission error 112 // means that it's a security.* xattr label or something similar. 113 if os.IsPermission(errors.Cause(err)) { 114 continue 115 } 116 return errors.Wrap(err, "lclearxattrs: remove xattr") 117 } 118 } 119 return nil 120 }