GetXattr/ListXattr implementation
parent
8aade5c71f
commit
d20c4665c1
|
@ -434,6 +434,10 @@ func (c *Connection) shouldLogError(
|
|||
return false
|
||||
}
|
||||
|
||||
case *fuseops.GetXattrOp:
|
||||
if err == syscall.ENODATA || err == syscall.ERANGE {
|
||||
return false
|
||||
}
|
||||
case *unknownOp:
|
||||
// Don't bother the user with methods we intentionally don't support.
|
||||
if err == syscall.ENOSYS {
|
||||
|
@ -489,7 +493,7 @@ func (c *Connection) Reply(ctx context.Context, opErr error) {
|
|||
if !noResponse {
|
||||
err := c.writeMessage(outMsg.Bytes())
|
||||
if err != nil && c.errorLogger != nil {
|
||||
c.errorLogger.Printf("writeMessage: %v", err)
|
||||
c.errorLogger.Printf("writeMessage: %v %v", err, outMsg.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
110
conversions.go
110
conversions.go
|
@ -433,6 +433,61 @@ func convertInMessage(
|
|||
Name: string(buf[:n-1]),
|
||||
}
|
||||
|
||||
case fusekernel.OpGetxattr:
|
||||
type input fusekernel.GetxattrIn
|
||||
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
|
||||
if in == nil {
|
||||
err = errors.New("Corrupt OpGetxattr")
|
||||
return
|
||||
}
|
||||
|
||||
name := inMsg.ConsumeBytes(inMsg.Len())
|
||||
i := bytes.IndexByte(name, '\x00')
|
||||
if i < 0 {
|
||||
err = errors.New("Corrupt OpGetxattr")
|
||||
return
|
||||
}
|
||||
name = name[:i]
|
||||
|
||||
to := &fuseops.GetXattrOp{
|
||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||
Name: string(name),
|
||||
}
|
||||
o = to
|
||||
|
||||
readSize := int(in.Size)
|
||||
p := outMsg.GrowNoZero(readSize)
|
||||
if p == nil {
|
||||
err = fmt.Errorf("Can't grow for %d-byte read", readSize)
|
||||
return
|
||||
}
|
||||
|
||||
sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst))
|
||||
sh.Data = uintptr(p)
|
||||
sh.Len = readSize
|
||||
sh.Cap = readSize
|
||||
|
||||
case fusekernel.OpListxattr:
|
||||
type input fusekernel.ListxattrIn
|
||||
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
|
||||
if in == nil {
|
||||
err = errors.New("Corrupt OpListxattr")
|
||||
return
|
||||
}
|
||||
|
||||
o = &fuseops.ListXattrOp{
|
||||
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
|
||||
}
|
||||
|
||||
readSize := int(in.Size)
|
||||
if readSize != 0 {
|
||||
p := outMsg.GrowNoZero(readSize)
|
||||
if p == nil {
|
||||
err = fmt.Errorf("Can't grow for %d-byte read", readSize)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
o = &unknownOp{
|
||||
OpCode: inMsg.Header().Opcode,
|
||||
|
@ -472,17 +527,32 @@ func (c *Connection) kernelResponse(
|
|||
// If the user returned the error, fill in the error field of the outgoing
|
||||
// message header.
|
||||
if opErr != nil {
|
||||
m.OutHeader().Error = -int32(syscall.EIO)
|
||||
if errno, ok := opErr.(syscall.Errno); ok {
|
||||
m.OutHeader().Error = -int32(errno)
|
||||
handled := false
|
||||
|
||||
if opErr == syscall.ERANGE {
|
||||
switch o := op.(type) {
|
||||
case *fuseops.GetXattrOp:
|
||||
writeXattrSize(m, uint32(o.BytesRead))
|
||||
handled = true
|
||||
case *fuseops.ListXattrOp:
|
||||
writeXattrSize(m, uint32(o.BytesRead))
|
||||
handled = true
|
||||
}
|
||||
}
|
||||
|
||||
// Special case: for some types, convertInMessage grew the message in order
|
||||
// to obtain a destination buffer. Make sure that we shrink back to just
|
||||
// the header, because on OS X the kernel otherwise returns EINVAL when we
|
||||
// attempt to write an error response with a length that extends beyond the
|
||||
// header.
|
||||
m.ShrinkTo(buffer.OutMessageHeaderSize)
|
||||
if !handled {
|
||||
m.OutHeader().Error = -int32(syscall.EIO)
|
||||
if errno, ok := opErr.(syscall.Errno); ok {
|
||||
m.OutHeader().Error = -int32(errno)
|
||||
}
|
||||
|
||||
// Special case: for some types, convertInMessage grew the message in order
|
||||
// to obtain a destination buffer. Make sure that we shrink back to just
|
||||
// the header, because on OS X the kernel otherwise returns EINVAL when we
|
||||
// attempt to write an error response with a length that extends beyond the
|
||||
// header.
|
||||
m.ShrinkTo(buffer.OutMessageHeaderSize)
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, fill in the rest of the response.
|
||||
|
@ -639,6 +709,23 @@ func (c *Connection) kernelResponseForOp(
|
|||
case *fuseops.RemoveXattrOp:
|
||||
// Empty response
|
||||
|
||||
case *fuseops.GetXattrOp:
|
||||
// convertInMessage already set up the destination buffer to be at the end
|
||||
// of the out message. We need only shrink to the right size based on how
|
||||
// much the user read.
|
||||
if o.BytesRead == 0 {
|
||||
writeXattrSize(m, uint32(o.BytesRead))
|
||||
} else {
|
||||
m.ShrinkTo(buffer.OutMessageHeaderSize + o.BytesRead)
|
||||
}
|
||||
|
||||
case *fuseops.ListXattrOp:
|
||||
if o.BytesRead == 0 {
|
||||
writeXattrSize(m, uint32(o.BytesRead))
|
||||
} else {
|
||||
m.ShrinkTo(buffer.OutMessageHeaderSize + o.BytesRead)
|
||||
}
|
||||
|
||||
case *initOp:
|
||||
out := (*fusekernel.InitOut)(m.Grow(int(unsafe.Sizeof(fusekernel.InitOut{}))))
|
||||
|
||||
|
@ -760,3 +847,8 @@ func convertFileMode(unixMode uint32) os.FileMode {
|
|||
}
|
||||
return mode
|
||||
}
|
||||
|
||||
func writeXattrSize(m *buffer.OutMessage, size uint32) {
|
||||
out := (*fusekernel.GetxattrOut)(m.Grow(int(unsafe.Sizeof(fusekernel.GetxattrOut{}))))
|
||||
out.Size = size
|
||||
}
|
||||
|
|
6
debug.go
6
debug.go
|
@ -89,6 +89,12 @@ func describeRequest(op interface{}) (s string) {
|
|||
addComponent("handle %d", typed.Handle)
|
||||
addComponent("offset %d", typed.Offset)
|
||||
addComponent("%d bytes", len(typed.Data))
|
||||
|
||||
case *fuseops.RemoveXattrOp:
|
||||
addComponent("name %s", typed.Name)
|
||||
|
||||
case *fuseops.GetXattrOp:
|
||||
addComponent("name %s", typed.Name)
|
||||
}
|
||||
|
||||
// Use just the name if there is no extra info.
|
||||
|
|
|
@ -780,3 +780,38 @@ type RemoveXattrOp struct {
|
|||
// The name of the extended attribute
|
||||
Name string
|
||||
}
|
||||
|
||||
// Get an extended attribute
|
||||
type GetXattrOp struct {
|
||||
// The inode that we are reading
|
||||
Inode InodeID
|
||||
|
||||
// The name of the extended attribute
|
||||
Name string
|
||||
|
||||
// The destination buffer. If the size is too small for the
|
||||
// value, the ERANGE error should be sent.
|
||||
Dst []byte
|
||||
|
||||
// Set by the file system: the number of bytes read into Dst, or
|
||||
// the number of bytes that would have been read into Dst if Dst was
|
||||
// big enough
|
||||
BytesRead int
|
||||
}
|
||||
|
||||
type ListXattrOp struct {
|
||||
// The inode that we are reading
|
||||
Inode InodeID
|
||||
|
||||
// The destination buffer. If the size is too small for the
|
||||
// value, the ERANGE error should be sent.
|
||||
//
|
||||
// The output data should consist of a sequence of NUL-terminated strings,
|
||||
// one for each xattr
|
||||
Dst []byte
|
||||
|
||||
// Set by the file system: the number of bytes read into Dst, or
|
||||
// the number of bytes that would have been read into Dst if Dst was
|
||||
// big enough
|
||||
BytesRead int
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ type FileSystem interface {
|
|||
ReleaseFileHandle(context.Context, *fuseops.ReleaseFileHandleOp) error
|
||||
ReadSymlink(context.Context, *fuseops.ReadSymlinkOp) error
|
||||
RemoveXattr(context.Context, *fuseops.RemoveXattrOp) error
|
||||
GetXattr(context.Context, *fuseops.GetXattrOp) error
|
||||
ListXattr(context.Context, *fuseops.ListXattrOp) error
|
||||
|
||||
// Regard all inodes (including the root inode) as having their lookup counts
|
||||
// decremented to zero, and clean up any resources associated with the file
|
||||
|
@ -190,6 +192,12 @@ func (s *fileSystemServer) handleOp(
|
|||
|
||||
case *fuseops.RemoveXattrOp:
|
||||
err = s.fs.RemoveXattr(ctx, typed)
|
||||
|
||||
case *fuseops.GetXattrOp:
|
||||
err = s.fs.GetXattr(ctx, typed)
|
||||
|
||||
case *fuseops.ListXattrOp:
|
||||
err = s.fs.ListXattr(ctx, typed)
|
||||
}
|
||||
|
||||
c.Reply(ctx, err)
|
||||
|
|
|
@ -190,5 +190,19 @@ func (fs *NotImplementedFileSystem) RemoveXattr(
|
|||
return
|
||||
}
|
||||
|
||||
func (fs *NotImplementedFileSystem) GetXattr(
|
||||
ctx context.Context,
|
||||
op *fuseops.GetXattrOp) (err error) {
|
||||
err = fuse.ENOSYS
|
||||
return
|
||||
}
|
||||
|
||||
func (fs *NotImplementedFileSystem) ListXattr(
|
||||
ctx context.Context,
|
||||
op *fuseops.ListXattrOp) (err error) {
|
||||
err = fuse.ENOSYS
|
||||
return
|
||||
}
|
||||
|
||||
func (fs *NotImplementedFileSystem) Destroy() {
|
||||
}
|
||||
|
|
|
@ -660,6 +660,11 @@ type GetxattrOut struct {
|
|||
Padding uint32
|
||||
}
|
||||
|
||||
type ListxattrIn struct {
|
||||
Size uint32
|
||||
Padding uint32
|
||||
}
|
||||
|
||||
type LkIn struct {
|
||||
Fh uint64
|
||||
Owner uint64
|
||||
|
|
Loading…
Reference in New Issue