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) { ...@@ -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)) 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 var hout OutHeader
hout.Unique = h.Unique hout.Unique = h.Unique
hout.Status = res hout.Status = res
...@@ -289,7 +290,7 @@ func read(fs FileSystem, h *InHeader, ing interface{}, c *managerClient) (interf ...@@ -289,7 +290,7 @@ func read(fs FileSystem, h *InHeader, ing interface{}, c *managerClient) (interf
} }
fileRespChan := make(chan *fileResponse, 1) fileRespChan := make(chan *fileResponse, 1)
fmt.Printf("Sending file request, in.Offset: %v\n", in.Offset) 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") fmt.Printf("receiving file response\n")
fileResp := <-fileRespChan fileResp := <-fileRespChan
fmt.Printf("received %v\n", fileResp) fmt.Printf("received %v\n", fileResp)
...@@ -357,14 +358,14 @@ func writer(f *os.File, in chan [][]byte, errors chan os.Error) { ...@@ -357,14 +358,14 @@ func writer(f *os.File, in chan [][]byte, errors chan os.Error) {
type FileOp int type FileOp int
const ( const (
openDirOp = FileOp(1) openDirOp = FileOp(1)
getHandleOp = FileOp(2) getHandleOp = FileOp(2)
closeDirOp = FileOp(3) closeDirOp = FileOp(3)
lookupOp = FileOp(4) lookupOp = FileOp(4)
getPathOp = FileOp(5) getPathOp = FileOp(5)
openOp = FileOp(6) openOp = FileOp(6)
getFileHandleOp = FileOp(7) getFileHandleOp = FileOp(7)
closeFileOp = FileOp(8) closeFileOp = FileOp(8)
) )
type managerRequest struct { type managerRequest struct {
...@@ -376,13 +377,13 @@ type managerRequest struct { ...@@ -376,13 +377,13 @@ type managerRequest struct {
} }
type managerResponse struct { type managerResponse struct {
nodeId uint64 nodeId uint64
fh uint64 fh uint64
dirReq chan *dirRequest dirReq chan *dirRequest
fileReq chan *fileRequest fileReq chan *fileRequest
status Status status Status
attr Attr attr Attr
path string path string
} }
type dirEntry struct { type dirEntry struct {
...@@ -412,20 +413,20 @@ type dirHandle struct { ...@@ -412,20 +413,20 @@ type dirHandle struct {
type fileRequest struct { type fileRequest struct {
nodeId uint64 nodeId uint64
offset uint64 offset uint64
size uint32 size uint32
resp chan *fileResponse resp chan *fileResponse
} }
type fileResponse struct { type fileResponse struct {
data []byte data []byte
status Status status Status
} }
type fileHandle struct { type fileHandle struct {
fh uint64 fh uint64
nodeId uint64 nodeId uint64
file File file File
req chan *fileRequest req chan *fileRequest
} }
type manager struct { type manager struct {
...@@ -699,9 +700,9 @@ func readFileRoutine(fs FileSystem, c *managerClient, h *fileHandle) { ...@@ -699,9 +700,9 @@ func readFileRoutine(fs FileSystem, c *managerClient, h *fileHandle) {
data := make([]byte, req.size) data := make([]byte, req.size)
n, err := h.file.ReadAt(data, int64(offset)) n, err := h.file.ReadAt(data, int64(offset))
if err != nil { if err != nil {
req.resp <- &fileResponse { nil, EIO } req.resp <- &fileResponse{nil, EIO}
continue continue
} }
req.resp <- &fileResponse { data[0:n], OK } req.resp <- &fileResponse{data[0:n], OK}
} }
} }
package fuse package fuse
import ( import (
"fmt"
"log" "log"
"os" "os"
"path"
"rand"
"strings" "strings"
"testing" "testing"
"time" "time"
) )
const (
tempMountDir = "testMountDir2"
)
var ( var (
testFileNames = []string{"one", "two", "three.txt"} testFileNames = []string{"one", "two", "three.txt"}
) )
...@@ -39,7 +38,7 @@ func (fs *testFuse) Open(path string) (file File, code Status) { ...@@ -39,7 +38,7 @@ func (fs *testFuse) Open(path string) (file File, code Status) {
return return
} }
type testFile struct {} type testFile struct{}
func (f *testFile) ReadAt(data []byte, offset int64) (n int, err os.Error) { func (f *testFile) ReadAt(data []byte, offset int64) (n int, err os.Error) {
if offset < 13 { if offset < 13 {
...@@ -59,21 +58,19 @@ func (f *testFile) Close() (status Status) { ...@@ -59,21 +58,19 @@ func (f *testFile) Close() (status Status) {
func errorHandler(errors chan os.Error) { func errorHandler(errors chan os.Error) {
for err := range errors { for err := range errors {
log.Stderr("MountPoint.errorHandler: ", err) log.Println("MountPoint.errorHandler: ", err)
if err == os.EOF { if err == os.EOF {
break break
} }
} }
} }
func TestMount(t *testing.T) { func TestMount(t *testing.T) {
fs := new(testFuse) fs := new(testFuse)
err := os.Mkdir(tempMountDir, 0777) tempMountDir := MakeTempDir()
if err != nil {
t.Fatalf("Can't create temp mount dir at %s, err: %v", tempMountDir, err) fmt.Println("Tmpdir is: ", tempMountDir)
}
defer os.Remove(tempMountDir) defer os.Remove(tempMountDir)
m, err, errors := Mount(tempMountDir, fs) m, err, errors := Mount(tempMountDir, fs)
if err != nil { if err != nil {
...@@ -85,7 +82,9 @@ func TestMount(t *testing.T) { ...@@ -85,7 +82,9 @@ func TestMount(t *testing.T) {
t.Fatalf("Can't unmount a dir, err: %v", err) 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) f, err := os.Open(tempMountDir, os.O_RDONLY, 0)
if err != nil { if err != nil {
t.Fatalf("Can't open a dir: %s, err: %v", tempMountDir, err) t.Fatalf("Can't open a dir: %s, err: %v", tempMountDir, err)
...@@ -102,3 +101,17 @@ func TestMount(t *testing.T) { ...@@ -102,3 +101,17 @@ func TestMount(t *testing.T) {
return 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 package fuse
// Written with a look to http://ptspts.blogspot.com/2009/11/fuse-protocol-tutorial-for-linux-26.html // Written with a look to http://ptspts.blogspot.com/2009/11/fuse-protocol-tutorial-for-linux-26.html
import ( import (
"fmt" "fmt"
"net"
"os" "os"
"path" "path"
"syscall" "syscall"
"unsafe" "unsafe"
) )
// Make a type to attach the Unmount method.
type mounted string 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) { 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 { if err != nil {
return return
} }
...@@ -35,7 +57,7 @@ func mount(mountPoint string) (f *os.File, m mounted, err os.Error) { ...@@ -35,7 +57,7 @@ func mount(mountPoint string) (f *os.File, m mounted, err os.Error) {
[]string{"/bin/fusermount", mountPoint}, []string{"/bin/fusermount", mountPoint},
[]string{"_FUSE_COMMFD=3"}, []string{"_FUSE_COMMFD=3"},
"", "",
[]*os.File{nil, nil, nil, remote.File()}) []*os.File{nil, nil, nil, remote})
if err != nil { if err != nil {
return return
} }
...@@ -55,10 +77,11 @@ func mount(mountPoint string) (f *os.File, m mounted, err os.Error) { ...@@ -55,10 +77,11 @@ func mount(mountPoint string) (f *os.File, m mounted, err os.Error) {
func (m mounted) Unmount() (err os.Error) { func (m mounted) Unmount() (err os.Error) {
mountPoint := string(m) mountPoint := string(m)
dir, _ := path.Split(mountPoint)
pid, err := os.ForkExec("/bin/fusermount", pid, err := os.ForkExec("/bin/fusermount",
[]string{"/bin/fusermount", "-u", mountPoint}, []string{"/bin/fusermount", "-u", mountPoint},
nil, nil,
"", dir,
[]*os.File{nil, nil, os.Stderr}) []*os.File{nil, nil, os.Stderr})
if err != nil { if err != nil {
return return
...@@ -68,25 +91,7 @@ func (m mounted) Unmount() (err os.Error) { ...@@ -68,25 +91,7 @@ func (m mounted) Unmount() (err os.Error) {
return return
} }
if w.ExitStatus() != 0 { if w.ExitStatus() != 0 {
return os.NewError(fmt.Sprintf("fusermount exited with code %d\n", w.ExitStatus())) return os.NewError(fmt.Sprintf("fusermount -u 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 return
} }
...@@ -108,7 +113,7 @@ func Writev(fd int, packet [][]byte) (n int, err os.Error) { ...@@ -108,7 +113,7 @@ func Writev(fd int, packet [][]byte) (n int, err os.Error) {
continue continue
} }
iovecs[i].Base = (*byte)(unsafe.Pointer(&packet[i][0])) 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)) 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) { ...@@ -119,36 +124,29 @@ func Writev(fd int, packet [][]byte) (n int, err os.Error) {
return return
} }
func getFuseConn(local net.Conn) (f *os.File, err os.Error) { func getFuseConn(local *os.File) (f *os.File, err os.Error) {
var msg syscall.Msghdr var data [4]byte
var iov syscall.Iovec control := make([]byte, 4*256)
base := make([]int32, 256)
control := make([]int32, 256)
iov.Base = (*byte)(unsafe.Pointer(&base[0])) // n, oobn, recvflags - todo: error checking.
iov.Len = uint64(len(base) * 4) _, oobn, _,
msg.Iov = (*syscall.Iovec)(unsafe.Pointer(&iov)) errno := syscall.Recvmsg(
msg.Iovlen = 1 local.Fd(), data[:], control[:], nil, 0)
msg.Control = (*byte)(unsafe.Pointer(&control[0])) if errno != 0 {
msg.Controllen = uint64(len(control) * 4)
_, err = Recvmsg(local.File().Fd(), &msg, 0)
if err != nil {
return return
} }
length := control[0] message := *(*syscall.Cmsghdr)(unsafe.Pointer(&control[0]))
typ := control[2] // syscall.Cmsghdr.Type fd := *(*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&control[0])) + syscall.SizeofCmsghdr))
fd := control[4]
if typ != 1 { if message.Type != 1 {
err = os.NewError(fmt.Sprintf("getFuseConn: recvmsg returned wrong control type: %d", typ)) err = os.NewError(fmt.Sprintf("getFuseConn: recvmsg returned wrong control type: %d", message.Type))
return return
} }
if length < 20 { if oobn <= syscall.SizeofCmsghdr {
err = os.NewError(fmt.Sprintf("getFuseConn: too short control message. Length: %d", length)) err = os.NewError(fmt.Sprintf("getFuseConn: too short control message. Length: %d", oobn))
return return
} }
if fd < 0 { if fd < 0 {
err = os.NewError(fmt.Sprintf("getFuseConn: fd < 0: %d", fd)) err = os.NewError(fmt.Sprintf("getFuseConn: fd < 0: %d", fd))
return 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