268 lines
6.7 KiB
Go
268 lines
6.7 KiB
Go
// +build darwin linux
|
|
|
|
/*
|
|
* passthrough.go
|
|
*
|
|
* Copyright 2017 Bill Zissimopoulos
|
|
*/
|
|
/*
|
|
* This file is part of Cgofuse.
|
|
*
|
|
* It is licensed under the MIT license. The full license text can be found
|
|
* in the License.txt file at the root of this project.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"github.com/billziss-gh/cgofuse/examples/shared"
|
|
"github.com/billziss-gh/cgofuse/fuse"
|
|
)
|
|
|
|
func trace(vals ...interface{}) func(vals ...interface{}) {
|
|
uid, gid, _ := fuse.Getcontext()
|
|
return shared.Trace(1, fmt.Sprintf("[uid=%v,gid=%v]", uid, gid), vals...)
|
|
}
|
|
|
|
func errno(err error) int {
|
|
if nil != err {
|
|
return -int(err.(syscall.Errno))
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
var (
|
|
_host *fuse.FileSystemHost
|
|
)
|
|
|
|
type Ptfs struct {
|
|
fuse.FileSystemBase
|
|
root string
|
|
}
|
|
|
|
func (self *Ptfs) Init() {
|
|
defer trace()()
|
|
e := syscall.Chdir(self.root)
|
|
if nil == e {
|
|
self.root = "./"
|
|
}
|
|
}
|
|
|
|
func (self *Ptfs) Statfs(path string, stat *fuse.Statfs_t) (errc int) {
|
|
defer trace(path)(&errc, stat)
|
|
path = filepath.Join(self.root, path)
|
|
stgo := syscall.Statfs_t{}
|
|
errc = errno(syscall.Statfs(path, &stgo))
|
|
copyFusestatfsFromGostatfs(stat, &stgo)
|
|
return
|
|
}
|
|
|
|
func (self *Ptfs) Mknod(path string, mode uint32, dev uint64) (errc int) {
|
|
defer trace(path, mode, dev)(&errc)
|
|
defer setuidgid()()
|
|
path = filepath.Join(self.root, path)
|
|
return errno(syscall.Mknod(path, mode, int(dev)))
|
|
}
|
|
|
|
func (self *Ptfs) Mkdir(path string, mode uint32) (errc int) {
|
|
defer trace(path, mode)(&errc)
|
|
defer setuidgid()()
|
|
path = filepath.Join(self.root, path)
|
|
return errno(syscall.Mkdir(path, mode))
|
|
}
|
|
|
|
func (self *Ptfs) Unlink(path string) (errc int) {
|
|
defer trace(path)(&errc)
|
|
path = filepath.Join(self.root, path)
|
|
return errno(syscall.Unlink(path))
|
|
}
|
|
|
|
func (self *Ptfs) Rmdir(path string) (errc int) {
|
|
defer trace(path)(&errc)
|
|
path = filepath.Join(self.root, path)
|
|
return errno(syscall.Rmdir(path))
|
|
}
|
|
|
|
func (self *Ptfs) Link(oldpath string, newpath string) (errc int) {
|
|
defer trace(oldpath, newpath)(&errc)
|
|
defer setuidgid()()
|
|
oldpath = filepath.Join(self.root, oldpath)
|
|
newpath = filepath.Join(self.root, newpath)
|
|
return errno(syscall.Link(oldpath, newpath))
|
|
}
|
|
|
|
func (self *Ptfs) Symlink(target string, newpath string) (errc int) {
|
|
defer trace(target, newpath)(&errc)
|
|
defer setuidgid()()
|
|
newpath = filepath.Join(self.root, newpath)
|
|
return errno(syscall.Symlink(target, newpath))
|
|
}
|
|
|
|
func (self *Ptfs) Readlink(path string) (errc int, target string) {
|
|
defer trace(path)(&errc, &target)
|
|
path = filepath.Join(self.root, path)
|
|
buff := [1024]byte{}
|
|
n, e := syscall.Readlink(path, buff[:])
|
|
if nil != e {
|
|
return errno(e), ""
|
|
}
|
|
return 0, string(buff[:n])
|
|
}
|
|
|
|
func (self *Ptfs) Rename(oldpath string, newpath string) (errc int) {
|
|
defer trace(oldpath, newpath)(&errc)
|
|
defer setuidgid()()
|
|
oldpath = filepath.Join(self.root, oldpath)
|
|
newpath = filepath.Join(self.root, newpath)
|
|
return errno(syscall.Rename(oldpath, newpath))
|
|
}
|
|
|
|
func (self *Ptfs) Chmod(path string, mode uint32) (errc int) {
|
|
defer trace(path, mode)(&errc)
|
|
path = filepath.Join(self.root, path)
|
|
return errno(syscall.Chmod(path, mode))
|
|
}
|
|
|
|
func (self *Ptfs) Chown(path string, uid uint32, gid uint32) (errc int) {
|
|
defer trace(path, uid, gid)(&errc)
|
|
path = filepath.Join(self.root, path)
|
|
return errno(syscall.Lchown(path, int(uid), int(gid)))
|
|
}
|
|
|
|
func (self *Ptfs) Utimens(path string, tmsp1 []fuse.Timespec) (errc int) {
|
|
defer trace(path, tmsp1)(&errc)
|
|
path = filepath.Join(self.root, path)
|
|
tmsp := [2]syscall.Timespec{}
|
|
tmsp[0].Sec, tmsp[0].Nsec = tmsp1[0].Sec, tmsp1[0].Nsec
|
|
tmsp[1].Sec, tmsp[1].Nsec = tmsp1[1].Sec, tmsp1[1].Nsec
|
|
return errno(syscall.UtimesNano(path, tmsp[:]))
|
|
}
|
|
|
|
func (self *Ptfs) Create(path string, flags int, mode uint32) (errc int, fh uint64) {
|
|
defer trace(path, flags, mode)(&errc, &fh)
|
|
defer setuidgid()()
|
|
return self.open(path, flags, mode)
|
|
}
|
|
|
|
func (self *Ptfs) Open(path string, flags int) (errc int, fh uint64) {
|
|
defer trace(path, flags)(&errc, &fh)
|
|
return self.open(path, flags, 0)
|
|
}
|
|
|
|
func (self *Ptfs) open(path string, flags int, mode uint32) (errc int, fh uint64) {
|
|
path = filepath.Join(self.root, path)
|
|
f, e := syscall.Open(path, flags, mode)
|
|
if nil != e {
|
|
return errno(e), ^uint64(0)
|
|
}
|
|
return 0, uint64(f)
|
|
}
|
|
|
|
func (self *Ptfs) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) {
|
|
defer trace(path, fh)(&errc, stat)
|
|
stgo := syscall.Stat_t{}
|
|
if ^uint64(0) == fh {
|
|
path = filepath.Join(self.root, path)
|
|
errc = errno(syscall.Lstat(path, &stgo))
|
|
} else {
|
|
errc = errno(syscall.Fstat(int(fh), &stgo))
|
|
}
|
|
copyFusestatFromGostat(stat, &stgo)
|
|
return
|
|
}
|
|
|
|
func (self *Ptfs) Truncate(path string, size int64, fh uint64) (errc int) {
|
|
defer trace(path, size, fh)(&errc)
|
|
if ^uint64(0) == fh {
|
|
path = filepath.Join(self.root, path)
|
|
errc = errno(syscall.Truncate(path, size))
|
|
} else {
|
|
errc = errno(syscall.Ftruncate(int(fh), size))
|
|
}
|
|
return
|
|
}
|
|
|
|
func (self *Ptfs) Read(path string, buff []byte, ofst int64, fh uint64) (n int) {
|
|
defer trace(path, buff, ofst, fh)(&n)
|
|
n, e := syscall.Pread(int(fh), buff, ofst)
|
|
if nil != e {
|
|
return errno(e)
|
|
}
|
|
return n
|
|
}
|
|
|
|
func (self *Ptfs) Write(path string, buff []byte, ofst int64, fh uint64) (n int) {
|
|
defer trace(path, buff, ofst, fh)(&n)
|
|
n, e := syscall.Pwrite(int(fh), buff, ofst)
|
|
if nil != e {
|
|
return errno(e)
|
|
}
|
|
return n
|
|
}
|
|
|
|
func (self *Ptfs) Release(path string, fh uint64) (errc int) {
|
|
defer trace(path, fh)(&errc)
|
|
return errno(syscall.Close(int(fh)))
|
|
}
|
|
|
|
func (self *Ptfs) Fsync(path string, datasync bool, fh uint64) (errc int) {
|
|
defer trace(path, datasync, fh)(&errc)
|
|
return errno(syscall.Fsync(int(fh)))
|
|
}
|
|
|
|
func (self *Ptfs) Opendir(path string) (errc int, fh uint64) {
|
|
defer trace(path)(&errc, &fh)
|
|
path = filepath.Join(self.root, path)
|
|
f, e := syscall.Open(path, syscall.O_RDONLY|syscall.O_DIRECTORY, 0)
|
|
if nil != e {
|
|
return errno(e), ^uint64(0)
|
|
}
|
|
return 0, uint64(f)
|
|
}
|
|
|
|
func (self *Ptfs) Readdir(path string,
|
|
fill func(name string, stat *fuse.Stat_t, ofst int64) bool,
|
|
ofst int64,
|
|
fh uint64) (errc int) {
|
|
defer trace(path, fill, ofst, fh)(&errc)
|
|
path = filepath.Join(self.root, path)
|
|
file, e := os.Open(path)
|
|
if nil != e {
|
|
return errno(e)
|
|
}
|
|
defer file.Close()
|
|
nams, e := file.Readdirnames(0)
|
|
if nil != e {
|
|
return errno(e)
|
|
}
|
|
nams = append([]string{".", ".."}, nams...)
|
|
for _, name := range nams {
|
|
if !fill(name, nil, 0) {
|
|
break
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (self *Ptfs) Releasedir(path string, fh uint64) (errc int) {
|
|
defer trace(path, fh)(&errc)
|
|
return errno(syscall.Close(int(fh)))
|
|
}
|
|
|
|
func main() {
|
|
syscall.Umask(0)
|
|
ptfs := Ptfs{}
|
|
args := os.Args
|
|
if 3 <= len(args) && '-' != args[len(args)-2][0] && '-' != args[len(args)-1][0] {
|
|
ptfs.root, _ = filepath.Abs(args[len(args)-2])
|
|
args = append(args[:len(args)-2], args[len(args)-1])
|
|
}
|
|
_host = fuse.NewFileSystemHost(&ptfs)
|
|
_host.Mount("", args[1:])
|
|
}
|