From 0e76d5a88363bbf4b577a7d578a65236a22b1c26 Mon Sep 17 00:00:00 2001 From: James Fantin Date: Sat, 23 Nov 2024 12:47:47 -0700 Subject: [PATCH] Add support for FUSE3 on Linux --- .github/workflows/test.yml | 89 +++++---- examples/hellofs/hellofs.go | 3 +- examples/memfs/memfs.go | 34 ++-- examples/notifyfs/notifyfs.go | 2 +- examples/passthrough/passthrough.go | 12 +- examples/passthrough/port_darwin.go | 1 + examples/passthrough/port_freebsd.go | 1 + examples/passthrough/port_linux.go | 1 + examples/passthrough/port_netbsd.go | 1 + examples/passthrough/port_openbsd.go | 1 + fuse/fsop.go | 24 ++- fuse/host.go | 139 ++++++++----- fuse/host_cgo.go | 279 ++++++++++++++++++++++----- fuse/host_nocgo_windows.go | 87 +++++++-- fuse/host_test.go | 2 +- 15 files changed, 491 insertions(+), 185 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 37228ca..65a89a6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: GOARCH: ${{ matrix.arch }} CGO_ENABLED: ${{ matrix.cgo }} CPATH: ${{ matrix.cpath }} - GODEBUG: cgocheck=2 + GOEXPERIMENT: cgocheck2 strategy: matrix: include: @@ -26,33 +26,36 @@ jobs: - os: windows-latest arch: amd64 cgo: 0 - - os: windows-latest - arch: 386 - cgo: 0 - os: ubuntu-latest arch: amd64 cgo: 1 - - os: macos-10.15 + - os: macos-latest arch: amd64 cgo: 1 fail-fast: false steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: recursive - name: Install go - uses: actions/setup-go@v2 + uses: actions/setup-go@v5 with: - stable: true - go-version: 1.17.* + go-version: '1.23' - name: Install winfsp and winfsp-tests (Windows) + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} if: runner.os == 'Windows' run: | - $releases = Invoke-WebRequest https://api.github.com/repos/winfsp/winfsp/releases | ` + $headers = @{ + Authorization = "token $env:GITHUB_TOKEN" + "User-Agent" = "GitHub Actions" + } + + $releases = Invoke-WebRequest https://api.github.com/repos/winfsp/winfsp/releases -Headers $headers | ` ConvertFrom-Json $asseturi = $releases[0].assets.browser_download_url | ` @@ -69,8 +72,7 @@ jobs: - name: Install FUSE and secfs.test (Linux) if: runner.os == 'Linux' run: | - sudo apt-get -qq install libfuse-dev - sudo apt-get -qq install libacl1-dev + sudo apt-get -qq install libfuse-dev libfuse3-dev libacl1-dev git clone -q https://github.com/billziss-gh/secfs.test.git secfs.test git -C secfs.test checkout -q edf5eb4a108bfb41073f765aef0cdd32bb3ee1ed @@ -86,37 +88,21 @@ jobs: rm -rf secfs.test/fstest/fstest/tests/xacl rm -rf secfs.test/fstest/fstest/tests/zzz_ResourceFork - - name: Install FUSE and secfs.test (macOS) + - name: Install FUSE (macOS) if: runner.os == 'macOS' run: | - # requires macos-10.15; does not work on macos-latest - # see https://github.com/actions/virtual-environments/issues/4731 brew install macfuse - git clone -q https://github.com/billziss-gh/secfs.test.git secfs.test - git -C secfs.test checkout -q edf5eb4a108bfb41073f765aef0cdd32bb3ee1ed - mkdir -p secfs.test/tools/bin - touch secfs.test/tools/bin/bonnie++ - touch secfs.test/tools/bin/iozone - make -C secfs.test - - # configure fstest for cgofuse - sed -e 's/^fs=.*$/fs="cgofuse"/' -i "" secfs.test/fstest/fstest/tests/conf - - # monkey-patch/disable some tests for macOS - rm secfs.test/fstest/fstest/tests/rmdir/12.t - sed -e 's/lchmod)/lchmod) return 1/' -i "" secfs.test/fstest/fstest/tests/misc.sh - - # remove irrelevant tests - rm -rf secfs.test/fstest/fstest/tests/xacl - rm -rf secfs.test/fstest/fstest/tests/zzz_ResourceFork - - - name: Build packages + - name: Build packages with fuse2 run: | go build -v -o . ./... + + - name: Test packages with fuse2 + if: runner.os == 'Linux' || runner.os == 'Windows' + run: | go test -v -count=1 ./fuse - - name: Test file systems (Windows) + - name: Test file systems (Windows) with fuse2 if: runner.os == 'Windows' run: | Set-PSDebug -Trace 1 @@ -134,8 +120,8 @@ jobs: Start-Sleep 3 Pop-Location - - name: Test file systems (Linux / macOS) - if: runner.os == 'Linux' || runner.os == 'macOS' + - name: Test file systems (Linux) with fuse2 + if: runner.os == 'Linux' run: | set -x @@ -156,3 +142,32 @@ jobs: rm -rf p rmdir mnt + + - name: Build packages with fuse3 (Linux) + if: runner.os == 'Linux' + run: | + go build -tags=fuse3 -v -o . ./... + go test -v -count=1 ./fuse + + - name: Test file systems (Linux) with fuse3 + if: runner.os == 'Linux' + run: | + set -x + + mkdir p mnt + + sudo ./memfs -o allow_other,default_permissions,attr_timeout=0 mnt & + sleep 3 + (cd mnt && sudo prove -fr ../secfs.test/fstest/fstest/tests) + (cd mnt && ../secfs.test/tools/bin/fsx -N 10000 test xxxxxx) + (cd mnt && ../secfs.test/tools/bin/fsx -e -N 1000 test xxxx) + sudo umount mnt + + sudo ./passthrough -o allow_other,default_permissions,attr_timeout=0 p mnt & + sleep 3 + (cd mnt && sudo prove -fr ../secfs.test/fstest/fstest/tests) + (cd mnt && ../secfs.test/tools/bin/fsx -N 10000 test xxxxxx) + sudo umount mnt + + rm -rf p + rmdir mnt diff --git a/examples/hellofs/hellofs.go b/examples/hellofs/hellofs.go index e4d7687..98a93a7 100644 --- a/examples/hellofs/hellofs.go +++ b/examples/hellofs/hellofs.go @@ -64,8 +64,7 @@ func (self *Hellofs) Read(path string, buff []byte, ofst int64, fh uint64) (n in func (self *Hellofs) Readdir(path string, fill func(name string, stat *fuse.Stat_t, ofst int64) bool, - ofst int64, - fh uint64) (errc int) { + ofst int64, fh uint64, flags uint32) (errc int) { fill(".", nil, 0) fill("..", nil, 0) fill(filename, nil, 0) diff --git a/examples/memfs/memfs.go b/examples/memfs/memfs.go index ca63548..ab5049d 100644 --- a/examples/memfs/memfs.go +++ b/examples/memfs/memfs.go @@ -17,6 +17,7 @@ import ( "os" "strings" "sync" + "unicode/utf8" "github.com/winfsp/cgofuse/examples/shared" "github.com/winfsp/cgofuse/fuse" @@ -164,7 +165,7 @@ func (self *Memfs) Readlink(path string) (errc int, target string) { return 0, string(node.data) } -func (self *Memfs) Rename(oldpath string, newpath string) (errc int) { +func (self *Memfs) Rename(oldpath string, newpath string, flags uint32) (errc int) { defer trace(oldpath, newpath)(&errc) defer self.synchronize()() oldprnt, oldname, oldnode := self.lookupNode(oldpath, nil) @@ -193,7 +194,7 @@ func (self *Memfs) Rename(oldpath string, newpath string) (errc int) { return 0 } -func (self *Memfs) Chmod(path string, mode uint32) (errc int) { +func (self *Memfs) Chmod(path string, mode uint32, fh uint64) (errc int) { defer trace(path, mode)(&errc) defer self.synchronize()() _, _, node := self.lookupNode(path, nil) @@ -205,7 +206,7 @@ func (self *Memfs) Chmod(path string, mode uint32) (errc int) { return 0 } -func (self *Memfs) Chown(path string, uid uint32, gid uint32) (errc int) { +func (self *Memfs) Chown(path string, uid uint32, gid uint32, fh uint64) (errc int) { defer trace(path, uid, gid)(&errc) defer self.synchronize()() _, _, node := self.lookupNode(path, nil) @@ -222,7 +223,7 @@ func (self *Memfs) Chown(path string, uid uint32, gid uint32) (errc int) { return 0 } -func (self *Memfs) Utimens(path string, tmsp []fuse.Timespec) (errc int) { +func (self *Memfs) Utimens(path string, tmsp []fuse.Timespec, fh uint64) (errc int) { defer trace(path, tmsp)(&errc) defer self.synchronize()() _, _, node := self.lookupNode(path, nil) @@ -230,7 +231,7 @@ func (self *Memfs) Utimens(path string, tmsp []fuse.Timespec) (errc int) { return -fuse.ENOENT } node.stat.Ctim = fuse.Now() - if nil == tmsp { + if tmsp == nil || (len(tmsp) == 2 && tmsp[0].Sec == 0 && tmsp[1].Sec == 0) { tmsp0 := node.stat.Ctim tmsa := [2]fuse.Timespec{tmsp0, tmsp0} tmsp = tmsa[:] @@ -243,7 +244,7 @@ func (self *Memfs) Utimens(path string, tmsp []fuse.Timespec) (errc int) { 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) + return self.openNode(path, false, flags) } func (self *Memfs) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) { @@ -319,13 +320,13 @@ func (self *Memfs) Release(path string, fh uint64) (errc int) { func (self *Memfs) Opendir(path string) (errc int, fh uint64) { defer trace(path)(&errc, &fh) defer self.synchronize()() - return self.openNode(path, true) + return self.openNode(path, true, 0) } func (self *Memfs) Readdir(path string, fill func(name string, stat *fuse.Stat_t, ofst int64) bool, ofst int64, - fh uint64) (errc int) { + fh uint64, flags uint32) (errc int) { defer trace(path, fill, ofst, fh)(&errc) defer self.synchronize()() node := self.openmap[fh] @@ -463,7 +464,7 @@ func (self *Memfs) lookupNode(path string, ancestor *node_t) (prnt *node_t, name node = self.root for _, c := range split(path) { if "" != c { - if 255 < len(c) { + if 255 < utf8.RuneCountInString(c) { panic(fuse.Error(-fuse.ENAMETOOLONG)) } prnt, name = node, c @@ -525,7 +526,7 @@ func (self *Memfs) removeNode(path string, dir bool) int { return 0 } -func (self *Memfs) openNode(path string, dir bool) (int, uint64) { +func (self *Memfs) openNode(path string, dir bool, flags int) (int, uint64) { _, _, node := self.lookupNode(path, nil) if nil == node { return -fuse.ENOENT, ^uint64(0) @@ -536,6 +537,13 @@ func (self *Memfs) openNode(path string, dir bool) (int, uint64) { if dir && fuse.S_IFDIR != node.stat.Mode&fuse.S_IFMT { return -fuse.ENOTDIR, ^uint64(0) } + if flags&fuse.O_TRUNC == fuse.O_TRUNC { + node.data = resize(node.data, 0, true) + node.stat.Size = 0 + tmsp := fuse.Now() + node.stat.Ctim = tmsp + node.stat.Mtim = tmsp + } node.opencnt++ if 1 == node.opencnt { self.openmap[node.stat.Ino] = node @@ -545,9 +553,12 @@ func (self *Memfs) openNode(path string, dir bool) (int, uint64) { func (self *Memfs) closeNode(fh uint64) int { node := self.openmap[fh] + if node == nil { + return -fuse.EBADF + } node.opencnt-- if 0 == node.opencnt { - delete(self.openmap, node.stat.Ino) + delete(self.openmap, fh) } return 0 } @@ -585,5 +596,6 @@ func main() { memfs := NewMemfs() host := fuse.NewFileSystemHost(memfs) host.SetCapReaddirPlus(true) + host.SetUseIno(true) host.Mount("", os.Args[1:]) } diff --git a/examples/notifyfs/notifyfs.go b/examples/notifyfs/notifyfs.go index 5d9c7e8..eb62503 100644 --- a/examples/notifyfs/notifyfs.go +++ b/examples/notifyfs/notifyfs.go @@ -100,7 +100,7 @@ func (self *Notifyfs) Read(path string, buff []byte, ofst int64, fh uint64) (n i func (self *Notifyfs) Readdir(path string, fill func(name string, stat *fuse.Stat_t, ofst int64) bool, ofst int64, - fh uint64) (errc int) { + fh uint64, flags uint32) (errc int) { fill(".", nil, 0) fill("..", nil, 0) count := self.count() diff --git a/examples/passthrough/passthrough.go b/examples/passthrough/passthrough.go index 1caecdc..23f01ab 100644 --- a/examples/passthrough/passthrough.go +++ b/examples/passthrough/passthrough.go @@ -1,3 +1,4 @@ +//go:build darwin || freebsd || netbsd || openbsd || linux // +build darwin freebsd netbsd openbsd linux /* @@ -115,7 +116,7 @@ func (self *Ptfs) Readlink(path string) (errc int, target string) { return 0, string(buff[:n]) } -func (self *Ptfs) Rename(oldpath string, newpath string) (errc int) { +func (self *Ptfs) Rename(oldpath string, newpath string, flags uint32) (errc int) { defer trace(oldpath, newpath)(&errc) defer setuidgid()() oldpath = filepath.Join(self.root, oldpath) @@ -123,19 +124,19 @@ func (self *Ptfs) Rename(oldpath string, newpath string) (errc int) { return errno(syscall.Rename(oldpath, newpath)) } -func (self *Ptfs) Chmod(path string, mode uint32) (errc int) { +func (self *Ptfs) Chmod(path string, mode uint32, fh uint64) (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) { +func (self *Ptfs) Chown(path string, uid uint32, gid uint32, fh uint64) (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) { +func (self *Ptfs) Utimens(path string, tmsp1 []fuse.Timespec, fh uint64) (errc int) { defer trace(path, tmsp1)(&errc) path = filepath.Join(self.root, path) tmsp := [2]syscall.Timespec{} @@ -229,7 +230,7 @@ func (self *Ptfs) Opendir(path string) (errc int, fh uint64) { func (self *Ptfs) Readdir(path string, fill func(name string, stat *fuse.Stat_t, ofst int64) bool, ofst int64, - fh uint64) (errc int) { + fh uint64, flags uint32) (errc int) { defer trace(path, fill, ofst, fh)(&errc) path = filepath.Join(self.root, path) file, e := os.Open(path) @@ -264,5 +265,6 @@ func main() { args = append(args[:len(args)-2], args[len(args)-1]) } _host = fuse.NewFileSystemHost(&ptfs) + _host.SetUseIno(true) _host.Mount("", args[1:]) } diff --git a/examples/passthrough/port_darwin.go b/examples/passthrough/port_darwin.go index 6ccf30c..5f50344 100644 --- a/examples/passthrough/port_darwin.go +++ b/examples/passthrough/port_darwin.go @@ -1,3 +1,4 @@ +//go:build darwin // +build darwin /* diff --git a/examples/passthrough/port_freebsd.go b/examples/passthrough/port_freebsd.go index 1d794af..4911e25 100644 --- a/examples/passthrough/port_freebsd.go +++ b/examples/passthrough/port_freebsd.go @@ -1,3 +1,4 @@ +//go:build freebsd // +build freebsd /* diff --git a/examples/passthrough/port_linux.go b/examples/passthrough/port_linux.go index 6f512ee..5615ef6 100644 --- a/examples/passthrough/port_linux.go +++ b/examples/passthrough/port_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux /* diff --git a/examples/passthrough/port_netbsd.go b/examples/passthrough/port_netbsd.go index f664637..107e322 100644 --- a/examples/passthrough/port_netbsd.go +++ b/examples/passthrough/port_netbsd.go @@ -1,3 +1,4 @@ +//go:build netbsd // +build netbsd /* diff --git a/examples/passthrough/port_openbsd.go b/examples/passthrough/port_openbsd.go index c309f0e..5d4515e 100644 --- a/examples/passthrough/port_openbsd.go +++ b/examples/passthrough/port_openbsd.go @@ -1,3 +1,4 @@ +//go:build openbsd // +build openbsd /* diff --git a/fuse/fsop.go b/fuse/fsop.go index 68dadf9..7f63319 100644 --- a/fuse/fsop.go +++ b/fuse/fsop.go @@ -12,6 +12,10 @@ // Package fuse allows the creation of user mode file systems in Go. // +// This packages supports both FUSE2 and FUSE3 on Linux and FUSE2 on Windows and macOS. +// By default, cgofuse will link with FUSE2. To link with FUSE3, simply add '-tags=fuse3' +// to your 'go build' flags. +// // A user mode file system is a user mode process that receives file system operations // from the OS FUSE layer and satisfies them in user mode. A user mode file system // implements the interface FileSystemInterface either directly or by embedding a @@ -235,16 +239,16 @@ type FileSystemInterface interface { Readlink(path string) (int, string) // Rename renames a file. - Rename(oldpath string, newpath string) int + Rename(oldpath string, newpath string, flags uint32) int // Chmod changes the permission bits of a file. - Chmod(path string, mode uint32) int + Chmod(path string, mode uint32, fh uint64) int // Chown changes the owner and group of a file. - Chown(path string, uid uint32, gid uint32) int + Chown(path string, uid uint32, gid uint32, fh uint64) int // Utimens changes the access and modification times of a file. - Utimens(path string, tmsp []Timespec) int + Utimens(path string, tmsp []Timespec, fh uint64) int // Access checks file access permissions. Access(path string, mask uint32) int @@ -288,7 +292,7 @@ type FileSystemInterface interface { Readdir(path string, fill func(name string, stat *Stat_t, ofst int64) bool, ofst int64, - fh uint64) int + fh uint64, flags uint32) int // Releasedir closes an open directory. Releasedir(path string, fh uint64) int @@ -450,25 +454,25 @@ func (*FileSystemBase) Readlink(path string) (int, string) { // Rename renames a file. // The FileSystemBase implementation returns -ENOSYS. -func (*FileSystemBase) Rename(oldpath string, newpath string) int { +func (*FileSystemBase) Rename(oldpath string, newpath string, flags uint32) int { return -ENOSYS } // Chmod changes the permission bits of a file. // The FileSystemBase implementation returns -ENOSYS. -func (*FileSystemBase) Chmod(path string, mode uint32) int { +func (*FileSystemBase) Chmod(path string, mode uint32, fh uint64) 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 { +func (*FileSystemBase) Chown(path string, uid uint32, gid uint32, fh uint64) 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 { +func (*FileSystemBase) Utimens(path string, tmsp []Timespec, fh uint64) int { return -ENOSYS } @@ -553,7 +557,7 @@ func (*FileSystemBase) Opendir(path string) (int, uint64) { func (*FileSystemBase) Readdir(path string, fill func(name string, stat *Stat_t, ofst int64) bool, ofst int64, - fh uint64) int { + fh uint64, flags uint32) int { return -ENOSYS } diff --git a/fuse/host.go b/fuse/host.go index 368c5d6..caf50e7 100644 --- a/fuse/host.go +++ b/fuse/host.go @@ -32,6 +32,7 @@ type FileSystemHost struct { sigc chan os.Signal capCaseInsensitive, capReaddirPlus, capDeleteAccess bool + directIO, useIno bool } var ( @@ -111,12 +112,17 @@ func recoverAsErrno(errc0 *c_int) { } } -func hostGetattr(path0 *c_char, stat0 *c_fuse_stat_t) (errc0 c_int) { +func hostGetattr(path0 *c_char, stat0 *c_fuse_stat_t, + fi0 *c_struct_fuse_file_info) (errc0 c_int) { defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop path := c_GoString(path0) stat := &Stat_t{} - errc := fsop.Getattr(path, stat, ^uint64(0)) + fifh := ^uint64(0) + if nil != fi0 { + fifh = uint64(fi0.fh) + } + errc := fsop.Getattr(path, stat, fifh) copyCstatFromFusestat(stat0, stat) return c_int(errc) } @@ -175,11 +181,11 @@ func hostSymlink(target0 *c_char, newpath0 *c_char) (errc0 c_int) { return c_int(errc) } -func hostRename(oldpath0 *c_char, newpath0 *c_char) (errc0 c_int) { +func hostRename(oldpath0 *c_char, newpath0 *c_char, flags c_uint32_t) (errc0 c_int) { defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop oldpath, newpath := c_GoString(oldpath0), c_GoString(newpath0) - errc := fsop.Rename(oldpath, newpath) + errc := fsop.Rename(oldpath, newpath, uint32(flags)) return c_int(errc) } @@ -191,27 +197,39 @@ func hostLink(oldpath0 *c_char, newpath0 *c_char) (errc0 c_int) { return c_int(errc) } -func hostChmod(path0 *c_char, mode0 c_fuse_mode_t) (errc0 c_int) { +func hostChmod(path0 *c_char, mode0 c_fuse_mode_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop path := c_GoString(path0) - errc := fsop.Chmod(path, uint32(mode0)) + fifh := ^uint64(0) + if nil != fi0 { + fifh = uint64(fi0.fh) + } + errc := fsop.Chmod(path, uint32(mode0), fifh) return c_int(errc) } -func hostChown(path0 *c_char, uid0 c_fuse_uid_t, gid0 c_fuse_gid_t) (errc0 c_int) { +func hostChown(path0 *c_char, uid0 c_fuse_uid_t, gid0 c_fuse_gid_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop path := c_GoString(path0) - errc := fsop.Chown(path, uint32(uid0), uint32(gid0)) + fifh := ^uint64(0) + if nil != fi0 { + fifh = uint64(fi0.fh) + } + errc := fsop.Chown(path, uint32(uid0), uint32(gid0), fifh) return c_int(errc) } -func hostTruncate(path0 *c_char, size0 c_fuse_off_t) (errc0 c_int) { +func hostTruncate(path0 *c_char, size0 c_fuse_off_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop path := c_GoString(path0) - errc := fsop.Truncate(path, int64(size0), ^uint64(0)) + fifh := ^uint64(0) + if nil != fi0 { + fifh = uint64(fi0.fh) + } + errc := fsop.Truncate(path, int64(size0), fifh) return c_int(errc) } @@ -375,10 +393,11 @@ func hostOpendir(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 c_int) { } func hostReaddir(path0 *c_char, buff0 unsafe.Pointer, fill0 c_fuse_fill_dir_t, ofst0 c_fuse_off_t, - fi0 *c_struct_fuse_file_info) (errc0 c_int) { + fi0 *c_struct_fuse_file_info, flags c_fuse_readdir_flags_t) (errc0 c_int) { defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop path := c_GoString(path0) + flag := uint32(flags) fill := func(name1 string, stat1 *Stat_t, off1 int64) bool { name := c_CString(name1) defer c_free(unsafe.Pointer(name)) @@ -391,7 +410,7 @@ func hostReaddir(path0 *c_char, buff0 unsafe.Pointer, fill0 c_fuse_fill_dir_t, o return 0 == c_hostFilldir(fill0, buff0, name, stat, c_fuse_off_t(off1)) } } - errc := fsop.Readdir(path, fill, int64(ofst0), uint64(fi0.fh)) + errc := fsop.Readdir(path, fill, int64(ofst0), uint64(fi0.fh), flag) return c_int(errc) } @@ -414,7 +433,7 @@ func hostFsyncdir(path0 *c_char, datasync c_int, fi0 *c_struct_fuse_file_info) ( return c_int(errc) } -func hostInit(conn0 *c_struct_fuse_conn_info) (user_data unsafe.Pointer) { +func hostInit(conn0 *c_struct_fuse_conn_info, cfg *c_struct_fuse_config) (user_data unsafe.Pointer) { defer func() { recover() }() @@ -426,6 +445,9 @@ func hostInit(conn0 *c_struct_fuse_conn_info) (user_data unsafe.Pointer) { c_bool(host.capCaseInsensitive), c_bool(host.capReaddirPlus), c_bool(host.capDeleteAccess)) + c_hostAsgnCconfig(cfg, + c_bool(host.directIO), + c_bool(host.useIno)) if nil != host.sigc { signal.Notify(host.sigc, syscall.SIGINT, syscall.SIGTERM) } @@ -508,19 +530,23 @@ func hostFgetattr(path0 *c_char, stat0 *c_fuse_stat_t, return c_int(errc) } -func hostUtimens(path0 *c_char, tmsp0 *c_fuse_timespec_t) (errc0 c_int) { +func hostUtimens(path0 *c_char, tmsp0 *c_fuse_timespec_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop path := c_GoString(path0) - if nil == tmsp0 { - errc := fsop.Utimens(path, nil) + fifh := ^uint64(0) + if nil != fi0 { + fifh = uint64(fi0.fh) + } + if tmsp0 == nil { + errc := fsop.Utimens(path, nil, fifh) return c_int(errc) } else { tmsp := [2]Timespec{} tmsa := (*[2]c_fuse_timespec_t)(unsafe.Pointer(tmsp0)) copyFusetimespecFromCtimespec(&tmsp[0], &tmsa[0]) copyFusetimespecFromCtimespec(&tmsp[1], &tmsa[1]) - errc := fsop.Utimens(path, tmsp[:]) + errc := fsop.Utimens(path, tmsp[:], fifh) return c_int(errc) } } @@ -605,7 +631,7 @@ func (host *FileSystemHost) SetCapCaseInsensitive(value bool) { } // SetCapReaddirPlus informs the host that the hosted file system has the readdir-plus -// capability [Windows only]. A file system that has the readdir-plus capability can send +// capability [Linux and Windows only]. A file system that has the readdir-plus capability can send // full stat information during Readdir, thus avoiding extraneous Getattr calls. func (host *FileSystemHost) SetCapReaddirPlus(value bool) { host.capReaddirPlus = value @@ -618,15 +644,27 @@ func (host *FileSystemHost) SetCapDeleteAccess(value bool) { host.capDeleteAccess = value } +// SetDirectIO causes the file system to disable page caching [Fuse3 only]. Must be set +// before Mount is called. +func (host *FileSystemHost) SetDirectIO(value bool) { + host.directIO = value +} + +// SetUseIno causes the file system to use its own inode values [Fuse3 only]. Must be set +// before Mount is called. +func (host *FileSystemHost) SetUseIno(value bool) { + host.useIno = value +} + // Mount mounts a file system on the given mountpoint with the mount options in opts. // // Many of the mount options in opts are specific to the underlying FUSE implementation. // Some of the common options include: // -// -h --help print help -// -V --version print FUSE version -// -d -o debug enable FUSE debug output -// -s disable multi-threaded operation +// -h --help print help +// -V --version print FUSE version +// -d -o debug enable FUSE debug output +// -s disable multi-threaded operation // // Please refer to the individual FUSE implementation documentation for additional options. // @@ -836,49 +874,48 @@ func optNormStr(opt string) string { // // For pointer to bool types: // -// -x Match -x without parameter. -// -foo --foo As above for -foo or --foo. -// foo Match "-o foo". -// -x= -foo= --foo= foo= Match option with parameter. -// -x=%VERB ... foo=%VERB Match option with parameter of syntax. -// Allowed verbs: d,o,x,X,v -// - d,o,x,X: set to true if parameter non-0. -// - v: set to true if parameter present. +// -x Match -x without parameter. +// -foo --foo As above for -foo or --foo. +// foo Match "-o foo". +// -x= -foo= --foo= foo= Match option with parameter. +// -x=%VERB ... foo=%VERB Match option with parameter of syntax. +// Allowed verbs: d,o,x,X,v +// - d,o,x,X: set to true if parameter non-0. +// - v: set to true if parameter present. // -// The formats -x=, and -x=%v are equivalent. +// The formats -x=, and -x=%v are equivalent. // // For pointer to other types: // -// -x Match -x with parameter (-x=PARAM). -// -foo --foo As above for -foo or --foo. -// foo Match "-o foo=PARAM". -// -x= -foo= --foo= foo= Match option with parameter. -// -x=%VERB ... foo=%VERB Match option with parameter of syntax. -// Allowed verbs for pointer to int types: d,o,x,X,v -// Allowed verbs for pointer to string types: s,v +// -x Match -x with parameter (-x=PARAM). +// -foo --foo As above for -foo or --foo. +// foo Match "-o foo=PARAM". +// -x= -foo= --foo= foo= Match option with parameter. +// -x=%VERB ... foo=%VERB Match option with parameter of syntax. +// Allowed verbs for pointer to int types: d,o,x,X,v +// Allowed verbs for pointer to string types: s,v // -// The formats -x, -x=, and -x=%v are equivalent. +// The formats -x, -x=, and -x=%v are equivalent. // // For example: // -// var f bool -// var set_attr_timeout bool -// var attr_timeout int -// var umask uint32 -// outargs, err := OptParse(args, "-f attr_timeout= attr_timeout umask=%o", -// &f, &set_attr_timeout, &attr_timeout, &umask) +// var f bool +// var set_attr_timeout bool +// var attr_timeout int +// var umask uint32 +// outargs, err := OptParse(args, "-f attr_timeout= attr_timeout umask=%o", +// &f, &set_attr_timeout, &attr_timeout, &umask) // // Will accept a command line of: // -// $ program -f -o attr_timeout=42,umask=077 +// $ program -f -o attr_timeout=42,umask=077 // // And will set variables as follows: // -// f == true -// set_attr_timeout == true -// attr_timeout == 42 -// umask == 077 -// +// f == true +// set_attr_timeout == true +// attr_timeout == 42 +// umask == 077 func OptParse(args []string, format string, vals ...interface{}) (outargs []string, err error) { if 0 == c_hostFuseInit() { if "windows" == runtime.GOOS { diff --git a/fuse/host_cgo.go b/fuse/host_cgo.go index 8f8a019..34cda0b 100644 --- a/fuse/host_cgo.go +++ b/fuse/host_cgo.go @@ -16,12 +16,18 @@ package fuse /* +#cgo fuse3,freebsd CFLAGS: -DFUSE_USE_VERSION=39 -D_FILE_OFFSET_BITS=64 -I/usr/local/include/fuse3 +#cgo fuse3,netbsd CFLAGS: -DFUSE_USE_VERSION=39 -D_FILE_OFFSET_BITS=64 -D_KERNTYPES +#cgo fuse3,openbsd CFLAGS: -DFUSE_USE_VERSION=39 -D_FILE_OFFSET_BITS=64 +#cgo fuse3,linux CFLAGS: -DFUSE_USE_VERSION=39 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3 +#cgo fuse3,linux LDFLAGS: -lfuse3 -ldl + #cgo darwin CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -I/usr/local/include/osxfuse/fuse -I/usr/local/include/fuse -#cgo freebsd CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -I/usr/local/include/fuse -#cgo netbsd CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -D_KERNTYPES -#cgo openbsd CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -#cgo linux CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse -#cgo linux LDFLAGS: -ldl +#cgo !fuse3,freebsd CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -I/usr/local/include/fuse +#cgo !fuse3,netbsd CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -D_KERNTYPES +#cgo !fuse3,openbsd CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 +#cgo !fuse3,linux CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse +#cgo !fuse3,linux LDFLAGS: -ldl #cgo windows CFLAGS: -DFUSE_USE_VERSION=28 -I/usr/local/include/winfsp // Use `set CPATH=C:\Program Files (x86)\WinFsp\inc\fuse` on Windows. // The flag `I/usr/local/include/winfsp` only works on xgo and docker. @@ -114,7 +120,11 @@ static void cgofuse_init_fail(void) #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__linux__) -#include +#if FUSE_USE_VERSION >= 30 + #include +#else + #include +#endif #if defined(__OpenBSD__) static int (*pfn_fuse_main)(int argc, char *argv[], @@ -175,13 +185,29 @@ static void *cgofuse_init_fuse(void) if (0 == h) h = dlopen("/usr/local/lib/libfuse-t.dylib", RTLD_NOW); // FUSE-T #elif defined(__FreeBSD__) - h = dlopen("libfuse.so.2", RTLD_NOW); +#if FUSE_USE_VERSION >= 30 + h = dlopen("libfuse3.so.3", RTLD_NOW); +#else + h = dlopen("libfuse.so.2", RTLD_NOW); +#endif #elif defined(__NetBSD__) - h = dlopen("librefuse.so.2", RTLD_NOW); +#if FUSE_USE_VERSION >= 30 + h = dlopen("libfuse3.so.3", RTLD_NOW); +#else + h = dlopen("libfuse.so.2", RTLD_NOW); +#endif #elif defined(__OpenBSD__) - h = dlopen("libfuse.so.2.0", RTLD_NOW); +#if FUSE_USE_VERSION >= 30 + h = dlopen("libfuse3.so.3", RTLD_NOW); +#else + h = dlopen("libfuse.so.2", RTLD_NOW); +#endif #elif defined(__linux__) - h = dlopen("libfuse.so.2", RTLD_NOW); +#if FUSE_USE_VERSION >= 30 + h = dlopen("libfuse3.so.3", RTLD_NOW); +#else + h = dlopen("libfuse.so.2", RTLD_NOW); +#endif #endif if (0 == h) return 0; @@ -321,18 +347,41 @@ typedef struct fuse_timespec fuse_timespec_t; typedef unsigned int fuse_opt_offset_t; #endif -extern int go_hostGetattr(char *path, fuse_stat_t *stbuf); +#if FUSE_USE_VERSION >= 30 + typedef enum fuse_readdir_flags fuse_readdir_flags_t; + typedef enum fuse_fill_dir_flags fuse_fill_dir_flags_t; + static int fill_dir_plus = (1 << 1); +#else + typedef int fuse_readdir_flags_t; + struct fuse_config; +#endif + +#if FUSE_USE_VERSION >= 30 +extern int go_hostGetattrFuse3(char *path, fuse_stat_t *stbuf, struct fuse_file_info *fi); +#else +extern int go_hostGetattrFuse2(char *path, fuse_stat_t *stbuf); +#endif extern int go_hostReadlink(char *path, char *buf, size_t size); extern int go_hostMknod(char *path, fuse_mode_t mode, fuse_dev_t dev); extern int go_hostMkdir(char *path, fuse_mode_t mode); extern int go_hostUnlink(char *path); extern int go_hostRmdir(char *path); extern int go_hostSymlink(char *target, char *newpath); -extern int go_hostRename(char *oldpath, char *newpath); +#if FUSE_USE_VERSION >= 30 +extern int go_hostRenameFuse3(char *oldpath, char *newpath, unsigned int flags); +#else +extern int go_hostRenameFuse2(char *oldpath, char *newpath); +#endif extern int go_hostLink(char *oldpath, char *newpath); -extern int go_hostChmod(char *path, fuse_mode_t mode); -extern int go_hostChown(char *path, fuse_uid_t uid, fuse_gid_t gid); -extern int go_hostTruncate(char *path, fuse_off_t size); +#if FUSE_USE_VERSION >= 30 +extern int go_hostChmodFuse3(char *path, fuse_mode_t mode, struct fuse_file_info *fi); +extern int go_hostChownFuse3(char *path, fuse_uid_t uid, fuse_gid_t gid, struct fuse_file_info *fi); +extern int go_hostTruncateFuse3(char *path, fuse_off_t size, struct fuse_file_info *fi); +#else +extern int go_hostChmodFuse2(char *path, fuse_mode_t mode); +extern int go_hostChownFuse2(char *path, fuse_uid_t uid, fuse_gid_t gid); +extern int go_hostTruncateFuse2(char *path, fuse_off_t size); +#endif extern int go_hostOpen(char *path, struct fuse_file_info *fi); extern int go_hostRead(char *path, char *buf, size_t size, fuse_off_t off, struct fuse_file_info *fi); @@ -347,18 +396,33 @@ extern int go_hostGetxattr(char *path, char *name, char *value, size_t size); extern int go_hostListxattr(char *path, char *namebuf, size_t size); extern int go_hostRemovexattr(char *path, char *name); extern int go_hostOpendir(char *path, struct fuse_file_info *fi); -extern int go_hostReaddir(char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off, +#if FUSE_USE_VERSION >= 30 +extern int go_hostReaddirFuse3(char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off, + struct fuse_file_info *fi, fuse_readdir_flags_t flags); +#else +extern int go_hostReaddirFuse2(char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off, struct fuse_file_info *fi); +#endif extern int go_hostReleasedir(char *path, struct fuse_file_info *fi); extern int go_hostFsyncdir(char *path, int datasync, struct fuse_file_info *fi); -extern void *go_hostInit(struct fuse_conn_info *conn); +#if FUSE_USE_VERSION >= 30 +extern void *go_hostInitFuse3(struct fuse_conn_info *conn, struct fuse_config *cfg); +#else +extern void *go_hostInitFuse2(struct fuse_conn_info *conn); +#endif extern void go_hostDestroy(void *data); extern int go_hostAccess(char *path, int mask); extern int go_hostCreate(char *path, fuse_mode_t mode, struct fuse_file_info *fi); +#if FUSE_USE_VERSION < 30 extern int go_hostFtruncate(char *path, fuse_off_t off, struct fuse_file_info *fi); extern int go_hostFgetattr(char *path, fuse_stat_t *stbuf, struct fuse_file_info *fi); +#endif //extern int go_hostLock(char *path, struct fuse_file_info *fi, int cmd, struct fuse_flock *lock); -extern int go_hostUtimens(char *path, fuse_timespec_t tv[2]); +#if FUSE_USE_VERSION >= 30 +extern int go_hostUtimensFuse3(char *path, fuse_timespec_t tv[2], struct fuse_file_info *fi); +#else +extern int go_hostUtimensFuse2(char *path, fuse_timespec_t tv[2]); +#endif extern int go_hostGetpath(char *path, char *buf, size_t size, struct fuse_file_info *fi); extern int go_hostSetchgtime(char *path, fuse_timespec_t *tv); @@ -388,6 +452,23 @@ static inline void hostAsgnCconninfo(struct fuse_conn_info *conn, #endif } +#if FUSE_USE_VERSION >= 30 +static inline void hostAsgnCconfig(struct fuse_config *cfg, + bool direct_io, + bool use_ino) +{ + memset(cfg, 0, sizeof *cfg); + cfg->direct_io = direct_io; + cfg->use_ino = use_ino; + cfg->attr_timeout = 0; +} +#else +static inline void hostAsgnCconfig(struct fuse_config *cfg, + bool direct_io, + bool use_ino) +{} +#endif + static inline void hostCstatvfsFromFusestatfs(fuse_statvfs_t *stbuf, uint64_t bsize, uint64_t frsize, @@ -500,7 +581,11 @@ static inline void hostAsgnCfileinfo(struct fuse_file_info *fi, static inline int hostFilldir(fuse_fill_dir_t filler, void *buf, char *name, fuse_stat_t *stbuf, fuse_off_t off) { +#if FUSE_USE_VERSION >= 30 + return filler(buf, name, stbuf, off, fill_dir_plus); +#else return filler(buf, name, stbuf, off); +#endif } #if defined(__APPLE__) @@ -542,18 +627,32 @@ static int hostMount(int argc, char *argv[], void *data) { static struct fuse_operations fsop = { - .getattr = (int (*)(const char *, fuse_stat_t *))go_hostGetattr, +#if FUSE_USE_VERSION >= 30 + .getattr = (int (*)(const char *, fuse_stat_t *, struct fuse_file_info *))go_hostGetattrFuse3, +#else + .getattr = (int (*)(const char *, fuse_stat_t *))go_hostGetattrFuse2, +#endif .readlink = (int (*)(const char *, char *, size_t))go_hostReadlink, .mknod = (int (*)(const char *, fuse_mode_t, fuse_dev_t))go_hostMknod, .mkdir = (int (*)(const char *, fuse_mode_t))go_hostMkdir, .unlink = (int (*)(const char *))go_hostUnlink, .rmdir = (int (*)(const char *))go_hostRmdir, .symlink = (int (*)(const char *, const char *))go_hostSymlink, - .rename = (int (*)(const char *, const char *))go_hostRename, +#if FUSE_USE_VERSION >= 30 + .rename = (int (*)(const char *, const char *, unsigned int flags))go_hostRenameFuse3, +#else + .rename = (int (*)(const char *, const char *))go_hostRenameFuse2, +#endif .link = (int (*)(const char *, const char *))go_hostLink, - .chmod = (int (*)(const char *, fuse_mode_t))go_hostChmod, - .chown = (int (*)(const char *, fuse_uid_t, fuse_gid_t))go_hostChown, - .truncate = (int (*)(const char *, fuse_off_t))go_hostTruncate, +#if FUSE_USE_VERSION >= 30 + .chmod = (int (*)(const char *, fuse_mode_t, struct fuse_file_info *))go_hostChmodFuse3, + .chown = (int (*)(const char *, fuse_uid_t, fuse_gid_t, struct fuse_file_info *))go_hostChownFuse3, + .truncate = (int (*)(const char *, fuse_off_t, struct fuse_file_info *))go_hostTruncateFuse3, +#else + .chmod = (int (*)(const char *, fuse_mode_t))go_hostChmodFuse2, + .chown = (int (*)(const char *, fuse_uid_t, fuse_gid_t))go_hostChownFuse2, + .truncate = (int (*)(const char *, fuse_off_t))go_hostTruncateFuse2, +#endif .open = (int (*)(const char *, struct fuse_file_info *))go_hostOpen, .read = (int (*)(const char *, char *, size_t, fuse_off_t, struct fuse_file_info *)) go_hostRead, @@ -575,19 +674,34 @@ static int hostMount(int argc, char *argv[], void *data) .listxattr = (int (*)(const char *, char *, size_t))go_hostListxattr, .removexattr = (int (*)(const char *, const char *))go_hostRemovexattr, .opendir = (int (*)(const char *, struct fuse_file_info *))go_hostOpendir, +#if FUSE_USE_VERSION >= 30 + .readdir = (int (*)(const char *, void *, fuse_fill_dir_t, fuse_off_t, + struct fuse_file_info *, fuse_readdir_flags_t flags))go_hostReaddirFuse3, +#else .readdir = (int (*)(const char *, void *, fuse_fill_dir_t, fuse_off_t, - struct fuse_file_info *))go_hostReaddir, + struct fuse_file_info *))go_hostReaddirFuse2, +#endif .releasedir = (int (*)(const char *, struct fuse_file_info *))go_hostReleasedir, .fsyncdir = (int (*)(const char *, int, struct fuse_file_info *))go_hostFsyncdir, - .init = (void *(*)(struct fuse_conn_info *))go_hostInit, +#if FUSE_USE_VERSION >= 30 + .init = (void *(*)(struct fuse_conn_info *, struct fuse_config *))go_hostInitFuse3, +#else + .init = (void *(*)(struct fuse_conn_info *))go_hostInitFuse2, +#endif .destroy = (void (*)(void *))go_hostDestroy, .access = (int (*)(const char *, int))go_hostAccess, .create = (int (*)(const char *, fuse_mode_t, struct fuse_file_info *))go_hostCreate, +#if FUSE_USE_VERSION < 30 .ftruncate = (int (*)(const char *, fuse_off_t, struct fuse_file_info *))go_hostFtruncate, .fgetattr = (int (*)(const char *, fuse_stat_t *, struct fuse_file_info *))go_hostFgetattr, +#endif //.lock = (int (*)(const char *, struct fuse_file_info *, int, struct fuse_flock *)) // go_hostFlock, - .utimens = (int (*)(const char *, const fuse_timespec_t [2]))go_hostUtimens, +#if FUSE_USE_VERSION >= 30 + .utimens = (int (*)(const char *, const fuse_timespec_t [2], struct fuse_file_info *))go_hostUtimensFuse3, +#else + .utimens = (int (*)(const char *, const fuse_timespec_t [2]))go_hostUtimensFuse2, +#endif #if defined(__APPLE__) || (defined(_WIN32) && defined(FSP_FUSE_CAP_STAT_EX)) .setchgtime = (int (*)(const char *, const fuse_timespec_t *))go_hostSetchgtime, .setcrtime = (int (*)(const char *, const fuse_timespec_t *))go_hostSetcrtime, @@ -634,9 +748,21 @@ static int hostUnmount(struct fuse *fuse, char *mountpoint) if (0 == umount2(mountpoint, MNT_DETACH)) return 1; // linux: umount2 failed; try fusermount - char *argv[] = + char *paths[] = { "/bin/fusermount", + "/usr/bin/fusermount", + }; + char *path = paths[0]; + for (size_t i = 0; sizeof paths / sizeof paths[0] > i; i++) + if (0 == access(paths[i], X_OK)) + { + path = paths[i]; + break; + } + char *argv[] = + { + path, "-z", "-u", mountpoint, @@ -711,6 +837,7 @@ type ( c_fuse_mode_t = C.fuse_mode_t c_fuse_off_t = C.fuse_off_t c_fuse_opt_offset_t = C.fuse_opt_offset_t + c_fuse_readdir_flags_t = C.fuse_readdir_flags_t c_fuse_stat_t = C.fuse_stat_t c_fuse_stat_ex_t = C.fuse_stat_ex_t c_fuse_statvfs_t = C.fuse_statvfs_t @@ -724,6 +851,7 @@ type ( c_size_t = C.size_t c_struct_fuse = C.struct_fuse c_struct_fuse_args = C.struct_fuse_args + c_struct_fuse_config = C.struct_fuse_config c_struct_fuse_conn_info = C.struct_fuse_conn_info c_struct_fuse_context = C.struct_fuse_context c_struct_fuse_file_info = C.struct_fuse_file_info @@ -766,6 +894,11 @@ func c_hostAsgnCconninfo(conn *c_struct_fuse_conn_info, capDeleteAccess c_bool) { C.hostAsgnCconninfo(conn, capCaseInsensitive, capReaddirPlus, capDeleteAccess) } +func c_hostAsgnCconfig(cfg *c_struct_fuse_config, + directIO c_bool, + useIno c_bool) { + C.hostAsgnCconfig(cfg, directIO, useIno) +} func c_hostCstatvfsFromFusestatfs(stbuf *c_fuse_statvfs_t, bsize c_uint64_t, frsize c_uint64_t, @@ -867,9 +1000,15 @@ func c_hostOptParse(args *c_struct_fuse_args, data unsafe.Pointer, opts *c_struc return C.hostOptParse(args, data, opts, nonopts) } -//export go_hostGetattr -func go_hostGetattr(path0 *c_char, stat0 *c_fuse_stat_t) (errc0 c_int) { - return hostGetattr(path0, stat0) +//export go_hostGetattrFuse3 +func go_hostGetattrFuse3(path0 *c_char, stat0 *c_fuse_stat_t, + fi0 *c_struct_fuse_file_info) (errc0 c_int) { + return hostGetattr(path0, stat0, fi0) +} + +//export go_hostGetattrFuse2 +func go_hostGetattrFuse2(path0 *c_char, stat0 *c_fuse_stat_t) (errc0 c_int) { + return hostGetattr(path0, stat0, nil) } //export go_hostReadlink @@ -902,9 +1041,14 @@ func go_hostSymlink(target0 *c_char, newpath0 *c_char) (errc0 c_int) { return hostSymlink(target0, newpath0) } -//export go_hostRename -func go_hostRename(oldpath0 *c_char, newpath0 *c_char) (errc0 c_int) { - return hostRename(oldpath0, newpath0) +//export go_hostRenameFuse3 +func go_hostRenameFuse3(oldpath0 *c_char, newpath0 *c_char, flags c_uint32_t) (errc0 c_int) { + return hostRename(oldpath0, newpath0, flags) +} + +//export go_hostRenameFuse2 +func go_hostRenameFuse2(oldpath0 *c_char, newpath0 *c_char) (errc0 c_int) { + return hostRename(oldpath0, newpath0, 0) } //export go_hostLink @@ -912,19 +1056,35 @@ func go_hostLink(oldpath0 *c_char, newpath0 *c_char) (errc0 c_int) { return hostLink(oldpath0, newpath0) } -//export go_hostChmod -func go_hostChmod(path0 *c_char, mode0 c_fuse_mode_t) (errc0 c_int) { - return hostChmod(path0, mode0) +//export go_hostChmodFuse3 +func go_hostChmodFuse3(path0 *c_char, mode0 c_fuse_mode_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { + return hostChmod(path0, mode0, fi0) } -//export go_hostChown -func go_hostChown(path0 *c_char, uid0 c_fuse_uid_t, gid0 c_fuse_gid_t) (errc0 c_int) { - return hostChown(path0, uid0, gid0) +//export go_hostChmodFuse2 +func go_hostChmodFuse2(path0 *c_char, mode0 c_fuse_mode_t) (errc0 c_int) { + return hostChmod(path0, mode0, nil) } -//export go_hostTruncate -func go_hostTruncate(path0 *c_char, size0 c_fuse_off_t) (errc0 c_int) { - return hostTruncate(path0, size0) +//export go_hostChownFuse3 +func go_hostChownFuse3(path0 *c_char, uid0 c_fuse_uid_t, gid0 c_fuse_gid_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { + return hostChown(path0, uid0, gid0, fi0) +} + +//export go_hostChownFuse2 +func go_hostChownFuse2(path0 *c_char, uid0 c_fuse_uid_t, gid0 c_fuse_gid_t) (errc0 c_int) { + return hostChown(path0, uid0, gid0, nil) +} + +//export go_hostTruncateFuse3 +func go_hostTruncateFuse3(path0 *c_char, size0 c_fuse_off_t, + fi0 *c_struct_fuse_file_info) (errc0 c_int) { + return hostTruncate(path0, size0, fi0) +} + +//export go_hostTruncateFuse2 +func go_hostTruncateFuse2(path0 *c_char, size0 c_fuse_off_t) (errc0 c_int) { + return hostTruncate(path0, size0, nil) } //export go_hostOpen @@ -990,11 +1150,18 @@ func go_hostOpendir(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 c_int) { return hostOpendir(path0, fi0) } -//export go_hostReaddir -func go_hostReaddir(path0 *c_char, +//export go_hostReaddirFuse3 +func go_hostReaddirFuse3(path0 *c_char, + buff0 unsafe.Pointer, fill0 c_fuse_fill_dir_t, ofst0 c_fuse_off_t, + fi0 *c_struct_fuse_file_info, flags c_fuse_readdir_flags_t) (errc0 c_int) { + return hostReaddir(path0, buff0, fill0, ofst0, fi0, flags) +} + +//export go_hostReaddirFuse2 +func go_hostReaddirFuse2(path0 *c_char, buff0 unsafe.Pointer, fill0 c_fuse_fill_dir_t, ofst0 c_fuse_off_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { - return hostReaddir(path0, buff0, fill0, ofst0, fi0) + return hostReaddir(path0, buff0, fill0, ofst0, fi0, 0) } //export go_hostReleasedir @@ -1007,9 +1174,14 @@ func go_hostFsyncdir(path0 *c_char, datasync c_int, fi0 *c_struct_fuse_file_info return hostFsyncdir(path0, datasync, fi0) } -//export go_hostInit -func go_hostInit(conn0 *c_struct_fuse_conn_info) (user_data unsafe.Pointer) { - return hostInit(conn0) +//export go_hostInitFuse3 +func go_hostInitFuse3(conn0 *c_struct_fuse_conn_info, conf0 *c_struct_fuse_config) (user_data unsafe.Pointer) { + return hostInit(conn0, conf0) +} + +//export go_hostInitFuse2 +func go_hostInitFuse2(conn0 *c_struct_fuse_conn_info) (user_data unsafe.Pointer) { + return hostInit(conn0, nil) } //export go_hostDestroy @@ -1039,9 +1211,14 @@ func go_hostFgetattr(path0 *c_char, stat0 *c_fuse_stat_t, return hostFgetattr(path0, stat0, fi0) } -//export go_hostUtimens -func go_hostUtimens(path0 *c_char, tmsp0 *c_fuse_timespec_t) (errc0 c_int) { - return hostUtimens(path0, tmsp0) +//export go_hostUtimensFuse3 +func go_hostUtimensFuse3(path0 *c_char, tmsp0 *c_fuse_timespec_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { + return hostUtimens(path0, tmsp0, fi0) +} + +//export go_hostUtimensFuse2 +func go_hostUtimensFuse2(path0 *c_char, tmsp0 *c_fuse_timespec_t) (errc0 c_int) { + return hostUtimens(path0, tmsp0, nil) } //export go_hostGetpath diff --git a/fuse/host_nocgo_windows.go b/fuse/host_nocgo_windows.go index 10549dc..ed5d474 100644 --- a/fuse/host_nocgo_windows.go +++ b/fuse/host_nocgo_windows.go @@ -86,6 +86,26 @@ type fuse_operations struct { fsetattr_x uintptr } +type fuse_readdir_flags_t struct { + st_dev c_fuse_dev_t + _ align64 + st_ino c_fuse_ino_t + st_mode c_fuse_mode_t + st_nlink c_fuse_nlink_t + st_uid c_fuse_uid_t + st_gid c_fuse_gid_t + st_rdev c_fuse_dev_t + _ align64 + st_size c_fuse_off_t + st_atim c_fuse_timespec_t + st_mtim c_fuse_timespec_t + st_ctim c_fuse_timespec_t + st_blksize c_fuse_blksize_t + _ align64 + st_blocks c_fuse_blkcnt_t + st_birthtim c_fuse_timespec_t +} + type fuse_stat_t struct { st_dev c_fuse_dev_t _ align64 @@ -142,6 +162,34 @@ type struct_fuse_args struct { allocated c_int } +type struct_fuse_config struct { + set_gid c_int + gid c_unsigned + set_uid c_int + uid c_unsigned + set_mode c_int + umask c_unsigned + entry_timeout c_double + negative_timeout c_double + attr_timeout c_double + intr c_int + intr_signal c_int + remember c_int + hard_remove c_int + use_ino c_int + readdir_ino c_int + direct_io c_int + kernel_cache c_int + auto_cache c_int + no_rofd_flush c_int + ac_attr_timeout_set c_int + ac_attr_timeout c_double + nullpath_ok c_int + parallel_direct_writes c_int + fmask c_unsigned + dmask c_unsigned +} + type struct_fuse_conn_info struct { proto_major c_unsigned proto_minor c_unsigned @@ -180,6 +228,7 @@ type struct_fuse_opt struct { type ( c_bool = bool c_char = byte + c_double = float64 c_fuse_blkcnt_t = int64 c_fuse_blksize_t = int32 c_fuse_dev_t = uint32 @@ -193,6 +242,7 @@ type ( c_fuse_off_t = int64 c_fuse_opt_offset_t = uint32 c_fuse_pid_t = int32 + c_fuse_readdir_flags_t = uintptr c_fuse_stat_t = fuse_stat_t c_fuse_stat_ex_t = fuse_stat_ex_t c_fuse_statvfs_t = fuse_statvfs_t @@ -206,6 +256,7 @@ type ( c_size_t = uintptr c_struct_fuse = struct_fuse c_struct_fuse_args = struct_fuse_args + c_struct_fuse_config = struct_fuse_config c_struct_fuse_conn_info = struct_fuse_conn_info c_struct_fuse_context = struct_fuse_context c_struct_fuse_file_info = struct_fuse_file_info @@ -318,6 +369,10 @@ func c_hostAsgnCconninfo(conn *c_struct_fuse_conn_info, conn.want |= conn.capable & FSP_FUSE_CAP_DELETE_ACCESS } } +func c_hostAsgnCconfig(cfg *c_struct_fuse_config, + directIO c_bool, + useIno c_bool) { +} func c_hostCstatvfsFromFusestatfs(stbuf *c_fuse_statvfs_t, bsize c_uint64_t, frsize c_uint64_t, @@ -683,7 +738,7 @@ func init() { // 64-bit func go_hostGetattr64(path0 *c_char, stat0 *c_fuse_stat_t) (errc0 uintptr) { - return uintptr(int(hostGetattr(path0, stat0))) + return uintptr(int(hostGetattr(path0, stat0, nil))) } func go_hostReadlink64(path0 *c_char, buff0 *c_char, size0 uintptr) (errc0 uintptr) { @@ -711,7 +766,7 @@ func go_hostSymlink64(target0 *c_char, newpath0 *c_char) (errc0 uintptr) { } func go_hostRename64(oldpath0 *c_char, newpath0 *c_char) (errc0 uintptr) { - return uintptr(int(hostRename(oldpath0, newpath0))) + return uintptr(int(hostRename(oldpath0, newpath0, 0))) } func go_hostLink64(oldpath0 *c_char, newpath0 *c_char) (errc0 uintptr) { @@ -719,15 +774,15 @@ func go_hostLink64(oldpath0 *c_char, newpath0 *c_char) (errc0 uintptr) { } func go_hostChmod64(path0 *c_char, mode0 uintptr) (errc0 uintptr) { - return uintptr(int(hostChmod(path0, c_fuse_mode_t(mode0)))) + return uintptr(int(hostChmod(path0, c_fuse_mode_t(mode0), nil))) } func go_hostChown64(path0 *c_char, uid0 uintptr, gid0 uintptr) (errc0 uintptr) { - return uintptr(int(hostChown(path0, c_fuse_uid_t(uid0), c_fuse_gid_t(gid0)))) + return uintptr(int(hostChown(path0, c_fuse_uid_t(uid0), c_fuse_gid_t(gid0), nil))) } func go_hostTruncate64(path0 *c_char, size0 uintptr) (errc0 uintptr) { - return uintptr(int(hostTruncate(path0, c_fuse_off_t(size0)))) + return uintptr(int(hostTruncate(path0, c_fuse_off_t(size0), nil))) } func go_hostOpen64(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 uintptr) { @@ -784,7 +839,7 @@ func go_hostOpendir64(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 uintpt func go_hostReaddir64(path0 *c_char, buff0 unsafe.Pointer, fill0 c_fuse_fill_dir_t, ofst0 uintptr, fi0 *c_struct_fuse_file_info) (errc0 uintptr) { - return uintptr(int(hostReaddir(path0, buff0, fill0, c_fuse_off_t(ofst0), fi0))) + return uintptr(int(hostReaddir(path0, buff0, fill0, c_fuse_off_t(ofst0), fi0, 0))) } func go_hostReleasedir64(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 uintptr) { @@ -797,7 +852,7 @@ func go_hostFsyncdir64(path0 *c_char, datasync uintptr, } func go_hostInit64(conn0 *c_struct_fuse_conn_info) (user_data unsafe.Pointer) { - return hostInit(conn0) + return hostInit(conn0, nil) } func go_hostDestroy64(user_data unsafe.Pointer) uintptr { @@ -824,7 +879,7 @@ func go_hostFgetattr64(path0 *c_char, stat0 *c_fuse_stat_t, } func go_hostUtimens64(path0 *c_char, tmsp0 *c_fuse_timespec_t) (errc0 uintptr) { - return uintptr(int(hostUtimens(path0, tmsp0))) + return uintptr(int(hostUtimens(path0, tmsp0, nil))) } func go_hostGetpath64(path0 *c_char, buff0 *c_char, size0 uintptr, @@ -847,7 +902,7 @@ func go_hostChflags64(path0 *c_char, flags c_uint32_t) (errc0 uintptr) { // 32-bit func go_hostGetattr32(path0 *c_char, stat0 *c_fuse_stat_t) (errc0 uintptr) { - return uintptr(int(hostGetattr(path0, stat0))) + return uintptr(int(hostGetattr(path0, stat0, nil))) } func go_hostReadlink32(path0 *c_char, buff0 *c_char, size0 uintptr) (errc0 uintptr) { @@ -875,7 +930,7 @@ func go_hostSymlink32(target0 *c_char, newpath0 *c_char) (errc0 uintptr) { } func go_hostRename32(oldpath0 *c_char, newpath0 *c_char) (errc0 uintptr) { - return uintptr(int(hostRename(oldpath0, newpath0))) + return uintptr(int(hostRename(oldpath0, newpath0, 0))) } func go_hostLink32(oldpath0 *c_char, newpath0 *c_char) (errc0 uintptr) { @@ -883,15 +938,15 @@ func go_hostLink32(oldpath0 *c_char, newpath0 *c_char) (errc0 uintptr) { } func go_hostChmod32(path0 *c_char, mode0 uintptr) (errc0 uintptr) { - return uintptr(int(hostChmod(path0, c_fuse_mode_t(mode0)))) + return uintptr(int(hostChmod(path0, c_fuse_mode_t(mode0), nil))) } func go_hostChown32(path0 *c_char, uid0 uintptr, gid0 uintptr) (errc0 uintptr) { - return uintptr(int(hostChown(path0, c_fuse_uid_t(uid0), c_fuse_gid_t(gid0)))) + return uintptr(int(hostChown(path0, c_fuse_uid_t(uid0), c_fuse_gid_t(gid0), nil))) } func go_hostTruncate32(path0 *c_char, lsize0, hsize0 uintptr) (errc0 uintptr) { - return uintptr(int(hostTruncate(path0, (c_fuse_off_t(hsize0)<<32)|c_fuse_off_t(lsize0)))) + return uintptr(int(hostTruncate(path0, (c_fuse_off_t(hsize0)<<32)|c_fuse_off_t(lsize0), nil))) } func go_hostOpen32(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 uintptr) { @@ -951,7 +1006,7 @@ func go_hostReaddir32(path0 *c_char, buff0 unsafe.Pointer, fill0 c_fuse_fill_dir_t, lofst0, hofst0 uintptr, fi0 *c_struct_fuse_file_info) (errc0 uintptr) { return uintptr(int(hostReaddir(path0, - buff0, fill0, (c_fuse_off_t(hofst0)<<32)|c_fuse_off_t(lofst0), fi0))) + buff0, fill0, (c_fuse_off_t(hofst0)<<32)|c_fuse_off_t(lofst0), fi0, 0))) } func go_hostReleasedir32(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 uintptr) { @@ -964,7 +1019,7 @@ func go_hostFsyncdir32(path0 *c_char, datasync uintptr, } func go_hostInit32(conn0 *c_struct_fuse_conn_info) (user_data unsafe.Pointer) { - return hostInit(conn0) + return hostInit(conn0, nil) } func go_hostDestroy32(user_data unsafe.Pointer) uintptr { @@ -991,7 +1046,7 @@ func go_hostFgetattr32(path0 *c_char, stat0 *c_fuse_stat_t, } func go_hostUtimens32(path0 *c_char, tmsp0 *c_fuse_timespec_t) (errc0 uintptr) { - return uintptr(int(hostUtimens(path0, tmsp0))) + return uintptr(int(hostUtimens(path0, tmsp0, nil))) } func go_hostGetpath32(path0 *c_char, buff0 *c_char, size0 uintptr, diff --git a/fuse/host_test.go b/fuse/host_test.go index de07d42..8a1d64a 100644 --- a/fuse/host_test.go +++ b/fuse/host_test.go @@ -47,7 +47,7 @@ func (self *testfs) Getattr(path string, stat *Stat_t, fh uint64) (errc int) { func (self *testfs) Readdir(path string, fill func(name string, stat *Stat_t, ofst int64) bool, ofst int64, - fh uint64) (errc int) { + fh uint64, flags uint32) (errc int) { fill(".", nil, 0) fill("..", nil, 0) return 0