pax_global_header00006660000000000000000000000064132437754660014533gustar00rootroot0000000000000052 comment=bc67bfc801466b4b8e62df951397972652fa8414 xattr-0.2.2/000077500000000000000000000000001324377546600126765ustar00rootroot00000000000000xattr-0.2.2/.gitignore000066400000000000000000000004241324377546600146660ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test .DS_Store # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.swp xattr-0.2.2/.travis.yml000066400000000000000000000005001324377546600150020ustar00rootroot00000000000000language: go sudo: false go: - 1.8 - tip os: - linux - osx install: - go version - export GOBIN="$GOPATH/bin" - export PATH="$PATH:$GOBIN" - go get golang.org/x/tools/cmd/goimports - go build script: - go vet - go test -v -race - diff <(GOPATH="$PWD:$PWD/vendor" goimports -d .) <(printf "") xattr-0.2.2/LICENSE000066400000000000000000000025051324377546600137050ustar00rootroot00000000000000Copyright (c) 2012 Dave Cheney. All rights reserved. Copyright (c) 2014 Kuba Podgórski. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. xattr-0.2.2/README.md000066400000000000000000000022471324377546600141620ustar00rootroot00000000000000[![GoDoc](https://godoc.org/github.com/pkg/xattr?status.svg)](http://godoc.org/github.com/pkg/xattr) [![Go Report Card](https://goreportcard.com/badge/github.com/pkg/xattr)](https://goreportcard.com/report/github.com/pkg/xattr) [![Build Status](https://travis-ci.org/pkg/xattr.svg?branch=master)](https://travis-ci.org/pkg/xattr) xattr ===== Extended attribute support for Go (linux + darwin + freebsd). "Extended attributes are name:value pairs associated permanently with files and directories, similar to the environment strings associated with a process. An attribute may be defined or undefined. If it is defined, its value may be empty or non-empty." [See more...](https://en.wikipedia.org/wiki/Extended_file_attributes) ### Example ``` const path = "/tmp/myfile" const prefix = "user." if err := xattr.Set(path, prefix+"test", []byte("test-attr-value")); err != nil { log.Fatal(err) } var list []string if list, err = xattr.List(path); err != nil { log.Fatal(err) } var data []byte if data, err = xattr.Get(path, prefix+"test"); err != nil { log.Fatal(err) } if err = xattr.Remove(path, prefix+"test"); err != nil { log.Fatal(err) } ``` xattr-0.2.2/go.mod000066400000000000000000000000361324377546600140030ustar00rootroot00000000000000module "github.com/pkg/xattr" xattr-0.2.2/syscall_darwin.go000066400000000000000000000027541324377546600162530ustar00rootroot00000000000000// +build darwin package xattr import ( "syscall" "unsafe" ) func getxattr(path string, name string, value *byte, size int, pos int, options int) (int, error) { r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), uintptr(unsafe.Pointer(value)), uintptr(size), uintptr(pos), uintptr(options)) if e1 != syscall.Errno(0) { return int(r0), e1 } return int(r0), nil } func listxattr(path string, namebuf *byte, size int, options int) (int, error) { r0, _, e1 := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), uintptr(unsafe.Pointer(namebuf)), uintptr(size), uintptr(options), 0, 0) if e1 != syscall.Errno(0) { return int(r0), e1 } return int(r0), nil } func setxattr(path string, name string, value *byte, size int, pos int, options int) error { if _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), uintptr(unsafe.Pointer(value)), uintptr(size), uintptr(pos), uintptr(options)); e1 != syscall.Errno(0) { return e1 } return nil } func removexattr(path string, name string, options int) error { if _, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), uintptr(options)); e1 != syscall.Errno(0) { return e1 } return nil } xattr-0.2.2/syscall_freebsd.go000066400000000000000000000041141324377546600163710ustar00rootroot00000000000000// +build freebsd package xattr import ( "syscall" "unsafe" ) /* ssize_t extattr_get_file(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); ssize_t extattr_set_file(const char *path, int attrnamespace, const char *attrname, const void *data, size_t nbytes); int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); ssize_t extattr_list_file(const char *path, int attrnamespace, void *data, size_t nbytes); */ func extattr_get_file(path string, attrnamespace int, attrname string, data *byte, nbytes int) (int, error) { r, _, e := syscall.Syscall6( syscall.SYS_EXTATTR_GET_FILE, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), uintptr(attrnamespace), uintptr(unsafe.Pointer(syscall.StringBytePtr(attrname))), uintptr(unsafe.Pointer(data)), uintptr(nbytes), 0, ) var err error if e != 0 { err = e } return int(r), err } func extattr_set_file(path string, attrnamespace int, attrname string, data *byte, nbytes int) (int, error) { r, _, e := syscall.Syscall6( syscall.SYS_EXTATTR_SET_FILE, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), uintptr(attrnamespace), uintptr(unsafe.Pointer(syscall.StringBytePtr(attrname))), uintptr(unsafe.Pointer(data)), uintptr(nbytes), 0, ) var err error if e != 0 { err = e } return int(r), err } func extattr_delete_file(path string, attrnamespace int, attrname string) error { _, _, e := syscall.Syscall( syscall.SYS_EXTATTR_DELETE_FILE, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), uintptr(attrnamespace), uintptr(unsafe.Pointer(syscall.StringBytePtr(attrname))), ) var err error if e != 0 { err = e } return err } func extattr_list_file(path string, attrnamespace int, data *byte, nbytes int) (int, error) { r, _, e := syscall.Syscall6( syscall.SYS_EXTATTR_LIST_FILE, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), uintptr(attrnamespace), uintptr(unsafe.Pointer(data)), uintptr(nbytes), 0, 0, ) var err error if e != 0 { err = e } return int(r), err } xattr-0.2.2/xattr.go000066400000000000000000000017441324377546600143750ustar00rootroot00000000000000/* Package xattr provides support for extended attributes on linux, darwin and freebsd. Extended attributes are name:value pairs associated permanently with files and directories, similar to the environment strings associated with a process. An attribute may be defined or undefined. If it is defined, its value may be empty or non-empty. More details you can find here: https://en.wikipedia.org/wiki/Extended_file_attributes */ package xattr // Error records an error and the operation, file path and attribute that caused it. type Error struct { Op string Path string Name string Err error } func (e *Error) Error() string { return e.Op + " " + e.Path + " " + e.Name + ": " + e.Err.Error() } // nullTermToStrings converts an array of NULL 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 } xattr-0.2.2/xattr_darwin.go000066400000000000000000000035251324377546600157400ustar00rootroot00000000000000// +build darwin package xattr import "syscall" // Get retrieves extended attribute data associated with path. func Get(path, name string) ([]byte, error) { // find size. size, err := getxattr(path, name, nil, 0, 0, 0) if err != nil { return nil, &Error{"xattr.Get", path, name, err} } if size > 0 { buf := make([]byte, size) // Read into buffer of that size. read, err := getxattr(path, name, &buf[0], size, 0, 0) if err != nil { return nil, &Error{"xattr.Get", path, name, err} } return buf[:read], nil } return []byte{}, nil } // List retrieves a list of names of extended attributes associated // with the given path in the file system. func List(path string) ([]string, error) { // find size. size, err := listxattr(path, nil, 0, 0) if err != nil { return nil, &Error{"xattr.List", path, "", err} } if size > 0 { buf := make([]byte, size) // Read into buffer of that size. read, err := listxattr(path, &buf[0], size, 0) if err != nil { return nil, &Error{"xattr.List", path, "", err} } return nullTermToStrings(buf[:read]), nil } return []string{}, nil } // Set associates name and data together as an attribute of path. func Set(path, name string, data []byte) error { var dataval *byte = nil datalen := len(data) if datalen > 0 { dataval = &data[0] } if err := setxattr(path, name, dataval, datalen, 0, 0); err != nil { return &Error{"xattr.Set", path, name, err} } return nil } // Remove removes the attribute associated with the given path. func Remove(path, name string) error { if err := removexattr(path, name, 0); err != nil { return &Error{"xattr.Remove", path, name, err} } return nil } // Supported checks if filesystem supports extended attributes func Supported(path string) bool { if _, err := listxattr(path, nil, 0, 0); err != nil { return err != syscall.ENOTSUP } return true } xattr-0.2.2/xattr_freebsd.go000066400000000000000000000051671324377546600160720ustar00rootroot00000000000000// +build freebsd package xattr import ( "syscall" ) const ( EXTATTR_NAMESPACE_USER = 1 ) // Get retrieves extended attribute data associated with path. func Get(path, name string) ([]byte, error) { // find size. size, err := extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, nil, 0) if err != nil { return nil, &Error{"xattr.Get", path, name, err} } if size > 0 { buf := make([]byte, size) // Read into buffer of that size. read, err := extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, &buf[0], size) if err != nil { return nil, &Error{"xattr.Get", path, name, err} } return buf[:read], nil } return []byte{}, nil } // List retrieves a list of names of extended attributes associated // with the given path in the file system. func List(path string) ([]string, error) { // find size. size, err := extattr_list_file(path, EXTATTR_NAMESPACE_USER, nil, 0) if err != nil { return nil, &Error{"xattr.List", path, "", err} } if size > 0 { buf := make([]byte, size) // Read into buffer of that size. read, err := extattr_list_file(path, EXTATTR_NAMESPACE_USER, &buf[0], size) if err != nil { return nil, &Error{"xattr.List", path, "", err} } return attrListToStrings(buf[:read]), nil } return []string{}, nil } // Set associates name and data together as an attribute of path. func Set(path, name string, data []byte) error { var dataval *byte = nil datalen := len(data) if datalen > 0 { dataval = &data[0] } written, err := extattr_set_file(path, EXTATTR_NAMESPACE_USER, name, dataval, datalen) if err != nil { return &Error{"xattr.Set", path, name, err} } if written != datalen { return &Error{"xattr.Set", path, name, syscall.E2BIG} } return nil } // Remove removes the attribute associated with the given path. func Remove(path, name string) error { if err := extattr_delete_file(path, EXTATTR_NAMESPACE_USER, name); err != nil { return &Error{"xattr.Remove", path, name, err} } return nil } // Supported checks if filesystem supports extended attributes func Supported(path string) bool { if _, err := extattr_list_file(path, EXTATTR_NAMESPACE_USER, nil, 0); err != nil { return err != syscall.ENOTSUP } return true } // attrListToStrings converts a sequnce of attribute name entries to a []string. // Each entry consists of a single byte containing the length // of the attribute name, followed by the attribute name. // The name is _not_ terminated by NUL. func attrListToStrings(buf []byte) []string { var result []string index := 0 for index < len(buf) { next := index + 1 + int(buf[index]) result = append(result, string(buf[index+1:next])) index = next } return result } xattr-0.2.2/xattr_linux.go000066400000000000000000000033641324377546600156140ustar00rootroot00000000000000// +build linux package xattr import "syscall" // Get retrieves extended attribute data associated with path. func Get(path, name string) ([]byte, error) { // find size. size, err := syscall.Getxattr(path, name, nil) if err != nil { return nil, &Error{"xattr.Get", path, name, err} } if size > 0 { data := make([]byte, size) // Read into buffer of that size. read, err := syscall.Getxattr(path, name, data) if err != nil { return nil, &Error{"xattr.Get", path, name, err} } return data[:read], nil } return []byte{}, nil } // List retrieves a list of names of extended attributes associated // with the given path in the file system. func List(path string) ([]string, error) { // find size. size, err := syscall.Listxattr(path, nil) if err != nil { return nil, &Error{"xattr.List", path, "", err} } if size > 0 { buf := make([]byte, size) // Read into buffer of that size. read, err := syscall.Listxattr(path, buf) if err != nil { return nil, &Error{"xattr.List", path, "", err} } return nullTermToStrings(buf[:read]), nil } return []string{}, nil } // Set associates name and data together as an attribute of path. func Set(path, name string, data []byte) error { if err := syscall.Setxattr(path, name, data, 0); err != nil { return &Error{"xattr.Set", path, name, err} } return nil } // Remove removes the attribute associated // with the given path. func Remove(path, name string) error { if err := syscall.Removexattr(path, name); err != nil { return &Error{"xattr.Remove", path, name, err} } return nil } // Supported checks if filesystem supports extended attributes func Supported(path string) bool { if _, err := syscall.Listxattr(path, nil); err != nil { return err != syscall.ENOTSUP } return true } xattr-0.2.2/xattr_test.go000066400000000000000000000031531324377546600154300ustar00rootroot00000000000000// +build linux darwin freebsd package xattr import ( "io/ioutil" "os" "testing" ) const UserPrefix = "user." func Test(t *testing.T) { tmp, err := ioutil.TempFile("", "") if err != nil { t.Fatal(err) } defer os.Remove(tmp.Name()) // Check if filesystem supports extended attributes if !Supported(tmp.Name()) { t.Skip("Skipping test - filesystem does not support extended attributes") } err = Set(tmp.Name(), UserPrefix+"test", []byte("test-attr-value")) if err != nil { t.Fatal(err) } list, err := List(tmp.Name()) if err != nil { t.Fatal(err) } found := false for _, name := range list { if name == UserPrefix+"test" { found = true } } if !found { t.Fatal("Listxattr did not return test attribute") } var data []byte data, err = Get(tmp.Name(), UserPrefix+"test") if err != nil { t.Fatal(err) } value := string(data) t.Log(value) if "test-attr-value" != value { t.Fail() } err = Remove(tmp.Name(), UserPrefix+"test") if err != nil { t.Fatal(err) } } func TestNoData(t *testing.T) { tmp, err := ioutil.TempFile("", "") if err != nil { t.Fatal(err) } defer os.Remove(tmp.Name()) // Check if filesystem supports extended attributes if !Supported(tmp.Name()) { t.Skip("Skipping test - filesystem does not support extended attributes") } err = Set(tmp.Name(), UserPrefix+"test", []byte{}) if err != nil { t.Fatal(err) } list, err := List(tmp.Name()) if err != nil { t.Fatal(err) } found := false for _, name := range list { if name == UserPrefix+"test" { found = true } } if !found { t.Fatal("Listxattr did not return test attribute") } }