1
mirror of https://github.com/rclone/rclone synced 2024-11-11 09:30:44 +01:00

cmount: Vendor github.com/billziss-gh/cgofuse

This commit is contained in:
Nick Craig-Wood 2017-05-12 11:01:05 +01:00
parent b553c23d5b
commit ea0bc278ba
17 changed files with 3333 additions and 1 deletions

8
Gopkg.lock generated
View File

@ -1,4 +1,4 @@
memo = "0c86c911e62d7207fb8549d69519a5a795ce4b36aadce87b84504f109eefe60b"
memo = "28c7ca08636da6264c587a36b72ce4f3a45fdf5c32969ffd2092b98456c73685"
[[projects]]
branch = "master"
@ -30,6 +30,12 @@ memo = "0c86c911e62d7207fb8549d69519a5a795ce4b36aadce87b84504f109eefe60b"
packages = ["aws","aws/awserr","aws/awsutil","aws/client","aws/client/metadata","aws/corehandlers","aws/credentials","aws/credentials/ec2rolecreds","aws/credentials/endpointcreds","aws/credentials/stscreds","aws/defaults","aws/ec2metadata","aws/endpoints","aws/request","aws/session","aws/signer/v4","private/protocol","private/protocol/query","private/protocol/query/queryutil","private/protocol/rest","private/protocol/restxml","private/protocol/xml/xmlutil","service/s3","service/s3/s3iface","service/s3/s3manager","service/sts"]
revision = "57572ec625c9aa8bf5c45453efa923bacabc0afe"
[[projects]]
name = "github.com/billziss-gh/cgofuse"
packages = ["fuse"]
revision = "b402ef9fb28afcc443348ba2d46b5bfd88867fea"
version = "v1.0"
[[projects]]
name = "github.com/cpuguy83/go-md2man"
packages = ["md2man"]

29
vendor/github.com/billziss-gh/cgofuse/.appveyor.yml generated vendored Normal file
View File

@ -0,0 +1,29 @@
version: '{build}'
clone_folder: C:\projects\go\src\github.com\billziss-gh\cgofuse
environment:
CPATH: C:\Program Files (x86)\WinFsp\inc\fuse
GODEBUG: cgocheck=2
GOPATH: C:\projects\go
PATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;%PATH%
install:
- choco install winfsp -y
build_script:
- go install -v ./...
test_script:
- go test ./fuse
- git clone -q https://github.com/billziss-gh/winfsp.git C:\projects\winfsp
- git -C C:\projects\winfsp checkout -q v1.0
- call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
- devenv C:\projects\winfsp\build\VStudio\winfsp.sln /build "Release|x64"
# hard code fsreg parameters because appveyor does not like percents ("--VolumePrefix=%1 %2")
- C:\projects\winfsp\tools\fsreg.bat gomemfs "C:\projects\go\bin\memfs.exe" "--VolumePrefix=\gomemfs\share M:" "D:P(A;;RPWPLC;;;WD)"
- 'net use M: \\gomemfs\share'
- 'M: & cd'
- C:\projects\winfsp\build\VStudio\build\Release\winfsp-tests-x64.exe --external --resilient --share-prefix=\gomemfs\share -create_allocation_test -getfileinfo_name_test -setfileinfo_test -delete_access_test -setsecurity_test -reparse* -stream*
- 'C: & cd'
- 'net use M: /delete'

47
vendor/github.com/billziss-gh/cgofuse/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,47 @@
os:
- osx
- linux
language: go
env:
- GODEBUG=cgocheck=2
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update; fi
# FUSE
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install caskroom/cask/osxfuse; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq install libfuse-dev; fi
# secfs.test
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq install libacl1-dev; fi
- mkdir -p /tmp/t/{m,p}
- git clone -q https://github.com/billziss-gh/secfs.test.git /tmp/t/secfs.test
- git -C /tmp/t/secfs.test checkout -q a00c9165646f78ad53d3ec052860384a029683e5
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sed -e 's/^fs=.*$/fs="cgofuse"/' -i "" /tmp/t/secfs.test/fstest/fstest/tests/conf; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sed -e 's/^fs=.*$/fs="cgofuse"/' -i"" /tmp/t/secfs.test/fstest/fstest/tests/conf; fi
# the following test succeeds on my Mac but fails on Travis OSX; I have no clue why; disabling!
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mv /tmp/t/secfs.test/fstest/fstest/tests/rmdir/{,.}12.t; fi
- mv /tmp/t/secfs.test/fstest/fstest/tests/{,.}zzz_ResourceFork
- make -C /tmp/t/secfs.test
install:
- go install -v ./...
script:
- go test ./fuse
# cgofuse/memfs
- sudo $GOPATH/bin/memfs -o allow_other,default_permissions,use_ino,attr_timeout=0 /tmp/t/m &
- (cd /tmp/t/m && sudo prove -fr /tmp/t/secfs.test/fstest/fstest/tests)
- (cd /tmp/t/m && /tmp/t/secfs.test/tools/bin/fsx -N 10000 test xxxxxx)
- (cd /tmp/t/m && /tmp/t/secfs.test/tools/bin/fsx -e -N 1000 test xxxx)
- sudo umount /tmp/t/m
# cgofuse/passthrough
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sed -e 's/lchmod)/lchmod) return 1/' -i "" /tmp/t/secfs.test/fstest/fstest/tests/misc.sh; fi
- sudo $GOPATH/bin/passthrough -o allow_other,default_permissions,use_ino,attr_timeout=0 /tmp/t/p /tmp/t/m &
- (cd /tmp/t/m && sudo prove -fr /tmp/t/secfs.test/fstest/fstest/tests)
- (cd /tmp/t/m && /tmp/t/secfs.test/tools/bin/fsx -N 10000 test xxxxxx)
- sudo umount /tmp/t/m
notifications:
email: false

6
vendor/github.com/billziss-gh/cgofuse/Changelog.md generated vendored Normal file
View File

@ -0,0 +1,6 @@
# Changelog
**v1.0**
- Initial cgofuse release.
- The API is now **FROZEN**. Breaking API changes will receive a major version update (`2.0`). Incremental API changes will receive a minor version update (`1.x`).

21
vendor/github.com/billziss-gh/cgofuse/License.txt generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Bill Zissimopoulos
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

63
vendor/github.com/billziss-gh/cgofuse/README.md generated vendored Normal file
View File

