restic/vendor/src/github.com/ivaxer/go-xattr/xattr.go
2017-02-16 11:44:51 +01:00

171 lines
5.2 KiB
Go

// Package xattr provides a simple interface to user extended attributes on
// Linux and OSX. Support for xattrs is filesystem dependant, so not a given
// even if you are running one of those operating systems.
//
// On Linux you have to edit /etc/fstab to include "user_xattr". Also, on Linux
// user's extended attributes have a manditory prefix of "user.".
package xattr
import (
"os"
)
// IsNotExist returns a boolean indicating whether the error is known to report
// that an extended attribute does not exist.
func IsNotExist(err error) bool {
if e, ok := err.(*os.PathError); ok {
err = e.Err
}
return isNotExist(err)
}
// Converts an array of NUL terminated UTF-8 strings
// to a []string.
func nullTermToStrings(buf []byte) (result []string) {
offset := 0
for index, b := range buf {
if b == 0 {
result = append(result, string(buf[offset:index]))
offset = index + 1
}
}
return
}
// Getxattr retrieves value of the extended attribute identified by attr
// associated with given path in filesystem into buffer dest.
//
// On success, dest contains data associated with attr, retrieved value size sz
// and nil error are returned.
//
// On error, non-nil error is returned. Getxattr returns error if dest was too
// small for attribute value.
//
// A nil slice can be passed as dest to get current size of attribute value,
// which can be used to estimate dest length for value associated with attr.
//
// See getxattr(2) for more information.
//
// Get is high-level function on top of Getxattr. Getxattr more efficient,
// because it issues one syscall per call, doesn't allocate memory for
// attribute data (caller can reuse buffer).
func Getxattr(path, attr string, dest []byte) (sz int, err error) {
return get(path, attr, dest)
}
// Get retrieves extended attribute data associated with path. If there is an
// error, it will be of type *os.PathError.
//
// See Getxattr for low-level usage.
func Get(path, attr string) ([]byte, error) {
// find size
size, err := Getxattr(path, attr, nil)
if err != nil {
return nil, &os.PathError{"getxattr", path, err}
}
if size == 0 {
return []byte{}, nil
}
// read into buffer of that size
buf := make([]byte, size)
size, err = Getxattr(path, attr, buf)
if err != nil {
return nil, &os.PathError{"getxattr", path, err}
}
return buf[:size], nil
}
// Listxattr retrieves the list of extended attribute names associated with
// path. The list is set of NULL-terminated names.
//
// On success, dest containes list of NULL-terminated names, the length of the
// extended attribute list and nil error are returned.
//
// On error, non nil error is returned. Listxattr returns error if dest buffer
// was too small for extended attribute list.
//
// The list of names is returned as an unordered array of NULL-terminated
// character strings (attribute names are separated by NULL characters), like
// this:
// user.name1\0system.name1\0user.name2\0
//
// A nil slice can be passed as dest to get the current size of the list of
// extended attribute names, which can be used to estimate dest length for
// the list of names.
//
// See listxattr(2) for more information.
//
// List is high-level function on top of Listxattr.
func Listxattr(path string, dest []byte) (sz int, err error) {
return list(path, dest)
}
// List retrieves a list of names of extended attributes associated with path.
// If there is an error, it will be of type *os.PathError.
//
// See Listxattr for low-level usage.
func List(path string) ([]string, error) {
// find size
size, err := Listxattr(path, nil)
if err != nil {
return nil, &os.PathError{"listxattr", path, err}
}
if size == 0 {
return []string{}, nil
}
// read into buffer of that size
buf := make([]byte, size)
size, err = Listxattr(path, buf)
if err != nil {
return nil, &os.PathError{"listxattr", path, err}
}
return nullTermToStrings(buf[:size]), nil
}
// Setxattr sets value in data of extended attribute attr and accosiated with
// path.
//
// The flags refine the semantic of the operation. XATTR_CREATE specifies pure
// create, which fails if attr already exists. XATTR_REPLACE specifies a pure
// replace operation, which fails if the attr does not already exist. By
// default (no flags), the attr will be created if need be, or will simply
// replace the value if attr exists.
//
// On error, non nil error is returned.
//
// See setxattr(2) for more information.
func Setxattr(path, attr string, data []byte, flags int) error {
return set(path, attr, data, flags)
}
// Set associates data as an extended attribute of path. If there is an error,
// it will be of type *os.PathError.
//
// See Setxattr for low-level usage.
func Set(path, attr string, data []byte) error {
if err := Setxattr(path, attr, data, 0); err != nil {
return &os.PathError{"setxattr", path, err}
}
return nil
}
// Removexattr removes the extended attribute attr accosiated with path.
//
// On error, non-nil error is returned.
//
// See removexattr(2) for more information.
func Removexattr(path, attr string) error {
return remove(path, attr)
}
// Remove removes the extended attribute. If there is an error, it will be of
// type *os.PathError.
func Remove(path, attr string) error {
if err := Removexattr(path, attr); err != nil {
return &os.PathError{"removexattr", path, err}
}
return nil
}