fuse: support extended attributes

Change-Id: I0698d5adfc756bf8f589f2cdbb0057f2789cd40a
This commit is contained in:
Dustin Sallings 2014-01-01 23:02:58 -08:00
parent 535cb01877
commit aa7196e33b
4 changed files with 157 additions and 21 deletions

View File

@ -594,12 +594,15 @@ func (c *Conn) ReadRequest() (Request, error) {
req = r
case opGetxattr:
var r *GetxattrRequest
nameOff := 8
if runtime.GOOS == "darwin" {
in := (*getxattrInOSX)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &GetxattrRequest{
nameOff += 8
r = &GetxattrRequest{
Header: m.Header(),
Size: in.Size,
Position: in.Position,
@ -609,11 +612,19 @@ func (c *Conn) ReadRequest() (Request, error) {
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &GetxattrRequest{
r = &GetxattrRequest{
Header: m.Header(),
Size: in.Size,
}
}
r.Header = m.Header()
name := m.bytes()[nameOff:]
i := bytes.IndexByte(name, 0)
if i < 0 {
goto corrupt
}
r.Name = string(name[:i])
req = r
case opListxattr:
if runtime.GOOS == "darwin" {
@ -987,6 +998,7 @@ type GetxattrRequest struct {
Header
Size uint32 // maximum size to return
Position uint32 // offset within extended attributes
Name string // Name of the attribute being requested
}
func (r *GetxattrRequest) String() string {
@ -995,11 +1007,16 @@ func (r *GetxattrRequest) String() string {
// Respond replies to the request with the given response.
func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
out := &getxattrOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Size: uint32(len(resp.Xattr)),
hdr := outHeader{Unique: uint64(r.ID)}
if r.Size == 0 {
out := &getxattrOut{
outHeader: hdr,
Size: uint32(len(resp.Xattr)),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
} else {
r.Conn.respondData(&hdr, unsafe.Sizeof(hdr), resp.Xattr)
}
r.Conn.respondData(&out.outHeader, unsafe.Sizeof(*out), resp.Xattr)
}
// A GetxattrResponse is the response to a GetxattrRequest.
@ -1024,18 +1041,39 @@ func (r *ListxattrRequest) String() string {
// Respond replies to the request with the given response.
func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
out := &getxattrOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Size: uint32(len(resp.Xattr)),
hdr := outHeader{Unique: uint64(r.ID)}
if r.Size == 0 {
out := &getxattrOut{
outHeader: hdr,
Size: resp.Size,
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
} else {
r.Conn.respondData(&hdr, unsafe.Sizeof(hdr), resp.Xattr)
}
r.Conn.respondData(&out.outHeader, unsafe.Sizeof(*out), resp.Xattr)
}
// A ListxattrResponse is the response to a ListxattrRequest.
type ListxattrResponse struct {
Size uint32
Xattr []byte
}
// SetattrNames initializes the ListxattrResponse with the list of
// attribute names.
func (l *ListxattrResponse) SetAttrNames(req *ListxattrRequest, to []string) {
var buf bytes.Buffer
for _, b := range to {
buf.WriteString(b)
buf.WriteByte(0)
}
l.Size = uint32(buf.Len())
l.Xattr = buf.Bytes()
if len(l.Xattr) > int(req.Size) {
l.Xattr = l.Xattr[:req.Size]
}
}
func (r *ListxattrResponse) String() string {
return fmt.Sprintf("Listxattr %x", r.Xattr)
}

View File

@ -92,16 +92,18 @@ type FS interface {
// but not the open(2) system call. If Access is not implemented, the Node behaves
// as if it always returns nil (permission granted), relying on checks in Open instead.
//
// Getxattr
// Getxattr(req *GetxattrRequest, res *GetxattrResponse, intr Intr) fuse.Error
//
// Getxattr obtains an extended attribute for the receiver.
// XXX
// Getxattr obtains an extended attribute for the receiver. If the
// attribute is not found, fuse.ENOATTR should be returned.
//
// Listxattr(req *ListxattrRequest, *ListxattrResponse) Error
//
// Listxattr
//
// Listxattr lists the extended attributes recorded for the receiver.
// The response method SetAttrNames(*ListxattrRequest, []string) takes
// care of the encoding.
//
// Removexattr
// Removexattr(req *RemotexattrRequest) fuse.Error
//
// Removexattr removes an extended attribute from the receiver.
//
@ -109,7 +111,7 @@ type FS interface {
//
// Setattr sets the standard metadata for the receiver.
//
// Setxattr
// Setxattr(req *SetxattrRequest) fuse.Error
//
// Setxattr sets an extended attribute for the receiver.
//
@ -741,10 +743,80 @@ func (c *Conn) serve(fs FS, r Request) {
done(s)
r.Respond(s)
case *GetxattrRequest, *SetxattrRequest, *ListxattrRequest, *RemovexattrRequest:
// TODO: Use n.
done(ENOSYS)
r.RespondError(ENOSYS)
case *GetxattrRequest:
n, ok := node.(interface {
Getxattr(*GetxattrRequest, *GetxattrResponse, Intr) Error
})
if !ok {
done(ENOSYS)
r.RespondError(ENOSYS)
break
}
s := &GetxattrResponse{}
err := n.Getxattr(r, s, intr)
if err != nil {
done(err)
r.RespondError(err)
break
}
log.Printf("xattr response: %#v", s)
done(nil)
r.Respond(s)
case *SetxattrRequest:
n, ok := node.(interface {
Setxattr(*SetxattrRequest, Intr) Error
})
if !ok {
done(ENOSYS)
r.RespondError(ENOSYS)
break
}
err := n.Setxattr(r, intr)
if err != nil {
done(err)
r.RespondError(err)
break
}
done(nil)
r.Respond()
case *ListxattrRequest:
n, ok := node.(interface {
Listxattr(*ListxattrRequest, *ListxattrResponse, Intr) Error
})
s := &ListxattrResponse{}
if !ok {
done(nil)
r.Respond(s)
break
}
err := n.Listxattr(r, s, intr)
if err != nil {
done(err)
r.RespondError(err)
break
}
done(nil)
r.Respond(s)
case *RemovexattrRequest:
n, ok := node.(interface {
Removexattr(*RemovexattrRequest, Intr) Error
})
if !ok {
done(ENOSYS)
r.RespondError(ENOSYS)
break
}
err := n.Removexattr(r, intr)
if err != nil {
done(err)
r.RespondError(err)
break
}
done(nil)
r.Respond()
case *ForgetRequest:
n, ok := node.(interface {

View File

@ -0,0 +1,11 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import "syscall"
// ENOATTR is a fuse.Error returned when a request is made for an
// extended attribute that doesn't exist.
var ENOATTR = Errno(syscall.ENOATTR)

View File

@ -0,0 +1,15 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import "syscall"
// This is mildly confusing, but the value to return when an attribute
// doesn't exist seems to vary from system to system.
// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013091.html
// ENOATTR is a fuse.Error returned when a request is made for an
// extended attribute that doesn't exist.
var ENOATTR = Errno(syscall.ENODATA)