@ -0,0 +1,63 @@
# Cross-platform FUSE library for Go
[![Travis CI](https://img.shields.io/travis/billziss-gh/cgofuse.svg?label=osx/linux)](https://travis-ci.org/billziss-gh/cgofuse)
[![AppVeyor](https://img.shields.io/appveyor/ci/billziss-gh/cgofuse.svg?label=windows)](https://ci.appveyor.com/project/billziss-gh/cgofuse)
[![GoDoc](https://godoc.org/github.com/billziss-gh/cgofuse/fuse?status.svg)](https://godoc.org/github.com/billziss-gh/cgofuse/fuse)
Cgofuse is a cross-platform FUSE library for Go. It is implemented using [cgo](https://golang.org/cmd/cgo/) and can be ported to any platform that has a FUSE implementation.
Cgofuse currently runs on **OSX**, **Linux** and **Windows** (using [WinFsp](https://github.com/billziss-gh/winfsp)).
## How to build
**OSX**
- Prerequisites: [OSXFUSE](https://osxfuse.github.io), [command line tools](https://developer.apple.com/library/content/technotes/tn2339/_index.html)
- Build:
```
$ cd cgofuse
$ go install -v ./fuse ./examples/memfs ./examples/passthrough
```
**Linux**
- Prerequisites: libfuse-dev, gcc
- Build:
```
$ cd cgofuse
$ go install -v ./fuse ./examples/memfs ./examples/passthrough
```
**Windows**
- Prerequisites: [WinFsp](https://github.com/billziss-gh/winfsp), gcc (e.g. from [Mingw-builds](http://mingw-w64.org/doku.php/download))
- Build:
```
> cd cgofuse
> set CPATH=C:\Program Files (x86)\WinFsp\inc\fuse
> go install -v ./fuse ./examples/memfs
```
## How to use
User mode file systems are expected to implement `fuse.FileSystemInterface`. To make implementation simpler a file system can embed ("inherit") a `fuse.FileSystemBase` which provides default implementations for all operations. To mount a file system one must instantiate a `fuse.FileSystemHost` using `fuse.NewFileSystemHost`.
The full documentation is available at GoDoc.org: [package fuse](https://godoc.org/github.com/billziss-gh/cgofuse/fuse)
There are currently three example file systems:
- [Hellofs](examples/hellofs/hellofs.go) is an extremely simple file system. Runs on OSX, Linux and Windows.
- [Memfs](examples/memfs/memfs.go) is an in memory file system. Runs on OSX, Linux and Windows.
- [Passthrough](examples/passthrough/passthrough.go) is a file system that passes all operations to the underlying file system. Runs on OSX, Linux.
## How it is tested
Cgofuse is regularly built and tested on [Travis CI](https://travis-ci.org/billziss-gh/cgofuse) and [AppVeyor](https://ci.appveyor.com/project/billziss-gh/cgofuse). The following software is being used to test cgofuse.
**OSX/Linux**
- [fstest](https://github.com/billziss-gh/secfs.test/tree/master/fstest/ntfs-3g-pjd-fstest-8af5670)
- [fsx](https://github.com/billziss-gh/secfs.test/tree/master/fstools/src/fsx)
**Windows**
- [winfsp-tests](https://github.com/billziss-gh/winfsp/tree/master/tst/winfsp-tests)
## Contributors
- Bill Zissimopoulos \<billziss at navimatics.com>
- Nick Craig-Wood \<nick at craig-wood.com>

View File

@ -0,0 +1,79 @@
/*
* hellofs.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 (
"os"
"github.com/billziss-gh/cgofuse/fuse"
)
const (
filename = "hello"
contents = "hello, world\n"
)
type Hellofs struct {
fuse.FileSystemBase
}
func (self *Hellofs) Open(path string, flags int) (errc int, fh uint64) {
switch path {
case "/" + filename:
return 0, 0
default:
return -fuse.ENOENT, ^uint64(0)
}
}
func (self *Hellofs) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) {
switch path {
case "/":
stat.Mode = fuse.S_IFDIR | 0555
return 0
case "/" + filename:
stat.Mode = fuse.S_IFREG | 0444
stat.Size = int64(len(contents))
return 0
default:
return -fuse.ENOENT
}
}
func (self *Hellofs) Read(path string, buff []byte, ofst int64, fh uint64) (n int) {
endofst := ofst + int64(len(buff))
if endofst > int64(len(contents)) {
endofst = int64(len(contents))
}
if endofst < ofst {
return 0
}
n = copy(buff, contents[ofst:endofst])
return
}
func (self *Hellofs) Readdir(path string,
fill func(name string, stat *fuse.Stat_t, ofst int64) bool,
ofst int64,
fh uint64) (errc int) {
fill(".", nil, 0)
fill("..", nil, 0)
fill(filename, nil, 0)
return 0
}
func main() {
hellofs := &Hellofs{}
host := fuse.NewFileSystemHost(hellofs)
host.Mount("", os.Args[1:])
}

View File

@ -0,0 +1,545 @@
/*
* memfs.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"
"strings"
"sync"
"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 split(path string) []string {
return strings.Split(path, "/")
}
func resize(slice []byte, size int64, zeroinit bool) []byte {
const allocunit = 64 * 1024
allocsize := (size + allocunit - 1) / allocunit * allocunit
if cap(slice) != int(allocsize) {
var newslice []byte
{
defer func() {
if r := recover(); nil != r {
panic(fuse.Error(-fuse.ENOSPC))
}
}()
newslice = make([]byte, size, allocsize)
}
copy(newslice, slice)
slice = newslice
} else if zeroinit {
i := len(slice)
slice = slice[:size]
for ; len(slice) > i; i++ {
slice[i] = 0
}
}
return slice
}
type node_t struct {
stat fuse.Stat_t
xatr map[string][]byte
chld map[string]*node_t
data []byte
opencnt int
}
func newNode(dev uint64, ino uint64, mode uint32, uid uint32, gid uint32) *node_t {
tmsp := fuse.Now()
self := node_t{
fuse.Stat_t{
Dev: dev,
Ino: ino,
Mode: mode,
Nlink: 1,
Uid: uid,
Gid: gid,
Atim: tmsp,
Mtim: tmsp,
Ctim: tmsp,
Birthtim: tmsp,
},
nil,
nil,
nil,
0}
if fuse.S_IFDIR == self.stat.Mode&fuse.S_IFMT {
self.chld = map[string]*node_t{}
}
return &self
}
type Memfs struct {
fuse.FileSystemBase
lock sync.Mutex
ino uint64
root *node_t
openmap map[uint64]*node_t
}
func (self *Memfs) Mknod(path string, mode uint32, dev uint64) (errc int) {
defer trace(path, mode, dev)(&errc)
defer self.synchronize()()
return self.makeNode(path, mode, dev, nil)
}
func (self *Memfs) Mkdir(path string, mode uint32) (errc int) {
defer trace(path, mode)(&errc)
defer self.synchronize()()
return self.makeNode(path, fuse.S_IFDIR|(mode&07777), 0, nil)
}
func (self *Memfs) Unlink(path string) (errc int) {
defer trace(path)(&errc)
defer self.synchronize()()
return self.removeNode(path, false)
}
func (self *Memfs) Rmdir(path string) (errc int) {
defer trace(path)(&errc)
defer self.synchronize()()
return self.removeNode(path, true)
}
func (self *Memfs) Link(oldpath string, newpath string) (errc int) {
defer trace(oldpath, newpath)(&errc)
defer self.synchronize()()
_, _, oldnode := self.lookupNode(oldpath, nil)
if nil == oldnode {
return -fuse.ENOENT
}
newprnt, newname, newnode := self.lookupNode(newpath, nil)
if nil == newprnt {
return -fuse.ENOENT
}
if nil != newnode {
return -fuse.EEXIST
}
oldnode.stat.Nlink++
newprnt.chld[newname] = oldnode
tmsp := fuse.Now()
oldnode.stat.Ctim = tmsp
newprnt.stat.Ctim = tmsp
newprnt.stat.Mtim = tmsp
return 0
}
func (self *Memfs) Symlink(target string, newpath string) (errc int) {
defer trace(target, newpath)(&errc)
defer self.synchronize()()
return self.makeNode(newpath, fuse.S_IFLNK|00777, 0, []byte(target))
}
func (self *Memfs) Readlink(path string) (errc int, target string) {
defer trace(path)(&errc, &target)
defer self.synchronize()()
_, _, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT, ""
}
if fuse.S_IFLNK != node.stat.Mode&fuse.S_IFMT {
return -fuse.EINVAL, ""
}
return 0, string(node.data)
}
func (self *Memfs) Rename(oldpath string, newpath string) (errc int) {
defer trace(oldpath, newpath)(&errc)
defer self.synchronize()()
oldprnt, oldname, oldnode := self.lookupNode(oldpath, nil)
if nil == oldnode {
return -fuse.ENOENT
}
newprnt, newname, newnode := self.lookupNode(newpath, oldnode)
if nil == newprnt {
return -fuse.ENOENT
}
if "" == newname {
// guard against directory loop creation
return -fuse.EINVAL
}
if oldprnt == newprnt && oldname == newname {
return 0
}
if nil != newnode {
errc = self.removeNode(newpath, fuse.S_IFDIR == oldnode.stat.Mode&fuse.S_IFMT)
if 0 != errc {
return errc
}
}
delete(oldprnt.chld, oldname)
newprnt.chld[newname] = oldnode
return 0
}
func (self *Memfs) Chmod(path string, mode uint32) (errc int) {
defer trace(path, mode)(&errc)
defer self.synchronize()()
_, _, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT
}
node.stat.Mode = (node.stat.Mode & fuse.S_IFMT) | mode&07777
node.stat.Ctim = fuse.Now()
return 0
}
func (self *Memfs) Chown(path string, uid uint32, gid uint32) (errc int) {
defer trace(path, uid, gid)(&errc)
defer self.synchronize()()
_, _, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT
}
if ^uint32(0) != uid {
node.stat.Uid = uid
}
if ^uint32(0) != gid {
node.stat.Gid = gid
}
node.stat.Ctim = fuse.Now()
return 0
}
func (self *Memfs) Utimens(path string, tmsp []fuse.Timespec) (errc int) {
defer trace(path, tmsp)(&errc)
defer self.synchronize()()
_, _, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT
}
if nil == tmsp {
tmsp0 := fuse.Now()
tmsa := [2]fuse.Timespec{tmsp0, tmsp0}
tmsp = tmsa[:]
}
node.stat.Atim = tmsp[0]
node.stat.Mtim = tmsp[1]
return 0
}
func (self *Memfs) Open(path string, flags int) (errc int, fh uint64) {
defer trace(path, flags)(&errc, &fh)
defer self.synchronize()()
return self.openNode(path, false)
}
func (self *Memfs) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) {
defer trace(path, fh)(&errc, stat)
defer self.synchronize()()
node := self.getNode(path, fh)
if nil == node {
return -fuse.ENOENT
}
*stat = node.stat
return 0
}
func (self *Memfs) Truncate(path string, size int64, fh uint64) (errc int) {
defer trace(path, size, fh)(&errc)
defer self.synchronize()()
node := self.getNode(path, fh)
if nil == node {
return -fuse.ENOENT
}
node.data = resize(node.data, size, true)
node.stat.Size = size
tmsp := fuse.Now()
node.stat.Ctim = tmsp
node.stat.Mtim = tmsp
return 0
}
func (self *Memfs) Read(path string, buff []byte, ofst int64, fh uint64) (n int) {
defer trace(path, buff, ofst, fh)(&n)
defer self.synchronize()()
node := self.getNode(path, fh)
if nil == node {
return -fuse.ENOENT
}
endofst := ofst + int64(len(buff))
if endofst > node.stat.Size {
endofst = node.stat.Size
}
if endofst < ofst {
return 0
}
n = copy(buff, node.data[ofst:endofst])
node.stat.Atim = fuse.Now()
return
}
func (self *Memfs) Write(path string, buff []byte, ofst int64, fh uint64) (n int) {
defer trace(path, buff, ofst, fh)(&n)
defer self.synchronize()()
node := self.getNode(path, fh)
if nil == node {
return -fuse.ENOENT
}
endofst := ofst + int64(len(buff))
if endofst > node.stat.Size {
node.data = resize(node.data, endofst, true)
node.stat.Size = endofst
}
n = copy(node.data[ofst:endofst], buff)
tmsp := fuse.Now()
node.stat.Ctim = tmsp
node.stat.Mtim = tmsp
return
}
func (self *Memfs) Release(path string, fh uint64) (errc int) {
defer trace(path, fh)(&errc)
defer self.synchronize()()
return self.closeNode(fh)
}
func (self *Memfs) Opendir(path string) (errc int, fh uint64) {
defer trace(path)(&errc, &fh)
defer self.synchronize()()
return self.openNode(path, true)
}
func (self *Memfs) 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)
defer self.synchronize()()
node := self.openmap[fh]
fill(".", &node.stat, 0)
fill("..", nil, 0)
for name, chld := range node.chld {
if !fill(name, &chld.stat, 0) {
break
}
}
return 0
}
func (self *Memfs) Releasedir(path string, fh uint64) (errc int) {
defer trace(path, fh)(&errc)
defer self.synchronize()()
return self.closeNode(fh)
}
func (self *Memfs) Setxattr(path string, name string, value []byte, flags int) (errc int) {
defer trace(path, name, value, flags)(&errc)
defer self.synchronize()()
_, _, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT
}
if "com.apple.ResourceFork" == name {
return -fuse.ENOTSUP
}
if fuse.XATTR_CREATE == flags {
if _, ok := node.xatr[name]; ok {
return -fuse.EEXIST
}
} else if fuse.XATTR_REPLACE == flags {
if _, ok := node.xatr[name]; !ok {
return -fuse.ENOATTR
}
}
xatr := make([]byte, len(value))
copy(xatr, value)
if nil == node.xatr {
node.xatr = map[string][]byte{}
}
node.xatr[name] = xatr
return 0
}
func (self *Memfs) Getxattr(path string, name string) (errc int, xatr []byte) {
defer trace(path, name)(&errc, &xatr)
defer self.synchronize()()
_, _, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT, nil
}
if "com.apple.ResourceFork" == name {
return -fuse.ENOTSUP, nil
}
xatr, ok := node.xatr[name]
if !ok {
return -fuse.ENOATTR, nil
}
return 0, xatr
}
func (self *Memfs) Removexattr(path string, name string) (errc int) {
defer trace(path, name)(&errc)
defer self.synchronize()()
_, _, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT
}
if "com.apple.ResourceFork" == name {
return -fuse.ENOTSUP
}
if _, ok := node.xatr[name]; !ok {
return -fuse.ENOATTR
}
delete(node.xatr, name)
return 0
}
func (self *Memfs) Listxattr(path string, fill func(name string) bool) (errc int) {
defer trace(path, fill)(&errc)
defer self.synchronize()()
_, _, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT
}
for name := range node.xatr {
if !fill(name) {
return -fuse.ERANGE
}
}
return 0
}
func (self *Memfs) lookupNode(path string, ancestor *node_t) (prnt *node_t, name string, node *node_t) {
prnt = self.root
name = ""
node = self.root
for _, c := range split(path) {
if "" != c {
if 255 < len(c) {
panic(fuse.Error(-fuse.ENAMETOOLONG))
}
prnt, name = node, c
node = node.chld[c]
if nil != ancestor && node == ancestor {
name = "" // special case loop condition
return
}
}
}
return
}
func (self *Memfs) makeNode(path string, mode uint32, dev uint64, data []byte) int {
prnt, name, node := self.lookupNode(path, nil)
if nil == prnt {
return -fuse.ENOENT
}
if nil != node {
return -fuse.EEXIST
}
self.ino++
uid, gid, _ := fuse.Getcontext()
node = newNode(dev, self.ino, mode, uid, gid)
if nil != data {
node.data = make([]byte, len(data))
node.stat.Size = int64(len(data))
copy(node.data, data)
}
prnt.chld[name] = node
prnt.stat.Ctim = node.stat.Ctim
prnt.stat.Mtim = node.stat.Ctim
return 0
}
func (self *Memfs) removeNode(path string, dir bool) int {
prnt, name, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT
}
if !dir && fuse.S_IFDIR == node.stat.Mode&fuse.S_IFMT {
return -fuse.EISDIR
}
if dir && fuse.S_IFDIR != node.stat.Mode&fuse.S_IFMT {
return -fuse.ENOTDIR
}
if 0 < len(node.chld) {
return -fuse.ENOTEMPTY
}
node.stat.Nlink--
delete(prnt.chld, name)
tmsp := fuse.Now()
node.stat.Ctim = tmsp
prnt.stat.Ctim = tmsp
prnt.stat.Mtim = tmsp
return 0
}
func (self *Memfs) openNode(path string, dir bool) (int, uint64) {
_, _, node := self.lookupNode(path, nil)
if nil == node {
return -fuse.ENOENT, ^uint64(0)
}
if !dir && fuse.S_IFDIR == node.stat.Mode&fuse.S_IFMT {
return -fuse.EISDIR, ^uint64(0)
}
if dir && fuse.S_IFDIR != node.stat.Mode&fuse.S_IFMT {
return -fuse.ENOTDIR, ^uint64(0)
}
node.opencnt++
if 1 == node.opencnt {
self.openmap[node.stat.Ino] = node
}
return 0, node.stat.Ino
}
func (self *Memfs) closeNode(fh uint64) int {
node := self.openmap[fh]
node.opencnt--
if 0 == node.opencnt {
delete(self.openmap, node.stat.Ino)
}
return 0
}
func (self *Memfs) getNode(path string, fh uint64) *node_t {
if ^uint64(0) == fh {
_, _, node := self.lookupNode(path, nil)
return node
} else {
return self.openmap[fh]
}
}
func (self *Memfs) synchronize() func() {
self.lock.Lock()
return func() {
self.lock.Unlock()
}
}
func NewMemfs() *Memfs {
self := Memfs{}
defer self.synchronize()()
self.ino++
self.root = newNode(0, self.ino, fuse.S_IFDIR|00777, 0, 0)
self.openmap = map[uint64]*node_t{}
return &self
}
func main() {
memfs := NewMemfs()
host := fuse.NewFileSystemHost(memfs)
host.SetCapReaddirPlus(true)
host.Mount("", os.Args[1:])
}

View File

@ -0,0 +1,268 @@
// +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:])
}

View File

@ -0,0 +1,68 @@
// +build darwin
/*
* struct_darwin.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 (
"syscall"
"github.com/billziss-gh/cgofuse/fuse"
)
func setuidgid() func() {
euid := syscall.Geteuid()
if 0 == euid {
uid, gid, _ := fuse.Getcontext()
egid := syscall.Getegid()
syscall.Setegid(int(gid))
syscall.Seteuid(int(uid))
return func() {
syscall.Seteuid(euid)
syscall.Setegid(egid)
}
}
return func() {
}
}
func copyFusestatfsFromGostatfs(dst *fuse.Statfs_t, src *syscall.Statfs_t) {
*dst = fuse.Statfs_t{}
dst.Bsize = uint64(src.Bsize)
dst.Frsize = 1
dst.Blocks = uint64(src.Blocks)
dst.Bfree = uint64(src.Bfree)
dst.Bavail = uint64(src.Bavail)
dst.Files = uint64(src.Files)
dst.Ffree = uint64(src.Ffree)
dst.Favail = uint64(src.Ffree)
dst.Namemax = 255 //uint64(src.Namelen)
}
func copyFusestatFromGostat(dst *fuse.Stat_t, src *syscall.Stat_t) {
*dst = fuse.Stat_t{}
dst.Dev = uint64(src.Dev)
dst.Ino = uint64(src.Ino)
dst.Mode = uint32(src.Mode)
dst.Nlink = uint32(src.Nlink)
dst.Uid = uint32(src.Uid)
dst.Gid = uint32(src.Gid)
dst.Rdev = uint64(src.Rdev)
dst.Size = int64(src.Size)
dst.Atim.Sec, dst.Atim.Nsec = src.Atimespec.Sec, src.Atimespec.Nsec
dst.Mtim.Sec, dst.Mtim.Nsec = src.Mtimespec.Sec, src.Mtimespec.Nsec
dst.Ctim.Sec, dst.Ctim.Nsec = src.Ctimespec.Sec, src.Ctimespec.Nsec
dst.Blksize = int64(src.Blksize)
dst.Blocks = int64(src.Blocks)
dst.Birthtim.Sec, dst.Birthtim.Nsec = src.Birthtimespec.Sec, src.Birthtimespec.Nsec
}

View File

@ -0,0 +1,67 @@
// +build linux
/*
* struct_linux.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 (
"syscall"
"github.com/billziss-gh/cgofuse/fuse"
)
func setuidgid() func() {
euid := syscall.Geteuid()
if 0 == euid {
uid, gid, _ := fuse.Getcontext()
egid := syscall.Getegid()
syscall.Setregid(-1, int(gid))
syscall.Setreuid(-1, int(uid))
return func() {
syscall.Setreuid(-1, int(euid))
syscall.Setregid(-1, int(egid))
}
}
return func() {
}
}
func copyFusestatfsFromGostatfs(dst *fuse.Statfs_t, src *syscall.Statfs_t) {
*dst = fuse.Statfs_t{}
dst.Bsize = uint64(src.Bsize)
dst.Frsize = 1
dst.Blocks = uint64(src.Blocks)
dst.Bfree = uint64(src.Bfree)
dst.Bavail = uint64(src.Bavail)
dst.Files = uint64(src.Files)
dst.Ffree = uint64(src.Ffree)
dst.Favail = uint64(src.Ffree)
dst.Namemax = 255 //uint64(src.Namelen)
}
func copyFusestatFromGostat(dst *fuse.Stat_t, src *syscall.Stat_t) {
*dst = fuse.Stat_t{}
dst.Dev = uint64(src.Dev)
dst.Ino = uint64(src.Ino)
dst.Mode = uint32(src.Mode)
dst.Nlink = uint32(src.Nlink)
dst.Uid = uint32(src.Uid)
dst.Gid = uint32(src.Gid)
dst.Rdev = uint64(src.Rdev)
dst.Size = int64(src.Size)
dst.Atim.Sec, dst.Atim.Nsec = src.Atim.Sec, src.Atim.Nsec
dst.Mtim.Sec, dst.Mtim.Nsec = src.Mtim.Sec, src.Mtim.Nsec
dst.Ctim.Sec, dst.Ctim.Nsec = src.Ctim.Sec, src.Ctim.Nsec
dst.Blksize = int64(src.Blksize)
dst.Blocks = int64(src.Blocks)
}

View File

@ -0,0 +1,115 @@
/*
* trace.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 shared
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
)
var (
TracePattern = os.Getenv("CGOFUSE_TRACE")
)
func traceJoin(deref bool, vals []interface{}) string {
rslt := ""
for _, v := range vals {
if deref {
switch i := v.(type) {
case *bool:
rslt += fmt.Sprintf(", %#v", *i)
case *int:
rslt += fmt.Sprintf(", %#v", *i)
case *int8:
rslt += fmt.Sprintf(", %#v", *i)
case *int16:
rslt += fmt.Sprintf(", %#v", *i)
case *int32:
rslt += fmt.Sprintf(", %#v", *i)
case *int64:
rslt += fmt.Sprintf(", %#v", *i)
case *uint:
rslt += fmt.Sprintf(", %#v", *i)
case *uint8:
rslt += fmt.Sprintf(", %#v", *i)
case *uint16:
rslt += fmt.Sprintf(", %#v", *i)
case *uint32:
rslt += fmt.Sprintf(", %#v", *i)
case *uint64:
rslt += fmt.Sprintf(", %#v", *i)
case *uintptr:
rslt += fmt.Sprintf(", %#v", *i)
case *float32:
rslt += fmt.Sprintf(", %#v", *i)
case *float64:
rslt += fmt.Sprintf(", %#v", *i)
case *complex64:
rslt += fmt.Sprintf(", %#v", *i)
case *complex128:
rslt += fmt.Sprintf(", %#v", *i)
case *string:
rslt += fmt.Sprintf(", %#v", *i)
default:
rslt += fmt.Sprintf(", %#v", v)
}
} else {
rslt += fmt.Sprintf(", %#v", v)
}
}
if len(rslt) > 0 {
rslt = rslt[2:]
}
return rslt
}
func Trace(skip int, prfx string, vals ...interface{}) func(vals ...interface{}) {
if "" == TracePattern {
return func(vals ...interface{}) {
}
}
pc, _, _, ok := runtime.Caller(skip + 1)
name := "<UNKNOWN>"
if ok {
fn := runtime.FuncForPC(pc)
name = fn.Name()
if m, _ := filepath.Match(TracePattern, name); !m {
return func(vals ...interface{}) {
}
}
}
if "" != prfx {
prfx = prfx + ": "
}
args := traceJoin(false, vals)
return func(vals ...interface{}) {
form := "%v%v(%v) = %v"
rslt := ""
rcvr := recover()
if nil != rcvr {
rslt = fmt.Sprintf("!PANIC:%v", rcvr)
} else {
if len(vals) != 1 {
form = "%v%v(%v) = (%v)"
}
rslt = traceJoin(true, vals)
}
log.Printf(form, prfx, name, args, rslt)
if nil != rcvr {
panic(rcvr)
}
}
}

730
vendor/github.com/billziss-gh/cgofuse/fuse/fsop.go generated vendored Normal file
View File

@ -0,0 +1,730 @@
/*
* fsop.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 fuse allows the creation of user mode file systems in Go.
//
// A user mode file system must implement the methods in FileSystemInterface
// and be hosted (mounted) by a FileSystemHost.
// Alternatively a user mode file system can use the FileSystemBase struct which
// provides default implementations of the methods in FileSystemInterface.
package fuse
/*
#if !(defined(__APPLE__) || defined(__linux__) || defined(_WIN32))
#error platform not supported
#endif
#if defined(__APPLE__) || defined(__linux__)
#include <errno.h>
#include <fcntl.h>
#elif defined(_WIN32)
#define EPERM 1
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define EIO 5
#define ENXIO 6
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define ECHILD 10
#define EAGAIN 11
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define EBUSY 16
#define EEXIST 17
#define EXDEV 18
#define ENODEV 19
#define ENOTDIR 20
#define EISDIR 21
#define ENFILE 23
#define EMFILE 24
#define ENOTTY 25
#define EFBIG 27
#define ENOSPC 28
#define ESPIPE 29
#define EROFS 30
#define EMLINK 31
#define EPIPE 32
#define EDOM 33
#define EDEADLK 36
#define ENAMETOOLONG 38
#define ENOLCK 39
#define ENOSYS 40
#define ENOTEMPTY 41
#define EINVAL 22
#define ERANGE 34
#define EILSEQ 42
#define EADDRINUSE 100
#define EADDRNOTAVAIL 101
#define EAFNOSUPPORT 102
#define EALREADY 103
#define EBADMSG 104
#define ECANCELED 105
#define ECONNABORTED 106
#define ECONNREFUSED 107
#define ECONNRESET 108
#define EDESTADDRREQ 109
#define EHOSTUNREACH 110
#define EIDRM 111
#define EINPROGRESS 112
#define EISCONN 113
#define ELOOP 114
#define EMSGSIZE 115
#define ENETDOWN 116
#define ENETRESET 117
#define ENETUNREACH 118
#define ENOBUFS 119
#define ENODATA 120
#define ENOLINK 121
#define ENOMSG 122
#define ENOPROTOOPT 123
#define ENOSR 124
#define ENOSTR 125
#define ENOTCONN 126
#define ENOTRECOVERABLE 127
#define ENOTSOCK 128
#define ENOTSUP 129
#define EOPNOTSUPP 130
#define EOTHER 131
#define EOVERFLOW 132
#define EOWNERDEAD 133
#define EPROTO 134
#define EPROTONOSUPPORT 135
#define EPROTOTYPE 136
#define ETIME 137
#define ETIMEDOUT 138
#define ETXTBSY 139
#define EWOULDBLOCK 140
#include <fcntl.h>
#define O_RDONLY _O_RDONLY
#define O_WRONLY _O_WRONLY
#define O_RDWR _O_RDWR
#define O_APPEND _O_APPEND
#define O_CREAT _O_CREAT
#define O_EXCL _O_EXCL
#define O_TRUNC _O_TRUNC
#if !defined(O_ACCMODE)
#define O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR)
#endif
#endif
#if defined(__linux__) || defined(_WIN32)
// incantation needed for cgo to figure out "kind of name" for ENOATTR
#define ENOATTR ((int)ENODATA)
#endif
#if defined(__APPLE__) || defined(__linux__)
#include <sys/xattr.h>
#elif defined(_WIN32)
#define XATTR_CREATE 1
#define XATTR_REPLACE 2
#endif
*/
import "C"
import (
"strconv"
"time"
)
const (
E2BIG = int(C.E2BIG)
EACCES = int(C.EACCES)
EADDRINUSE = int(C.EADDRINUSE)
EADDRNOTAVAIL = int(C.EADDRNOTAVAIL)
EAFNOSUPPORT = int(C.EAFNOSUPPORT)
EAGAIN = int(C.EAGAIN)
EALREADY = int(C.EALREADY)
EBADF = int(C.EBADF)
EBADMSG = int(C.EBADMSG)
EBUSY = int(C.EBUSY)
ECANCELED = int(C.ECANCELED)
ECHILD = int(C.ECHILD)
ECONNABORTED = int(C.ECONNABORTED)
ECONNREFUSED = int(C.ECONNREFUSED)
ECONNRESET = int(C.ECONNRESET)
EDEADLK = int(C.EDEADLK)
EDESTADDRREQ = int(C.EDESTADDRREQ)
EDOM = int(C.EDOM)
EEXIST = int(C.EEXIST)
EFAULT = int(C.EFAULT)
EFBIG = int(C.EFBIG)
EHOSTUNREACH = int(C.EHOSTUNREACH)
EIDRM = int(C.EIDRM)
EILSEQ = int(C.EILSEQ)
EINPROGRESS = int(C.EINPROGRESS)
EINTR = int(C.EINTR)
EINVAL = int(C.EINVAL)
EIO = int(C.EIO)
EISCONN = int(C.EISCONN)
EISDIR = int(C.EISDIR)
ELOOP = int(C.ELOOP)
EMFILE = int(C.EMFILE)
EMLINK = int(C.EMLINK)
EMSGSIZE = int(C.EMSGSIZE)
ENAMETOOLONG = int(C.ENAMETOOLONG)
ENETDOWN = int(C.ENETDOWN)
ENETRESET = int(C.ENETRESET)
ENETUNREACH = int(C.ENETUNREACH)
ENFILE = int(C.ENFILE)
ENOATTR = int(C.ENOATTR)
ENOBUFS = int(C.ENOBUFS)
ENODATA = int(C.ENODATA)
ENODEV = int(C.ENODEV)
ENOENT = int(C.ENOENT)
ENOEXEC = int(C.ENOEXEC)
ENOLCK = int(C.ENOLCK)
ENOLINK = int(C.ENOLINK)
ENOMEM = int(C.ENOMEM)
ENOMSG = int(C.ENOMSG)
ENOPROTOOPT = int(C.ENOPROTOOPT)
ENOSPC = int(C.ENOSPC)
ENOSR = int(C.ENOSR)
ENOSTR = int(C.ENOSTR)
ENOSYS = int(C.ENOSYS)
ENOTCONN = int(C.ENOTCONN)
ENOTDIR = int(C.ENOTDIR)
ENOTEMPTY = int(C.ENOTEMPTY)
ENOTRECOVERABLE = int(C.ENOTRECOVERABLE)
ENOTSOCK = int(C.ENOTSOCK)
ENOTSUP = int(C.ENOTSUP)
ENOTTY = int(C.ENOTTY)
ENXIO = int(C.ENXIO)
EOPNOTSUPP = int(C.EOPNOTSUPP)
EOVERFLOW = int(C.EOVERFLOW)
EOWNERDEAD = int(C.EOWNERDEAD)
EPERM = int(C.EPERM)
EPIPE = int(C.EPIPE)
EPROTO = int(C.EPROTO)
EPROTONOSUPPORT = int(C.EPROTONOSUPPORT)
EPROTOTYPE = int(C.EPROTOTYPE)
ERANGE = int(C.ERANGE)
EROFS = int(C.EROFS)
ESPIPE = int(C.ESPIPE)
ESRCH = int(C.ESRCH)
ETIME = int(C.ETIME)
ETIMEDOUT = int(C.ETIMEDOUT)
ETXTBSY = int(C.ETXTBSY)
EWOULDBLOCK = int(C.EWOULDBLOCK)
EXDEV = int(C.EXDEV)
)
const (
O_RDONLY = int(C.O_RDONLY)
O_WRONLY = int(C.O_WRONLY)
O_RDWR = int(C.O_RDWR)
O_APPEND = int(C.O_APPEND)
O_CREAT = int(C.O_CREAT)
O_EXCL = int(C.O_EXCL)
O_TRUNC = int(C.O_TRUNC)
O_ACCMODE = int(C.O_ACCMODE)
)
const (
S_IFMT = 0170000
S_IFBLK = 0060000
S_IFCHR = 0020000
S_IFIFO = 0010000
S_IFREG = 0100000
S_IFDIR = 0040000
S_IFLNK = 0120000
S_IFSOCK = 0140000
S_IRWXU = 00700
S_IRUSR = 00400
S_IWUSR = 00200
S_IXUSR = 00100
S_IRWXG = 00070
S_IRGRP = 00040
S_IWGRP = 00020
S_IXGRP = 00010
S_IRWXO = 00007
S_IROTH = 00004
S_IWOTH = 00002
S_IXOTH = 00001
S_ISUID = 04000
S_ISGID = 02000
S_ISVTX = 01000
)
const (
XATTR_CREATE = int(C.XATTR_CREATE)
XATTR_REPLACE = int(C.XATTR_REPLACE)
)
// Timespec contains a time as the UNIX time in seconds and nanoseconds.
// This structure is analogous to the POSIX struct timespec.
type Timespec struct {
Sec int64
Nsec int64
}
// NewTimespec creates a Timespec from a time.Time.
func NewTimespec(t time.Time) Timespec {
return Timespec{t.Unix(), int64(t.Nanosecond())}
}
// Now creates a Timespec that contains the current time.
func Now() Timespec {
return NewTimespec(time.Now())
}
// Time returns the Timespec as a time.Time.
func (ts *Timespec) Time() time.Time {
return time.Unix(ts.Sec, ts.Nsec)
}
// Statfs_t contains file system information.
// This structure is analogous to the POSIX struct statvfs (NOT struct statfs).
// Not all fields are honored by all FUSE implementations.
type Statfs_t struct {
// File system block size.
Bsize uint64
// Fundamental file system block size.
Frsize uint64
// Total number of blocks on file system in units of Frsize.
Blocks uint64
// Total number of free blocks.
Bfree uint64
// Number of free blocks available to non-privileged process.
Bavail uint64
// Total number of file serial numbers.
Files uint64
// Total number of free file serial numbers.
Ffree uint64
// Number of file serial numbers available to non-privileged process.
Favail uint64
// File system ID. [IGNORED]
Fsid uint64
// Bit mask of Flag values. [IGNORED]
Flag uint64
// Maximum filename length.
Namemax uint64
}
// Stat_t contains file metadata information.
// This structure is analogous to the POSIX struct stat.
// Not all fields are honored by all FUSE implementations.
type Stat_t struct {
// Device ID of device containing file. [IGNORED]
Dev uint64
// File serial number. [IGNORED unless the use_ino mount option is given.]
Ino uint64
// Mode of file.
Mode uint32
// Number of hard links to the file.
Nlink uint32
// User ID of file.
Uid uint32
// Group ID of file.
Gid uint32
// Device ID (if file is character or block special).
Rdev uint64
// For regular files, the file size in bytes.
// For symbolic links, the length in bytes of the
// pathname contained in the symbolic link.
Size int64
// Last data access timestamp.
Atim Timespec
// Last data modification timestamp.
Mtim Timespec
// Last file status change timestamp.
Ctim Timespec
// A file system-specific preferred I/O block size for this object.
Blksize int64
// Number of blocks allocated for this object.
Blocks int64
// File creation (birth) timestamp. [OSX only]
Birthtim Timespec
}
/*
// Lock_t contains file locking information.
// This structure is analogous to the POSIX struct flock.
type Lock_t struct {
// Type of lock; F_RDLCK, F_WRLCK, F_UNLCK.
Type int16
// Flag for starting offset.
Whence int16
// Relative offset in bytes.
Start int64
// Size; if 0 then until EOF.
Len int64
// Process ID of the process holding the lock
Pid int
}
*/
// FileSystemInterface is the interface that all file systems must implement.
// The file system will receive an Init() call when it is mounted and a Destroy()
// call when it is unmounted (note that depending on how the file system is
// terminated the file system may not receive the Destroy() call). All other
// operations must return 0 on success or a FUSE error on failure. To return an
// error return the NEGATIVE value of a particular error. For example, to report
// "file not found" return -fuse.ENOENT.
type FileSystemInterface interface {
// Init is called when the file system is mounted.
Init()
// Destroy is called when the file system is unmounted.
Destroy()
// Statfs gets file system statistics.
Statfs(path string, stat *Statfs_t) int
// Mknod creates a file node.
Mknod(path string, mode uint32, dev uint64) int
// Mkdir creates a directory.
Mkdir(path string, mode uint32) int
// Unlink removes a file.
Unlink(path string) int
// Rmdir removes a directory.
Rmdir(path string) int
// Link creates a hard link to a file.
Link(oldpath string, newpath string) int
// Symlink creates a symbolic link.
Symlink(target string, newpath string) int
// Readlink reads the target of a symbolic link.
Readlink(path string) (int, string)
// Rename renames a file.
Rename(oldpath string, newpath string) int
// Chmod changes the permission bits of a file.
Chmod(path string, mode uint32) int
// Chown changes the owner and group of a file.
Chown(path string, uid uint32, gid uint32) int
// Utimens changes the access and modification times of a file.
Utimens(path string, tmsp []Timespec) int
// Access checks file access permissions.
Access(path string, mask uint32) int
// Create creates and opens a file.
Create(path string, flags int, mode uint32) (int, uint64)
// Open opens a file.
Open(path string, flags int) (int, uint64)
// Getattr gets file attributes.
Getattr(path string, stat *Stat_t, fh uint64) int
// Truncate changes the size of a file.
Truncate(path string, size int64, fh uint64) int
// Read reads data from a file.
Read(path string, buff []byte, ofst int64, fh uint64) int
// Write writes data to a file.
Write(path string, buff []byte, ofst int64, fh uint64) int
// Flush flushes cached file data.
Flush(path string, fh uint64) int
// Release closes an open file.
Release(path string, fh uint64) int
// Fsync synchronizes file contents.
Fsync(path string, datasync bool, fh uint64) int
// Lock performs a file locking operation.
//Lock(path string, cmd int, lock *Lock_t, fh uint64) int
// Opendir opens a directory.
Opendir(path string) (int, uint64)
// Readdir reads a directory.
Readdir(path string,
fill func(name string, stat *Stat_t, ofst int64) bool,
ofst int64,
fh uint64) int
// Releasedir closes an open directory.
Releasedir(path string, fh uint64) int
// Fsyncdir synchronizes directory contents.
Fsyncdir(path string, datasync bool, fh uint64) int
// Setxattr sets extended attributes.
Setxattr(path string, name string, value []byte, flags int) int
// Getxattr gets extended attributes.
Getxattr(path string, name string) (int, []byte)
// Removexattr removes extended attributes.
Removexattr(path string, name string) int
// Listxattr lists extended attributes.
Listxattr(path string, fill func(name string) bool) int
}
// Error encapsulates a FUSE error code. In some rare circumstances it is useful
// to signal an error to the FUSE layer by boxing the error code using Error and
// calling panic(). The FUSE layer will recover and report the boxed error code
// to the OS.
type Error int
func (self Error) Error() string {
return "fuse.Error(" + strconv.Itoa(int(self)) + ")"
}
var _ error = (*Error)(nil)
// FileSystemBase provides default implementations of the methods in FileSystemInterface.
// The default implementations are either empty or return -ENOSYS to signal that the
// file system does not implement a particular operation to the FUSE layer.
type FileSystemBase struct {
}
// Init is called when the file system is mounted.
// The FileSystemBase implementation does nothing.
func (*FileSystemBase) Init() {
}
// Destroy is called when the file system is unmounted.
// The FileSystemBase implementation does nothing.
func (*FileSystemBase) Destroy() {
}
// Statfs gets file system statistics.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Statfs(path string, stat *Statfs_t) int {
return -ENOSYS
}
// Mknod creates a file node.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Mknod(path string, mode uint32, dev uint64) int {
return -ENOSYS
}
// Mkdir creates a directory.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Mkdir(path string, mode uint32) int {
return -ENOSYS
}
// Unlink removes a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Unlink(path string) int {
return -ENOSYS
}
// Rmdir removes a directory.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Rmdir(path string) int {
return -ENOSYS
}
// Link creates a hard link to a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Link(oldpath string, newpath string) int {
return -ENOSYS
}
// Symlink creates a symbolic link.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Symlink(target string, newpath string) int {
return -ENOSYS
}
// Readlink reads the target of a symbolic link.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Readlink(path string) (int, string) {
return -ENOSYS, ""
}
// Rename renames a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Rename(oldpath string, newpath string) int {
return -ENOSYS
}
// Chmod changes the permission bits of a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Chmod(path string, mode uint32) int {
return -ENOSYS
}
// Chown changes the owner and group of a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Chown(path string, uid uint32, gid uint32) int {
return -ENOSYS
}
// Utimens changes the access and modification times of a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Utimens(path string, tmsp []Timespec) int {
return -ENOSYS
}
// Access checks file access permissions.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Access(path string, mask uint32) int {
return -ENOSYS
}
// Create creates and opens a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Create(path string, flags int, mode uint32) (int, uint64) {
return -ENOSYS, ^uint64(0)
}
// Open opens a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Open(path string, flags int) (int, uint64) {
return -ENOSYS, ^uint64(0)
}
// Getattr gets file attributes.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Getattr(path string, stat *Stat_t, fh uint64) int {
return -ENOSYS
}
// Truncate changes the size of a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Truncate(path string, size int64, fh uint64) int {
return -ENOSYS
}
// Read reads data from a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Read(path string, buff []byte, ofst int64, fh uint64) int {
return -ENOSYS
}
// Write writes data to a file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Write(path string, buff []byte, ofst int64, fh uint64) int {
return -ENOSYS
}
// Flush flushes cached file data.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Flush(path string, fh uint64) int {
return -ENOSYS
}
// Release closes an open file.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Release(path string, fh uint64) int {
return -ENOSYS
}
// Fsync synchronizes file contents.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Fsync(path string, datasync bool, fh uint64) int {
return -ENOSYS
}
/*
// Lock performs a file locking operation.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Lock(path string, cmd int, lock *Lock_t, fh uint64) int {
return -ENOSYS
}
*/
// Opendir opens a directory.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Opendir(path string) (int, uint64) {
return -ENOSYS, ^uint64(0)
}
// Readdir reads a directory.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Readdir(path string,
fill func(name string, stat *Stat_t, ofst int64) bool,
ofst int64,
fh uint64) int {
return -ENOSYS
}
// Releasedir closes an open directory.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Releasedir(path string, fh uint64) int {
return -ENOSYS
}
// Fsyncdir synchronizes directory contents.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Fsyncdir(path string, datasync bool, fh uint64) int {
return -ENOSYS
}
// Setxattr sets extended attributes.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Setxattr(path string, name string, value []byte, flags int) int {
return -ENOSYS
}
// Getxattr gets extended attributes.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Getxattr(path string, name string) (int, []byte) {
return -ENOSYS, nil
}
// Removexattr removes extended attributes.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Removexattr(path string, name string) int {
return -ENOSYS
}
// Listxattr lists extended attributes.
// The FileSystemBase implementation returns -ENOSYS.
func (*FileSystemBase) Listxattr(path string, fill func(name string) bool) int {
return -ENOSYS
}
var _ FileSystemInterface = (*FileSystemBase)(nil)

