Skip to content

Commit

Permalink
Merge pull request #150 from kolyshkin/xattr
Browse files Browse the repository at this point in the history
sysx/xattr: fix and improve
  • Loading branch information
estesp authored Feb 28, 2020
2 parents 26c1120 + bbd0be0 commit 0f16d7a
Showing 1 changed file with 30 additions and 38 deletions.
68 changes: 30 additions & 38 deletions sysx/xattr.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ package sysx

import (
"bytes"
"syscall"

"golang.org/x/sys/unix"
)
Expand Down Expand Up @@ -66,60 +65,53 @@ func LGetxattr(path, attr string) ([]byte, error) {
return getxattrAll(path, attr, unix.Lgetxattr)
}

const defaultXattrBufferSize = 5
const defaultXattrBufferSize = 128

type listxattrFunc func(path string, dest []byte) (int, error)

func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) {
var p []byte // nil on first execution

for {
n, err := listFunc(path, p) // first call gets buffer size.
buf := make([]byte, defaultXattrBufferSize)
n, err := listFunc(path, buf)
for err == unix.ERANGE {
// Buffer too small, use zero-sized buffer to get the actual size
n, err = listFunc(path, []byte{})
if err != nil {
return nil, err
}
buf = make([]byte, n)
n, err = listFunc(path, buf)
}
if err != nil {
return nil, err
}

if n > len(p) {
p = make([]byte, n)
continue
}

p = p[:n]

ps := bytes.Split(bytes.TrimSuffix(p, []byte{0}), []byte{0})
var entries []string
for _, p := range ps {
s := string(p)
if s != "" {
entries = append(entries, s)
}
ps := bytes.Split(bytes.TrimSuffix(buf[:n], []byte{0}), []byte{0})
var entries []string
for _, p := range ps {
if len(p) > 0 {
entries = append(entries, string(p))
}

return entries, nil
}

return entries, nil
}

type getxattrFunc func(string, string, []byte) (int, error)

func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) {
p := make([]byte, defaultXattrBufferSize)
for {
n, err := getFunc(path, attr, p)
buf := make([]byte, defaultXattrBufferSize)
n, err := getFunc(path, attr, buf)
for err == unix.ERANGE {
// Buffer too small, use zero-sized buffer to get the actual size
n, err = getFunc(path, attr, []byte{})
if err != nil {
if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERANGE {
p = make([]byte, len(p)*2) // this can't be ideal.
continue // try again!
}

return nil, err
}

// realloc to correct size and repeat
if n > len(p) {
p = make([]byte, n)
continue
}

return p[:n], nil
buf = make([]byte, n)
n, err = getFunc(path, attr, buf)
}
if err != nil {
return nil, err
}
return buf[:n], nil
}

0 comments on commit 0f16d7a

Please sign in to comment.