diff --git a/third_party/code.google.com/p/rsc/fuse/fuse.go b/third_party/code.google.com/p/rsc/fuse/fuse.go index 99357bb8c..624d48341 100644 --- a/third_party/code.google.com/p/rsc/fuse/fuse.go +++ b/third_party/code.google.com/p/rsc/fuse/fuse.go @@ -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) } diff --git a/third_party/code.google.com/p/rsc/fuse/serve.go b/third_party/code.google.com/p/rsc/fuse/serve.go index 81307c3b4..6d07f24bc 100644 --- a/third_party/code.google.com/p/rsc/fuse/serve.go +++ b/third_party/code.google.com/p/rsc/fuse/serve.go @@ -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 { diff --git a/third_party/code.google.com/p/rsc/fuse/xattr_darwin.go b/third_party/code.google.com/p/rsc/fuse/xattr_darwin.go new file mode 100644 index 000000000..a5e833c5e --- /dev/null +++ b/third_party/code.google.com/p/rsc/fuse/xattr_darwin.go @@ -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) diff --git a/third_party/code.google.com/p/rsc/fuse/xattr_linux.go b/third_party/code.google.com/p/rsc/fuse/xattr_linux.go new file mode 100644 index 000000000..6f50e1f36 --- /dev/null +++ b/third_party/code.google.com/p/rsc/fuse/xattr_linux.go @@ -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)