1129
vendor/github.com/billziss-gh/cgofuse/fuse/host.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

109
vendor/github.com/billziss-gh/cgofuse/fuse/host_test.go generated vendored Normal file
View File

@ -0,0 +1,109 @@
/*
* host_test.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 fuse
import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"testing"
"time"
)
type testfs struct {
FileSystemBase
init, dstr int
}
func (self *testfs) Init() {
self.init++
}
func (self *testfs) Destroy() {
self.dstr++
}
func (self *testfs) Getattr(path string, stat *Stat_t, fh uint64) (errc int) {
switch path {
case "/":
stat.Mode = S_IFDIR | 0555
return 0
default:
return -ENOENT
}
}
func (self *testfs) Readdir(path string,
fill func(name string, stat *Stat_t, ofst int64) bool,
ofst int64,
fh uint64) (errc int) {
fill(".", nil, 0)
fill("..", nil, 0)
return 0
}
func testHost(t *testing.T, unmount bool) {
path, err := ioutil.TempDir("", "test")
if nil != err {
panic(err)
}
defer os.Remove(path)
mntp := filepath.Join(path, "m")
if "windows" != runtime.GOOS {
err = os.Mkdir(mntp, os.FileMode(0755))
if nil != err {
panic(err)
}
defer os.Remove(mntp)
}
done := make(chan bool)
tmch := time.After(3 * time.Second)
tstf := &testfs{}
host := NewFileSystemHost(tstf)
mres := false
ures := false
go func() {
mres = host.Mount(mntp, nil)
done <- true
}()
<-tmch
if unmount {
ures = host.Unmount()
} else {
ures = sendInterrupt()
}
<-done
if !mres {
t.Error("Mount failed")
}
if !ures {
t.Error("Unmount failed")
}
if 1 != tstf.init {
t.Errorf("Init() called %v times; expected 1", tstf.init)
}
if 1 != tstf.dstr {
t.Errorf("Destroy() called %v times; expected 1", tstf.dstr)
}
}
func TestUnmount(t *testing.T) {
testHost(t, true)
}
func TestSignal(t *testing.T) {
if "windows" != runtime.GOOS {
testHost(t, false)
}
}

View File

@ -0,0 +1,23 @@
// +build darwin linux
/*
* host_unix_test.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 fuse
import (
"syscall"
)
func sendInterrupt() bool {
return nil == syscall.Kill(syscall.Getpid(), syscall.SIGINT)
}

View File

@ -0,0 +1,27 @@
// +build windows
/*
* host_windows_test.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 fuse
import (
"os"
"syscall"
)
func sendInterrupt() bool {
dll := syscall.MustLoadDLL("kernel32")
prc := dll.MustFindProc("GenerateConsoleCtrlEvent")
r, _, _ := prc.Call(syscall.CTRL_BREAK_EVENT, uintptr(os.Getpid()))
return 0 != r
}