fusego/conversions.go

993 lines
28 KiB
Go
Raw Normal View History

2015-03-24 06:24:00 +03:00
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2015-07-27 07:21:36 +03:00
package fuse
2015-03-24 06:24:00 +03:00
2015-03-24 06:36:44 +03:00
import (
2015-07-24 01:02:49 +03:00
"bytes"
2015-07-24 03:04:12 +03:00
"errors"
"fmt"
2015-07-24 03:54:09 +03:00
"os"
"reflect"
2015-07-24 03:54:09 +03:00
"syscall"
2015-03-24 07:00:05 +03:00
"time"
2015-07-24 00:53:16 +03:00
"unsafe"
2015-03-24 07:00:05 +03:00
2015-07-27 07:30:34 +03:00
"github.com/jacobsa/fuse/fuseops"
2015-07-24 07:33:27 +03:00
"github.com/jacobsa/fuse/internal/buffer"
2015-07-23 09:22:32 +03:00
"github.com/jacobsa/fuse/internal/fusekernel"
2015-03-24 06:36:44 +03:00
)
2015-03-24 06:24:00 +03:00
////////////////////////////////////////////////////////////////////////
// Incoming messages
////////////////////////////////////////////////////////////////////////
2015-07-27 08:43:41 +03:00
// Convert a kernel message to an appropriate op. If the op is unknown, a
// special unexported type will be used.
2015-05-05 03:00:18 +03:00
//
2015-07-27 07:30:34 +03:00
// The caller is responsible for arranging for the message to be destroyed.
func convertInMessage(
config *MountConfig,
inMsg *buffer.InMessage,
outMsg *buffer.OutMessage,
2015-07-27 08:43:41 +03:00
protocol fusekernel.Protocol) (o interface{}, err error) {
switch inMsg.Header().Opcode {
2015-07-23 09:40:27 +03:00
case fusekernel.OpLookup:
buf := inMsg.ConsumeBytes(inMsg.Len())
2015-07-23 09:40:27 +03:00
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
return nil, errors.New("Corrupt OpLookup")
2015-07-23 09:40:27 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.LookUpInodeOp{
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(buf[:n-1]),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-23 09:41:34 +03:00
case fusekernel.OpGetattr:
2015-07-27 07:35:26 +03:00
o = &fuseops.GetInodeAttributesOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 00:53:16 +03:00
case fusekernel.OpSetattr:
2015-07-24 07:36:59 +03:00
type input fusekernel.SetattrIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
2015-07-24 07:36:59 +03:00
if in == nil {
return nil, errors.New("Corrupt OpSetattr")
2015-07-24 00:53:16 +03:00
}
2015-07-27 07:32:29 +03:00
to := &fuseops.SetInodeAttributesOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:46:31 +03:00
}
2015-07-27 07:35:26 +03:00
o = to
2015-03-24 08:32:12 +03:00
2015-07-24 00:53:16 +03:00
valid := fusekernel.SetattrValid(in.Valid)
if valid&fusekernel.SetattrUid != 0 {
to.Uid = &in.Uid
}
if valid&fusekernel.SetattrGid != 0 {
to.Gid = &in.Gid
}
2015-07-24 00:53:16 +03:00
if valid&fusekernel.SetattrSize != 0 {
to.Size = &in.Size
2015-03-24 08:32:12 +03:00
}
2015-07-24 00:53:16 +03:00
if valid&fusekernel.SetattrMode != 0 {
mode := fuseops.ConvertFileMode(in.Mode)
2015-07-24 00:53:16 +03:00
to.Mode = &mode
2015-03-24 08:32:12 +03:00
}
2015-07-24 00:53:16 +03:00
if valid&fusekernel.SetattrAtime != 0 {
t := time.Unix(int64(in.Atime), int64(in.AtimeNsec))
to.Atime = &t
2015-03-24 08:32:12 +03:00
}
2015-07-24 00:53:16 +03:00
if valid&fusekernel.SetattrMtime != 0 {
t := time.Unix(int64(in.Mtime), int64(in.MtimeNsec))
to.Mtime = &t
2015-03-24 08:32:12 +03:00
}
if valid.Handle() {
t := fuseops.HandleID(in.Fh)
to.Handle = &t
}
2015-07-24 00:57:31 +03:00
case fusekernel.OpForget:
2015-07-24 07:36:59 +03:00
type input fusekernel.ForgetIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
2015-07-24 07:36:59 +03:00
if in == nil {
return nil, errors.New("Corrupt OpForget")
2015-07-24 00:57:31 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.ForgetInodeOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
N: in.Nlookup,
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
}
case fusekernel.OpBatchForget:
type input fusekernel.BatchForgetCountIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpBatchForget")
}
entries := make([]fuseops.BatchForgetEntry, 0, in.Count)
for i := uint32(0); i < in.Count; i++ {
type entry fusekernel.BatchForgetEntryIn
ein := (*entry)(inMsg.Consume(unsafe.Sizeof(entry{})))
if ein == nil {
return nil, errors.New("Corrupt OpBatchForget")
}
entries = append(entries, fuseops.BatchForgetEntry{
Inode: fuseops.InodeID(ein.Inode),
N: ein.Nlookup,
})
}
o = &fuseops.BatchForgetOp{
Entries: entries,
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
}
2015-07-24 01:02:49 +03:00
case fusekernel.OpMkdir:
in := (*fusekernel.MkdirIn)(inMsg.Consume(fusekernel.MkdirInSize(protocol)))
2015-07-24 07:40:43 +03:00
if in == nil {
return nil, errors.New("Corrupt OpMkdir")
2015-07-24 01:02:49 +03:00
}
2015-07-24 07:40:43 +03:00
name := inMsg.ConsumeBytes(inMsg.Len())
2015-07-24 01:02:49 +03:00
i := bytes.IndexByte(name, '\x00')
if i < 0 {
return nil, errors.New("Corrupt OpMkdir")
2015-07-24 01:02:49 +03:00
}
name = name[:i]
2015-07-27 07:35:26 +03:00
o = &fuseops.MkDirOp{
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
2015-07-27 07:33:19 +03:00
Name: string(name),
2015-07-24 06:23:39 +03:00
// On Linux, vfs_mkdir calls through to the inode with at most
// permissions and sticky bits set (cf. https://goo.gl/WxgQXk), and fuse
// passes that on directly (cf. https://goo.gl/f31aMo). In other words,
// the fact that this is a directory is implicit in the fact that the
// opcode is mkdir. But we want the correct mode to go through, so ensure
// that os.ModeDir is set.
Mode: fuseops.ConvertFileMode(in.Mode) | os.ModeDir,
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:46:31 +03:00
}
2015-07-24 06:23:39 +03:00
2015-12-15 02:34:09 +03:00
case fusekernel.OpMknod:
in := (*fusekernel.MknodIn)(inMsg.Consume(fusekernel.MknodInSize(protocol)))
if in == nil {
return nil, errors.New("Corrupt OpMknod")
2015-12-15 02:34:09 +03:00
}
name := inMsg.ConsumeBytes(inMsg.Len())
i := bytes.IndexByte(name, '\x00')
if i < 0 {
return nil, errors.New("Corrupt OpMknod")
2015-12-15 02:34:09 +03:00
}
name = name[:i]
o = &fuseops.MkNodeOp{
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(name),
Mode: fuseops.ConvertFileMode(in.Mode),
2022-11-02 01:25:28 +03:00
Rdev: in.Rdev,
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-12-15 02:34:09 +03:00
}
2015-07-24 01:04:03 +03:00
case fusekernel.OpCreate:
in := (*fusekernel.CreateIn)(inMsg.Consume(fusekernel.CreateInSize(protocol)))
2015-07-24 07:40:43 +03:00
if in == nil {
return nil, errors.New("Corrupt OpCreate")
2015-07-24 01:04:03 +03:00
}
2015-07-24 07:40:43 +03:00
name := inMsg.ConsumeBytes(inMsg.Len())
2015-07-24 01:04:03 +03:00
i := bytes.IndexByte(name, '\x00')
if i < 0 {
return nil, errors.New("Corrupt OpCreate")
2015-07-24 01:04:03 +03:00
}
name = name[:i]
2015-07-27 07:35:26 +03:00
o = &fuseops.CreateFileOp{
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(name),
Mode: fuseops.ConvertFileMode(in.Mode),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:04:59 +03:00
case fusekernel.OpSymlink:
2015-07-24 07:40:43 +03:00
// The message is "newName\0target\0".
names := inMsg.ConsumeBytes(inMsg.Len())
2015-07-24 01:04:59 +03:00
if len(names) == 0 || names[len(names)-1] != 0 {
return nil, errors.New("Corrupt OpSymlink")
2015-07-24 01:04:59 +03:00
}
i := bytes.IndexByte(names, '\x00')
if i < 0 {
return nil, errors.New("Corrupt OpSymlink")
2015-07-24 01:04:59 +03:00
}
newName, target := names[0:i], names[i+1:len(names)-1]
2015-07-27 07:35:26 +03:00
o = &fuseops.CreateSymlinkOp{
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(newName),
Target: string(target),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-05-19 08:34:14 +03:00
}
2015-07-24 01:07:22 +03:00
case fusekernel.OpRename:
2015-07-24 07:40:43 +03:00
type input fusekernel.RenameIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
2015-07-24 07:40:43 +03:00
if in == nil {
return nil, errors.New("Corrupt OpRename")
2015-07-24 01:07:22 +03:00
}
2015-07-24 07:40:43 +03:00
names := inMsg.ConsumeBytes(inMsg.Len())
// closed-source macfuse 4.x has broken compatibility with osxfuse 3.x:
// it passes an additional 64-bit field (flags) after RenameIn regardless
// that we don't enable the support for RENAME_SWAP/RENAME_EXCL
// macfuse doesn't want change the behaviour back which is motivated by
// not breaking compatibility the second time, look here for details:
// https://github.com/osxfuse/osxfuse/issues/839
//
// the simplest fix is just to check for the presence of all-zero flags
if len(names) >= 8 &&
names[0] == 0 && names[1] == 0 && names[2] == 0 && names[3] == 0 &&
names[4] == 0 && names[5] == 0 && names[6] == 0 && names[7] == 0 {
names = names[8:]
}
2015-07-24 01:07:22 +03:00
// names should be "old\x00new\x00"
if len(names) < 4 {
return nil, errors.New("Corrupt OpRename")
2015-07-24 01:07:22 +03:00
}
if names[len(names)-1] != '\x00' {
return nil, errors.New("Corrupt OpRename")
2015-07-24 01:07:22 +03:00
}
i := bytes.IndexByte(names, '\x00')
if i < 0 {
return nil, errors.New("Corrupt OpRename")
2015-07-24 01:07:22 +03:00
}
oldName, newName := names[:i], names[i+1:len(names)-1]
2015-07-27 07:35:26 +03:00
o = &fuseops.RenameOp{
OldParent: fuseops.InodeID(inMsg.Header().Nodeid),
2015-07-24 01:07:22 +03:00
OldName: string(oldName),
2015-07-27 07:33:19 +03:00
NewParent: fuseops.InodeID(in.Newdir),
2015-07-24 01:07:22 +03:00
NewName: string(newName),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-06-25 08:37:04 +03:00
}
2015-07-24 01:08:41 +03:00
case fusekernel.OpUnlink:
buf := inMsg.ConsumeBytes(inMsg.Len())
2015-07-24 01:08:41 +03:00
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
return nil, errors.New("Corrupt OpUnlink")
2015-07-24 01:08:41 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.UnlinkOp{
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(buf[:n-1]),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-07-24 01:08:41 +03:00
}
2015-07-24 01:09:07 +03:00
case fusekernel.OpRmdir:
buf := inMsg.ConsumeBytes(inMsg.Len())
2015-07-24 01:09:07 +03:00
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
return nil, errors.New("Corrupt OpRmdir")
2015-07-24 01:09:07 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.RmDirOp{
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(buf[:n-1]),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:51:07 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:12:07 +03:00
case fusekernel.OpOpen:
2022-07-18 14:15:27 +03:00
type input fusekernel.OpenIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpOpen")
}
2015-07-27 07:35:26 +03:00
o = &fuseops.OpenFileOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
OpenFlags: fusekernel.OpenFlags(in.Flags),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-07-24 01:12:07 +03:00
}
2015-07-24 01:12:29 +03:00
case fusekernel.OpOpendir:
2015-07-27 07:35:26 +03:00
o = &fuseops.OpenDirOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:56:41 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:10:45 +03:00
case fusekernel.OpRead:
in := (*fusekernel.ReadIn)(inMsg.Consume(fusekernel.ReadInSize(protocol)))
2015-07-24 07:40:43 +03:00
if in == nil {
return nil, errors.New("Corrupt OpRead")
2015-07-24 01:10:45 +03:00
}
to := &fuseops.ReadFileOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Handle: fuseops.HandleID(in.Fh),
Offset: int64(in.Offset),
Size: int64(in.Size),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-07-24 01:10:45 +03:00
}
if !config.UseVectoredRead {
// Use part of the incoming message storage as the read buffer
// For vectored zero-copy reads, don't allocate any buffers
to.Dst = inMsg.GetFree(int(in.Size))
}
o = to
2015-07-24 01:10:45 +03:00
2023-08-02 00:09:40 +03:00
case fusekernel.OpReaddirplus:
fallthrough
2015-07-24 01:11:24 +03:00
case fusekernel.OpReaddir:
in := (*fusekernel.ReadIn)(inMsg.Consume(fusekernel.ReadInSize(protocol)))
2015-07-24 07:40:43 +03:00
if in == nil {
return nil, errors.New("Corrupt OpReaddir")
2015-03-24 06:56:41 +03:00
}
2015-03-24 06:40:58 +03:00
to := &fuseops.ReadDirOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Handle: fuseops.HandleID(in.Fh),
Offset: fuseops.DirOffset(in.Offset),
2023-08-02 00:09:40 +03:00
Plus: inMsg.Header().Opcode == fusekernel.OpReaddirplus,
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-07-24 01:11:24 +03:00
}
o = to
readSize := int(in.Size)
p := outMsg.Grow(readSize)
if p == nil {
return nil, fmt.Errorf("Can't grow for %d-byte read", readSize)
}
sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst))
sh.Data = uintptr(p)
sh.Len = readSize
sh.Cap = readSize
2015-07-24 01:11:24 +03:00
2015-07-24 01:13:36 +03:00
case fusekernel.OpRelease:
2015-07-24 07:40:43 +03:00
type input fusekernel.ReleaseIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
2015-07-24 07:40:43 +03:00
if in == nil {
return nil, errors.New("Corrupt OpRelease")
2015-07-24 01:13:36 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.ReleaseFileHandleOp{
Handle: fuseops.HandleID(in.Fh),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-07-24 01:13:36 +03:00
}
2015-07-24 01:14:02 +03:00
case fusekernel.OpReleasedir:
2015-07-24 07:40:43 +03:00
type input fusekernel.ReleaseIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
2015-07-24 07:40:43 +03:00
if in == nil {
return nil, errors.New("Corrupt OpReleasedir")
2015-03-24 06:56:41 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-27 07:35:26 +03:00
o = &fuseops.ReleaseDirHandleOp{
Handle: fuseops.HandleID(in.Fh),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-07-24 01:14:02 +03:00
}
2015-07-24 01:15:52 +03:00
case fusekernel.OpWrite:
in := (*fusekernel.WriteIn)(inMsg.Consume(fusekernel.WriteInSize(protocol)))
2015-07-24 07:41:59 +03:00
if in == nil {
return nil, errors.New("Corrupt OpWrite")
2015-07-24 01:15:52 +03:00
}
buf := inMsg.ConsumeBytes(inMsg.Len())
2015-07-24 01:15:52 +03:00
if len(buf) < int(in.Size) {
return nil, errors.New("Corrupt OpWrite")
2015-07-24 01:15:52 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.WriteFileOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Handle: fuseops.HandleID(in.Fh),
Data: buf,
Offset: int64(in.Offset),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
case fusekernel.OpFsync, fusekernel.OpFsyncdir:
2015-07-24 07:41:59 +03:00
type input fusekernel.FsyncIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
2015-07-24 07:41:59 +03:00
if in == nil {
return nil, errors.New("Corrupt OpFsync")
2015-07-24 01:16:46 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.SyncFileOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Handle: fuseops.HandleID(in.Fh),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:19:04 +03:00
case fusekernel.OpFlush:
2015-07-24 07:41:59 +03:00
type input fusekernel.FlushIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
2015-07-24 07:41:59 +03:00
if in == nil {
return nil, errors.New("Corrupt OpFlush")
2015-07-24 01:19:04 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.FlushFileOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Handle: fuseops.HandleID(in.Fh),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:19:32 +03:00
case fusekernel.OpReadlink:
2015-07-27 07:35:26 +03:00
o = &fuseops.ReadSymlinkOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-05-19 09:05:54 +03:00
}
case fusekernel.OpStatfs:
2015-09-09 02:49:54 +03:00
o = &fuseops.StatFSOp{}
case fusekernel.OpInterrupt:
2015-07-24 07:41:59 +03:00
type input fusekernel.InterruptIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
2015-07-24 07:41:59 +03:00
if in == nil {
return nil, errors.New("Corrupt OpInterrupt")
}
2015-07-27 08:52:13 +03:00
o = &interruptOp{
FuseID: in.Unique,
}
2015-07-24 09:35:14 +03:00
case fusekernel.OpInit:
type input fusekernel.InitIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
2015-07-24 09:35:14 +03:00
if in == nil {
return nil, errors.New("Corrupt OpInit")
2015-07-24 09:35:14 +03:00
}
2015-07-27 08:52:13 +03:00
o = &initOp{
2015-07-24 09:35:14 +03:00
Kernel: fusekernel.Protocol{in.Major, in.Minor},
MaxReadahead: in.MaxReadahead,
Flags: fusekernel.InitFlags(in.Flags),
}
2017-11-24 14:44:41 +03:00
case fusekernel.OpLink:
type input fusekernel.LinkIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpLink")
2017-11-24 14:44:41 +03:00
}
name := inMsg.ConsumeBytes(inMsg.Len())
i := bytes.IndexByte(name, '\x00')
if i < 0 {
return nil, errors.New("Corrupt OpLink")
2017-11-24 14:44:41 +03:00
}
name = name[:i]
if len(name) == 0 {
return nil, errors.New("Corrupt OpLink (Name not read)")
2017-11-24 14:44:41 +03:00
}
o = &fuseops.CreateLinkOp{
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(name),
Target: fuseops.InodeID(in.Oldnodeid),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2017-11-24 14:44:41 +03:00
}
2015-12-04 23:26:49 +03:00
case fusekernel.OpRemovexattr:
buf := inMsg.ConsumeBytes(inMsg.Len())
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
return nil, errors.New("Corrupt OpRemovexattr")
2015-12-04 23:26:49 +03:00
}
o = &fuseops.RemoveXattrOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(buf[:n-1]),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-12-04 23:26:49 +03:00
}
2015-12-10 23:58:46 +03:00
case fusekernel.OpGetxattr:
type input fusekernel.GetxattrIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpGetxattr")
2015-12-10 23:58:46 +03:00
}
name := inMsg.ConsumeBytes(inMsg.Len())
i := bytes.IndexByte(name, '\x00')
if i < 0 {
return nil, errors.New("Corrupt OpGetxattr")
2015-12-10 23:58:46 +03:00
}
name = name[:i]
to := &fuseops.GetXattrOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(name),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-12-10 23:58:46 +03:00
}
o = to
readSize := int(in.Size)
if readSize > 0 {
p := outMsg.Grow(readSize)
if p == nil {
return nil, fmt.Errorf("Can't grow for %d-byte read", readSize)
}
2015-12-10 23:58:46 +03:00
sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst))
sh.Data = uintptr(p)
sh.Len = readSize
sh.Cap = readSize
} else {
to.Dst = nil
}
2015-12-10 23:58:46 +03:00
case fusekernel.OpListxattr:
type input fusekernel.ListxattrIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpListxattr")
2015-12-10 23:58:46 +03:00
}
2017-03-15 10:23:54 +03:00
to := &fuseops.ListXattrOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2015-12-10 23:58:46 +03:00
}
2017-03-15 10:23:54 +03:00
o = to
2015-12-10 23:58:46 +03:00
readSize := int(in.Size)
if readSize != 0 {
p := outMsg.Grow(readSize)
2015-12-10 23:58:46 +03:00
if p == nil {
return nil, fmt.Errorf("Can't grow for %d-byte read", readSize)
2015-12-10 23:58:46 +03:00
}
2017-03-15 10:23:54 +03:00
sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst))
sh.Data = uintptr(p)
sh.Len = readSize
sh.Cap = readSize
2015-12-10 23:58:46 +03:00
}
2017-03-06 06:40:50 +03:00
case fusekernel.OpSetxattr:
type input fusekernel.SetxattrIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpSetxattr")
2017-03-06 06:40:50 +03:00
}
payload := inMsg.ConsumeBytes(inMsg.Len())
// payload should be "name\x00value"
if len(payload) < 3 {
return nil, errors.New("Corrupt OpSetxattr")
2017-03-06 06:40:50 +03:00
}
i := bytes.IndexByte(payload, '\x00')
if i < 0 {
return nil, errors.New("Corrupt OpSetxattr")
2017-03-06 06:40:50 +03:00
}
name, value := payload[:i], payload[i+1:len(payload)]
o = &fuseops.SetXattrOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(name),
Value: value,
Flags: in.Flags,
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
2017-03-06 06:40:50 +03:00
}
case fusekernel.OpFallocate:
type input fusekernel.FallocateIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpFallocate")
}
o = &fuseops.FallocateOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Handle: fuseops.HandleID(in.Fh),
Offset: in.Offset,
Length: in.Length,
Mode: in.Mode,
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
}
2015-12-10 23:58:46 +03:00
2023-03-22 18:46:22 +03:00
case fusekernel.OpPoll:
type input fusekernel.PollIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpPoll")
}
o = &fuseops.PollOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Handle: fuseops.HandleID(in.Fh),
Kh: in.Kh,
Flags: fusekernel.PollFlags(in.Flags),
Events: fusekernel.PollEvents(in.Events),
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
}
2023-03-23 00:30:11 +03:00
case fusekernel.OpNotifyReply:
type input fusekernel.NotifyRetrieveIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil {
return nil, errors.New("Corrupt OpNotifyReply")
}
buf := inMsg.ConsumeBytes(inMsg.Len())
if len(buf) < int(in.Size) {
return nil, errors.New("Corrupt OpNotifyReply")
}
o = &fuseops.NotifyRetrieveReplyOp{
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
Unique: inMsg.Header().Unique,
Offset: in.Offset,
Length: in.Size,
OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid},
}
2015-03-24 06:36:44 +03:00
default:
2015-07-27 07:35:26 +03:00
o = &unknownOp{
2015-08-06 09:25:43 +03:00
OpCode: inMsg.Header().Opcode,
Inode: fuseops.InodeID(inMsg.Header().Nodeid),
2015-07-24 02:58:42 +03:00
}
2015-03-24 06:36:44 +03:00
}
return o, nil
2015-03-24 06:36:44 +03:00
}
////////////////////////////////////////////////////////////////////////
// Outgoing messages
////////////////////////////////////////////////////////////////////////
// Fill in the response that should be sent to the kernel, or set noResponse if
// the op requires no response.
2015-07-28 09:13:18 +03:00
func (c *Connection) kernelResponse(
m *buffer.OutMessage,
fuseID uint64,
op interface{},
opErr error) (noResponse bool) {
h := m.OutHeader()
h.Unique = fuseID
// Special case: handle the ops for which the kernel expects no response.
// interruptOp .
switch op.(type) {
case *fuseops.ForgetInodeOp:
return true
case *fuseops.BatchForgetOp:
return true
2023-03-23 00:30:11 +03:00
case *fuseops.NotifyRetrieveReplyOp:
return true
case *interruptOp:
return true
}
// If the user returned the error, fill in the error field of the outgoing
// message header.
if opErr != nil {
2015-12-10 23:58:46 +03:00
handled := false
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.
if opErr == nil {
c.kernelResponseForOp(m, op)
}