Commit 5f24a9ec authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Implement ListXAttr.

parent 133852b3
...@@ -87,6 +87,8 @@ type SubmountFileSystem struct { ...@@ -87,6 +87,8 @@ type SubmountFileSystem struct {
nextFreeInode uint64 nextFreeInode uint64
Options SubmountFileSystemOptions Options SubmountFileSystemOptions
fuse.DefaultRawFuseFileSystem
} }
type SubmountFileSystemOptions struct { type SubmountFileSystemOptions struct {
......
...@@ -73,6 +73,10 @@ func (me *DefaultRawFuseFileSystem) GetXAttr(header *InHeader, attr string) (dat ...@@ -73,6 +73,10 @@ func (me *DefaultRawFuseFileSystem) GetXAttr(header *InHeader, attr string) (dat
return nil, ENOSYS return nil, ENOSYS
} }
func (me *DefaultRawFuseFileSystem) ListXAttr(header *InHeader) (data []byte, code Status) {
return nil, ENOSYS
}
func (me *DefaultRawFuseFileSystem) Access(header *InHeader, input *AccessIn) (code Status) { func (me *DefaultRawFuseFileSystem) Access(header *InHeader, input *AccessIn) (code Status) {
return ENOSYS return ENOSYS
} }
...@@ -153,6 +157,10 @@ func (me *DefaultPathFilesystem) GetXAttr(name string, attr string) ([]byte, Sta ...@@ -153,6 +157,10 @@ func (me *DefaultPathFilesystem) GetXAttr(name string, attr string) ([]byte, Sta
return nil, ENOSYS return nil, ENOSYS
} }
func (me *DefaultPathFilesystem) ListXAttr(name string) ([]string, Status) {
return nil, ENOSYS
}
func (me *DefaultPathFilesystem) Readlink(name string) (string, Status) { func (me *DefaultPathFilesystem) Readlink(name string) (string, Status) {
return "", ENOSYS return "", ENOSYS
} }
......
...@@ -475,9 +475,9 @@ func (me *MountState) dispatch(req *fuseRequest) { ...@@ -475,9 +475,9 @@ func (me *MountState) dispatch(req *fuseRequest) {
// case FUSE_SETXATTR: // case FUSE_SETXATTR:
// status = fs.SetXAttr(h, (*SetXAttrIn)(inData)) // status = fs.SetXAttr(h, (*SetXAttrIn)(inData))
case FUSE_GETXATTR: case FUSE_GETXATTR:
req.data, req.flatData, status = doGetXAttr(me, h, (*GetXAttrIn)(inData), filename) req.data, req.flatData, status = doGetXAttr(me, h, (*GetXAttrIn)(inData), filename, h.Opcode)
case FUSE_LISTXATTR:
// case FUSE_LISTXATTR: req.data, req.flatData, status = doGetXAttr(me, h, (*GetXAttrIn)(inData), filename, h.Opcode)
// case FUSE_REMOVEXATTR // case FUSE_REMOVEXATTR
case FUSE_ACCESS: case FUSE_ACCESS:
...@@ -642,8 +642,12 @@ func doSetattr(state *MountState, header *InHeader, input *SetAttrIn) (out unsaf ...@@ -642,8 +642,12 @@ func doSetattr(state *MountState, header *InHeader, input *SetAttrIn) (out unsaf
return unsafe.Pointer(o), s return unsafe.Pointer(o), s
} }
func doGetXAttr(state *MountState, header *InHeader, input *GetXAttrIn, attr string) (out unsafe.Pointer, data []byte, code Status) { func doGetXAttr(state *MountState, header *InHeader, input *GetXAttrIn, attr string, opcode uint32) (out unsafe.Pointer, data []byte, code Status) {
data, code = state.fileSystem.GetXAttr(header, attr) if opcode == FUSE_GETXATTR {
data, code = state.fileSystem.GetXAttr(header, attr)
} else {
data, code = state.fileSystem.ListXAttr(header)
}
if code != OK { if code != OK {
return nil, nil, code return nil, nil, code
} }
......
...@@ -152,6 +152,12 @@ func (me *LoopbackFileSystem) GetXAttr(name string, attr string) ([]byte, Status ...@@ -152,6 +152,12 @@ func (me *LoopbackFileSystem) GetXAttr(name string, attr string) ([]byte, Status
return data, Status(errNo) return data, Status(errNo)
} }
func (me *LoopbackFileSystem) ListXAttr(name string) ([]string, Status) {
data, errNo := ListXAttr(me.GetPath(name))
return data, Status(errNo)
}
func (me *LoopbackFileSystem) FillOptions(options *PathFileSystemConnectorOptions) { func (me *LoopbackFileSystem) FillOptions(options *PathFileSystemConnectorOptions) {
options.NegativeTimeout = 3.0 options.NegativeTimeout = 3.0
options.AttrTimeout = 3.0 options.AttrTimeout = 3.0
......
...@@ -281,7 +281,7 @@ func init() { ...@@ -281,7 +281,7 @@ func init() {
FUSE_FSYNC: unsafe.Sizeof(FsyncIn{}), FUSE_FSYNC: unsafe.Sizeof(FsyncIn{}),
FUSE_SETXATTR: unsafe.Sizeof(SetXAttrIn{}), FUSE_SETXATTR: unsafe.Sizeof(SetXAttrIn{}),
FUSE_GETXATTR: unsafe.Sizeof(GetXAttrIn{}), FUSE_GETXATTR: unsafe.Sizeof(GetXAttrIn{}),
FUSE_LISTXATTR: 0, FUSE_LISTXATTR: unsafe.Sizeof(GetXAttrIn{}),
FUSE_REMOVEXATTR: 0, FUSE_REMOVEXATTR: 0,
FUSE_FLUSH: unsafe.Sizeof(FlushIn{}), FUSE_FLUSH: unsafe.Sizeof(FlushIn{}),
FUSE_INIT: unsafe.Sizeof(InitIn{}), FUSE_INIT: unsafe.Sizeof(InitIn{}),
...@@ -322,7 +322,7 @@ func init() { ...@@ -322,7 +322,7 @@ func init() {
FUSE_FSYNC: 0, FUSE_FSYNC: 0,
FUSE_SETXATTR: 0, FUSE_SETXATTR: 0,
FUSE_GETXATTR: unsafe.Sizeof(GetXAttrOut{}), FUSE_GETXATTR: unsafe.Sizeof(GetXAttrOut{}),
FUSE_LISTXATTR: 0, FUSE_LISTXATTR: unsafe.Sizeof(GetXAttrOut{}),
FUSE_REMOVEXATTR: 0, FUSE_REMOVEXATTR: 0,
FUSE_FLUSH: 0, FUSE_FLUSH: 0,
FUSE_INIT: unsafe.Sizeof(InitOut{}), FUSE_INIT: unsafe.Sizeof(InitOut{}),
......
...@@ -728,6 +728,26 @@ func (me *PathFileSystemConnector) GetXAttr(header *InHeader, attribute string) ...@@ -728,6 +728,26 @@ func (me *PathFileSystemConnector) GetXAttr(header *InHeader, attribute string)
return data, code return data, code
} }
func (me *PathFileSystemConnector) ListXAttr(header *InHeader) (data []byte, code Status) {
path, mount := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
attrs, code := mount.fs.ListXAttr(path)
if code != OK {
return nil, code
}
b := bytes.NewBuffer([]byte{})
for _, v := range attrs {
b.Write([]byte(v))
b.WriteByte(0)
}
return b.Bytes(), code
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// unimplemented. // unimplemented.
......
...@@ -96,6 +96,11 @@ func (me *TimingPathFilesystem) GetXAttr(name string, attr string) ([]byte, Stat ...@@ -96,6 +96,11 @@ func (me *TimingPathFilesystem) GetXAttr(name string, attr string) ([]byte, Stat
return me.original.GetXAttr(name, attr) return me.original.GetXAttr(name, attr)
} }
func (me *TimingPathFilesystem) ListXAttr(name string) ([]string, Status) {
defer me.startTimer("ListXAttr", name)()
return me.original.ListXAttr(name)
}
func (me *TimingPathFilesystem) Readlink(name string) (string, Status) { func (me *TimingPathFilesystem) Readlink(name string) (string, Status) {
defer me.startTimer("Readlink", name)() defer me.startTimer("Readlink", name)()
return me.original.Readlink(name) return me.original.Readlink(name)
...@@ -185,3 +190,4 @@ func (me *TimingPathFilesystem) Utimens(name string, AtimeNs uint64, CtimeNs uin ...@@ -185,3 +190,4 @@ func (me *TimingPathFilesystem) Utimens(name string, AtimeNs uint64, CtimeNs uin
defer me.startTimer("Utimens", name)() defer me.startTimer("Utimens", name)()
return me.original.Utimens(name, AtimeNs, CtimeNs) return me.original.Utimens(name, AtimeNs, CtimeNs)
} }
...@@ -131,6 +131,11 @@ func (me *TimingRawFilesystem) GetXAttr(header *InHeader, attr string) (data []b ...@@ -131,6 +131,11 @@ func (me *TimingRawFilesystem) GetXAttr(header *InHeader, attr string) (data []b
return me.original.GetXAttr(header, attr) return me.original.GetXAttr(header, attr)
} }
func (me *TimingRawFilesystem) ListXAttr(header *InHeader) (data []byte, code Status) {
defer me.startTimer("ListXAttr")()
return me.original.ListXAttr(header)
}
func (me *TimingRawFilesystem) Access(header *InHeader, input *AccessIn) (code Status) { func (me *TimingRawFilesystem) Access(header *InHeader, input *AccessIn) (code Status) {
defer me.startTimer("Access")() defer me.startTimer("Access")()
return me.original.Access(header, input) return me.original.Access(header, input)
...@@ -170,3 +175,4 @@ func (me *TimingRawFilesystem) ReleaseDir(header *InHeader, f RawFuseDir) { ...@@ -170,3 +175,4 @@ func (me *TimingRawFilesystem) ReleaseDir(header *InHeader, f RawFuseDir) {
defer me.startTimer("ReleaseDir")() defer me.startTimer("ReleaseDir")()
me.original.ReleaseDir(header, f) me.original.ReleaseDir(header, f)
} }
...@@ -517,7 +517,8 @@ type RawFileSystem interface { ...@@ -517,7 +517,8 @@ type RawFileSystem interface {
Link(header *InHeader, input *LinkIn, filename string) (out *EntryOut, code Status) Link(header *InHeader, input *LinkIn, filename string) (out *EntryOut, code Status)
GetXAttr(header *InHeader, attr string) (data []byte, code Status) GetXAttr(header *InHeader, attr string) (data []byte, code Status)
ListXAttr(header *InHeader) (attributes []byte, code Status)
// Unused: // Unused:
SetXAttr(header *InHeader, input *SetXAttrIn) Status SetXAttr(header *InHeader, input *SetXAttrIn) Status
...@@ -570,7 +571,8 @@ type PathFilesystem interface { ...@@ -570,7 +571,8 @@ type PathFilesystem interface {
// Where to hook up statfs? // Where to hook up statfs?
// //
// Unimplemented: // Unimplemented:
// RemoveXAttr, SetXAttr, GetXAttr, ListXAttr. // RemoveXAttr, SetXAttr,
ListXAttr(name string) (attributes []string, code Status)
OpenDir(name string) (stream chan DirEntry, code Status) OpenDir(name string) (stream chan DirEntry, code Status)
......
...@@ -80,6 +80,13 @@ func (me *WrappingPathFilesystem) Utimens(name string, AtimeNs uint64, CtimeNs u ...@@ -80,6 +80,13 @@ func (me *WrappingPathFilesystem) Utimens(name string, AtimeNs uint64, CtimeNs u
return me.original.Utimens(name, AtimeNs, CtimeNs) return me.original.Utimens(name, AtimeNs, CtimeNs)
} }
func (me *WrappingPathFilesystem) GetXAttr(name string, attr string) ([]byte, Status) {
return me.original.GetXAttr(name, attr)
}
func (me *WrappingPathFilesystem) ListXAttr(name string) ([]string, Status) {
return me.original.ListXAttr(name)
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Wrapping raw FS. // Wrapping raw FS.
...@@ -157,6 +164,10 @@ func (me *WrappingRawFilesystem) GetXAttr(header *InHeader, attr string) (data [ ...@@ -157,6 +164,10 @@ func (me *WrappingRawFilesystem) GetXAttr(header *InHeader, attr string) (data [
return me.original.GetXAttr(header, attr) return me.original.GetXAttr(header, attr)
} }
func (me *WrappingRawFilesystem) ListXAttr(header *InHeader) (data []byte, code Status) {
return me.original.ListXAttr(header)
}
func (me *WrappingRawFilesystem) Access(header *InHeader, input *AccessIn) (code Status) { func (me *WrappingRawFilesystem) Access(header *InHeader, input *AccessIn) (code Status) {
return me.original.Access(header, input) return me.original.Access(header, input)
} }
......
...@@ -51,7 +51,7 @@ func listxattr(path string, dest []byte) (sz int, errno int) { ...@@ -51,7 +51,7 @@ func listxattr(path string, dest []byte) (sz int, errno int) {
return int(size), int(errNo) return int(size), int(errNo)
} }
func ListXAttr(path string) (attributes [][]byte, errno int) { func ListXAttr(path string) (attributes []string, errno int) {
dest := make([]byte, 1024) dest := make([]byte, 1024)
sz, errno := listxattr(path, dest) sz, errno := listxattr(path, dest)
if errno != 0 { if errno != 0 {
...@@ -65,6 +65,10 @@ func ListXAttr(path string) (attributes [][]byte, errno int) { ...@@ -65,6 +65,10 @@ func ListXAttr(path string) (attributes [][]byte, errno int) {
// -1 to drop the final empty slice. // -1 to drop the final empty slice.
dest = dest[:sz-1] dest = dest[:sz-1]
attributes = bytes.Split(dest, []byte{0}, -1) attributesBytes := bytes.Split(dest, []byte{0}, -1)
attributes = make([]string, len(attributesBytes))
for i, v := range attributesBytes {
attributes[i] = string(v)
}
return attributes, errno return attributes, errno
} }
package fuse package fuse
import ( import (
"bytes"
"testing" "testing"
"path/filepath" "path/filepath"
"os" "os"
...@@ -33,6 +35,7 @@ func (me *XAttrTestFs) GetAttr(name string) (*Attr, Status) { ...@@ -33,6 +35,7 @@ func (me *XAttrTestFs) GetAttr(name string) (*Attr, Status) {
return nil, ENOENT return nil, ENOENT
} }
func (me *XAttrTestFs) GetXAttr(name string, attr string) ([]byte, Status) { func (me *XAttrTestFs) GetXAttr(name string, attr string) ([]byte, Status) {
if name != me.filename { if name != me.filename {
return nil, ENOENT return nil, ENOENT
...@@ -44,19 +47,31 @@ func (me *XAttrTestFs) GetXAttr(name string, attr string) ([]byte, Status) { ...@@ -44,19 +47,31 @@ func (me *XAttrTestFs) GetXAttr(name string, attr string) ([]byte, Status) {
return v, OK return v, OK
} }
func (me *XAttrTestFs) ListXAttr(name string) (data []string, code Status) {
if name != me.filename {
return nil, ENOENT
}
func TestXAttr(t *testing.T) { for k, _ := range me.attrs {
data = append(data, k)
}
return data, OK
}
func TestXAttrRead(t *testing.T) {
nm := "filename" nm := "filename"
xfs := NewXAttrFs(nm,
map[string][]byte{ golden := map[string][]byte{
"user.attr1": []byte("val1"), "user.attr1": []byte("val1"),
"user.attr2": []byte("val2")}) "user.attr2": []byte("val2")}
xfs := NewXAttrFs(nm, golden)
connector := NewPathFileSystemConnector(xfs) connector := NewPathFileSystemConnector(xfs)
mountPoint := MakeTempDir() mountPoint := MakeTempDir()
state := NewMountState(connector) state := NewMountState(connector)
state.Mount(mountPoint) state.Mount(mountPoint)
state.Debug = true
defer state.Unmount() defer state.Unmount()
go state.Loop(false) go state.Loop(false)
...@@ -69,16 +84,32 @@ func TestXAttr(t *testing.T) { ...@@ -69,16 +84,32 @@ func TestXAttr(t *testing.T) {
val, errno := GetXAttr(mounted, "noexist") val, errno := GetXAttr(mounted, "noexist")
if errno == 0 { if errno == 0 {
t.Error("Expected GetXAttr error") t.Error("Expected GetXAttr error", val)
} }
val, errno = GetXAttr(mounted, "user.attr1") attrs, errno := ListXAttr(mounted)
if err != nil {
t.Error("Unexpected GetXAttr error", errno) readback := make(map[string][]byte)
if errno != 0 {
t.Error("Unexpected ListXAttr error", errno)
} else {
for _, a := range attrs {
val, errno = GetXAttr(mounted, a)
if errno != 0 {
t.Error("Unexpected GetXAttr error", errno)
}
readback[a] = val
}
} }
if string(val) != "val1" { if len(readback) != len(golden) {
t.Error("Unexpected value", val) t.Error("length mismatch", golden, readback)
} else {
for k, v := range(readback) {
if bytes.Compare(golden[k], v) != 0 {
t.Error("val mismatch", k, v, golden[k])
}
}
} }
} }
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