mirror of https://github.com/perkeep/perkeep.git
fuse: support extended attributes
Change-Id: I0698d5adfc756bf8f589f2cdbb0057f2789cd40a
This commit is contained in:
parent
535cb01877
commit
aa7196e33b
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
Loading…
Reference in New Issue