Commit da579c85 authored by Ivan Krasin's avatar Ivan Krasin

Port FUSE bindings to Go release.2010-12-15.1. Review URL:...

Port FUSE bindings to Go release.2010-12-15.1. Review URL: http://codereview.appspot.com/3807042/ Author: Han-Wen Nienhuys <hanwen@google.com>. Committer: Ivan Krasin <imkrasin@gmail.com>
parent 1d3f8250
......@@ -155,7 +155,8 @@ func serialize(h *InHeader, res Status, out interface{}) (data [][]byte) {
panic(fmt.Sprintf("Can't serialize out: %v, err: %v", out, err))
}
}
fmt.Printf("out_data: %v, len(out_data): %d, SizeOfOutHeader: %d\n", out_data, len(out_data), SizeOfOutHeader)
fmt.Printf("out_data: %v, len(out_data): %d, SizeOfOutHeader: %d\n",
out_data, len(out_data), SizeOfOutHeader)
var hout OutHeader
hout.Unique = h.Unique
hout.Status = res
......@@ -289,7 +290,7 @@ func read(fs FileSystem, h *InHeader, ing interface{}, c *managerClient) (interf
}
fileRespChan := make(chan *fileResponse, 1)
fmt.Printf("Sending file request, in.Offset: %v\n", in.Offset)
resp.fileReq <- &fileRequest{ h.NodeId, in.Offset, in.Size, fileRespChan}
resp.fileReq <- &fileRequest{h.NodeId, in.Offset, in.Size, fileRespChan}
fmt.Printf("receiving file response\n")
fileResp := <-fileRespChan
fmt.Printf("received %v\n", fileResp)
......@@ -357,14 +358,14 @@ func writer(f *os.File, in chan [][]byte, errors chan os.Error) {
type FileOp int
const (
openDirOp = FileOp(1)
getHandleOp = FileOp(2)
closeDirOp = FileOp(3)
lookupOp = FileOp(4)
getPathOp = FileOp(5)
openOp = FileOp(6)
openDirOp = FileOp(1)
getHandleOp = FileOp(2)
closeDirOp = FileOp(3)
lookupOp = FileOp(4)
getPathOp = FileOp(5)
openOp = FileOp(6)
getFileHandleOp = FileOp(7)
closeFileOp = FileOp(8)
closeFileOp = FileOp(8)
)
type managerRequest struct {
......@@ -376,13 +377,13 @@ type managerRequest struct {
}
type managerResponse struct {
nodeId uint64
fh uint64
dirReq chan *dirRequest
nodeId uint64
fh uint64
dirReq chan *dirRequest
fileReq chan *fileRequest
status Status
attr Attr
path string
status Status
attr Attr
path string
}
type dirEntry struct {
......@@ -412,20 +413,20 @@ type dirHandle struct {
type fileRequest struct {
nodeId uint64
offset uint64
size uint32
resp chan *fileResponse
size uint32
resp chan *fileResponse
}
type fileResponse struct {
data []byte
data []byte
status Status
}
type fileHandle struct {
fh uint64
fh uint64
nodeId uint64
file File
req chan *fileRequest
file File
req chan *fileRequest
}
type manager struct {
......@@ -699,9 +700,9 @@ func readFileRoutine(fs FileSystem, c *managerClient, h *fileHandle) {
data := make([]byte, req.size)
n, err := h.file.ReadAt(data, int64(offset))
if err != nil {
req.resp <- &fileResponse { nil, EIO }
req.resp <- &fileResponse{nil, EIO}
continue
}
req.resp <- &fileResponse { data[0:n], OK }
req.resp <- &fileResponse{data[0:n], OK}
}
}
package fuse
import (
"fmt"
"log"
"os"
"path"
"rand"
"strings"
"testing"
"time"
)
const (
tempMountDir = "testMountDir2"
)
var (
testFileNames = []string{"one", "two", "three.txt"}
)
......@@ -39,7 +38,7 @@ func (fs *testFuse) Open(path string) (file File, code Status) {
return
}
type testFile struct {}
type testFile struct{}
func (f *testFile) ReadAt(data []byte, offset int64) (n int, err os.Error) {
if offset < 13 {
......@@ -59,21 +58,19 @@ func (f *testFile) Close() (status Status) {
func errorHandler(errors chan os.Error) {
for err := range errors {
log.Stderr("MountPoint.errorHandler: ", err)
log.Println("MountPoint.errorHandler: ", err)
if err == os.EOF {
break
}
}
}
func TestMount(t *testing.T) {
fs := new(testFuse)
err := os.Mkdir(tempMountDir, 0777)
if err != nil {
t.Fatalf("Can't create temp mount dir at %s, err: %v", tempMountDir, err)
}
tempMountDir := MakeTempDir()
fmt.Println("Tmpdir is: ", tempMountDir)
defer os.Remove(tempMountDir)
m, err, errors := Mount(tempMountDir, fs)
if err != nil {
......@@ -85,7 +82,9 @@ func TestMount(t *testing.T) {
t.Fatalf("Can't unmount a dir, err: %v", err)
}
}()
errorHandler(errors)
// Question: how to neatly do error handling?
go errorHandler(errors)
f, err := os.Open(tempMountDir, os.O_RDONLY, 0)
if err != nil {
t.Fatalf("Can't open a dir: %s, err: %v", tempMountDir, err)
......@@ -102,3 +101,17 @@ func TestMount(t *testing.T) {
return
}
}
// Make a temporary directory securely.
func MakeTempDir() string {
source := rand.NewSource(time.Nanoseconds())
number := source.Int63() & 0xffff
name := fmt.Sprintf("tmp%d", number)
fullName := path.Join(os.TempDir(), name)
err := os.Mkdir(fullName, 0700)
if err != nil {
panic("Mkdir() should always succeed: " + fullName)
}
return fullName
}
package fuse
// Written with a look to http://ptspts.blogspot.com/2009/11/fuse-protocol-tutorial-for-linux-26.html
import (
"fmt"
"net"
"os"
"path"
"syscall"
"unsafe"
)
// Make a type to attach the Unmount method.
type mounted string
// Mount create a fuse fs on the specified mount point.
func Socketpair(network string) (l, r *os.File, err os.Error) {
var domain int
var typ int
switch network {
default:
panic("unknown network " + network)
case "unix":
domain = syscall.AF_UNIX
typ = syscall.SOCK_STREAM
case "unixgram":
domain = syscall.AF_UNIX
typ = syscall.SOCK_SEQPACKET
}
fd, errno := syscall.Socketpair(domain, typ, 0)
if errno != 0 {
return nil, nil, os.NewSyscallError("socketpair", errno)
}
l = os.NewFile(fd[0], "socketpair-half1")
r = os.NewFile(fd[1], "socketpair-half2")
return
}
// Mount create a fuse fs on the specified mount point. The returned
// mount point is always absolute.
func mount(mountPoint string) (f *os.File, m mounted, err os.Error) {
local, remote, err := net.Socketpair("unixgram")
local, remote, err := Socketpair("unixgram")
if err != nil {
return
}
......@@ -35,7 +57,7 @@ func mount(mountPoint string) (f *os.File, m mounted, err os.Error) {
[]string{"/bin/fusermount", mountPoint},
[]string{"_FUSE_COMMFD=3"},
"",
[]*os.File{nil, nil, nil, remote.File()})
[]*os.File{nil, nil, nil, remote})
if err != nil {
return
}
......@@ -55,10 +77,11 @@ func mount(mountPoint string) (f *os.File, m mounted, err os.Error) {
func (m mounted) Unmount() (err os.Error) {
mountPoint := string(m)
dir, _ := path.Split(mountPoint)
pid, err := os.ForkExec("/bin/fusermount",
[]string{"/bin/fusermount", "-u", mountPoint},
nil,
"",
dir,
[]*os.File{nil, nil, os.Stderr})
if err != nil {
return
......@@ -68,25 +91,7 @@ func (m mounted) Unmount() (err os.Error) {
return
}
if w.ExitStatus() != 0 {
return os.NewError(fmt.Sprintf("fusermount exited with code %d\n", w.ExitStatus()))
}
return
}
func recvmsg(fd int, msg *syscall.Msghdr, flags int) (n int, errno int) {
n1, _, e1 := syscall.Syscall(syscall.SYS_RECVMSG, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(n1)
errno = int(e1)
return
}
func Recvmsg(fd int, msg *syscall.Msghdr, flags int) (n int, err os.Error) {
n, errno := recvmsg(fd, msg, flags)
if n == 0 && errno == 0 {
return 0, os.EOF
}
if errno != 0 {
err = os.NewSyscallError("recvmsg", errno)
return os.NewError(fmt.Sprintf("fusermount -u exited with code %d\n", w.ExitStatus()))
}
return
}
......@@ -108,7 +113,7 @@ func Writev(fd int, packet [][]byte) (n int, err os.Error) {
continue
}
iovecs[i].Base = (*byte)(unsafe.Pointer(&packet[i][0]))
iovecs[i].Len = uint64(len(packet[i]))
iovecs[i].SetLen(len(packet[i]))
}
n, errno := writev(fd, (*syscall.Iovec)(unsafe.Pointer(&iovecs[0])), len(iovecs))
......@@ -119,36 +124,29 @@ func Writev(fd int, packet [][]byte) (n int, err os.Error) {
return
}
func getFuseConn(local net.Conn) (f *os.File, err os.Error) {
var msg syscall.Msghdr
var iov syscall.Iovec
base := make([]int32, 256)
control := make([]int32, 256)
func getFuseConn(local *os.File) (f *os.File, err os.Error) {
var data [4]byte
control := make([]byte, 4*256)
iov.Base = (*byte)(unsafe.Pointer(&base[0]))
iov.Len = uint64(len(base) * 4)
msg.Iov = (*syscall.Iovec)(unsafe.Pointer(&iov))
msg.Iovlen = 1
msg.Control = (*byte)(unsafe.Pointer(&control[0]))
msg.Controllen = uint64(len(control) * 4)
_, err = Recvmsg(local.File().Fd(), &msg, 0)
if err != nil {
// n, oobn, recvflags - todo: error checking.
_, oobn, _,
errno := syscall.Recvmsg(
local.Fd(), data[:], control[:], nil, 0)
if errno != 0 {
return
}
length := control[0]
typ := control[2] // syscall.Cmsghdr.Type
fd := control[4]
if typ != 1 {
err = os.NewError(fmt.Sprintf("getFuseConn: recvmsg returned wrong control type: %d", typ))
message := *(*syscall.Cmsghdr)(unsafe.Pointer(&control[0]))
fd := *(*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&control[0])) + syscall.SizeofCmsghdr))
if message.Type != 1 {
err = os.NewError(fmt.Sprintf("getFuseConn: recvmsg returned wrong control type: %d", message.Type))
return
}
if length < 20 {
err = os.NewError(fmt.Sprintf("getFuseConn: too short control message. Length: %d", length))
if oobn <= syscall.SizeofCmsghdr {
err = os.NewError(fmt.Sprintf("getFuseConn: too short control message. Length: %d", oobn))
return
}
if fd < 0 {
err = os.NewError(fmt.Sprintf("getFuseConn: fd < 0: %d", fd))
return
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment