remove naked returns across the code base (#75)

fixes #73
geesefs-0-30-9
Michael Stapelberg 2020-01-28 10:10:08 +01:00 committed by GitHub
parent 4898d79241
commit ae5da07e4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 678 additions and 929 deletions

View File

@ -95,8 +95,8 @@ func newConnection(
cfg MountConfig, cfg MountConfig,
debugLogger *log.Logger, debugLogger *log.Logger,
errorLogger *log.Logger, errorLogger *log.Logger,
dev *os.File) (c *Connection, err error) { dev *os.File) (*Connection, error) {
c = &Connection{ c := &Connection{
cfg: cfg, cfg: cfg,
debugLogger: debugLogger, debugLogger: debugLogger,
errorLogger: errorLogger, errorLogger: errorLogger,
@ -105,30 +105,26 @@ func newConnection(
} }
// Initialize. // Initialize.
err = c.Init() if err := c.Init(); err != nil {
if err != nil {
c.close() c.close()
err = fmt.Errorf("Init: %v", err) return nil, fmt.Errorf("Init: %v", err)
return
} }
return return c, nil
} }
// Init performs the work necessary to cause the mount process to complete. // Init performs the work necessary to cause the mount process to complete.
func (c *Connection) Init() (err error) { func (c *Connection) Init() error {
// Read the init op. // Read the init op.
ctx, op, err := c.ReadOp() ctx, op, err := c.ReadOp()
if err != nil { if err != nil {
err = fmt.Errorf("Reading init op: %v", err) return fmt.Errorf("Reading init op: %v", err)
return
} }
initOp, ok := op.(*initOp) initOp, ok := op.(*initOp)
if !ok { if !ok {
c.Reply(ctx, syscall.EPROTO) c.Reply(ctx, syscall.EPROTO)
err = fmt.Errorf("Expected *initOp, got %T", op) return fmt.Errorf("Expected *initOp, got %T", op)
return
} }
// Make sure the protocol version spoken by the kernel is new enough. // Make sure the protocol version spoken by the kernel is new enough.
@ -139,8 +135,7 @@ func (c *Connection) Init() (err error) {
if initOp.Kernel.LT(min) { if initOp.Kernel.LT(min) {
c.Reply(ctx, syscall.EPROTO) c.Reply(ctx, syscall.EPROTO)
err = fmt.Errorf("Version too old: %v", initOp.Kernel) return fmt.Errorf("Version too old: %v", initOp.Kernel)
return
} }
// Downgrade our protocol if necessary. // Downgrade our protocol if necessary.
@ -169,7 +164,7 @@ func (c *Connection) Init() (err error) {
} }
c.Reply(ctx, nil) c.Reply(ctx, nil)
return return nil
} }
// Log information for an operation with the given ID. calldepth is the depth // Log information for an operation with the given ID. calldepth is the depth
@ -228,9 +223,9 @@ func (c *Connection) recordCancelFunc(
// LOCKS_EXCLUDED(c.mu) // LOCKS_EXCLUDED(c.mu)
func (c *Connection) beginOp( func (c *Connection) beginOp(
opCode uint32, opCode uint32,
fuseID uint64) (ctx context.Context) { fuseID uint64) context.Context {
// Start with the parent context. // Start with the parent context.
ctx = c.cfg.OpContext ctx := c.cfg.OpContext
// Set up a cancellation function. // Set up a cancellation function.
// //
@ -246,7 +241,7 @@ func (c *Connection) beginOp(
c.recordCancelFunc(fuseID, cancel) c.recordCancelFunc(fuseID, cancel)
} }
return return ctx
} }
// Clean up all state associated with an op to which the user has responded, // Clean up all state associated with an op to which the user has responded,
@ -307,14 +302,14 @@ func (c *Connection) handleInterrupt(fuseID uint64) {
// Read the next message from the kernel. The message must later be destroyed // Read the next message from the kernel. The message must later be destroyed
// using destroyInMessage. // using destroyInMessage.
func (c *Connection) readMessage() (m *buffer.InMessage, err error) { func (c *Connection) readMessage() (*buffer.InMessage, error) {
// Allocate a message. // Allocate a message.
m = c.getInMessage() m := c.getInMessage()
// Loop past transient errors. // Loop past transient errors.
for { for {
// Attempt a reaed. // Attempt a reaed.
err = m.Init(c.dev) err := m.Init(c.dev)
// Special cases: // Special cases:
// //
@ -336,28 +331,26 @@ func (c *Connection) readMessage() (m *buffer.InMessage, err error) {
if err != nil { if err != nil {
c.putInMessage(m) c.putInMessage(m)
m = nil return nil, err
return
} }
return return m, nil
} }
} }
// Write the supplied message to the kernel. // Write the supplied message to the kernel.
func (c *Connection) writeMessage(msg []byte) (err error) { func (c *Connection) writeMessage(msg []byte) error {
// Avoid the retry loop in os.File.Write. // Avoid the retry loop in os.File.Write.
n, err := syscall.Write(int(c.dev.Fd()), msg) n, err := syscall.Write(int(c.dev.Fd()), msg)
if err != nil { if err != nil {
return return err
} }
if n != len(msg) { if n != len(msg) {
err = fmt.Errorf("Wrote %d bytes; expected %d", n, len(msg)) return fmt.Errorf("Wrote %d bytes; expected %d", n, len(msg))
return
} }
return return nil
} }
// ReadOp consumes the next op from the kernel process, returning the op and a // ReadOp consumes the next op from the kernel process, returning the op and a
@ -371,14 +364,13 @@ func (c *Connection) writeMessage(msg []byte) (err error) {
// /dev/fuse. It must not be called multiple times concurrently. // /dev/fuse. It must not be called multiple times concurrently.
// //
// LOCKS_EXCLUDED(c.mu) // LOCKS_EXCLUDED(c.mu)
func (c *Connection) ReadOp() (ctx context.Context, op interface{}, err error) { func (c *Connection) ReadOp() (_ context.Context, op interface{}, _ error) {
// Keep going until we find a request we know how to convert. // Keep going until we find a request we know how to convert.
for { for {
// Read the next message from the kernel. // Read the next message from the kernel.
var inMsg *buffer.InMessage inMsg, err := c.readMessage()
inMsg, err = c.readMessage()
if err != nil { if err != nil {
return return nil, nil, err
} }
// Convert the message to an op. // Convert the message to an op.
@ -386,8 +378,7 @@ func (c *Connection) ReadOp() (ctx context.Context, op interface{}, err error) {
op, err = convertInMessage(inMsg, outMsg, c.protocol) op, err = convertInMessage(inMsg, outMsg, c.protocol)
if err != nil { if err != nil {
c.putOutMessage(outMsg) c.putOutMessage(outMsg)
err = fmt.Errorf("convertInMessage: %v", err) return nil, nil, fmt.Errorf("convertInMessage: %v", err)
return
} }
// Choose an ID for this operation for the purposes of logging, and log it. // Choose an ID for this operation for the purposes of logging, and log it.
@ -402,11 +393,11 @@ func (c *Connection) ReadOp() (ctx context.Context, op interface{}, err error) {
} }
// Set up a context that remembers information about this op. // Set up a context that remembers information about this op.
ctx = c.beginOp(inMsg.Header().Opcode, inMsg.Header().Unique) ctx := c.beginOp(inMsg.Header().Opcode, inMsg.Header().Unique)
ctx = context.WithValue(ctx, contextKey, opState{inMsg, outMsg, op}) ctx = context.WithValue(ctx, contextKey, opState{inMsg, outMsg, op})
// Return the op to the user. // Return the op to the user.
return return ctx, op, nil
} }
} }
@ -499,10 +490,9 @@ func (c *Connection) Reply(ctx context.Context, opErr error) {
// Close the connection. Must not be called until operations that were read // Close the connection. Must not be called until operations that were read
// from the connection have been responded to. // from the connection have been responded to.
func (c *Connection) close() (err error) { func (c *Connection) close() error {
// Posix doesn't say that close can be called concurrently with read or // Posix doesn't say that close can be called concurrently with read or
// write, but luckily we exclude the possibility of a race by requiring the // write, but luckily we exclude the possibility of a race by requiring the
// user to respond to all ops first. // user to respond to all ops first.
err = c.dev.Close() return c.dev.Close()
return
} }

View File

@ -46,8 +46,7 @@ func convertInMessage(
buf := inMsg.ConsumeBytes(inMsg.Len()) buf := inMsg.ConsumeBytes(inMsg.Len())
n := len(buf) n := len(buf)
if n == 0 || buf[n-1] != '\x00' { if n == 0 || buf[n-1] != '\x00' {
err = errors.New("Corrupt OpLookup") return nil, errors.New("Corrupt OpLookup")
return
} }
o = &fuseops.LookUpInodeOp{ o = &fuseops.LookUpInodeOp{
@ -64,8 +63,7 @@ func convertInMessage(
type input fusekernel.SetattrIn type input fusekernel.SetattrIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpSetattr") return nil, errors.New("Corrupt OpSetattr")
return
} }
to := &fuseops.SetInodeAttributesOp{ to := &fuseops.SetInodeAttributesOp{
@ -102,8 +100,7 @@ func convertInMessage(
type input fusekernel.ForgetIn type input fusekernel.ForgetIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpForget") return nil, errors.New("Corrupt OpForget")
return
} }
o = &fuseops.ForgetInodeOp{ o = &fuseops.ForgetInodeOp{
@ -114,15 +111,13 @@ func convertInMessage(
case fusekernel.OpMkdir: case fusekernel.OpMkdir:
in := (*fusekernel.MkdirIn)(inMsg.Consume(fusekernel.MkdirInSize(protocol))) in := (*fusekernel.MkdirIn)(inMsg.Consume(fusekernel.MkdirInSize(protocol)))
if in == nil { if in == nil {
err = errors.New("Corrupt OpMkdir") return nil, errors.New("Corrupt OpMkdir")
return
} }
name := inMsg.ConsumeBytes(inMsg.Len()) name := inMsg.ConsumeBytes(inMsg.Len())
i := bytes.IndexByte(name, '\x00') i := bytes.IndexByte(name, '\x00')
if i < 0 { if i < 0 {
err = errors.New("Corrupt OpMkdir") return nil, errors.New("Corrupt OpMkdir")
return
} }
name = name[:i] name = name[:i]
@ -142,15 +137,13 @@ func convertInMessage(
case fusekernel.OpMknod: case fusekernel.OpMknod:
in := (*fusekernel.MknodIn)(inMsg.Consume(fusekernel.MknodInSize(protocol))) in := (*fusekernel.MknodIn)(inMsg.Consume(fusekernel.MknodInSize(protocol)))
if in == nil { if in == nil {
err = errors.New("Corrupt OpMknod") return nil, errors.New("Corrupt OpMknod")
return
} }
name := inMsg.ConsumeBytes(inMsg.Len()) name := inMsg.ConsumeBytes(inMsg.Len())
i := bytes.IndexByte(name, '\x00') i := bytes.IndexByte(name, '\x00')
if i < 0 { if i < 0 {
err = errors.New("Corrupt OpMknod") return nil, errors.New("Corrupt OpMknod")
return
} }
name = name[:i] name = name[:i]
@ -163,15 +156,13 @@ func convertInMessage(
case fusekernel.OpCreate: case fusekernel.OpCreate:
in := (*fusekernel.CreateIn)(inMsg.Consume(fusekernel.CreateInSize(protocol))) in := (*fusekernel.CreateIn)(inMsg.Consume(fusekernel.CreateInSize(protocol)))
if in == nil { if in == nil {
err = errors.New("Corrupt OpCreate") return nil, errors.New("Corrupt OpCreate")
return
} }
name := inMsg.ConsumeBytes(inMsg.Len()) name := inMsg.ConsumeBytes(inMsg.Len())
i := bytes.IndexByte(name, '\x00') i := bytes.IndexByte(name, '\x00')
if i < 0 { if i < 0 {
err = errors.New("Corrupt OpCreate") return nil, errors.New("Corrupt OpCreate")
return
} }
name = name[:i] name = name[:i]
@ -185,13 +176,11 @@ func convertInMessage(
// The message is "newName\0target\0". // The message is "newName\0target\0".
names := inMsg.ConsumeBytes(inMsg.Len()) names := inMsg.ConsumeBytes(inMsg.Len())
if len(names) == 0 || names[len(names)-1] != 0 { if len(names) == 0 || names[len(names)-1] != 0 {
err = errors.New("Corrupt OpSymlink") return nil, errors.New("Corrupt OpSymlink")
return
} }
i := bytes.IndexByte(names, '\x00') i := bytes.IndexByte(names, '\x00')
if i < 0 { if i < 0 {
err = errors.New("Corrupt OpSymlink") return nil, errors.New("Corrupt OpSymlink")
return
} }
newName, target := names[0:i], names[i+1:len(names)-1] newName, target := names[0:i], names[i+1:len(names)-1]
@ -205,24 +194,20 @@ func convertInMessage(
type input fusekernel.RenameIn type input fusekernel.RenameIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpRename") return nil, errors.New("Corrupt OpRename")
return
} }
names := inMsg.ConsumeBytes(inMsg.Len()) names := inMsg.ConsumeBytes(inMsg.Len())
// names should be "old\x00new\x00" // names should be "old\x00new\x00"
if len(names) < 4 { if len(names) < 4 {
err = errors.New("Corrupt OpRename") return nil, errors.New("Corrupt OpRename")
return
} }
if names[len(names)-1] != '\x00' { if names[len(names)-1] != '\x00' {
err = errors.New("Corrupt OpRename") return nil, errors.New("Corrupt OpRename")
return
} }
i := bytes.IndexByte(names, '\x00') i := bytes.IndexByte(names, '\x00')
if i < 0 { if i < 0 {
err = errors.New("Corrupt OpRename") return nil, errors.New("Corrupt OpRename")
return
} }
oldName, newName := names[:i], names[i+1:len(names)-1] oldName, newName := names[:i], names[i+1:len(names)-1]
@ -237,8 +222,7 @@ func convertInMessage(
buf := inMsg.ConsumeBytes(inMsg.Len()) buf := inMsg.ConsumeBytes(inMsg.Len())
n := len(buf) n := len(buf)
if n == 0 || buf[n-1] != '\x00' { if n == 0 || buf[n-1] != '\x00' {
err = errors.New("Corrupt OpUnlink") return nil, errors.New("Corrupt OpUnlink")
return
} }
o = &fuseops.UnlinkOp{ o = &fuseops.UnlinkOp{
@ -250,8 +234,7 @@ func convertInMessage(
buf := inMsg.ConsumeBytes(inMsg.Len()) buf := inMsg.ConsumeBytes(inMsg.Len())
n := len(buf) n := len(buf)
if n == 0 || buf[n-1] != '\x00' { if n == 0 || buf[n-1] != '\x00' {
err = errors.New("Corrupt OpRmdir") return nil, errors.New("Corrupt OpRmdir")
return
} }
o = &fuseops.RmDirOp{ o = &fuseops.RmDirOp{
@ -272,8 +255,7 @@ func convertInMessage(
case fusekernel.OpRead: case fusekernel.OpRead:
in := (*fusekernel.ReadIn)(inMsg.Consume(fusekernel.ReadInSize(protocol))) in := (*fusekernel.ReadIn)(inMsg.Consume(fusekernel.ReadInSize(protocol)))
if in == nil { if in == nil {
err = errors.New("Corrupt OpRead") return nil, errors.New("Corrupt OpRead")
return
} }
to := &fuseops.ReadFileOp{ to := &fuseops.ReadFileOp{
@ -286,8 +268,7 @@ func convertInMessage(
readSize := int(in.Size) readSize := int(in.Size)
p := outMsg.GrowNoZero(readSize) p := outMsg.GrowNoZero(readSize)
if p == nil { if p == nil {
err = fmt.Errorf("Can't grow for %d-byte read", readSize) return nil, fmt.Errorf("Can't grow for %d-byte read", readSize)
return
} }
sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst)) sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst))
@ -298,8 +279,7 @@ func convertInMessage(
case fusekernel.OpReaddir: case fusekernel.OpReaddir:
in := (*fusekernel.ReadIn)(inMsg.Consume(fusekernel.ReadInSize(protocol))) in := (*fusekernel.ReadIn)(inMsg.Consume(fusekernel.ReadInSize(protocol)))
if in == nil { if in == nil {
err = errors.New("Corrupt OpReaddir") return nil, errors.New("Corrupt OpReaddir")
return
} }
to := &fuseops.ReadDirOp{ to := &fuseops.ReadDirOp{
@ -312,8 +292,7 @@ func convertInMessage(
readSize := int(in.Size) readSize := int(in.Size)
p := outMsg.GrowNoZero(readSize) p := outMsg.GrowNoZero(readSize)
if p == nil { if p == nil {
err = fmt.Errorf("Can't grow for %d-byte read", readSize) return nil, fmt.Errorf("Can't grow for %d-byte read", readSize)
return
} }
sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst)) sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst))
@ -325,8 +304,7 @@ func convertInMessage(
type input fusekernel.ReleaseIn type input fusekernel.ReleaseIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpRelease") return nil, errors.New("Corrupt OpRelease")
return
} }
o = &fuseops.ReleaseFileHandleOp{ o = &fuseops.ReleaseFileHandleOp{
@ -337,8 +315,7 @@ func convertInMessage(
type input fusekernel.ReleaseIn type input fusekernel.ReleaseIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpReleasedir") return nil, errors.New("Corrupt OpReleasedir")
return
} }
o = &fuseops.ReleaseDirHandleOp{ o = &fuseops.ReleaseDirHandleOp{
@ -348,14 +325,12 @@ func convertInMessage(
case fusekernel.OpWrite: case fusekernel.OpWrite:
in := (*fusekernel.WriteIn)(inMsg.Consume(fusekernel.WriteInSize(protocol))) in := (*fusekernel.WriteIn)(inMsg.Consume(fusekernel.WriteInSize(protocol)))
if in == nil { if in == nil {
err = errors.New("Corrupt OpWrite") return nil, errors.New("Corrupt OpWrite")
return
} }
buf := inMsg.ConsumeBytes(inMsg.Len()) buf := inMsg.ConsumeBytes(inMsg.Len())
if len(buf) < int(in.Size) { if len(buf) < int(in.Size) {
err = errors.New("Corrupt OpWrite") return nil, errors.New("Corrupt OpWrite")
return
} }
o = &fuseops.WriteFileOp{ o = &fuseops.WriteFileOp{
@ -369,8 +344,7 @@ func convertInMessage(
type input fusekernel.FsyncIn type input fusekernel.FsyncIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpFsync") return nil, errors.New("Corrupt OpFsync")
return
} }
o = &fuseops.SyncFileOp{ o = &fuseops.SyncFileOp{
@ -382,8 +356,7 @@ func convertInMessage(
type input fusekernel.FlushIn type input fusekernel.FlushIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpFlush") return nil, errors.New("Corrupt OpFlush")
return
} }
o = &fuseops.FlushFileOp{ o = &fuseops.FlushFileOp{
@ -403,8 +376,7 @@ func convertInMessage(
type input fusekernel.InterruptIn type input fusekernel.InterruptIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpInterrupt") return nil, errors.New("Corrupt OpInterrupt")
return
} }
o = &interruptOp{ o = &interruptOp{
@ -415,8 +387,7 @@ func convertInMessage(
type input fusekernel.InitIn type input fusekernel.InitIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpInit") return nil, errors.New("Corrupt OpInit")
return
} }
o = &initOp{ o = &initOp{
@ -429,20 +400,17 @@ func convertInMessage(
type input fusekernel.LinkIn type input fusekernel.LinkIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpLink") return nil, errors.New("Corrupt OpLink")
return
} }
name := inMsg.ConsumeBytes(inMsg.Len()) name := inMsg.ConsumeBytes(inMsg.Len())
i := bytes.IndexByte(name, '\x00') i := bytes.IndexByte(name, '\x00')
if i < 0 { if i < 0 {
err = errors.New("Corrupt OpLink") return nil, errors.New("Corrupt OpLink")
return
} }
name = name[:i] name = name[:i]
if len(name) == 0 { if len(name) == 0 {
err = errors.New("Corrupt OpLink (Name not read)") return nil, errors.New("Corrupt OpLink (Name not read)")
return
} }
o = &fuseops.CreateLinkOp{ o = &fuseops.CreateLinkOp{
@ -455,8 +423,7 @@ func convertInMessage(
buf := inMsg.ConsumeBytes(inMsg.Len()) buf := inMsg.ConsumeBytes(inMsg.Len())
n := len(buf) n := len(buf)
if n == 0 || buf[n-1] != '\x00' { if n == 0 || buf[n-1] != '\x00' {
err = errors.New("Corrupt OpRemovexattr") return nil, errors.New("Corrupt OpRemovexattr")
return
} }
o = &fuseops.RemoveXattrOp{ o = &fuseops.RemoveXattrOp{
@ -468,15 +435,13 @@ func convertInMessage(
type input fusekernel.GetxattrIn type input fusekernel.GetxattrIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpGetxattr") return nil, errors.New("Corrupt OpGetxattr")
return
} }
name := inMsg.ConsumeBytes(inMsg.Len()) name := inMsg.ConsumeBytes(inMsg.Len())
i := bytes.IndexByte(name, '\x00') i := bytes.IndexByte(name, '\x00')
if i < 0 { if i < 0 {
err = errors.New("Corrupt OpGetxattr") return nil, errors.New("Corrupt OpGetxattr")
return
} }
name = name[:i] name = name[:i]
@ -489,8 +454,7 @@ func convertInMessage(
readSize := int(in.Size) readSize := int(in.Size)
p := outMsg.GrowNoZero(readSize) p := outMsg.GrowNoZero(readSize)
if p == nil { if p == nil {
err = fmt.Errorf("Can't grow for %d-byte read", readSize) return nil, fmt.Errorf("Can't grow for %d-byte read", readSize)
return
} }
sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst)) sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst))
@ -502,8 +466,7 @@ func convertInMessage(
type input fusekernel.ListxattrIn type input fusekernel.ListxattrIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpListxattr") return nil, errors.New("Corrupt OpListxattr")
return
} }
to := &fuseops.ListXattrOp{ to := &fuseops.ListXattrOp{
@ -515,8 +478,7 @@ func convertInMessage(
if readSize != 0 { if readSize != 0 {
p := outMsg.GrowNoZero(readSize) p := outMsg.GrowNoZero(readSize)
if p == nil { if p == nil {
err = fmt.Errorf("Can't grow for %d-byte read", readSize) return nil, fmt.Errorf("Can't grow for %d-byte read", readSize)
return
} }
sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst)) sh := (*reflect.SliceHeader)(unsafe.Pointer(&to.Dst))
sh.Data = uintptr(p) sh.Data = uintptr(p)
@ -527,20 +489,17 @@ func convertInMessage(
type input fusekernel.SetxattrIn type input fusekernel.SetxattrIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpSetxattr") return nil, errors.New("Corrupt OpSetxattr")
return
} }
payload := inMsg.ConsumeBytes(inMsg.Len()) payload := inMsg.ConsumeBytes(inMsg.Len())
// payload should be "name\x00value" // payload should be "name\x00value"
if len(payload) < 3 { if len(payload) < 3 {
err = errors.New("Corrupt OpSetxattr") return nil, errors.New("Corrupt OpSetxattr")
return
} }
i := bytes.IndexByte(payload, '\x00') i := bytes.IndexByte(payload, '\x00')
if i < 0 { if i < 0 {
err = errors.New("Corrupt OpSetxattr") return nil, errors.New("Corrupt OpSetxattr")
return
} }
name, value := payload[:i], payload[i+1:len(payload)] name, value := payload[:i], payload[i+1:len(payload)]
@ -555,8 +514,7 @@ func convertInMessage(
type input fusekernel.FallocateIn type input fusekernel.FallocateIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
if in == nil { if in == nil {
err = errors.New("Corrupt OpFallocate") return nil, errors.New("Corrupt OpFallocate")
return
} }
o = &fuseops.FallocateOp{ o = &fuseops.FallocateOp{
@ -574,7 +532,7 @@ func convertInMessage(
} }
} }
return return o, nil
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -595,12 +553,10 @@ func (c *Connection) kernelResponse(
// interruptOp . // interruptOp .
switch op.(type) { switch op.(type) {
case *fuseops.ForgetInodeOp: case *fuseops.ForgetInodeOp:
noResponse = true return true
return
case *interruptOp: case *interruptOp:
noResponse = true return true
return
} }
// If the user returned the error, fill in the error field of the outgoing // If the user returned the error, fill in the error field of the outgoing
@ -629,7 +585,7 @@ func (c *Connection) kernelResponse(
} }
h.Len = uint32(m.Len()) h.Len = uint32(m.Len())
return return false
} }
// Like kernelResponse, but assumes the user replied with a nil error to the // Like kernelResponse, but assumes the user replied with a nil error to the
@ -829,7 +785,7 @@ func convertTime(t time.Time) (secs uint64, nsec uint32) {
totalNano := t.UnixNano() totalNano := t.UnixNano()
secs = uint64(totalNano / 1e9) secs = uint64(totalNano / 1e9)
nsec = uint32(totalNano % 1e9) nsec = uint32(totalNano % 1e9)
return return secs, nsec
} }
func convertAttributes( func convertAttributes(
@ -886,7 +842,7 @@ func convertExpirationTime(t time.Time) (secs uint64, nsecs uint32) {
nsecs = uint32((d % time.Second) / time.Nanosecond) nsecs = uint32((d % time.Second) / time.Nanosecond)
} }
return return secs, nsecs
} }
func convertChildInodeEntry( func convertChildInodeEntry(

View File

@ -25,16 +25,16 @@ import (
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// LOCKS_EXCLUDED(c.mu) // LOCKS_EXCLUDED(c.mu)
func (c *Connection) getInMessage() (x *buffer.InMessage) { func (c *Connection) getInMessage() *buffer.InMessage {
c.mu.Lock() c.mu.Lock()
x = (*buffer.InMessage)(c.inMessages.Get()) x := (*buffer.InMessage)(c.inMessages.Get())
c.mu.Unlock() c.mu.Unlock()
if x == nil { if x == nil {
x = new(buffer.InMessage) x = new(buffer.InMessage)
} }
return return x
} }
// LOCKS_EXCLUDED(c.mu) // LOCKS_EXCLUDED(c.mu)
@ -49,9 +49,9 @@ func (c *Connection) putInMessage(x *buffer.InMessage) {
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// LOCKS_EXCLUDED(c.mu) // LOCKS_EXCLUDED(c.mu)
func (c *Connection) getOutMessage() (x *buffer.OutMessage) { func (c *Connection) getOutMessage() *buffer.OutMessage {
c.mu.Lock() c.mu.Lock()
x = (*buffer.OutMessage)(c.outMessages.Get()) x := (*buffer.OutMessage)(c.outMessages.Get())
c.mu.Unlock() c.mu.Unlock()
if x == nil { if x == nil {
@ -59,7 +59,7 @@ func (c *Connection) getOutMessage() (x *buffer.OutMessage) {
} }
x.Reset() x.Reset()
return return x
} }
// LOCKS_EXCLUDED(c.mu) // LOCKS_EXCLUDED(c.mu)

View File

@ -28,25 +28,22 @@ import (
// Warning: this is not production-quality code, and should only be used for // Warning: this is not production-quality code, and should only be used for
// testing purposes. In particular, there is a race between creating and // testing purposes. In particular, there is a race between creating and
// unlinking by name. // unlinking by name.
func AnonymousFile(dir string) (f *os.File, err error) { func AnonymousFile(dir string) (*os.File, error) {
// Choose a prefix based on the binary name. // Choose a prefix based on the binary name.
prefix := path.Base(os.Args[0]) prefix := path.Base(os.Args[0])
// Create the file. // Create the file.
f, err = ioutil.TempFile(dir, prefix) f, err := ioutil.TempFile(dir, prefix)
if err != nil { if err != nil {
err = fmt.Errorf("TempFile: %v", err) return nil, fmt.Errorf("TempFile: %v", err)
return
} }
// Unlink it. // Unlink it.
err = os.Remove(f.Name()) if err := os.Remove(f.Name()); err != nil {
if err != nil { return nil, fmt.Errorf("Remove: %v", err)
err = fmt.Errorf("Remove: %v", err)
return
} }
return return f, nil
} }
// Call fdatasync on the supplied file. // Call fdatasync on the supplied file.

View File

@ -44,22 +44,18 @@ func RunCreateInParallelTest_NoTruncate(
// Set up a function that opens the file with O_CREATE and then appends a // Set up a function that opens the file with O_CREATE and then appends a
// byte to it. // byte to it.
worker := func(id byte) (err error) { worker := func(id byte) error {
f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil { if err != nil {
err = fmt.Errorf("Worker %d: Open: %v", id, err) return fmt.Errorf("Worker %d: Open: %v", id, err)
return
} }
defer f.Close() defer f.Close()
_, err = f.Write([]byte{id}) if _, err := f.Write([]byte{id}); err != nil {
if err != nil { return fmt.Errorf("Worker %d: Write: %v", id, err)
err = fmt.Errorf("Worker %d: Write: %v", id, err)
return
} }
return return nil
} }
// Run several workers in parallel. // Run several workers in parallel.
@ -67,9 +63,8 @@ func RunCreateInParallelTest_NoTruncate(
b := syncutil.NewBundle(ctx) b := syncutil.NewBundle(ctx)
for i := 0; i < numWorkers; i++ { for i := 0; i < numWorkers; i++ {
id := byte(i) id := byte(i)
b.Add(func(ctx context.Context) (err error) { b.Add(func(ctx context.Context) error {
err = worker(id) return worker(id)
return
}) })
} }
@ -121,21 +116,16 @@ func RunCreateInParallelTest_Truncate(
filename, filename,
os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_TRUNC, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_TRUNC,
0600) 0600)
if err != nil { if err != nil {
err = fmt.Errorf("Worker %d: Open: %v", id, err) return fmt.Errorf("Worker %d: Open: %v", id, err)
return
} }
defer f.Close() defer f.Close()
_, err = f.Write([]byte{id}) if _, err := f.Write([]byte{id}); err != nil {
if err != nil { return fmt.Errorf("Worker %d: Write: %v", id, err)
err = fmt.Errorf("Worker %d: Write: %v", id, err)
return
} }
return return nil
} }
// Run several workers in parallel. // Run several workers in parallel.
@ -143,9 +133,8 @@ func RunCreateInParallelTest_Truncate(
b := syncutil.NewBundle(ctx) b := syncutil.NewBundle(ctx)
for i := 0; i < numWorkers; i++ { for i := 0; i < numWorkers; i++ {
id := byte(i) id := byte(i)
b.Add(func(ctx context.Context) (err error) { b.Add(func(ctx context.Context) error {
err = worker(id) return worker(id)
return
}) })
} }
@ -203,26 +192,22 @@ func RunCreateInParallelTest_Exclusive(
// If we failed to open due to the file already existing, just leave. // If we failed to open due to the file already existing, just leave.
if os.IsExist(err) { if os.IsExist(err) {
err = nil return nil
return
} }
// Propgate other errors. // Propgate other errors.
if err != nil { if err != nil {
err = fmt.Errorf("Worker %d: Open: %v", id, err) return fmt.Errorf("Worker %d: Open: %v", id, err)
return
} }
atomic.AddUint64(&openCount, 1) atomic.AddUint64(&openCount, 1)
defer f.Close() defer f.Close()
_, err = f.Write([]byte{id}) if _, err := f.Write([]byte{id}); err != nil {
if err != nil { return fmt.Errorf("Worker %d: Write: %v", id, err)
err = fmt.Errorf("Worker %d: Write: %v", id, err)
return
} }
return return nil
} }
// Run several workers in parallel. // Run several workers in parallel.
@ -230,9 +215,8 @@ func RunCreateInParallelTest_Exclusive(
b := syncutil.NewBundle(ctx) b := syncutil.NewBundle(ctx)
for i := 0; i < numWorkers; i++ { for i := 0; i < numWorkers; i++ {
id := byte(i) id := byte(i)
b.Add(func(ctx context.Context) (err error) { b.Add(func(ctx context.Context) error {
err = worker(id) return worker(id)
return
}) })
} }
@ -269,19 +253,16 @@ func RunMkdirInParallelTest(
filename := path.Join(dir, "foo") filename := path.Join(dir, "foo")
// Set up a function that creates the directory, ignoring EEXIST errors. // Set up a function that creates the directory, ignoring EEXIST errors.
worker := func(id byte) (err error) { worker := func(id byte) error {
err = os.Mkdir(filename, 0700) err := os.Mkdir(filename, 0700)
if os.IsExist(err) { if os.IsExist(err) {
err = nil return nil
} }
if err != nil { if err != nil {
err = fmt.Errorf("Worker %d: Mkdir: %v", id, err) return fmt.Errorf("Worker %d: Mkdir: %v", id, err)
return
} }
return return nil
} }
// Run several workers in parallel. // Run several workers in parallel.
@ -289,9 +270,8 @@ func RunMkdirInParallelTest(
b := syncutil.NewBundle(ctx) b := syncutil.NewBundle(ctx)
for i := 0; i < numWorkers; i++ { for i := 0; i < numWorkers; i++ {
id := byte(i) id := byte(i)
b.Add(func(ctx context.Context) (err error) { b.Add(func(ctx context.Context) error {
err = worker(id) return worker(id)
return
}) })
} }
@ -325,19 +305,17 @@ func RunSymlinkInParallelTest(
filename := path.Join(dir, "foo") filename := path.Join(dir, "foo")
// Set up a function that creates the symlink, ignoring EEXIST errors. // Set up a function that creates the symlink, ignoring EEXIST errors.
worker := func(id byte) (err error) { worker := func(id byte) error {
err = os.Symlink("blah", filename) err := os.Symlink("blah", filename)
if os.IsExist(err) { if os.IsExist(err) {
err = nil return nil
} }
if err != nil { if err != nil {
err = fmt.Errorf("Worker %d: Symlink: %v", id, err) return fmt.Errorf("Worker %d: Symlink: %v", id, err)
return
} }
return return nil
} }
// Run several workers in parallel. // Run several workers in parallel.
@ -345,9 +323,8 @@ func RunSymlinkInParallelTest(
b := syncutil.NewBundle(ctx) b := syncutil.NewBundle(ctx)
for i := 0; i < numWorkers; i++ { for i := 0; i < numWorkers; i++ {
id := byte(i) id := byte(i)
b.Add(func(ctx context.Context) (err error) { b.Add(func(ctx context.Context) error {
err = worker(id) return worker(id)
return
}) })
} }
@ -388,19 +365,16 @@ func RunHardlinkInParallelTest(
filename := path.Join(dir, "foo") filename := path.Join(dir, "foo")
// Set up a function that creates the symlink, ignoring EEXIST errors. // Set up a function that creates the symlink, ignoring EEXIST errors.
worker := func(id byte) (err error) { worker := func(id byte) error {
err = os.Link(originalFile, filename) err := os.Link(originalFile, filename)
if os.IsExist(err) { if os.IsExist(err) {
err = nil return nil
} }
if err != nil { if err != nil {
err = fmt.Errorf("Worker %d: Link: %v", id, err) return fmt.Errorf("Worker %d: Link: %v", id, err)
return
} }
return return nil
} }
// Run several workers in parallel. // Run several workers in parallel.
@ -408,9 +382,8 @@ func RunHardlinkInParallelTest(
b := syncutil.NewBundle(ctx) b := syncutil.NewBundle(ctx)
for i := 0; i < numWorkers; i++ { for i := 0; i < numWorkers; i++ {
id := byte(i) id := byte(i)
b.Add(func(ctx context.Context) (err error) { b.Add(func(ctx context.Context) error {
err = worker(id) return worker(id)
return
}) })
} }

View File

@ -37,8 +37,7 @@ func ReadDirPicky(dirname string) (entries []os.FileInfo, err error) {
// Open the directory. // Open the directory.
f, err := os.Open(dirname) f, err := os.Open(dirname)
if err != nil { if err != nil {
err = fmt.Errorf("Open: %v", err) return nil, fmt.Errorf("Open: %v", err)
return
} }
// Don't forget to close it later. // Don't forget to close it later.
@ -52,8 +51,7 @@ func ReadDirPicky(dirname string) (entries []os.FileInfo, err error) {
// Read all of the names from the directory. // Read all of the names from the directory.
names, err := f.Readdirnames(-1) names, err := f.Readdirnames(-1)
if err != nil { if err != nil {
err = fmt.Errorf("Readdirnames: %v", err) return nil, fmt.Errorf("Readdirnames: %v", err)
return
} }
// Stat each one. // Stat each one.
@ -62,8 +60,7 @@ func ReadDirPicky(dirname string) (entries []os.FileInfo, err error) {
fi, err = os.Lstat(path.Join(dirname, name)) fi, err = os.Lstat(path.Join(dirname, name))
if err != nil { if err != nil {
err = fmt.Errorf("Lstat(%s): %v", name, err) return nil, fmt.Errorf("Lstat(%s): %v", name, err)
return
} }
entries = append(entries, fi) entries = append(entries, fi)
@ -72,5 +69,5 @@ func ReadDirPicky(dirname string) (entries []os.FileInfo, err error) {
// Sort the entries by name. // Sort the entries by name.
sort.Sort(sortedEntries(entries)) sort.Sort(sortedEntries(entries))
return return entries, nil
} }

View File

@ -20,26 +20,20 @@ import (
) )
func extractMtime(sys interface{}) (mtime time.Time, ok bool) { func extractMtime(sys interface{}) (mtime time.Time, ok bool) {
mtime = time.Unix(sys.(*syscall.Stat_t).Mtimespec.Unix()) return time.Unix(sys.(*syscall.Stat_t).Mtimespec.Unix()), true
ok = true
return
} }
func extractBirthtime(sys interface{}) (birthtime time.Time, ok bool) { func extractBirthtime(sys interface{}) (birthtime time.Time, ok bool) {
birthtime = time.Unix(sys.(*syscall.Stat_t).Birthtimespec.Unix()) return time.Unix(sys.(*syscall.Stat_t).Birthtimespec.Unix()), true
ok = true
return
} }
func extractNlink(sys interface{}) (nlink uint64, ok bool) { func extractNlink(sys interface{}) (nlink uint64, ok bool) {
nlink = uint64(sys.(*syscall.Stat_t).Nlink) return uint64(sys.(*syscall.Stat_t).Nlink), true
ok = true
return
} }
func getTimes(stat *syscall.Stat_t) (atime, ctime, mtime time.Time) { func getTimes(stat *syscall.Stat_t) (atime, ctime, mtime time.Time) {
atime = time.Unix(stat.Atimespec.Unix()) atime = time.Unix(stat.Atimespec.Unix())
ctime = time.Unix(stat.Ctimespec.Unix()) ctime = time.Unix(stat.Ctimespec.Unix())
mtime = time.Unix(stat.Mtimespec.Unix()) mtime = time.Unix(stat.Mtimespec.Unix())
return return atime, ctime, mtime
} }

View File

@ -20,24 +20,20 @@ import (
) )
func extractMtime(sys interface{}) (mtime time.Time, ok bool) { func extractMtime(sys interface{}) (mtime time.Time, ok bool) {
mtime = time.Unix(sys.(*syscall.Stat_t).Mtim.Unix()) return time.Unix(sys.(*syscall.Stat_t).Mtim.Unix()), true
ok = true
return
} }
func extractBirthtime(sys interface{}) (birthtime time.Time, ok bool) { func extractBirthtime(sys interface{}) (birthtime time.Time, ok bool) {
return return time.Time{}, false
} }
func extractNlink(sys interface{}) (nlink uint64, ok bool) { func extractNlink(sys interface{}) (nlink uint64, ok bool) {
nlink = sys.(*syscall.Stat_t).Nlink return sys.(*syscall.Stat_t).Nlink, true
ok = true
return
} }
func getTimes(stat *syscall.Stat_t) (atime, ctime, mtime time.Time) { func getTimes(stat *syscall.Stat_t) (atime, ctime, mtime time.Time) {
atime = time.Unix(stat.Atim.Unix()) atime = time.Unix(stat.Atim.Unix())
ctime = time.Unix(stat.Ctim.Unix()) ctime = time.Unix(stat.Ctim.Unix())
mtime = time.Unix(stat.Mtim.Unix()) mtime = time.Unix(stat.Mtim.Unix())
return return atime, ctime, mtime
} }

View File

@ -79,7 +79,7 @@ func WriteDirent(buf []byte, d Dirent) (n int) {
// Do we have enough room? // Do we have enough room?
totalLen := direntSize + len(d.Name) + padLen totalLen := direntSize + len(d.Name) + padLen
if totalLen > len(buf) { if totalLen > len(buf) {
return return n
} }
// Write the header. // Write the header.
@ -101,5 +101,5 @@ func WriteDirent(buf []byte, d Dirent) (n int) {
n += copy(buf[n:], padding[:padLen]) n += copy(buf[n:], padding[:padLen])
} }
return return n
} }

View File

@ -32,198 +32,170 @@ var _ FileSystem = &NotImplementedFileSystem{}
func (fs *NotImplementedFileSystem) StatFS( func (fs *NotImplementedFileSystem) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) LookUpInode( func (fs *NotImplementedFileSystem) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) GetInodeAttributes( func (fs *NotImplementedFileSystem) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) SetInodeAttributes( func (fs *NotImplementedFileSystem) SetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.SetInodeAttributesOp) (err error) { op *fuseops.SetInodeAttributesOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) ForgetInode( func (fs *NotImplementedFileSystem) ForgetInode(
ctx context.Context, ctx context.Context,
op *fuseops.ForgetInodeOp) (err error) { op *fuseops.ForgetInodeOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) MkDir( func (fs *NotImplementedFileSystem) MkDir(
ctx context.Context, ctx context.Context,
op *fuseops.MkDirOp) (err error) { op *fuseops.MkDirOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) MkNode( func (fs *NotImplementedFileSystem) MkNode(
ctx context.Context, ctx context.Context,
op *fuseops.MkNodeOp) (err error) { op *fuseops.MkNodeOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) CreateFile( func (fs *NotImplementedFileSystem) CreateFile(
ctx context.Context, ctx context.Context,
op *fuseops.CreateFileOp) (err error) { op *fuseops.CreateFileOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) CreateSymlink( func (fs *NotImplementedFileSystem) CreateSymlink(
ctx context.Context, ctx context.Context,
op *fuseops.CreateSymlinkOp) (err error) { op *fuseops.CreateSymlinkOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) CreateLink( func (fs *NotImplementedFileSystem) CreateLink(
ctx context.Context, ctx context.Context,
op *fuseops.CreateLinkOp) (err error) { op *fuseops.CreateLinkOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) Rename( func (fs *NotImplementedFileSystem) Rename(
ctx context.Context, ctx context.Context,
op *fuseops.RenameOp) (err error) { op *fuseops.RenameOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) RmDir( func (fs *NotImplementedFileSystem) RmDir(
ctx context.Context, ctx context.Context,
op *fuseops.RmDirOp) (err error) { op *fuseops.RmDirOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) Unlink( func (fs *NotImplementedFileSystem) Unlink(
ctx context.Context, ctx context.Context,
op *fuseops.UnlinkOp) (err error) { op *fuseops.UnlinkOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) OpenDir( func (fs *NotImplementedFileSystem) OpenDir(
ctx context.Context, ctx context.Context,
op *fuseops.OpenDirOp) (err error) { op *fuseops.OpenDirOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) ReadDir( func (fs *NotImplementedFileSystem) ReadDir(
ctx context.Context, ctx context.Context,
op *fuseops.ReadDirOp) (err error) { op *fuseops.ReadDirOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) ReleaseDirHandle( func (fs *NotImplementedFileSystem) ReleaseDirHandle(
ctx context.Context, ctx context.Context,
op *fuseops.ReleaseDirHandleOp) (err error) { op *fuseops.ReleaseDirHandleOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) OpenFile( func (fs *NotImplementedFileSystem) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) ReadFile( func (fs *NotImplementedFileSystem) ReadFile(
ctx context.Context, ctx context.Context,
op *fuseops.ReadFileOp) (err error) { op *fuseops.ReadFileOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) WriteFile( func (fs *NotImplementedFileSystem) WriteFile(
ctx context.Context, ctx context.Context,
op *fuseops.WriteFileOp) (err error) { op *fuseops.WriteFileOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) SyncFile( func (fs *NotImplementedFileSystem) SyncFile(
ctx context.Context, ctx context.Context,
op *fuseops.SyncFileOp) (err error) { op *fuseops.SyncFileOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) FlushFile( func (fs *NotImplementedFileSystem) FlushFile(
ctx context.Context, ctx context.Context,
op *fuseops.FlushFileOp) (err error) { op *fuseops.FlushFileOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) ReleaseFileHandle( func (fs *NotImplementedFileSystem) ReleaseFileHandle(
ctx context.Context, ctx context.Context,
op *fuseops.ReleaseFileHandleOp) (err error) { op *fuseops.ReleaseFileHandleOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) ReadSymlink( func (fs *NotImplementedFileSystem) ReadSymlink(
ctx context.Context, ctx context.Context,
op *fuseops.ReadSymlinkOp) (err error) { op *fuseops.ReadSymlinkOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) RemoveXattr( func (fs *NotImplementedFileSystem) RemoveXattr(
ctx context.Context, ctx context.Context,
op *fuseops.RemoveXattrOp) (err error) { op *fuseops.RemoveXattrOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) GetXattr( func (fs *NotImplementedFileSystem) GetXattr(
ctx context.Context, ctx context.Context,
op *fuseops.GetXattrOp) (err error) { op *fuseops.GetXattrOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) ListXattr( func (fs *NotImplementedFileSystem) ListXattr(
ctx context.Context, ctx context.Context,
op *fuseops.ListXattrOp) (err error) { op *fuseops.ListXattrOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) SetXattr( func (fs *NotImplementedFileSystem) SetXattr(
ctx context.Context, ctx context.Context,
op *fuseops.SetXattrOp) (err error) { op *fuseops.SetXattrOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) Fallocate( func (fs *NotImplementedFileSystem) Fallocate(
ctx context.Context, ctx context.Context,
op *fuseops.FallocateOp) (err error) { op *fuseops.FallocateOp) error {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
func (fs *NotImplementedFileSystem) Destroy() { func (fs *NotImplementedFileSystem) Destroy() {

View File

@ -49,38 +49,34 @@ type InMessage struct {
// Initialize with the data read by a single call to r.Read. The first call to // Initialize with the data read by a single call to r.Read. The first call to
// Consume will consume the bytes directly after the fusekernel.InHeader // Consume will consume the bytes directly after the fusekernel.InHeader
// struct. // struct.
func (m *InMessage) Init(r io.Reader) (err error) { func (m *InMessage) Init(r io.Reader) error {
n, err := r.Read(m.storage[:]) n, err := r.Read(m.storage[:])
if err != nil { if err != nil {
return return err
} }
// Make sure the message is long enough. // Make sure the message is long enough.
const headerSize = unsafe.Sizeof(fusekernel.InHeader{}) const headerSize = unsafe.Sizeof(fusekernel.InHeader{})
if uintptr(n) < headerSize { if uintptr(n) < headerSize {
err = fmt.Errorf("Unexpectedly read only %d bytes.", n) return fmt.Errorf("Unexpectedly read only %d bytes.", n)
return
} }
m.remaining = m.storage[headerSize:n] m.remaining = m.storage[headerSize:n]
// Check the header's length. // Check the header's length.
if int(m.Header().Len) != n { if int(m.Header().Len) != n {
err = fmt.Errorf( return fmt.Errorf(
"Header says %d bytes, but we read %d", "Header says %d bytes, but we read %d",
m.Header().Len, m.Header().Len,
n) n)
return
} }
return return nil
} }
// Return a reference to the header read in the most recent call to Init. // Return a reference to the header read in the most recent call to Init.
func (m *InMessage) Header() (h *fusekernel.InHeader) { func (m *InMessage) Header() *fusekernel.InHeader {
h = (*fusekernel.InHeader)(unsafe.Pointer(&m.storage[0])) return (*fusekernel.InHeader)(unsafe.Pointer(&m.storage[0]))
return
} }
// Return the number of bytes left to consume. // Return the number of bytes left to consume.
@ -90,26 +86,26 @@ func (m *InMessage) Len() uintptr {
// Consume the next n bytes from the message, returning a nil pointer if there // Consume the next n bytes from the message, returning a nil pointer if there
// are fewer than n bytes available. // are fewer than n bytes available.
func (m *InMessage) Consume(n uintptr) (p unsafe.Pointer) { func (m *InMessage) Consume(n uintptr) unsafe.Pointer {
if m.Len() == 0 || n > m.Len() { if m.Len() == 0 || n > m.Len() {
return return nil
} }
p = unsafe.Pointer(&m.remaining[0]) p := unsafe.Pointer(&m.remaining[0])
m.remaining = m.remaining[n:] m.remaining = m.remaining[n:]
return return p
} }
// Equivalent to Consume, except returns a slice of bytes. The result will be // Equivalent to Consume, except returns a slice of bytes. The result will be
// nil if Consume would fail. // nil if Consume would fail.
func (m *InMessage) ConsumeBytes(n uintptr) (b []byte) { func (m *InMessage) ConsumeBytes(n uintptr) []byte {
if n > m.Len() { if n > m.Len() {
return return nil
} }
b = m.remaining[:n] b := m.remaining[:n]
m.remaining = m.remaining[n:] m.remaining = m.remaining[n:]
return return b
} }

View File

@ -81,28 +81,28 @@ func (m *OutMessage) OutHeader() *fusekernel.OutHeader {
// Grow grows m's buffer by the given number of bytes, returning a pointer to // Grow grows m's buffer by the given number of bytes, returning a pointer to
// the start of the new segment, which is guaranteed to be zeroed. If there is // the start of the new segment, which is guaranteed to be zeroed. If there is
// insufficient space, it returns nil. // insufficient space, it returns nil.
func (m *OutMessage) Grow(n int) (p unsafe.Pointer) { func (m *OutMessage) Grow(n int) unsafe.Pointer {
p = m.GrowNoZero(n) p := m.GrowNoZero(n)
if p != nil { if p != nil {
memclr(p, uintptr(n)) memclr(p, uintptr(n))
} }
return return p
} }
// GrowNoZero is equivalent to Grow, except the new segment is not zeroed. Use // GrowNoZero is equivalent to Grow, except the new segment is not zeroed. Use
// with caution! // with caution!
func (m *OutMessage) GrowNoZero(n int) (p unsafe.Pointer) { func (m *OutMessage) GrowNoZero(n int) unsafe.Pointer {
// Will we overflow the buffer? // Will we overflow the buffer?
o := m.payloadOffset o := m.payloadOffset
if len(m.payload)-o < n { if len(m.payload)-o < n {
return return nil
} }
p = unsafe.Pointer(uintptr(unsafe.Pointer(&m.payload)) + uintptr(o)) p := unsafe.Pointer(uintptr(unsafe.Pointer(&m.payload)) + uintptr(o))
m.payloadOffset = o + n m.payloadOffset = o + n
return return p
} }
// ShrinkTo shrinks m to the given size. It panics if the size is greater than // ShrinkTo shrinks m to the given size. It panics if the size is greater than

View File

@ -24,16 +24,16 @@ func toByteSlice(p unsafe.Pointer, n int) []byte {
} }
// fillWithGarbage writes random data to [p, p+n). // fillWithGarbage writes random data to [p, p+n).
func fillWithGarbage(p unsafe.Pointer, n int) (err error) { func fillWithGarbage(p unsafe.Pointer, n int) error {
b := toByteSlice(p, n) b := toByteSlice(p, n)
_, err = io.ReadFull(rand.Reader, b) _, err := io.ReadFull(rand.Reader, b)
return return err
} }
func randBytes(n int) (b []byte, err error) { func randBytes(n int) ([]byte, error) {
b = make([]byte, n) b := make([]byte, n)
_, err = io.ReadFull(rand.Reader, b) _, err := io.ReadFull(rand.Reader, b)
return return b, err
} }
// findNonZero finds the offset of the first non-zero byte in [p, p+n). If // findNonZero finds the offset of the first non-zero byte in [p, p+n). If

View File

@ -22,16 +22,16 @@ type Freelist struct {
} }
// Get an element from the freelist, returning nil if empty. // Get an element from the freelist, returning nil if empty.
func (fl *Freelist) Get() (p unsafe.Pointer) { func (fl *Freelist) Get() unsafe.Pointer {
l := len(fl.list) l := len(fl.list)
if l == 0 { if l == 0 {
return return nil
} }
p = fl.list[l-1] p := fl.list[l-1]
fl.list = fl.list[:l-1] fl.list = fl.list[:l-1]
return return p
} }
// Contribute an element back to the freelist. // Contribute an element back to the freelist.

View File

@ -35,25 +35,23 @@ type Server interface {
func Mount( func Mount(
dir string, dir string,
server Server, server Server,
config *MountConfig) (mfs *MountedFileSystem, err error) { config *MountConfig) (*MountedFileSystem, error) {
// Sanity check: make sure the mount point exists and is a directory. This // Sanity check: make sure the mount point exists and is a directory. This
// saves us from some confusing errors later on OS X. // saves us from some confusing errors later on OS X.
fi, err := os.Stat(dir) fi, err := os.Stat(dir)
switch { switch {
case os.IsNotExist(err): case os.IsNotExist(err):
return return nil, err
case err != nil: case err != nil:
err = fmt.Errorf("Statting mount point: %v", err) return nil, fmt.Errorf("Statting mount point: %v", err)
return
case !fi.IsDir(): case !fi.IsDir():
err = fmt.Errorf("Mount point %s is not a directory", dir) return nil, fmt.Errorf("Mount point %s is not a directory", dir)
return
} }
// Initialize the struct. // Initialize the struct.
mfs = &MountedFileSystem{ mfs := &MountedFileSystem{
dir: dir, dir: dir,
joinStatusAvailable: make(chan struct{}), joinStatusAvailable: make(chan struct{}),
} }
@ -62,8 +60,7 @@ func Mount(
ready := make(chan error, 1) ready := make(chan error, 1)
dev, err := mount(dir, config, ready) dev, err := mount(dir, config, ready)
if err != nil { if err != nil {
err = fmt.Errorf("mount: %v", err) return nil, fmt.Errorf("mount: %v", err)
return
} }
// Choose a parent context for ops. // Choose a parent context for ops.
@ -78,10 +75,8 @@ func Mount(
config.DebugLogger, config.DebugLogger,
config.ErrorLogger, config.ErrorLogger,
dev) dev)
if err != nil { if err != nil {
err = fmt.Errorf("newConnection: %v", err) return nil, fmt.Errorf("newConnection: %v", err)
return
} }
// Serve the connection in the background. When done, set the join status. // Serve the connection in the background. When done, set the join status.
@ -92,10 +87,9 @@ func Mount(
}() }()
// Wait for the mount process to complete. // Wait for the mount process to complete.
if err = <-ready; err != nil { if err := <-ready; err != nil {
err = fmt.Errorf("mount (background): %v", err) return nil, fmt.Errorf("mount (background): %v", err)
return
} }
return return mfs, nil
} }

View File

@ -213,14 +213,14 @@ func (c *MountConfig) toMap() (opts map[string]string) {
opts[k] = v opts[k] = v
} }
return return opts
} }
func escapeOptionsKey(s string) (res string) { func escapeOptionsKey(s string) (res string) {
res = s res = s
res = strings.Replace(res, `\`, `\\`, -1) res = strings.Replace(res, `\`, `\\`, -1)
res = strings.Replace(res, `,`, `\,`, -1) res = strings.Replace(res, `,`, `\,`, -1)
return return res
} }
func mapToOptionsString(opts map[string]string) string { func mapToOptionsString(opts map[string]string) string {

View File

@ -76,13 +76,11 @@ func openOSXFUSEDev(devPrefix string) (dev *os.File, err error) {
if os.IsNotExist(err) { if os.IsNotExist(err) {
if i == 0 { if i == 0 {
// Not even the first device was found. Fuse must not be loaded. // Not even the first device was found. Fuse must not be loaded.
err = errNotLoaded return nil, errNotLoaded
return
} }
// Otherwise we've run out of kernel-provided devices // Otherwise we've run out of kernel-provided devices
err = errNoAvail return nil, errNoAvail
return
} }
if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY { if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY {
@ -90,7 +88,7 @@ func openOSXFUSEDev(devPrefix string) (dev *os.File, err error) {
continue continue
} }
return return dev, nil
} }
} }
@ -100,7 +98,7 @@ func callMount(
dir string, dir string,
cfg *MountConfig, cfg *MountConfig,
dev *os.File, dev *os.File,
ready chan<- error) (err error) { ready chan<- error) error {
// The mount helper doesn't understand any escaping. // The mount helper doesn't understand any escaping.
for k, v := range cfg.toMap() { for k, v := range cfg.toMap() {
@ -143,9 +141,8 @@ func callMount(
cmd.Stdout = &buf cmd.Stdout = &buf
cmd.Stderr = &buf cmd.Stderr = &buf
err = cmd.Start() if err := cmd.Start(); err != nil {
if err != nil { return err
return
} }
// In the background, wait for the command to complete. // In the background, wait for the command to complete.
@ -162,7 +159,7 @@ func callMount(
ready <- err ready <- err
}() }()
return return nil
} }
// Begin the process of mounting at the given directory, returning a connection // Begin the process of mounting at the given directory, returning a connection
@ -188,8 +185,7 @@ func mount(
if err == errNotLoaded { if err == errNotLoaded {
err = loadOSXFUSE(loc.Load) err = loadOSXFUSE(loc.Load)
if err != nil { if err != nil {
err = fmt.Errorf("loadOSXFUSE: %v", err) return nil, fmt.Errorf("loadOSXFUSE: %v", err)
return
} }
dev, err = openOSXFUSEDev(loc.DevicePrefix) dev, err = openOSXFUSEDev(loc.DevicePrefix)
@ -197,21 +193,17 @@ func mount(
// Propagate errors. // Propagate errors.
if err != nil { if err != nil {
err = fmt.Errorf("openOSXFUSEDev: %v", err) return nil, fmt.Errorf("openOSXFUSEDev: %v", err)
return
} }
// Call the mount binary with the device. // Call the mount binary with the device.
err = callMount(loc.Mount, loc.DaemonVar, dir, cfg, dev, ready) if err := callMount(loc.Mount, loc.DaemonVar, dir, cfg, dev, ready); err != nil {
if err != nil {
dev.Close() dev.Close()
err = fmt.Errorf("callMount: %v", err) return nil, fmt.Errorf("callMount: %v", err)
return
} }
return return dev, nil
} }
err = errOSXFUSENotFound return nil, errOSXFUSENotFound
return
} }

View File

@ -26,8 +26,8 @@ type minimalFS struct {
func (fs *minimalFS) StatFS( func (fs *minimalFS) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
return return nil
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////

View File

@ -82,7 +82,7 @@ type CachingFS interface {
// //
func NewCachingFS( func NewCachingFS(
lookupEntryTimeout time.Duration, lookupEntryTimeout time.Duration,
getattrTimeout time.Duration) (fs CachingFS, err error) { getattrTimeout time.Duration) (CachingFS, error) {
roundUp := func(n fuseops.InodeID) fuseops.InodeID { roundUp := func(n fuseops.InodeID) fuseops.InodeID {
return numInodes * ((n + numInodes - 1) / numInodes) return numInodes * ((n + numInodes - 1) / numInodes)
} }
@ -96,8 +96,7 @@ func NewCachingFS(
cfs.mu = syncutil.NewInvariantMutex(cfs.checkInvariants) cfs.mu = syncutil.NewInvariantMutex(cfs.checkInvariants)
fs = cfs return cfs, nil
return
} }
const ( const (
@ -262,14 +261,14 @@ func (fs *cachingFS) SetKeepCache(keep bool) {
func (fs *cachingFS) StatFS( func (fs *cachingFS) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
return return nil
} }
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) LookUpInode( func (fs *cachingFS) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -281,8 +280,7 @@ func (fs *cachingFS) LookUpInode(
case "foo": case "foo":
// Parent must be the root. // Parent must be the root.
if op.Parent != fuseops.RootInodeID { if op.Parent != fuseops.RootInodeID {
err = fuse.ENOENT return fuse.ENOENT
return
} }
id = fs.fooID() id = fs.fooID()
@ -291,8 +289,7 @@ func (fs *cachingFS) LookUpInode(
case "dir": case "dir":
// Parent must be the root. // Parent must be the root.
if op.Parent != fuseops.RootInodeID { if op.Parent != fuseops.RootInodeID {
err = fuse.ENOENT return fuse.ENOENT
return
} }
id = fs.dirID() id = fs.dirID()
@ -301,16 +298,14 @@ func (fs *cachingFS) LookUpInode(
case "bar": case "bar":
// Parent must be dir. // Parent must be dir.
if op.Parent == fuseops.RootInodeID || op.Parent%numInodes != dirOffset { if op.Parent == fuseops.RootInodeID || op.Parent%numInodes != dirOffset {
err = fuse.ENOENT return fuse.ENOENT
return
} }
id = fs.barID() id = fs.barID()
attrs = fs.barAttrs() attrs = fs.barAttrs()
default: default:
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Fill in the response. // Fill in the response.
@ -318,13 +313,13 @@ func (fs *cachingFS) LookUpInode(
op.Entry.Attributes = attrs op.Entry.Attributes = attrs
op.Entry.EntryExpiration = time.Now().Add(fs.lookupEntryTimeout) op.Entry.EntryExpiration = time.Now().Add(fs.lookupEntryTimeout)
return return nil
} }
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) GetInodeAttributes( func (fs *cachingFS) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -349,29 +344,30 @@ func (fs *cachingFS) GetInodeAttributes(
op.Attributes = attrs op.Attributes = attrs
op.AttributesExpiration = time.Now().Add(fs.getattrTimeout) op.AttributesExpiration = time.Now().Add(fs.getattrTimeout)
return return nil
} }
func (fs *cachingFS) OpenDir( func (fs *cachingFS) OpenDir(
ctx context.Context, ctx context.Context,
op *fuseops.OpenDirOp) (err error) { op *fuseops.OpenDirOp) error {
return return nil
} }
func (fs *cachingFS) OpenFile( func (fs *cachingFS) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
op.KeepPageCache = fs.keepPageCache op.KeepPageCache = fs.keepPageCache
return return nil
} }
func (fs *cachingFS) ReadFile( func (fs *cachingFS) ReadFile(
ctx context.Context, ctx context.Context,
op *fuseops.ReadFileOp) (err error) { op *fuseops.ReadFileOp) error {
var err error
op.BytesRead, err = io.ReadFull(rand.Reader, op.Dst) op.BytesRead, err = io.ReadFull(rand.Reader, op.Dst)
return return err
} }

View File

@ -83,7 +83,7 @@ func (t *cachingFSTest) statAll() (foo, dir, bar os.FileInfo) {
bar, err = os.Stat(path.Join(t.Dir, "dir/bar")) bar, err = os.Stat(path.Join(t.Dir, "dir/bar"))
AssertEq(nil, err) AssertEq(nil, err)
return return foo, dir, bar
} }
func (t *cachingFSTest) openFiles() (foo, dir, bar *os.File) { func (t *cachingFSTest) openFiles() (foo, dir, bar *os.File) {
@ -98,7 +98,7 @@ func (t *cachingFSTest) openFiles() (foo, dir, bar *os.File) {
bar, err = os.Open(path.Join(t.Dir, "dir/bar")) bar, err = os.Open(path.Join(t.Dir, "dir/bar"))
AssertEq(nil, err) AssertEq(nil, err)
return return foo, dir, bar
} }
func (t *cachingFSTest) statFiles( func (t *cachingFSTest) statFiles(
@ -114,7 +114,7 @@ func (t *cachingFSTest) statFiles(
bar, err = h.Stat() bar, err = h.Stat()
AssertEq(nil, err) AssertEq(nil, err)
return return foo, dir, bar
} }
func getInodeID(fi os.FileInfo) uint64 { func getInodeID(fi os.FileInfo) uint64 {

View File

@ -33,15 +33,14 @@ import (
// This implementation depends on direct IO in fuse. Without it, all read // This implementation depends on direct IO in fuse. Without it, all read
// operations are suppressed because the kernel detects that they read beyond // operations are suppressed because the kernel detects that they read beyond
// the end of the files. // the end of the files.
func NewDynamicFS(clock timeutil.Clock) (server fuse.Server, err error) { func NewDynamicFS(clock timeutil.Clock) (fuse.Server, error) {
createTime := clock.Now() createTime := clock.Now()
fs := &dynamicFS{ fs := &dynamicFS{
clock: clock, clock: clock,
createTime: createTime, createTime: createTime,
fileHandles: make(map[fuseops.HandleID]string), fileHandles: make(map[fuseops.HandleID]string),
} }
server = fuseutil.NewFileSystemServer(fs) return fuseutil.NewFileSystemServer(fs), nil
return
} }
type dynamicFS struct { type dynamicFS struct {
@ -114,16 +113,14 @@ var gInodeInfo = map[fuseops.InodeID]inodeInfo{
func findChildInode( func findChildInode(
name string, name string,
children []fuseutil.Dirent) (inode fuseops.InodeID, err error) { children []fuseutil.Dirent) (fuseops.InodeID, error) {
for _, e := range children { for _, e := range children {
if e.Name == name { if e.Name == name {
inode = e.Inode return e.Inode, nil
return
} }
} }
err = fuse.ENOENT return 0, fuse.ENOENT
return
} }
func (fs *dynamicFS) findUnusedHandle() fuseops.HandleID { func (fs *dynamicFS) findUnusedHandle() fuseops.HandleID {
@ -138,69 +135,64 @@ func (fs *dynamicFS) findUnusedHandle() fuseops.HandleID {
func (fs *dynamicFS) GetInodeAttributes( func (fs *dynamicFS) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
// Find the info for this inode. // Find the info for this inode.
info, ok := gInodeInfo[op.Inode] info, ok := gInodeInfo[op.Inode]
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Copy over its attributes. // Copy over its attributes.
op.Attributes = info.attributes op.Attributes = info.attributes
return return nil
} }
func (fs *dynamicFS) LookUpInode( func (fs *dynamicFS) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
// Find the info for the parent. // Find the info for the parent.
parentInfo, ok := gInodeInfo[op.Parent] parentInfo, ok := gInodeInfo[op.Parent]
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Find the child within the parent. // Find the child within the parent.
childInode, err := findChildInode(op.Name, parentInfo.children) childInode, err := findChildInode(op.Name, parentInfo.children)
if err != nil { if err != nil {
return return err
} }
// Copy over information. // Copy over information.
op.Entry.Child = childInode op.Entry.Child = childInode
op.Entry.Attributes = gInodeInfo[childInode].attributes op.Entry.Attributes = gInodeInfo[childInode].attributes
return return nil
} }
func (fs *dynamicFS) OpenDir( func (fs *dynamicFS) OpenDir(
ctx context.Context, ctx context.Context,
op *fuseops.OpenDirOp) (err error) { op *fuseops.OpenDirOp) error {
// Allow opening directory. // Allow opening directory.
return return nil
} }
func (fs *dynamicFS) ReadDir( func (fs *dynamicFS) ReadDir(
ctx context.Context, ctx context.Context,
op *fuseops.ReadDirOp) (err error) { op *fuseops.ReadDirOp) error {
// Find the info for this inode. // Find the info for this inode.
info, ok := gInodeInfo[op.Inode] info, ok := gInodeInfo[op.Inode]
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
if !info.dir { if !info.dir {
err = fuse.EIO return fuse.EIO
return
} }
entries := info.children entries := info.children
// Grab the range of interest. // Grab the range of interest.
if op.Offset > fuseops.DirOffset(len(entries)) { if op.Offset > fuseops.DirOffset(len(entries)) {
err = fuse.EIO return fuse.EIO
return
} }
entries = entries[op.Offset:] entries = entries[op.Offset:]
@ -215,12 +207,12 @@ func (fs *dynamicFS) ReadDir(
op.BytesRead += n op.BytesRead += n
} }
return return nil
} }
func (fs *dynamicFS) OpenFile( func (fs *dynamicFS) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
var contents string var contents string
@ -233,51 +225,49 @@ func (fs *dynamicFS) OpenFile(
case weekdayInode: case weekdayInode:
contents = fmt.Sprintf("Today is %s.", fs.clock.Now().Weekday()) contents = fmt.Sprintf("Today is %s.", fs.clock.Now().Weekday())
default: default:
err = fuse.EINVAL return fuse.EINVAL
return
} }
handle := fs.findUnusedHandle() handle := fs.findUnusedHandle()
fs.fileHandles[handle] = contents fs.fileHandles[handle] = contents
op.UseDirectIO = true op.UseDirectIO = true
op.Handle = handle op.Handle = handle
return return nil
} }
func (fs *dynamicFS) ReadFile( func (fs *dynamicFS) ReadFile(
ctx context.Context, ctx context.Context,
op *fuseops.ReadFileOp) (err error) { op *fuseops.ReadFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
contents, ok := fs.fileHandles[op.Handle] contents, ok := fs.fileHandles[op.Handle]
if !ok { if !ok {
log.Printf("ReadFile: no open file handle: %d", op.Handle) log.Printf("ReadFile: no open file handle: %d", op.Handle)
err = fuse.EIO return fuse.EIO
return
} }
reader := strings.NewReader(contents) reader := strings.NewReader(contents)
var err error
op.BytesRead, err = reader.ReadAt(op.Dst, op.Offset) op.BytesRead, err = reader.ReadAt(op.Dst, op.Offset)
if err == io.EOF { if err == io.EOF {
err = nil return nil
} }
return return err
} }
func (fs *dynamicFS) ReleaseFileHandle( func (fs *dynamicFS) ReleaseFileHandle(
ctx context.Context, ctx context.Context,
op *fuseops.ReleaseFileHandleOp) (err error) { op *fuseops.ReleaseFileHandleOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
_, ok := fs.fileHandles[op.Handle] _, ok := fs.fileHandles[op.Handle]
if !ok { if !ok {
log.Printf("ReleaseFileHandle: bad handle: %d", op.Handle) log.Printf("ReleaseFileHandle: bad handle: %d", op.Handle)
err = fuse.EIO return fuse.EIO
return
} }
delete(fs.fileHandles, op.Handle) delete(fs.fileHandles, op.Handle)
return return nil
} }
func (fs *dynamicFS) StatFS(ctx context.Context, func (fs *dynamicFS) StatFS(ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
return return nil
} }

View File

@ -49,12 +49,10 @@ type FS interface {
SetError(t reflect.Type, err syscall.Errno) SetError(t reflect.Type, err syscall.Errno)
} }
func New() (fs FS, err error) { func New() (FS, error) {
fs = &errorFS{ return &errorFS{
errors: make(map[reflect.Type]syscall.Errno), errors: make(map[reflect.Type]syscall.Errno),
} }, nil
return
} }
type errorFS struct { type errorFS struct {
@ -95,9 +93,10 @@ func (fs *errorFS) transformError(op interface{}, err *error) bool {
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *errorFS) GetInodeAttributes( func (fs *errorFS) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
var err error
if fs.transformError(op, &err) { if fs.transformError(op, &err) {
return return err
} }
// Figure out which inode the request is for. // Figure out which inode the request is for.
@ -111,100 +110,99 @@ func (fs *errorFS) GetInodeAttributes(
op.Attributes = fooAttrs op.Attributes = fooAttrs
default: default:
err = fmt.Errorf("Unknown inode: %d", op.Inode) return fmt.Errorf("Unknown inode: %d", op.Inode)
return
} }
return return nil
} }
func (fs *errorFS) StatFS( func (fs *errorFS) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
return return nil
} }
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *errorFS) LookUpInode( func (fs *errorFS) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
var err error
if fs.transformError(op, &err) { if fs.transformError(op, &err) {
return return err
} }
// Is this a known inode? // Is this a known inode?
if !(op.Parent == fuseops.RootInodeID && op.Name == "foo") { if !(op.Parent == fuseops.RootInodeID && op.Name == "foo") {
err = syscall.ENOENT return syscall.ENOENT
return
} }
op.Entry.Child = fooInodeID op.Entry.Child = fooInodeID
op.Entry.Attributes = fooAttrs op.Entry.Attributes = fooAttrs
return return nil
} }
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *errorFS) OpenFile( func (fs *errorFS) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
var err error
if fs.transformError(op, &err) { if fs.transformError(op, &err) {
return return err
} }
if op.Inode != fooInodeID { if op.Inode != fooInodeID {
err = fmt.Errorf("Unsupported inode ID: %d", op.Inode) return fmt.Errorf("Unsupported inode ID: %d", op.Inode)
return
} }
return return nil
} }
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *errorFS) ReadFile( func (fs *errorFS) ReadFile(
ctx context.Context, ctx context.Context,
op *fuseops.ReadFileOp) (err error) { op *fuseops.ReadFileOp) error {
var err error
if fs.transformError(op, &err) { if fs.transformError(op, &err) {
return return err
} }
if op.Inode != fooInodeID || op.Offset != 0 { if op.Inode != fooInodeID || op.Offset != 0 {
err = fmt.Errorf("Unexpected request: %#v", op) return fmt.Errorf("Unexpected request: %#v", op)
return
} }
op.BytesRead = copy(op.Dst, FooContents) op.BytesRead = copy(op.Dst, FooContents)
return return nil
} }
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *errorFS) OpenDir( func (fs *errorFS) OpenDir(
ctx context.Context, ctx context.Context,
op *fuseops.OpenDirOp) (err error) { op *fuseops.OpenDirOp) error {
var err error
if fs.transformError(op, &err) { if fs.transformError(op, &err) {
return return err
} }
if op.Inode != fuseops.RootInodeID { if op.Inode != fuseops.RootInodeID {
err = fmt.Errorf("Unsupported inode ID: %d", op.Inode) return fmt.Errorf("Unsupported inode ID: %d", op.Inode)
return
} }
return return nil
} }
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *errorFS) ReadDir( func (fs *errorFS) ReadDir(
ctx context.Context, ctx context.Context,
op *fuseops.ReadDirOp) (err error) { op *fuseops.ReadDirOp) error {
var err error
if fs.transformError(op, &err) { if fs.transformError(op, &err) {
return return err
} }
if op.Inode != fuseops.RootInodeID || op.Offset != 0 { if op.Inode != fuseops.RootInodeID || op.Offset != 0 {
err = fmt.Errorf("Unexpected request: %#v", op) return fmt.Errorf("Unexpected request: %#v", op)
return
} }
op.BytesRead = fuseutil.WriteDirent( op.BytesRead = fuseutil.WriteDirent(
@ -216,5 +214,5 @@ func (fs *errorFS) ReadDir(
Type: fuseutil.DT_File, Type: fuseutil.DT_File,
}) })
return return nil
} }

View File

@ -35,14 +35,13 @@ import (
// The directory cannot be modified. // The directory cannot be modified.
func NewFileSystem( func NewFileSystem(
reportFlush func(string) error, reportFlush func(string) error,
reportFsync func(string) error) (server fuse.Server, err error) { reportFsync func(string) error) (fuse.Server, error) {
fs := &flushFS{ fs := &flushFS{
reportFlush: reportFlush, reportFlush: reportFlush,
reportFsync: reportFsync, reportFsync: reportFsync,
} }
server = fuseutil.NewFileSystemServer(fs) return fuseutil.NewFileSystemServer(fs), nil
return
} }
const ( const (
@ -90,25 +89,19 @@ func (fs *flushFS) barAttributes() fuseops.InodeAttributes {
} }
// LOCKS_REQUIRED(fs.mu) // LOCKS_REQUIRED(fs.mu)
func (fs *flushFS) getAttributes(id fuseops.InodeID) ( func (fs *flushFS) getAttributes(id fuseops.InodeID) (fuseops.InodeAttributes, error) {
attrs fuseops.InodeAttributes,
err error) {
switch id { switch id {
case fuseops.RootInodeID: case fuseops.RootInodeID:
attrs = fs.rootAttributes() return fs.rootAttributes(), nil
return
case fooID: case fooID:
attrs = fs.fooAttributes() return fs.fooAttributes(), nil
return
case barID: case barID:
attrs = fs.barAttributes() return fs.barAttributes(), nil
return
default: default:
err = fuse.ENOENT return fuseops.InodeAttributes{}, fuse.ENOENT
return
} }
} }
@ -118,20 +111,19 @@ func (fs *flushFS) getAttributes(id fuseops.InodeID) (
func (fs *flushFS) StatFS( func (fs *flushFS) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
return return nil
} }
func (fs *flushFS) LookUpInode( func (fs *flushFS) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
// Sanity check. // Sanity check.
if op.Parent != fuseops.RootInodeID { if op.Parent != fuseops.RootInodeID {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Set up the entry. // Set up the entry.
@ -149,70 +141,69 @@ func (fs *flushFS) LookUpInode(
} }
default: default:
err = fuse.ENOENT return fuse.ENOENT
return
} }
return return nil
} }
func (fs *flushFS) GetInodeAttributes( func (fs *flushFS) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
var err error
op.Attributes, err = fs.getAttributes(op.Inode) op.Attributes, err = fs.getAttributes(op.Inode)
return return err
} }
func (fs *flushFS) SetInodeAttributes( func (fs *flushFS) SetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.SetInodeAttributesOp) (err error) { op *fuseops.SetInodeAttributesOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
// Ignore any changes and simply return existing attributes. // Ignore any changes and simply return existing attributes.
var err error
op.Attributes, err = fs.getAttributes(op.Inode) op.Attributes, err = fs.getAttributes(op.Inode)
return err
return
} }
func (fs *flushFS) OpenFile( func (fs *flushFS) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
// Sanity check. // Sanity check.
if op.Inode != fooID { if op.Inode != fooID {
err = fuse.ENOSYS return fuse.ENOSYS
return
} }
return return nil
} }
func (fs *flushFS) ReadFile( func (fs *flushFS) ReadFile(
ctx context.Context, ctx context.Context,
op *fuseops.ReadFileOp) (err error) { op *fuseops.ReadFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
// Ensure the offset is in range. // Ensure the offset is in range.
if op.Offset > int64(len(fs.fooContents)) { if op.Offset > int64(len(fs.fooContents)) {
return return nil
} }
// Read what we can. // Read what we can.
op.BytesRead = copy(op.Dst, fs.fooContents[op.Offset:]) op.BytesRead = copy(op.Dst, fs.fooContents[op.Offset:])
return return nil
} }
func (fs *flushFS) WriteFile( func (fs *flushFS) WriteFile(
ctx context.Context, ctx context.Context,
op *fuseops.WriteFileOp) (err error) { op *fuseops.WriteFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -231,32 +222,30 @@ func (fs *flushFS) WriteFile(
panic(fmt.Sprintf("Unexpected short copy: %v", n)) panic(fmt.Sprintf("Unexpected short copy: %v", n))
} }
return return nil
} }
func (fs *flushFS) SyncFile( func (fs *flushFS) SyncFile(
ctx context.Context, ctx context.Context,
op *fuseops.SyncFileOp) (err error) { op *fuseops.SyncFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
err = fs.reportFsync(string(fs.fooContents)) return fs.reportFsync(string(fs.fooContents))
return
} }
func (fs *flushFS) FlushFile( func (fs *flushFS) FlushFile(
ctx context.Context, ctx context.Context,
op *fuseops.FlushFileOp) (err error) { op *fuseops.FlushFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
err = fs.reportFlush(string(fs.fooContents)) return fs.reportFlush(string(fs.fooContents))
return
} }
func (fs *flushFS) OpenDir( func (fs *flushFS) OpenDir(
ctx context.Context, ctx context.Context,
op *fuseops.OpenDirOp) (err error) { op *fuseops.OpenDirOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -266,16 +255,15 @@ func (fs *flushFS) OpenDir(
case barID: case barID:
default: default:
err = fuse.ENOENT return fuse.ENOENT
return
} }
return return nil
} }
func (fs *flushFS) ReadDir( func (fs *flushFS) ReadDir(
ctx context.Context, ctx context.Context,
op *fuseops.ReadDirOp) (err error) { op *fuseops.ReadDirOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -303,21 +291,19 @@ func (fs *flushFS) ReadDir(
case barID: case barID:
default: default:
err = fmt.Errorf("Unexpected inode: %v", op.Inode) return fmt.Errorf("Unexpected inode: %v", op.Inode)
return
} }
// If the offset is for the end of the listing, we're done. Otherwise we // If the offset is for the end of the listing, we're done. Otherwise we
// expect it to be for the start. // expect it to be for the start.
switch op.Offset { switch op.Offset {
case fuseops.DirOffset(len(dirents)): case fuseops.DirOffset(len(dirents)):
return return nil
case 0: case 0:
default: default:
err = fmt.Errorf("Unexpected offset: %v", op.Offset) return fmt.Errorf("Unexpected offset: %v", op.Offset)
return
} }
// Fill in the listing. // Fill in the listing.
@ -326,12 +312,11 @@ func (fs *flushFS) ReadDir(
// We don't support doing this in anything more than one shot. // We don't support doing this in anything more than one shot.
if n == 0 { if n == 0 {
err = fmt.Errorf("Couldn't fit listing in %v bytes", len(op.Dst)) return fmt.Errorf("Couldn't fit listing in %v bytes", len(op.Dst))
return
} }
op.BytesRead += n op.BytesRead += n
} }
return return nil
} }

View File

@ -121,30 +121,24 @@ var isDarwin = runtime.GOOS == "darwin"
func readReports(f *os.File) (reports []string, err error) { func readReports(f *os.File) (reports []string, err error) {
// Seek the file to the start. // Seek the file to the start.
_, err = f.Seek(0, 0) if _, err := f.Seek(0, 0); err != nil {
if err != nil { return nil, fmt.Errorf("Seek: %v", err)
err = fmt.Errorf("Seek: %v", err)
return
} }
// We expect reports to end in a newline (including the final one). // We expect reports to end in a newline (including the final one).
reader := bufio.NewReader(f) reader := bufio.NewReader(f)
for { for {
var record []byte record, err := reader.ReadBytes('\n')
record, err = reader.ReadBytes('\n')
if err == io.EOF { if err == io.EOF {
if len(record) != 0 { if len(record) != 0 {
err = fmt.Errorf("Unexpected record:\n%s", hex.Dump(record)) return nil, fmt.Errorf("Unexpected record:\n%s", hex.Dump(record))
return
} }
err = nil return reports, nil
return
} }
if err != nil { if err != nil {
err = fmt.Errorf("ReadBytes: %v", err) return nil, fmt.Errorf("ReadBytes: %v", err)
return
} }
// Strip the newline. // Strip the newline.
@ -153,41 +147,39 @@ func readReports(f *os.File) (reports []string, err error) {
} }
// Return a copy of the current contents of t.flushes. // Return a copy of the current contents of t.flushes.
func (t *flushFSTest) getFlushes() (p []string) { func (t *flushFSTest) getFlushes() []string {
var err error p, err := readReports(t.flushes)
if p, err = readReports(t.flushes); err != nil { if err != nil {
panic(err) panic(err)
} }
return p
return
} }
// Return a copy of the current contents of t.fsyncs. // Return a copy of the current contents of t.fsyncs.
func (t *flushFSTest) getFsyncs() (p []string) { func (t *flushFSTest) getFsyncs() []string {
var err error p, err := readReports(t.fsyncs)
if p, err = readReports(t.fsyncs); err != nil { if err != nil {
panic(err) panic(err)
} }
return p
return
} }
// Like syscall.Dup2, but correctly annotates the syscall as blocking. See here // Like syscall.Dup2, but correctly annotates the syscall as blocking. See here
// for more info: https://github.com/golang/go/issues/10202 // for more info: https://github.com/golang/go/issues/10202
func dup2(oldfd int, newfd int) (err error) { func dup2(oldfd int, newfd int) error {
_, _, e1 := syscall.Syscall( _, _, e1 := syscall.Syscall(
syscall.SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) syscall.SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
if e1 != 0 { if e1 != 0 {
err = e1 return e1
} }
return return nil
} }
// Call msync(2) with the MS_SYNC flag on a slice previously returned by // Call msync(2) with the MS_SYNC flag on a slice previously returned by
// mmap(2). // mmap(2).
func msync(p []byte) (err error) { func msync(p []byte) error {
_, _, errno := unix.Syscall( _, _, errno := unix.Syscall(
unix.SYS_MSYNC, unix.SYS_MSYNC,
uintptr(unsafe.Pointer(&p[0])), uintptr(unsafe.Pointer(&p[0])),
@ -195,11 +187,10 @@ func msync(p []byte) (err error) {
unix.MS_SYNC) unix.MS_SYNC)
if errno != 0 { if errno != 0 {
err = errno return errno
return
} }
return return nil
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////

View File

@ -38,7 +38,7 @@ import (
// after we expect it to be dead. Its Check method may be used to check that // after we expect it to be dead. Its Check method may be used to check that
// there are no inodes with unexpected reference counts remaining, after // there are no inodes with unexpected reference counts remaining, after
// unmounting. // unmounting.
func NewFileSystem() (fs *ForgetFS) { func NewFileSystem() *ForgetFS {
// Set up the actual file system. // Set up the actual file system.
impl := &fsImpl{ impl := &fsImpl{
inodes: map[fuseops.InodeID]*inode{ inodes: map[fuseops.InodeID]*inode{
@ -78,12 +78,10 @@ func NewFileSystem() (fs *ForgetFS) {
impl.mu = syncutil.NewInvariantMutex(impl.checkInvariants) impl.mu = syncutil.NewInvariantMutex(impl.checkInvariants)
// Set up a wrapper that exposes only certain methods. // Set up a wrapper that exposes only certain methods.
fs = &ForgetFS{ return &ForgetFS{
impl: impl, impl: impl,
server: fuseutil.NewFileSystemServer(impl), server: fuseutil.NewFileSystemServer(impl),
} }
return
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -206,8 +204,8 @@ func (fs *fsImpl) Check() {
// Look up the inode and verify it hasn't been forgotten. // Look up the inode and verify it hasn't been forgotten.
// //
// LOCKS_REQUIRED(fs.mu) // LOCKS_REQUIRED(fs.mu)
func (fs *fsImpl) findInodeByID(id fuseops.InodeID) (in *inode) { func (fs *fsImpl) findInodeByID(id fuseops.InodeID) *inode {
in = fs.inodes[id] in := fs.inodes[id]
if in == nil { if in == nil {
panic(fmt.Sprintf("Unknown inode: %v", id)) panic(fmt.Sprintf("Unknown inode: %v", id))
} }
@ -216,7 +214,7 @@ func (fs *fsImpl) findInodeByID(id fuseops.InodeID) (in *inode) {
panic(fmt.Sprintf("Forgotten inode: %v", id)) panic(fmt.Sprintf("Forgotten inode: %v", id))
} }
return return in
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -225,13 +223,13 @@ func (fs *fsImpl) findInodeByID(id fuseops.InodeID) (in *inode) {
func (fs *fsImpl) StatFS( func (fs *fsImpl) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
return return nil
} }
func (fs *fsImpl) LookUpInode( func (fs *fsImpl) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -248,8 +246,7 @@ func (fs *fsImpl) LookUpInode(
childID = cannedID_Bar childID = cannedID_Bar
default: default:
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Look up the child. // Look up the child.
@ -262,12 +259,12 @@ func (fs *fsImpl) LookUpInode(
Attributes: child.attributes, Attributes: child.attributes,
} }
return return nil
} }
func (fs *fsImpl) GetInodeAttributes( func (fs *fsImpl) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -277,12 +274,12 @@ func (fs *fsImpl) GetInodeAttributes(
// Return appropriate attributes. // Return appropriate attributes.
op.Attributes = in.attributes op.Attributes = in.attributes
return return nil
} }
func (fs *fsImpl) ForgetInode( func (fs *fsImpl) ForgetInode(
ctx context.Context, ctx context.Context,
op *fuseops.ForgetInodeOp) (err error) { op *fuseops.ForgetInodeOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -290,12 +287,12 @@ func (fs *fsImpl) ForgetInode(
in := fs.findInodeByID(op.Inode) in := fs.findInodeByID(op.Inode)
in.DecrementLookupCount(op.N) in.DecrementLookupCount(op.N)
return return nil
} }
func (fs *fsImpl) MkDir( func (fs *fsImpl) MkDir(
ctx context.Context, ctx context.Context,
op *fuseops.MkDirOp) (err error) { op *fuseops.MkDirOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -322,12 +319,12 @@ func (fs *fsImpl) MkDir(
Attributes: child.attributes, Attributes: child.attributes,
} }
return return nil
} }
func (fs *fsImpl) CreateFile( func (fs *fsImpl) CreateFile(
ctx context.Context, ctx context.Context,
op *fuseops.CreateFileOp) (err error) { op *fuseops.CreateFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -354,31 +351,31 @@ func (fs *fsImpl) CreateFile(
Attributes: child.attributes, Attributes: child.attributes,
} }
return return nil
} }
func (fs *fsImpl) OpenFile( func (fs *fsImpl) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
// Verify that the inode has not been forgotten. // Verify that the inode has not been forgotten.
_ = fs.findInodeByID(op.Inode) _ = fs.findInodeByID(op.Inode)
return return nil
} }
func (fs *fsImpl) OpenDir( func (fs *fsImpl) OpenDir(
ctx context.Context, ctx context.Context,
op *fuseops.OpenDirOp) (err error) { op *fuseops.OpenDirOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
// Verify that the inode has not been forgotten. // Verify that the inode has not been forgotten.
_ = fs.findInodeByID(op.Inode) _ = fs.findInodeByID(op.Inode)
return return nil
} }
func (fs *fsImpl) Destroy() { func (fs *fsImpl) Destroy() {

View File

@ -33,13 +33,12 @@ import (
// world // world
// //
// Each file contains the string "Hello, world!". // Each file contains the string "Hello, world!".
func NewHelloFS(clock timeutil.Clock) (server fuse.Server, err error) { func NewHelloFS(clock timeutil.Clock) (fuse.Server, error) {
fs := &helloFS{ fs := &helloFS{
Clock: clock, Clock: clock,
} }
server = fuseutil.NewFileSystemServer(fs) return fuseutil.NewFileSystemServer(fs), nil
return
} }
type helloFS struct { type helloFS struct {
@ -128,16 +127,14 @@ var gInodeInfo = map[fuseops.InodeID]inodeInfo{
func findChildInode( func findChildInode(
name string, name string,
children []fuseutil.Dirent) (inode fuseops.InodeID, err error) { children []fuseutil.Dirent) (fuseops.InodeID, error) {
for _, e := range children { for _, e := range children {
if e.Name == name { if e.Name == name {
inode = e.Inode return e.Inode, nil
return
} }
} }
err = fuse.ENOENT return 0, fuse.ENOENT
return
} }
func (fs *helloFS) patchAttributes( func (fs *helloFS) patchAttributes(
@ -150,24 +147,23 @@ func (fs *helloFS) patchAttributes(
func (fs *helloFS) StatFS( func (fs *helloFS) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
return return nil
} }
func (fs *helloFS) LookUpInode( func (fs *helloFS) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
// Find the info for the parent. // Find the info for the parent.
parentInfo, ok := gInodeInfo[op.Parent] parentInfo, ok := gInodeInfo[op.Parent]
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Find the child within the parent. // Find the child within the parent.
childInode, err := findChildInode(op.Name, parentInfo.children) childInode, err := findChildInode(op.Name, parentInfo.children)
if err != nil { if err != nil {
return return err
} }
// Copy over information. // Copy over information.
@ -177,17 +173,16 @@ func (fs *helloFS) LookUpInode(
// Patch attributes. // Patch attributes.
fs.patchAttributes(&op.Entry.Attributes) fs.patchAttributes(&op.Entry.Attributes)
return return nil
} }
func (fs *helloFS) GetInodeAttributes( func (fs *helloFS) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
// Find the info for this inode. // Find the info for this inode.
info, ok := gInodeInfo[op.Inode] info, ok := gInodeInfo[op.Inode]
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Copy over its attributes. // Copy over its attributes.
@ -196,37 +191,34 @@ func (fs *helloFS) GetInodeAttributes(
// Patch attributes. // Patch attributes.
fs.patchAttributes(&op.Attributes) fs.patchAttributes(&op.Attributes)
return return nil
} }
func (fs *helloFS) OpenDir( func (fs *helloFS) OpenDir(
ctx context.Context, ctx context.Context,
op *fuseops.OpenDirOp) (err error) { op *fuseops.OpenDirOp) error {
// Allow opening any directory. // Allow opening any directory.
return return nil
} }
func (fs *helloFS) ReadDir( func (fs *helloFS) ReadDir(
ctx context.Context, ctx context.Context,
op *fuseops.ReadDirOp) (err error) { op *fuseops.ReadDirOp) error {
// Find the info for this inode. // Find the info for this inode.
info, ok := gInodeInfo[op.Inode] info, ok := gInodeInfo[op.Inode]
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
if !info.dir { if !info.dir {
err = fuse.EIO return fuse.EIO
return
} }
entries := info.children entries := info.children
// Grab the range of interest. // Grab the range of interest.
if op.Offset > fuseops.DirOffset(len(entries)) { if op.Offset > fuseops.DirOffset(len(entries)) {
err = fuse.EIO return fuse.EIO
return
} }
entries = entries[op.Offset:] entries = entries[op.Offset:]
@ -241,28 +233,29 @@ func (fs *helloFS) ReadDir(
op.BytesRead += n op.BytesRead += n
} }
return return nil
} }
func (fs *helloFS) OpenFile( func (fs *helloFS) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
// Allow opening any file. // Allow opening any file.
return return nil
} }
func (fs *helloFS) ReadFile( func (fs *helloFS) ReadFile(
ctx context.Context, ctx context.Context,
op *fuseops.ReadFileOp) (err error) { op *fuseops.ReadFileOp) error {
// Let io.ReaderAt deal with the semantics. // Let io.ReaderAt deal with the semantics.
reader := strings.NewReader("Hello, world!") reader := strings.NewReader("Hello, world!")
var err error
op.BytesRead, err = reader.ReadAt(op.Dst, op.Offset) op.BytesRead, err = reader.ReadAt(op.Dst, op.Offset)
// Special case: FUSE doesn't expect us to return io.EOF. // Special case: FUSE doesn't expect us to return io.EOF.
if err == io.EOF { if err == io.EOF {
err = nil return nil
} }
return return err
} }

View File

@ -75,7 +75,7 @@ func (t *SampleTest) SetUp(ti *ogletest.TestInfo) {
func (t *SampleTest) initialize( func (t *SampleTest) initialize(
ctx context.Context, ctx context.Context,
server fuse.Server, server fuse.Server,
config *fuse.MountConfig) (err error) { config *fuse.MountConfig) error {
// Initialize the context used by the test. // Initialize the context used by the test.
t.Ctx = ctx t.Ctx = ctx
@ -89,20 +89,19 @@ func (t *SampleTest) initialize(
t.Clock.SetTime(time.Date(2012, 8, 15, 22, 56, 0, 0, time.Local)) t.Clock.SetTime(time.Date(2012, 8, 15, 22, 56, 0, 0, time.Local))
// Set up a temporary directory. // Set up a temporary directory.
var err error
t.Dir, err = ioutil.TempDir("", "sample_test") t.Dir, err = ioutil.TempDir("", "sample_test")
if err != nil { if err != nil {
err = fmt.Errorf("TempDir: %v", err) return fmt.Errorf("TempDir: %v", err)
return
} }
// Mount the file system. // Mount the file system.
t.mfs, err = fuse.Mount(t.Dir, server, config) t.mfs, err = fuse.Mount(t.Dir, server, config)
if err != nil { if err != nil {
err = fmt.Errorf("Mount: %v", err) return fmt.Errorf("Mount: %v", err)
return
} }
return return nil
} }
// Unmount the file system and clean up. Panics on error. // Unmount the file system and clean up. Panics on error.
@ -126,28 +125,23 @@ func (t *SampleTest) destroy() (err error) {
// Was the file system mounted? // Was the file system mounted?
if t.mfs == nil { if t.mfs == nil {
return return nil
} }
// Unmount the file system. // Unmount the file system.
err = unmount(t.Dir) if err := unmount(t.Dir); err != nil {
if err != nil { return fmt.Errorf("unmount: %v", err)
err = fmt.Errorf("unmount: %v", err)
return
} }
// Unlink the mount point. // Unlink the mount point.
if err = os.Remove(t.Dir); err != nil { if err := os.Remove(t.Dir); err != nil {
err = fmt.Errorf("Unlinking mount point: %v", err) return fmt.Errorf("Unlinking mount point: %v", err)
return
} }
// Join the file system. // Join the file system.
err = t.mfs.Join(t.Ctx) if err := t.mfs.Join(t.Ctx); err != nil {
if err != nil { return fmt.Errorf("mfs.Join: %v", err)
err = fmt.Errorf("mfs.Join: %v", err)
return
} }
return return nil
} }

View File

@ -56,13 +56,11 @@ type InterruptFS struct {
flushReceived chan struct{} flushReceived chan struct{}
} }
func New() (fs *InterruptFS) { func New() *InterruptFS {
fs = &InterruptFS{ return &InterruptFS{
readReceived: make(chan struct{}), readReceived: make(chan struct{}),
flushReceived: make(chan struct{}), flushReceived: make(chan struct{}),
} }
return
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -101,35 +99,33 @@ func (fs *InterruptFS) EnableFlushBlocking() {
func (fs *InterruptFS) StatFS( func (fs *InterruptFS) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
return return nil
} }
func (fs *InterruptFS) LookUpInode( func (fs *InterruptFS) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
// We support only one parent. // We support only one parent.
if op.Parent != fuseops.RootInodeID { if op.Parent != fuseops.RootInodeID {
err = fmt.Errorf("Unexpected parent: %v", op.Parent) return fmt.Errorf("Unexpected parent: %v", op.Parent)
return
} }
// We support only one name. // We support only one name.
if op.Name != "foo" { if op.Name != "foo" {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Fill in the response. // Fill in the response.
op.Entry.Child = fooID op.Entry.Child = fooID
op.Entry.Attributes = fooAttrs op.Entry.Attributes = fooAttrs
return return nil
} }
func (fs *InterruptFS) GetInodeAttributes( func (fs *InterruptFS) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
switch op.Inode { switch op.Inode {
case fuseops.RootInodeID: case fuseops.RootInodeID:
op.Attributes = rootAttrs op.Attributes = rootAttrs
@ -138,22 +134,21 @@ func (fs *InterruptFS) GetInodeAttributes(
op.Attributes = fooAttrs op.Attributes = fooAttrs
default: default:
err = fmt.Errorf("Unexpected inode ID: %v", op.Inode) return fmt.Errorf("Unexpected inode ID: %v", op.Inode)
return
} }
return return nil
} }
func (fs *InterruptFS) OpenFile( func (fs *InterruptFS) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
return return nil
} }
func (fs *InterruptFS) ReadFile( func (fs *InterruptFS) ReadFile(
ctx context.Context, ctx context.Context,
op *fuseops.ReadFileOp) (err error) { op *fuseops.ReadFileOp) error {
fs.mu.Lock() fs.mu.Lock()
shouldBlock := fs.blockForReads shouldBlock := fs.blockForReads
@ -173,15 +168,15 @@ func (fs *InterruptFS) ReadFile(
} }
<-done <-done
err = ctx.Err() return ctx.Err()
} }
return return nil
} }
func (fs *InterruptFS) FlushFile( func (fs *InterruptFS) FlushFile(
ctx context.Context, ctx context.Context,
op *fuseops.FlushFileOp) (err error) { op *fuseops.FlushFileOp) error {
fs.mu.Lock() fs.mu.Lock()
shouldBlock := fs.blockForFlushes shouldBlock := fs.blockForFlushes
@ -201,8 +196,8 @@ func (fs *InterruptFS) FlushFile(
} }
<-done <-done
err = ctx.Err() return ctx.Err()
} }
return return nil
} }

View File

@ -73,20 +73,17 @@ type inode struct {
// Create a new inode with the supplied attributes, which need not contain // Create a new inode with the supplied attributes, which need not contain
// time-related information (the inode object will take care of that). // time-related information (the inode object will take care of that).
func newInode( func newInode(attrs fuseops.InodeAttributes) *inode {
attrs fuseops.InodeAttributes) (in *inode) {
// Update time info. // Update time info.
now := time.Now() now := time.Now()
attrs.Mtime = now attrs.Mtime = now
attrs.Crtime = now attrs.Crtime = now
// Create the object. // Create the object.
in = &inode{ return &inode{
attrs: attrs, attrs: attrs,
xattrs: make(map[string][]byte), xattrs: make(map[string][]byte),
} }
return
} }
func (in *inode) CheckInvariants() { func (in *inode) CheckInvariants() {
@ -168,12 +165,11 @@ func (in *inode) findChild(name string) (i int, ok bool) {
var e fuseutil.Dirent var e fuseutil.Dirent
for i, e = range in.entries { for i, e = range in.entries {
if e.Name == name { if e.Name == name {
ok = true return i, true
return
} }
} }
return return 0, false
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -183,14 +179,15 @@ func (in *inode) findChild(name string) (i int, ok bool) {
// Return the number of children of the directory. // Return the number of children of the directory.
// //
// REQUIRES: in.isDir() // REQUIRES: in.isDir()
func (in *inode) Len() (n int) { func (in *inode) Len() int {
var n int
for _, e := range in.entries { for _, e := range in.entries {
if e.Type != fuseutil.DT_Unknown { if e.Type != fuseutil.DT_Unknown {
n++ n++
} }
} }
return return n
} }
// Find an entry for the given child name and return its inode ID. // Find an entry for the given child name and return its inode ID.
@ -206,7 +203,7 @@ func (in *inode) LookUpChild(name string) (
typ = in.entries[index].Type typ = in.entries[index].Type
} }
return return id, typ, ok
} }
// Add an entry for a child. // Add an entry for a child.
@ -272,11 +269,12 @@ func (in *inode) RemoveChild(name string) {
// Serve a ReadDir request. // Serve a ReadDir request.
// //
// REQUIRES: in.isDir() // REQUIRES: in.isDir()
func (in *inode) ReadDir(p []byte, offset int) (n int) { func (in *inode) ReadDir(p []byte, offset int) int {
if !in.isDir() { if !in.isDir() {
panic("ReadDir called on non-directory.") panic("ReadDir called on non-directory.")
} }
var n int
for i := offset; i < len(in.entries); i++ { for i := offset; i < len(in.entries); i++ {
e := in.entries[i] e := in.entries[i]
@ -293,36 +291,35 @@ func (in *inode) ReadDir(p []byte, offset int) (n int) {
n += tmp n += tmp
} }
return return n
} }
// Read from the file's contents. See documentation for ioutil.ReaderAt. // Read from the file's contents. See documentation for ioutil.ReaderAt.
// //
// REQUIRES: in.isFile() // REQUIRES: in.isFile()
func (in *inode) ReadAt(p []byte, off int64) (n int, err error) { func (in *inode) ReadAt(p []byte, off int64) (int, error) {
if !in.isFile() { if !in.isFile() {
panic("ReadAt called on non-file.") panic("ReadAt called on non-file.")
} }
// Ensure the offset is in range. // Ensure the offset is in range.
if off > int64(len(in.contents)) { if off > int64(len(in.contents)) {
err = io.EOF return 0, io.EOF
return
} }
// Read what we can. // Read what we can.
n = copy(p, in.contents[off:]) n := copy(p, in.contents[off:])
if n < len(p) { if n < len(p) {
err = io.EOF return n, io.EOF
} }
return return n, nil
} }
// Write to the file's contents. See documentation for ioutil.WriterAt. // Write to the file's contents. See documentation for ioutil.WriterAt.
// //
// REQUIRES: in.isFile() // REQUIRES: in.isFile()
func (in *inode) WriteAt(p []byte, off int64) (n int, err error) { func (in *inode) WriteAt(p []byte, off int64) (int, error) {
if !in.isFile() { if !in.isFile() {
panic("WriteAt called on non-file.") panic("WriteAt called on non-file.")
} }
@ -339,14 +336,14 @@ func (in *inode) WriteAt(p []byte, off int64) (n int, err error) {
} }
// Copy in the data. // Copy in the data.
n = copy(in.contents[off:], p) n := copy(in.contents[off:], p)
// Sanity check. // Sanity check.
if n != len(p) { if n != len(p) {
panic(fmt.Sprintf("Unexpected short copy: %v", n)) panic(fmt.Sprintf("Unexpected short copy: %v", n))
} }
return return n, nil
} }
// Update attributes from non-nil parameters. // Update attributes from non-nil parameters.
@ -384,17 +381,15 @@ func (in *inode) SetAttributes(
} }
} }
func (in *inode) Fallocate(mode uint32, offset uint64, length uint64) ( func (in *inode) Fallocate(mode uint32, offset uint64, length uint64) error {
err error) { if mode != 0 {
if mode == 0 { return fuse.ENOSYS
newSize := int(offset + length)
if newSize > len(in.contents) {
padding := make([]byte, newSize-len(in.contents))
in.contents = append(in.contents, padding...)
in.attrs.Size = offset + length
}
} else {
err = fuse.ENOSYS
} }
return newSize := int(offset + length)
if newSize > len(in.contents) {
padding := make([]byte, newSize-len(in.contents))
in.contents = append(in.contents, padding...)
in.attrs.Size = offset + length
}
return nil
} }

View File

@ -144,13 +144,13 @@ func (fs *memFS) checkInvariants() {
// Find the given inode. Panic if it doesn't exist. // Find the given inode. Panic if it doesn't exist.
// //
// LOCKS_REQUIRED(fs.mu) // LOCKS_REQUIRED(fs.mu)
func (fs *memFS) getInodeOrDie(id fuseops.InodeID) (inode *inode) { func (fs *memFS) getInodeOrDie(id fuseops.InodeID) *inode {
inode = fs.inodes[id] inode := fs.inodes[id]
if inode == nil { if inode == nil {
panic(fmt.Sprintf("Unknown inode: %v", id)) panic(fmt.Sprintf("Unknown inode: %v", id))
} }
return return inode
} }
// Allocate a new inode, assigning it an ID that is not in use. // Allocate a new inode, assigning it an ID that is not in use.
@ -172,7 +172,7 @@ func (fs *memFS) allocateInode(
fs.inodes = append(fs.inodes, inode) fs.inodes = append(fs.inodes, inode)
} }
return return id, inode
} }
// LOCKS_REQUIRED(fs.mu) // LOCKS_REQUIRED(fs.mu)
@ -187,13 +187,13 @@ func (fs *memFS) deallocateInode(id fuseops.InodeID) {
func (fs *memFS) StatFS( func (fs *memFS) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
return return nil
} }
func (fs *memFS) LookUpInode( func (fs *memFS) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -203,8 +203,7 @@ func (fs *memFS) LookUpInode(
// Does the directory have an entry with the given name? // Does the directory have an entry with the given name?
childID, _, ok := inode.LookUpChild(op.Name) childID, _, ok := inode.LookUpChild(op.Name)
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Grab the child. // Grab the child.
@ -219,12 +218,12 @@ func (fs *memFS) LookUpInode(
op.Entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour) op.Entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour)
op.Entry.EntryExpiration = op.Entry.AttributesExpiration op.Entry.EntryExpiration = op.Entry.AttributesExpiration
return return nil
} }
func (fs *memFS) GetInodeAttributes( func (fs *memFS) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -238,15 +237,16 @@ func (fs *memFS) GetInodeAttributes(
// (since it also handles invalidation). // (since it also handles invalidation).
op.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour) op.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour)
return return nil
} }
func (fs *memFS) SetInodeAttributes( func (fs *memFS) SetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.SetInodeAttributesOp) (err error) { op *fuseops.SetInodeAttributesOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
var err error
if op.Size != nil && op.Handle == nil && *op.Size != 0 { if op.Size != nil && op.Handle == nil && *op.Size != 0 {
// require that truncate to non-zero has to be ftruncate() // require that truncate to non-zero has to be ftruncate()
// but allow open(O_TRUNC) // but allow open(O_TRUNC)
@ -266,12 +266,12 @@ func (fs *memFS) SetInodeAttributes(
// (since it also handles invalidation). // (since it also handles invalidation).
op.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour) op.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour)
return return err
} }
func (fs *memFS) MkDir( func (fs *memFS) MkDir(
ctx context.Context, ctx context.Context,
op *fuseops.MkDirOp) (err error) { op *fuseops.MkDirOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -282,8 +282,7 @@ func (fs *memFS) MkDir(
// duplicate. // duplicate.
_, _, exists := parent.LookUpChild(op.Name) _, _, exists := parent.LookUpChild(op.Name)
if exists { if exists {
err = fuse.EEXIST return fuse.EEXIST
return
} }
// Set up attributes from the child. // Set up attributes from the child.
@ -309,24 +308,25 @@ func (fs *memFS) MkDir(
op.Entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour) op.Entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour)
op.Entry.EntryExpiration = op.Entry.AttributesExpiration op.Entry.EntryExpiration = op.Entry.AttributesExpiration
return return nil
} }
func (fs *memFS) MkNode( func (fs *memFS) MkNode(
ctx context.Context, ctx context.Context,
op *fuseops.MkNodeOp) (err error) { op *fuseops.MkNodeOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
var err error
op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode) op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode)
return return err
} }
// LOCKS_REQUIRED(fs.mu) // LOCKS_REQUIRED(fs.mu)
func (fs *memFS) createFile( func (fs *memFS) createFile(
parentID fuseops.InodeID, parentID fuseops.InodeID,
name string, name string,
mode os.FileMode) (entry fuseops.ChildInodeEntry, err error) { mode os.FileMode) (fuseops.ChildInodeEntry, error) {
// Grab the parent, which we will update shortly. // Grab the parent, which we will update shortly.
parent := fs.getInodeOrDie(parentID) parent := fs.getInodeOrDie(parentID)
@ -334,8 +334,7 @@ func (fs *memFS) createFile(
// duplicate. // duplicate.
_, _, exists := parent.LookUpChild(name) _, _, exists := parent.LookUpChild(name)
if exists { if exists {
err = fuse.EEXIST return fuseops.ChildInodeEntry{}, fuse.EEXIST
return
} }
// Set up attributes for the child. // Set up attributes for the child.
@ -358,6 +357,7 @@ func (fs *memFS) createFile(
parent.AddChild(childID, name, fuseutil.DT_File) parent.AddChild(childID, name, fuseutil.DT_File)
// Fill in the response entry. // Fill in the response entry.
var entry fuseops.ChildInodeEntry
entry.Child = childID entry.Child = childID
entry.Attributes = child.attrs entry.Attributes = child.attrs
@ -366,22 +366,23 @@ func (fs *memFS) createFile(
entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour) entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour)
entry.EntryExpiration = entry.AttributesExpiration entry.EntryExpiration = entry.AttributesExpiration
return return entry, nil
} }
func (fs *memFS) CreateFile( func (fs *memFS) CreateFile(
ctx context.Context, ctx context.Context,
op *fuseops.CreateFileOp) (err error) { op *fuseops.CreateFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
var err error
op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode) op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode)
return return err
} }
func (fs *memFS) CreateSymlink( func (fs *memFS) CreateSymlink(
ctx context.Context, ctx context.Context,
op *fuseops.CreateSymlinkOp) (err error) { op *fuseops.CreateSymlinkOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -392,8 +393,7 @@ func (fs *memFS) CreateSymlink(
// duplicate. // duplicate.
_, _, exists := parent.LookUpChild(op.Name) _, _, exists := parent.LookUpChild(op.Name)
if exists { if exists {
err = fuse.EEXIST return fuse.EEXIST
return
} }
// Set up attributes from the child. // Set up attributes from the child.
@ -427,12 +427,12 @@ func (fs *memFS) CreateSymlink(
op.Entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour) op.Entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour)
op.Entry.EntryExpiration = op.Entry.AttributesExpiration op.Entry.EntryExpiration = op.Entry.AttributesExpiration
return return nil
} }
func (fs *memFS) CreateLink( func (fs *memFS) CreateLink(
ctx context.Context, ctx context.Context,
op *fuseops.CreateLinkOp) (err error) { op *fuseops.CreateLinkOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -443,8 +443,7 @@ func (fs *memFS) CreateLink(
// duplicate. // duplicate.
_, _, exists := parent.LookUpChild(op.Name) _, _, exists := parent.LookUpChild(op.Name)
if exists { if exists {
err = fuse.EEXIST return fuse.EEXIST
return
} }
// Get the target inode to be linked // Get the target inode to be linked
@ -467,12 +466,12 @@ func (fs *memFS) CreateLink(
op.Entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour) op.Entry.AttributesExpiration = time.Now().Add(365 * 24 * time.Hour)
op.Entry.EntryExpiration = op.Entry.AttributesExpiration op.Entry.EntryExpiration = op.Entry.AttributesExpiration
return return nil
} }
func (fs *memFS) Rename( func (fs *memFS) Rename(
ctx context.Context, ctx context.Context,
op *fuseops.RenameOp) (err error) { op *fuseops.RenameOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -481,8 +480,7 @@ func (fs *memFS) Rename(
childID, childType, ok := oldParent.LookUpChild(op.OldName) childID, childType, ok := oldParent.LookUpChild(op.OldName)
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// If the new name exists already in the new parent, make sure it's not a // If the new name exists already in the new parent, make sure it's not a
@ -494,8 +492,7 @@ func (fs *memFS) Rename(
var buf [4096]byte var buf [4096]byte
if existing.isDir() && existing.ReadDir(buf[:], 0) > 0 { if existing.isDir() && existing.ReadDir(buf[:], 0) > 0 {
err = fuse.ENOTEMPTY return fuse.ENOTEMPTY
return
} }
newParent.RemoveChild(op.NewName) newParent.RemoveChild(op.NewName)
@ -510,12 +507,12 @@ func (fs *memFS) Rename(
// Finally, remove the old name from the old parent. // Finally, remove the old name from the old parent.
oldParent.RemoveChild(op.OldName) oldParent.RemoveChild(op.OldName)
return return nil
} }
func (fs *memFS) RmDir( func (fs *memFS) RmDir(
ctx context.Context, ctx context.Context,
op *fuseops.RmDirOp) (err error) { op *fuseops.RmDirOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -525,8 +522,7 @@ func (fs *memFS) RmDir(
// Find the child within the parent. // Find the child within the parent.
childID, _, ok := parent.LookUpChild(op.Name) childID, _, ok := parent.LookUpChild(op.Name)
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Grab the child. // Grab the child.
@ -534,8 +530,7 @@ func (fs *memFS) RmDir(
// Make sure the child is empty. // Make sure the child is empty.
if child.Len() != 0 { if child.Len() != 0 {
err = fuse.ENOTEMPTY return fuse.ENOTEMPTY
return
} }
// Remove the entry within the parent. // Remove the entry within the parent.
@ -544,12 +539,12 @@ func (fs *memFS) RmDir(
// Mark the child as unlinked. // Mark the child as unlinked.
child.attrs.Nlink-- child.attrs.Nlink--
return return nil
} }
func (fs *memFS) Unlink( func (fs *memFS) Unlink(
ctx context.Context, ctx context.Context,
op *fuseops.UnlinkOp) (err error) { op *fuseops.UnlinkOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -559,8 +554,7 @@ func (fs *memFS) Unlink(
// Find the child within the parent. // Find the child within the parent.
childID, _, ok := parent.LookUpChild(op.Name) childID, _, ok := parent.LookUpChild(op.Name)
if !ok { if !ok {
err = fuse.ENOENT return fuse.ENOENT
return
} }
// Grab the child. // Grab the child.
@ -572,12 +566,12 @@ func (fs *memFS) Unlink(
// Mark the child as unlinked. // Mark the child as unlinked.
child.attrs.Nlink-- child.attrs.Nlink--
return return nil
} }
func (fs *memFS) OpenDir( func (fs *memFS) OpenDir(
ctx context.Context, ctx context.Context,
op *fuseops.OpenDirOp) (err error) { op *fuseops.OpenDirOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -590,12 +584,12 @@ func (fs *memFS) OpenDir(
panic("Found non-dir.") panic("Found non-dir.")
} }
return return nil
} }
func (fs *memFS) ReadDir( func (fs *memFS) ReadDir(
ctx context.Context, ctx context.Context,
op *fuseops.ReadDirOp) (err error) { op *fuseops.ReadDirOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -605,12 +599,12 @@ func (fs *memFS) ReadDir(
// Serve the request. // Serve the request.
op.BytesRead = inode.ReadDir(op.Dst, int(op.Offset)) op.BytesRead = inode.ReadDir(op.Dst, int(op.Offset))
return return nil
} }
func (fs *memFS) OpenFile( func (fs *memFS) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -623,12 +617,12 @@ func (fs *memFS) OpenFile(
panic("Found non-file.") panic("Found non-file.")
} }
return return nil
} }
func (fs *memFS) ReadFile( func (fs *memFS) ReadFile(
ctx context.Context, ctx context.Context,
op *fuseops.ReadFileOp) (err error) { op *fuseops.ReadFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -636,19 +630,20 @@ func (fs *memFS) ReadFile(
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
// Serve the request. // Serve the request.
var err error
op.BytesRead, err = inode.ReadAt(op.Dst, op.Offset) op.BytesRead, err = inode.ReadAt(op.Dst, op.Offset)
// Don't return EOF errors; we just indicate EOF to fuse using a short read. // Don't return EOF errors; we just indicate EOF to fuse using a short read.
if err == io.EOF { if err == io.EOF {
err = nil return nil
} }
return return err
} }
func (fs *memFS) WriteFile( func (fs *memFS) WriteFile(
ctx context.Context, ctx context.Context,
op *fuseops.WriteFileOp) (err error) { op *fuseops.WriteFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -656,14 +651,14 @@ func (fs *memFS) WriteFile(
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
// Serve the request. // Serve the request.
_, err = inode.WriteAt(op.Data, op.Offset) _, err := inode.WriteAt(op.Data, op.Offset)
return return err
} }
func (fs *memFS) ReadSymlink( func (fs *memFS) ReadSymlink(
ctx context.Context, ctx context.Context,
op *fuseops.ReadSymlinkOp) (err error) { op *fuseops.ReadSymlinkOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -673,11 +668,11 @@ func (fs *memFS) ReadSymlink(
// Serve the request. // Serve the request.
op.Target = inode.target op.Target = inode.target
return return nil
} }
func (fs *memFS) GetXattr(ctx context.Context, func (fs *memFS) GetXattr(ctx context.Context,
op *fuseops.GetXattrOp) (err error) { op *fuseops.GetXattrOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -687,17 +682,17 @@ func (fs *memFS) GetXattr(ctx context.Context,
if len(op.Dst) >= len(value) { if len(op.Dst) >= len(value) {
copy(op.Dst, value) copy(op.Dst, value)
} else if len(op.Dst) != 0 { } else if len(op.Dst) != 0 {
err = syscall.ERANGE return syscall.ERANGE
} }
} else { } else {
err = fuse.ENOATTR return fuse.ENOATTR
} }
return return nil
} }
func (fs *memFS) ListXattr(ctx context.Context, func (fs *memFS) ListXattr(ctx context.Context,
op *fuseops.ListXattrOp) (err error) { op *fuseops.ListXattrOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
@ -707,7 +702,7 @@ func (fs *memFS) ListXattr(ctx context.Context,
for key := range inode.xattrs { for key := range inode.xattrs {
keyLen := len(key) + 1 keyLen := len(key) + 1
if err == nil && len(dst) >= keyLen { if len(dst) >= keyLen {
copy(dst, key) copy(dst, key)
dst = dst[keyLen:] dst = dst[keyLen:]
} else if len(op.Dst) != 0 { } else if len(op.Dst) != 0 {
@ -716,11 +711,11 @@ func (fs *memFS) ListXattr(ctx context.Context,
op.BytesRead += keyLen op.BytesRead += keyLen
} }
return return nil
} }
func (fs *memFS) RemoveXattr(ctx context.Context, func (fs *memFS) RemoveXattr(ctx context.Context,
op *fuseops.RemoveXattrOp) (err error) { op *fuseops.RemoveXattrOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
@ -728,13 +723,13 @@ func (fs *memFS) RemoveXattr(ctx context.Context,
if _, ok := inode.xattrs[op.Name]; ok { if _, ok := inode.xattrs[op.Name]; ok {
delete(inode.xattrs, op.Name) delete(inode.xattrs, op.Name)
} else { } else {
err = fuse.ENOATTR return fuse.ENOATTR
} }
return return nil
} }
func (fs *memFS) SetXattr(ctx context.Context, func (fs *memFS) SetXattr(ctx context.Context,
op *fuseops.SetXattrOp) (err error) { op *fuseops.SetXattrOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
@ -744,28 +739,25 @@ func (fs *memFS) SetXattr(ctx context.Context,
switch op.Flags { switch op.Flags {
case unix.XATTR_CREATE: case unix.XATTR_CREATE:
if ok { if ok {
err = fuse.EEXIST return fuse.EEXIST
} }
case unix.XATTR_REPLACE: case unix.XATTR_REPLACE:
if !ok { if !ok {
err = fuse.ENOATTR return fuse.ENOATTR
} }
} }
if err == nil { value := make([]byte, len(op.Value))
value := make([]byte, len(op.Value)) copy(value, op.Value)
copy(value, op.Value) inode.xattrs[op.Name] = value
inode.xattrs[op.Name] = value return nil
}
return
} }
func (fs *memFS) Fallocate(ctx context.Context, func (fs *memFS) Fallocate(ctx context.Context,
op *fuseops.FallocateOp) (err error) { op *fuseops.FallocateOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
inode := fs.getInodeOrDie(op.Inode) inode := fs.getInodeOrDie(op.Inode)
inode.Fallocate(op.Mode, op.Length, op.Length) inode.Fallocate(op.Mode, op.Length, op.Length)
return return nil
} }

View File

@ -39,8 +39,7 @@ func TestPosix(t *testing.T) { RunTests(t) }
func getFileOffset(f *os.File) (offset int64, err error) { func getFileOffset(f *os.File) (offset int64, err error) {
const relativeToCurrent = 1 const relativeToCurrent = 1
offset, err = f.Seek(0, relativeToCurrent) return f.Seek(0, relativeToCurrent)
return
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////

View File

@ -42,11 +42,10 @@ var fFsyncError = flag.Int("flushfs.fsync_error", 0, "")
var fReadOnly = flag.Bool("read_only", false, "Mount in read-only mode.") var fReadOnly = flag.Bool("read_only", false, "Mount in read-only mode.")
var fDebug = flag.Bool("debug", false, "Enable debug logging.") var fDebug = flag.Bool("debug", false, "Enable debug logging.")
func makeFlushFS() (server fuse.Server, err error) { func makeFlushFS() (fuse.Server, error) {
// Check the flags. // Check the flags.
if *fFlushesFile == 0 || *fFsyncsFile == 0 { if *fFlushesFile == 0 || *fFsyncsFile == 0 {
err = fmt.Errorf("You must set the flushfs flags.") return nil, fmt.Errorf("You must set the flushfs flags.")
return
} }
// Set up the files. // Set up the files.
@ -67,18 +66,15 @@ func makeFlushFS() (server fuse.Server, err error) {
// Report flushes and fsyncs by writing the contents followed by a newline. // Report flushes and fsyncs by writing the contents followed by a newline.
report := func(f *os.File, outErr error) func(string) error { report := func(f *os.File, outErr error) func(string) error {
return func(s string) (err error) { return func(s string) error {
buf := []byte(s) buf := []byte(s)
buf = append(buf, '\n') buf = append(buf, '\n')
_, err = f.Write(buf) if _, err := f.Write(buf); err != nil {
if err != nil { return fmt.Errorf("Write: %v", err)
err = fmt.Errorf("Write: %v", err)
return
} }
err = outErr return outErr
return
} }
} }
@ -86,31 +82,25 @@ func makeFlushFS() (server fuse.Server, err error) {
reportFsync := report(fsyncs, fsyncErr) reportFsync := report(fsyncs, fsyncErr)
// Create the file system. // Create the file system.
server, err = flushfs.NewFileSystem(reportFlush, reportFsync) return flushfs.NewFileSystem(reportFlush, reportFsync)
return
} }
func makeFS() (server fuse.Server, err error) { func makeFS() (fuse.Server, error) {
switch *fType { switch *fType {
default: default:
err = fmt.Errorf("Unknown FS type: %v", *fType) return nil, fmt.Errorf("Unknown FS type: %v", *fType)
case "flushfs": case "flushfs":
server, err = makeFlushFS() return makeFlushFS()
} }
return
} }
func getReadyFile() (f *os.File, err error) { func getReadyFile() (*os.File, error) {
if *fReadyFile == 0 { if *fReadyFile == 0 {
err = errors.New("You must set --ready_file.") return nil, errors.New("You must set --ready_file.")
return
} }
f = os.NewFile(uintptr(*fReadyFile), "(ready file)") return os.NewFile(uintptr(*fReadyFile), "(ready file)"), nil
return
} }
func main() { func main() {

View File

@ -47,15 +47,13 @@ type FS interface {
MostRecentWriteSize() int MostRecentWriteSize() int
} }
func New() (fs FS) { func New() FS {
fs = &statFS{ return &statFS{
cannedStatResponse: fuseops.InodeAttributes{ cannedStatResponse: fuseops.InodeAttributes{
Mode: 0666, Mode: 0666,
}, },
mostRecentWriteSize: -1, mostRecentWriteSize: -1,
} }
return
} }
const childInodeID = fuseops.RootInodeID + 1 const childInodeID = fuseops.RootInodeID + 1
@ -118,32 +116,31 @@ func (fs *statFS) MostRecentWriteSize() int {
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *statFS) StatFS( func (fs *statFS) StatFS(
ctx context.Context, ctx context.Context,
op *fuseops.StatFSOp) (err error) { op *fuseops.StatFSOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
*op = fs.cannedResponse *op = fs.cannedResponse
return return nil
} }
func (fs *statFS) LookUpInode( func (fs *statFS) LookUpInode(
ctx context.Context, ctx context.Context,
op *fuseops.LookUpInodeOp) (err error) { op *fuseops.LookUpInodeOp) error {
// Only the root has children. // Only the root has children.
if op.Parent != fuseops.RootInodeID { if op.Parent != fuseops.RootInodeID {
err = fuse.ENOENT return fuse.ENOENT
return
} }
op.Entry.Child = childInodeID op.Entry.Child = childInodeID
op.Entry.Attributes = fs.fileAttrs() op.Entry.Attributes = fs.fileAttrs()
return return nil
} }
func (fs *statFS) GetInodeAttributes( func (fs *statFS) GetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.GetInodeAttributesOp) (err error) { op *fuseops.GetInodeAttributesOp) error {
switch op.Inode { switch op.Inode {
case fuseops.RootInodeID: case fuseops.RootInodeID:
op.Attributes = dirAttrs() op.Attributes = dirAttrs()
@ -152,32 +149,32 @@ func (fs *statFS) GetInodeAttributes(
op.Attributes = fs.fileAttrs() op.Attributes = fs.fileAttrs()
default: default:
err = fuse.ENOENT return fuse.ENOENT
} }
return return nil
} }
func (fs *statFS) SetInodeAttributes( func (fs *statFS) SetInodeAttributes(
ctx context.Context, ctx context.Context,
op *fuseops.SetInodeAttributesOp) (err error) { op *fuseops.SetInodeAttributesOp) error {
// Ignore calls to truncate existing files when opening. // Ignore calls to truncate existing files when opening.
return return nil
} }
func (fs *statFS) OpenFile( func (fs *statFS) OpenFile(
ctx context.Context, ctx context.Context,
op *fuseops.OpenFileOp) (err error) { op *fuseops.OpenFileOp) error {
return return nil
} }
// LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(fs.mu)
func (fs *statFS) WriteFile( func (fs *statFS) WriteFile(
ctx context.Context, ctx context.Context,
op *fuseops.WriteFileOp) (err error) { op *fuseops.WriteFileOp) error {
fs.mu.Lock() fs.mu.Lock()
defer fs.mu.Unlock() defer fs.mu.Unlock()
fs.mostRecentWriteSize = len(op.Data) fs.mostRecentWriteSize = len(op.Data)
return return nil
} }

View File

@ -35,7 +35,7 @@ var gDfOutputRegexp = regexp.MustCompile(`^\S+\s+(\d+)\s+(\d+)\s+(\d+)\s+\d+%\s+
// Helpers // Helpers
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
func convertName(in []int8) (s string) { func convertName(in []int8) string {
var tmp []byte var tmp []byte
for _, v := range in { for _, v := range in {
if v == 0 { if v == 0 {
@ -45,8 +45,7 @@ func convertName(in []int8) (s string) {
tmp = append(tmp, byte(v)) tmp = append(tmp, byte(v))
} }
s = string(tmp) return string(tmp)
return
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////

View File

@ -53,7 +53,7 @@ func df(dir string) (capacity, used, available uint64, err error) {
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return return 0, 0, 0, err
} }
// Scrape it. // Scrape it.
@ -65,23 +65,22 @@ func df(dir string) (capacity, used, available uint64, err error) {
submatches := gDfOutputRegexp.FindSubmatch(line) submatches := gDfOutputRegexp.FindSubmatch(line)
if submatches == nil { if submatches == nil {
err = fmt.Errorf("Unable to parse line: %q", line) return 0, 0, 0, fmt.Errorf("Unable to parse line: %q", line)
return
} }
capacity, err = strconv.ParseUint(string(submatches[1]), 10, 64) capacity, err = strconv.ParseUint(string(submatches[1]), 10, 64)
if err != nil { if err != nil {
return return 0, 0, 0, err
} }
used, err = strconv.ParseUint(string(submatches[2]), 10, 64) used, err = strconv.ParseUint(string(submatches[2]), 10, 64)
if err != nil { if err != nil {
return return 0, 0, 0, err
} }
available, err = strconv.ParseUint(string(submatches[3]), 10, 64) available, err = strconv.ParseUint(string(submatches[3]), 10, 64)
if err != nil { if err != nil {
return return 0, 0, 0, err
} }
// Scale appropriately based on the BLOCKSIZE set above. // Scale appropriately based on the BLOCKSIZE set above.
@ -89,11 +88,10 @@ func df(dir string) (capacity, used, available uint64, err error) {
used *= 1024 used *= 1024
available *= 1024 available *= 1024
return return capacity, used, available, nil
} }
err = fmt.Errorf("Unable to parse df output:\n%s", output) return 0, 0, 0, fmt.Errorf("Unable to parse df output:\n%s", output)
return
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////

View File

@ -80,23 +80,21 @@ var getToolContents_Err error
var getToolContents_Once sync.Once var getToolContents_Once sync.Once
// Implementation detail of getToolPath. // Implementation detail of getToolPath.
func getToolContentsImpl() (contents []byte, err error) { func getToolContentsImpl() ([]byte, error) {
// Fast path: has the user set the flag? // Fast path: has the user set the flag?
if *fToolPath != "" { if *fToolPath != "" {
contents, err = ioutil.ReadFile(*fToolPath) contents, err := ioutil.ReadFile(*fToolPath)
if err != nil { if err != nil {
err = fmt.Errorf("Reading mount_sample contents: %v", err) return nil, fmt.Errorf("Reading mount_sample contents: %v", err)
return
} }
return return contents, err
} }
// Create a temporary directory into which we will compile the tool. // Create a temporary directory into which we will compile the tool.
tempDir, err := ioutil.TempDir("", "sample_test") tempDir, err := ioutil.TempDir("", "sample_test")
if err != nil { if err != nil {
err = fmt.Errorf("TempDir: %v", err) return nil, fmt.Errorf("TempDir: %v", err)
return
} }
toolPath := path.Join(tempDir, "mount_sample") toolPath := path.Join(tempDir, "mount_sample")
@ -114,34 +112,30 @@ func getToolContentsImpl() (contents []byte, err error) {
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if err != nil { if err != nil {
err = fmt.Errorf( return nil, fmt.Errorf(
"mount_sample exited with %v, output:\n%s", "mount_sample exited with %v, output:\n%s",
err, err,
string(output)) string(output))
return
} }
// Slurp the tool contents. // Slurp the tool contents.
contents, err = ioutil.ReadFile(toolPath) contents, err := ioutil.ReadFile(toolPath)
if err != nil { if err != nil {
err = fmt.Errorf("ReadFile: %v", err) return nil, fmt.Errorf("ReadFile: %v", err)
return
} }
return return contents, nil
} }
// Build the mount_sample tool if it has not yet been built for this process. // Build the mount_sample tool if it has not yet been built for this process.
// Return its contents. // Return its contents.
func getToolContents() (contents []byte, err error) { func getToolContents() ([]byte, error) {
// Get hold of the binary contents, if we haven't yet. // Get hold of the binary contents, if we haven't yet.
getToolContents_Once.Do(func() { getToolContents_Once.Do(func() {
getToolContents_Contents, getToolContents_Err = getToolContentsImpl() getToolContents_Contents, getToolContents_Err = getToolContentsImpl()
}) })
contents, err = getToolContents_Contents, getToolContents_Err return getToolContents_Contents, getToolContents_Err
return
} }
func waitForMountSample( func waitForMountSample(
@ -184,29 +178,27 @@ func waitForReady(readyReader *os.File, c chan<- struct{}) {
} }
// Like SetUp, but doens't panic. // Like SetUp, but doens't panic.
func (t *SubprocessTest) initialize(ctx context.Context) (err error) { func (t *SubprocessTest) initialize(ctx context.Context) error {
// Initialize the context. // Initialize the context.
t.Ctx = ctx t.Ctx = ctx
// Set up a temporary directory. // Set up a temporary directory.
var err error
t.Dir, err = ioutil.TempDir("", "sample_test") t.Dir, err = ioutil.TempDir("", "sample_test")
if err != nil { if err != nil {
err = fmt.Errorf("TempDir: %v", err) return fmt.Errorf("TempDir: %v", err)
return
} }
// Build/read the mount_sample tool. // Build/read the mount_sample tool.
toolContents, err := getToolContents() toolContents, err := getToolContents()
if err != nil { if err != nil {
err = fmt.Errorf("getTooltoolContents: %v", err) return fmt.Errorf("getTooltoolContents: %v", err)
return
} }
// Create a temporary file to hold the contents of the tool. // Create a temporary file to hold the contents of the tool.
toolFile, err := ioutil.TempFile("", "sample_test") toolFile, err := ioutil.TempFile("", "sample_test")
if err != nil { if err != nil {
err = fmt.Errorf("TempFile: %v", err) return fmt.Errorf("TempFile: %v", err)
return
} }
defer toolFile.Close() defer toolFile.Close()
@ -217,21 +209,18 @@ func (t *SubprocessTest) initialize(ctx context.Context) (err error) {
// Write out the tool contents and make them executable. // Write out the tool contents and make them executable.
if _, err = toolFile.Write(toolContents); err != nil { if _, err = toolFile.Write(toolContents); err != nil {
err = fmt.Errorf("toolFile.Write: %v", err) return fmt.Errorf("toolFile.Write: %v", err)
return
} }
if err = toolFile.Chmod(0500); err != nil { if err = toolFile.Chmod(0500); err != nil {
err = fmt.Errorf("toolFile.Chmod: %v", err) return fmt.Errorf("toolFile.Chmod: %v", err)
return
} }
// Close the tool file to prevent "text file busy" errors below. // Close the tool file to prevent "text file busy" errors below.
err = toolFile.Close() err = toolFile.Close()
toolFile = nil toolFile = nil
if err != nil { if err != nil {
err = fmt.Errorf("toolFile.Close: %v", err) return fmt.Errorf("toolFile.Close: %v", err)
return
} }
// Set up basic args for the subprocess. // Set up basic args for the subprocess.
@ -247,8 +236,7 @@ func (t *SubprocessTest) initialize(ctx context.Context) (err error) {
// Set up a pipe for the "ready" status. // Set up a pipe for the "ready" status.
readyReader, readyWriter, err := os.Pipe() readyReader, readyWriter, err := os.Pipe()
if err != nil { if err != nil {
err = fmt.Errorf("Pipe: %v", err) return fmt.Errorf("Pipe: %v", err)
return
} }
defer readyReader.Close() defer readyReader.Close()
@ -280,9 +268,8 @@ func (t *SubprocessTest) initialize(ctx context.Context) (err error) {
} }
// Start the command. // Start the command.
if err = mountCmd.Start(); err != nil { if err := mountCmd.Start(); err != nil {
err = fmt.Errorf("mountCmd.Start: %v", err) return fmt.Errorf("mountCmd.Start: %v", err)
return
} }
// Launch a goroutine that waits for it and returns its status. // Launch a goroutine that waits for it and returns its status.
@ -296,14 +283,14 @@ func (t *SubprocessTest) initialize(ctx context.Context) (err error) {
select { select {
case <-readyChan: case <-readyChan:
case err = <-mountSampleErr: case err := <-mountSampleErr:
return return err
} }
// TearDown is no responsible for joining. // TearDown is no responsible for joining.
t.mountSampleErr = mountSampleErr t.mountSampleErr = mountSampleErr
return return nil
} }
// Unmount the file system and clean up. Panics on error. // Unmount the file system and clean up. Panics on error.
@ -329,7 +316,7 @@ func (t *SubprocessTest) destroy() (err error) {
// If we didn't try to mount the file system, there's nothing further to do. // If we didn't try to mount the file system, there's nothing further to do.
if t.mountSampleErr == nil { if t.mountSampleErr == nil {
return return nil
} }
// In the background, initiate an unmount. // In the background, initiate an unmount.
@ -358,9 +345,9 @@ func (t *SubprocessTest) destroy() (err error) {
}() }()
// Wait for the subprocess. // Wait for the subprocess.
if err = <-t.mountSampleErr; err != nil { if err := <-t.mountSampleErr; err != nil {
return return err
} }
return return nil
} }

View File

@ -27,12 +27,12 @@ import (
// "resource busy" errors, which happen from time to time on OS X (due to weird // "resource busy" errors, which happen from time to time on OS X (due to weird
// requests from the Finder) and when tests don't or can't synchronize all // requests from the Finder) and when tests don't or can't synchronize all
// events. // events.
func unmount(dir string) (err error) { func unmount(dir string) error {
delay := 10 * time.Millisecond delay := 10 * time.Millisecond
for { for {
err = fuse.Unmount(dir) err := fuse.Unmount(dir)
if err == nil { if err == nil {
return return err
} }
if strings.Contains(err.Error(), "resource busy") { if strings.Contains(err.Error(), "resource busy") {
@ -42,7 +42,6 @@ func unmount(dir string) (err error) {
continue continue
} }
err = fmt.Errorf("Unmount: %v", err) return fmt.Errorf("Unmount: %v", err)
return
} }
} }

View File

@ -6,18 +6,17 @@ import (
"os/exec" "os/exec"
) )
func unmount(dir string) (err error) { func unmount(dir string) error {
// Call fusermount. // Call fusermount.
cmd := exec.Command("fusermount", "-u", dir) cmd := exec.Command("fusermount", "-u", dir)
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if err != nil { if err != nil {
if len(output) > 0 { if len(output) > 0 {
output = bytes.TrimRight(output, "\n") output = bytes.TrimRight(output, "\n")
err = fmt.Errorf("%v: %s", err, output) return fmt.Errorf("%v: %s", err, output)
} }
return return err
} }
return nil
return
} }

View File

@ -7,12 +7,10 @@ import (
"syscall" "syscall"
) )
func unmount(dir string) (err error) { func unmount(dir string) error {
err = syscall.Unmount(dir, 0) if err := syscall.Unmount(dir, 0); err != nil {
if err != nil { return &os.PathError{Op: "unmount", Path: dir, Err: err}
err = &os.PathError{Op: "unmount", Path: dir, Err: err}
return
} }
return return nil
} }