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  }