Commit 395b17f8 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

In Raw API, make separate calls for XAttr size and data.

parent 90cb7766
......@@ -260,7 +260,8 @@ type RawFileSystem interface {
Access(header *InHeader, input *AccessIn) (code Status)
// Extended attributes.
GetXAttr(header *InHeader, attr string) (data []byte, code Status)
GetXAttrSize(header *InHeader, attr string) (sz int, code Status)
GetXAttrData(header *InHeader, attr string) (data []byte, code Status)
ListXAttr(header *InHeader) (attributes []byte, code Status)
SetXAttr(header *InHeader, input *SetXAttrIn, attr string, data []byte) Status
RemoveXAttr(header *InHeader, attr string) (code Status)
......
......@@ -58,7 +58,11 @@ func (me *DefaultRawFileSystem) Link(header *InHeader, input *LinkIn, name strin
return nil, ENOSYS
}
func (me *DefaultRawFileSystem) GetXAttr(header *InHeader, attr string) (data []byte, code Status) {
func (me *DefaultRawFileSystem) GetXAttrSize(header *InHeader, attr string) (size int, code Status) {
return 0, ENOSYS
}
func (me *DefaultRawFileSystem) GetXAttrData(header *InHeader, attr string) (data []byte, code Status) {
return nil, ENOSYS
}
......
......@@ -289,7 +289,13 @@ func (me *FileSystemConnector) ReleaseDir(header *InHeader, input *ReleaseIn) {
me.considerDropInode(node)
}
func (me *FileSystemConnector) GetXAttr(header *InHeader, attribute string) (data []byte, code Status) {
func (me *FileSystemConnector) GetXAttrSize(header *InHeader, attribute string) (sz int, code Status) {
node := me.toInode(header.NodeId)
data, c := node.fsInode.GetXAttr(attribute, &header.Context)
return len(data), c
}
func (me *FileSystemConnector) GetXAttrData(header *InHeader, attribute string) (data []byte, code Status) {
node := me.toInode(header.NodeId)
return node.fsInode.GetXAttr(attribute, &header.Context)
}
......
......@@ -228,9 +228,14 @@ func (me *LockingRawFileSystem) SetXAttr(header *InHeader, input *SetXAttrIn, at
return me.RawFileSystem.SetXAttr(header, input, attr, data)
}
func (me *LockingRawFileSystem) GetXAttr(header *InHeader, attr string) (data []byte, code Status) {
func (me *LockingRawFileSystem) GetXAttrData(header *InHeader, attr string) (data []byte, code Status) {
defer me.locked()()
return me.RawFileSystem.GetXAttr(header, attr)
return me.RawFileSystem.GetXAttrData(header, attr)
}
func (me *LockingRawFileSystem) GetXAttrSize(header *InHeader, attr string) (sz int, code Status) {
defer me.locked()()
return me.RawFileSystem.GetXAttrSize(header, attr)
}
func (me *LockingRawFileSystem) ListXAttr(header *InHeader) (data []byte, code Status) {
......
......@@ -157,7 +157,8 @@ func (me *LoopbackFileSystem) Create(path string, flags uint32, mode uint32, con
}
func (me *LoopbackFileSystem) GetXAttr(name string, attr string, context *Context) ([]byte, Status) {
data, errNo := GetXAttr(me.GetPath(name), attr)
data := make([]byte, 1024)
data, errNo := GetXAttr(me.GetPath(name), attr, data)
return data, Status(errNo)
}
......
......@@ -161,28 +161,32 @@ func doWrite(state *MountState, req *request) {
func doGetXAttr(state *MountState, req *request) {
input := (*GetXAttrIn)(req.inData)
var data []byte
if req.inHeader.opcode == _OP_GETXATTR {
data, req.status = state.fileSystem.GetXAttr(req.inHeader, req.filenames[0])
} else {
data, req.status = state.fileSystem.ListXAttr(req.inHeader)
}
if req.status != OK {
return
}
size := uint32(len(data))
if input.Size == 0 {
switch {
case req.inHeader.opcode == _OP_GETXATTR && input.Size == 0:
sz, code := state.fileSystem.GetXAttrSize(req.inHeader, req.filenames[0])
if code.Ok() {
out := &GetXAttrOut{
Size: size,
Size: uint32(sz),
}
req.outData = unsafe.Pointer(out)
req.status = ERANGE
return
}
req.status = code
case req.inHeader.opcode == _OP_GETXATTR:
data, req.status = state.fileSystem.GetXAttrData(req.inHeader, req.filenames[0])
default:
data, req.status = state.fileSystem.ListXAttr(req.inHeader)
}
if size > input.Size {
if len(data) > int(input.Size) {
req.status = ERANGE
}
if !req.status.Ok() {
return
}
req.flatData = data
}
......
......@@ -50,8 +50,7 @@ func getxattr(path string, attr string, dest []byte) (sz int, errno int) {
return int(size), int(errNo)
}
func GetXAttr(path string, attr string) (value []byte, errno int) {
dest := make([]byte, 1024)
func GetXAttr(path string, attr string, dest []byte) (value []byte, errno int) {
sz, errno := getxattr(path, attr, dest)
for sz > cap(dest) && errno == 0 {
......
......@@ -6,6 +6,7 @@ import (
"log"
"os"
"path/filepath"
"syscall"
"testing"
)
......@@ -86,6 +87,11 @@ func (me *XAttrTestFs) RemoveXAttr(name string, attr string, context *Context) S
return OK
}
func readXAttr(p, a string) (val []byte, errno int) {
val = make([]byte, 1024)
return GetXAttr(p, a, val)
}
func TestXAttrRead(t *testing.T) {
nm := "filename"
......@@ -112,21 +118,20 @@ func TestXAttrRead(t *testing.T) {
t.Error("Unexpected stat error", err)
}
val, errno := GetXAttr(mounted, "noexist")
val, errno := readXAttr(mounted, "noexist")
if errno == 0 {
t.Error("Expected GetXAttr error", val)
}
attrs, errno := ListXAttr(mounted)
readback := make(map[string][]byte)
if errno != 0 {
t.Error("Unexpected ListXAttr error", errno)
} else {
for _, a := range attrs {
val, errno = GetXAttr(mounted, a)
val, errno = readXAttr(mounted, a)
if errno != 0 {
t.Error("Unexpected GetXAttr error", errno)
t.Error("Unexpected GetXAttr error", syscall.Errno(errno))
}
readback[a] = val
}
......@@ -146,13 +151,13 @@ func TestXAttrRead(t *testing.T) {
if errno != 0 {
t.Error("Setxattr error", errno)
}
val, errno = GetXAttr(mounted, "third")
val, errno = readXAttr(mounted, "third")
if errno != 0 || string(val) != "value" {
t.Error("Read back set xattr:", errno, string(val))
}
Removexattr(mounted, "third")
val, errno = GetXAttr(mounted, "third")
val, errno = readXAttr(mounted, "third")
if errno != int(ENODATA) {
t.Error("Data not removed?", errno, val)
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment