fusego/connection.go

115 lines
3.0 KiB
Go
Raw Normal View History

2015-03-24 07:19:42 +03:00
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fuse
2015-03-24 07:23:19 +03:00
import (
"log"
"sync"
2015-03-24 07:23:19 +03:00
"github.com/jacobsa/bazilfuse"
"github.com/jacobsa/fuse/fuseops"
)
2015-03-24 07:19:42 +03:00
// A connection to the fuse kernel process.
type Connection struct {
logger *log.Logger
wrapped *bazilfuse.Conn
opsInFlight sync.WaitGroup
nextOpID uint64
2015-03-24 07:19:42 +03:00
}
2015-03-24 07:34:50 +03:00
// Responsibility for closing the wrapped connection is transferred to the
// result. You must call c.close() eventually.
func newConnection(
logger *log.Logger,
2015-03-24 07:36:09 +03:00
wrapped *bazilfuse.Conn) (c *Connection, err error) {
c = &Connection{
logger: logger,
wrapped: wrapped,
}
return
}
2015-03-24 07:23:19 +03:00
// Log information for an operation with the given unique ID.
func (c *Connection) log(
opID uint64,
format string,
v ...interface{}) {
// TODO(jacobsa): Add op ID and fixed-width file:line to output.
c.logger.Printf(format, v...)
}
2015-03-24 07:19:42 +03:00
// Read the next op from the kernel process. Return io.EOF if the kernel has
// closed the connection.
2015-03-24 07:23:19 +03:00
//
// This function delivers ops in exactly the order they are received from
2015-04-29 04:28:16 +03:00
// /dev/fuse. It must not be called multiple times concurrently.
2015-03-24 07:26:02 +03:00
func (c *Connection) ReadOp() (op fuseops.Op, err error) {
var bfReq bazilfuse.Request
// Keep going until we find a request we know how to convert.
for {
// Read a bazilfuse request.
bfReq, err = c.wrapped.ReadRequest()
if err != nil {
return
}
// Choose an ID for this operation.
opID := c.nextOpID
c.nextOpID++
// Log the receipt of the operation.
c.log(opID, "Received: %v", bfReq)
2015-03-24 07:52:14 +03:00
2015-03-24 07:51:36 +03:00
// Special case: responding to this is required to make mounting work on OS
// X. We don't currently expose the capability for the file system to
// intercept this.
if statfsReq, ok := bfReq.(*bazilfuse.StatfsRequest); ok {
c.log(opID, "Responding OK to Statfs.")
2015-03-24 07:51:36 +03:00
statfsReq.Respond(&bazilfuse.StatfsResponse{})
continue
}
2015-03-24 07:26:02 +03:00
// Convert it, if possible.
2015-04-29 04:35:28 +03:00
logForOp := func(format string, v ...interface{}) {
c.log(opID, format, v)
}
if op = fuseops.Convert(bfReq, logForOp, &c.opsInFlight); op == nil {
c.log(opID, "Returning ENOSYS for unknown bazilfuse request: %v", bfReq)
2015-03-24 07:26:02 +03:00
bfReq.RespondError(ENOSYS)
continue
}
c.opsInFlight.Add(1)
2015-03-24 07:26:02 +03:00
return
}
}
2015-03-24 07:34:50 +03:00
2015-03-24 07:36:09 +03:00
func (c *Connection) waitForReady() (err error) {
<-c.wrapped.Ready
err = c.wrapped.MountError
return
}
2015-03-24 07:34:50 +03:00
// Close the connection and wait for in-flight ops.
2015-03-24 07:36:09 +03:00
func (c *Connection) close() (err error) {
err = c.wrapped.Close()
c.opsInFlight.Wait()
2015-03-24 07:36:09 +03:00
return
}