//go:build !openbsd && !plan9 // +build !openbsd,!plan9 package local import ( "fmt" "strings" "github.com/pkg/xattr" "github.com/rclone/rclone/fs" ) const ( xattrPrefix = "user." // FIXME is this correct for all unixes? xattrSupported = xattr.XATTR_SUPPORTED ) // getXattr returns the extended attributes for an object // // It doesn't return any attributes owned by this backend in // metadataKeys func (o *Object) getXattr() (metadata fs.Metadata, err error) { if !xattrSupported { return nil, nil } var list []string if o.fs.opt.FollowSymlinks { list, err = xattr.List(o.path) } else { list, err = xattr.LList(o.path) } if err != nil { return nil, fmt.Errorf("failed to read xattr: %w", err) } if len(list) == 0 { return nil, nil } metadata = make(fs.Metadata, len(list)) for _, k := range list { var v []byte if o.fs.opt.FollowSymlinks { v, err = xattr.Get(o.path, k) } else { v, err = xattr.LGet(o.path, k) } if err != nil { return nil, fmt.Errorf("failed to read xattr key %q: %w", k, err) } k = strings.ToLower(k) if !strings.HasPrefix(k, xattrPrefix) { continue } k = k[len(xattrPrefix):] if _, found := systemMetadataInfo[k]; found { continue } metadata[k] = string(v) } return metadata, nil } // setXattr sets the metadata on the file Xattrs // // It doesn't set any attributes owned by this backend in metadataKeys func (o *Object) setXattr(metadata fs.Metadata) (err error) { if !xattrSupported { return nil } for k, value := range metadata { k = strings.ToLower(k) if _, found := systemMetadataInfo[k]; found { continue } k = xattrPrefix + k v := []byte(value) if o.fs.opt.FollowSymlinks { err = xattr.Set(o.path, k, v) } else { err = xattr.LSet(o.path, k, v) } if err != nil { return fmt.Errorf("failed to set xattr key %q: %w", k, err) } } return nil }