diff --git a/.appveyor.yml b/.appveyor.yml index a333003..016f7e7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -31,6 +31,7 @@ build_script: - go version - go build -v ./... - go build -v ./examples/memfs +- go build -tags=memfs3 -v -o memfs3.exe ./examples/memfs test_script: - go test -v ./fuse @@ -43,6 +44,7 @@ test_script: # hard code fsreg parameters because appveyor does not like percents ("--VolumePrefix=%1 %2") - C:\projects\winfsp\tools\fsreg.bat gomemfs "C:\projects\go\src\github.com\winfsp\cgofuse\memfs.exe" "--VolumePrefix=\gomemfs\share M:" "D:P(A;;RPWPLC;;;WD)" +- C:\projects\winfsp\tools\fsreg.bat gomemfs3 "C:\projects\go\src\github.com\winfsp\cgofuse\memfs3.exe" "--VolumePrefix=\gomemfs3\share N:" "D:P(A;;RPWPLC;;;WD)" # test against WinFsp v1.0 - 'net use M: \\gomemfs\share' @@ -52,6 +54,13 @@ test_script: # - C:\Projects\winfsp\ext\test\fstools\src\fsx\fsx.exe -N 10000 test xxxxxx - 'C: & cd' - 'net use M: /delete' +- 'net use N: \\gomemfs3\share' +- 'N: & cd' +- C:\projects\winfsp\build\VStudio\build\Release\winfsp-tests-x64.exe --external --resilient --share-prefix=\gomemfs3\share -create_allocation_test -create_fileattr_test -getfileinfo_name_test -setfileinfo_test -delete_access_test -setsecurity_test -querydir_namelen_test -reparse* -stream* +# disable fsx test on WinFsp v1.0, as there was a bug in FUSE write. +# - C:\Projects\winfsp\ext\test\fstools\src\fsx\fsx.exe -N 10000 test xxxxxx +- 'C: & cd' +- 'net use N: /delete' # test against WinFsp v1.2 DLL with chflags, setcrtime and setchgtime # HACK: mixing DLL and FSD versions; do not try this at home @@ -63,3 +72,9 @@ test_script: - C:\Projects\winfsp\ext\test\fstools\src\fsx\fsx.exe -N 10000 test xxxxxx - 'C: & cd' - 'net use M: /delete' +- 'net use N: \\gomemfs3\share' +- 'N: & cd' +- C:\projects\winfsp\build\VStudio\build\Release\winfsp-tests-x64.exe --external --resilient --share-prefix=\gomemfs3\share -create_allocation_test -create_fileattr_test -getfileinfo_name_test -delete_access_test -setsecurity_test -querydir_namelen_test -reparse* -stream* +- C:\Projects\winfsp\ext\test\fstools\src\fsx\fsx.exe -N 10000 test xxxxxx +- 'C: & cd' +- 'net use N: /delete' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 65a89a6..65c50c3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,20 +15,27 @@ jobs: GOARCH: ${{ matrix.arch }} CGO_ENABLED: ${{ matrix.cgo }} CPATH: ${{ matrix.cpath }} - GOEXPERIMENT: cgocheck2 + GODEBUG: cgocheck=2 strategy: matrix: include: - os: windows-latest arch: amd64 + exe: .exe cgo: 1 cpath: C:\Program Files (x86)\WinFsp\inc\fuse - os: windows-latest arch: amd64 + exe: .exe + cgo: 0 + - os: windows-latest + arch: 386 + exe: .exe cgo: 0 - os: ubuntu-latest arch: amd64 cgo: 1 + # macOS runner can no longer load the macfuse kext; use runner only to build - os: macos-latest arch: amd64 cgo: 1 @@ -43,18 +50,14 @@ jobs: - name: Install go uses: actions/setup-go@v5 with: - go-version: '1.23' + go-version: 1.20.* - name: Install winfsp and winfsp-tests (Windows) - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} if: runner.os == 'Windows' run: | $headers = @{ - Authorization = "token $env:GITHUB_TOKEN" - "User-Agent" = "GitHub Actions" + Authorization = "token ${{ secrets.GITHUB_TOKEN }}" } - $releases = Invoke-WebRequest https://api.github.com/repos/winfsp/winfsp/releases -Headers $headers | ` ConvertFrom-Json @@ -88,26 +91,43 @@ jobs: rm -rf secfs.test/fstest/fstest/tests/xacl rm -rf secfs.test/fstest/fstest/tests/zzz_ResourceFork - - name: Install FUSE (macOS) + - name: Install FUSE and secfs.test if: runner.os == 'macOS' run: | brew install macfuse - - name: Build packages with fuse2 + 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 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 + go build -tags=memfs3 -v -o memfs3${{ matrix.exe }} ./examples/memfs - - name: Test file systems (Windows) with fuse2 + - name: Test file systems with FUSE2 (Windows) if: runner.os == 'Windows' run: | Set-PSDebug -Trace 1 + go test -v -count=1 ./fuse + $testexe = (Get-Item winfsp-tests\winfsp-tests-x64.exe) + Start-Process -NoNewWindow .\memfs.exe "-o uid=-1,rellinks,FileInfoTimeout=-1 X:" Start-Sleep 3 Push-Location X:\ @@ -120,11 +140,25 @@ jobs: Start-Sleep 3 Pop-Location - - name: Test file systems (Linux) with fuse2 - if: runner.os == 'Linux' + Start-Process -NoNewWindow .\memfs3.exe "-o uid=-1,rellinks,FileInfoTimeout=-1 X:" + Start-Sleep 3 + Push-Location X:\ + . $testexe --fuse-external --resilient --case-insensitive-cmp ` + +* ` + -create_fileattr_test ` + -reparse_nfs_test ` + -ea* + Stop-Process -Name memfs3 + Start-Sleep 3 + Pop-Location + + - name: Test file systems (Linux / macOS disabled) with FUSE2 + if: runner.os == 'Linux' || (false && runner.os == 'macOS') run: | set -x + go test -v -count=1 ./fuse + mkdir p mnt sudo ./memfs -o allow_other,default_permissions,use_ino,attr_timeout=0 mnt & @@ -134,6 +168,13 @@ jobs: (cd mnt && ../secfs.test/tools/bin/fsx -e -N 1000 test xxxx) sudo umount mnt + sudo ./memfs3 -o allow_other,default_permissions,use_ino,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,use_ino,attr_timeout=0 p mnt & sleep 3 (cd mnt && sudo prove -fr ../secfs.test/fstest/fstest/tests) @@ -143,17 +184,19 @@ jobs: rm -rf p rmdir mnt - - name: Build packages with fuse3 (Linux) + - name: Build packages with FUSE3 (Linux) if: runner.os == 'Linux' run: | go build -tags=fuse3 -v -o . ./... - go test -v -count=1 ./fuse + go build -tags=fuse3,memfs3 -v -o memfs3${{ matrix.exe }} ./examples/memfs - - name: Test file systems (Linux) with fuse3 + - name: Test file systems with FUSE3 (Linux) if: runner.os == 'Linux' run: | set -x + go test -tags=fuse3 -v -count=1 ./fuse + mkdir p mnt sudo ./memfs -o allow_other,default_permissions,attr_timeout=0 mnt & @@ -163,6 +206,13 @@ jobs: (cd mnt && ../secfs.test/tools/bin/fsx -e -N 1000 test xxxx) sudo umount mnt + sudo ./memfs3 -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) diff --git a/examples/hellofs/hellofs.go b/examples/hellofs/hellofs.go index 8b58555..e4d7687 100644 --- a/examples/hellofs/hellofs.go +++ b/examples/hellofs/hellofs.go @@ -64,7 +64,8 @@ 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) (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 d18ed7d..97cb930 100644 --- a/examples/memfs/memfs.go +++ b/examples/memfs/memfs.go @@ -231,7 +231,7 @@ func (self *Memfs) Utimens(path string, tmsp []fuse.Timespec) (errc int) { return -fuse.ENOENT } node.stat.Ctim = fuse.Now() - if tmsp == nil || (len(tmsp) == 2 && tmsp[0].Sec == 0 && tmsp[1].Sec == 0) { + if nil == tmsp { tmsp0 := node.stat.Ctim tmsa := [2]fuse.Timespec{tmsp0, tmsp0} tmsp = tmsa[:] @@ -244,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, flags) + return self.openNode(path, false) } func (self *Memfs) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) { @@ -320,7 +320,7 @@ 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, 0) + return self.openNode(path, true) } func (self *Memfs) Readdir(path string, @@ -526,7 +526,7 @@ func (self *Memfs) removeNode(path string, dir bool) int { return 0 } -func (self *Memfs) openNode(path string, dir bool, flags int) (int, uint64) { +func (self *Memfs) openNode(path string, dir bool) (int, uint64) { _, _, node := self.lookupNode(path, nil) if nil == node { return -fuse.ENOENT, ^uint64(0) @@ -537,13 +537,6 @@ func (self *Memfs) openNode(path string, dir bool, flags int) (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 @@ -553,12 +546,9 @@ func (self *Memfs) openNode(path string, dir bool, flags int) (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, fh) + delete(self.openmap, node.stat.Ino) } return 0 } @@ -596,6 +586,6 @@ func main() { memfs := NewMemfs() host := fuse.NewFileSystemHost(memfs) host.SetCapReaddirPlus(true) - host.SetUseIno(true) + host.SetUseIno(true) // FUSE3 only host.Mount("", os.Args[1:]) } diff --git a/examples/memfs/memfs3.go b/examples/memfs/memfs3.go new file mode 100644 index 0000000..a758936 --- /dev/null +++ b/examples/memfs/memfs3.go @@ -0,0 +1,108 @@ +//go:build memfs3 +// +build memfs3 + +/* + * memfs3.go + * + * Copyright 2017-2022 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 ( + "github.com/winfsp/cgofuse/fuse" +) + +func (self *Memfs) Rename3(oldpath string, newpath string, flags uint32) (errc int) { + defer trace(oldpath, newpath)(&errc) + defer self.synchronize()() + if 0 != flags&^fuse.RENAME_NOREPLACE { + // we only support NOREPLACE + return -fuse.EINVAL + } + 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 { + if fuse.RENAME_NOREPLACE == flags&fuse.RENAME_NOREPLACE { + return -fuse.EEXIST + } + 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) Chmod3(path string, mode uint32, fh uint64) (errc int) { + defer trace(path, mode, fh)(&errc) + defer self.synchronize()() + node := self.getNode(path, fh) + 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) Chown3(path string, uid uint32, gid uint32, fh uint64) (errc int) { + defer trace(path, uid, gid, fh)(&errc) + defer self.synchronize()() + node := self.getNode(path, fh) + 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) Utimens3(path string, tmsp []fuse.Timespec, fh uint64) (errc int) { + defer trace(path, tmsp, fh)(&errc) + defer self.synchronize()() + node := self.getNode(path, fh) + if nil == node { + return -fuse.ENOENT + } + node.stat.Ctim = fuse.Now() + if nil == tmsp { + tmsp0 := node.stat.Ctim + tmsa := [2]fuse.Timespec{tmsp0, tmsp0} + tmsp = tmsa[:] + } + node.stat.Atim = tmsp[0] + node.stat.Mtim = tmsp[1] + return 0 +} + +var _ fuse.FileSystemRename3 = (*Memfs)(nil) +var _ fuse.FileSystemChmod3 = (*Memfs)(nil) +var _ fuse.FileSystemChown3 = (*Memfs)(nil) +var _ fuse.FileSystemRename3 = (*Memfs)(nil) diff --git a/examples/passthrough/passthrough.go b/examples/passthrough/passthrough.go index 5db36cc..06629cb 100644 --- a/examples/passthrough/passthrough.go +++ b/examples/passthrough/passthrough.go @@ -1,4 +1,3 @@ -//go:build darwin || freebsd || netbsd || openbsd || linux // +build darwin freebsd netbsd openbsd linux /* @@ -265,6 +264,6 @@ func main() { args = append(args[:len(args)-2], args[len(args)-1]) } _host = fuse.NewFileSystemHost(&ptfs) - _host.SetUseIno(true) + _host.SetUseIno(true) // FUSE3 only _host.Mount("", args[1:]) } diff --git a/examples/passthrough/port_darwin.go b/examples/passthrough/port_darwin.go index 5f50344..6ccf30c 100644 --- a/examples/passthrough/port_darwin.go +++ b/examples/passthrough/port_darwin.go @@ -1,4 +1,3 @@ -//go:build darwin // +build darwin /* diff --git a/examples/passthrough/port_freebsd.go b/examples/passthrough/port_freebsd.go index 4911e25..1d794af 100644 --- a/examples/passthrough/port_freebsd.go +++ b/examples/passthrough/port_freebsd.go @@ -1,4 +1,3 @@ -//go:build freebsd // +build freebsd /* diff --git a/examples/passthrough/port_linux.go b/examples/passthrough/port_linux.go index 5615ef6..6f512ee 100644 --- a/examples/passthrough/port_linux.go +++ b/examples/passthrough/port_linux.go @@ -1,4 +1,3 @@ -//go:build linux // +build linux /* diff --git a/examples/passthrough/port_netbsd.go b/examples/passthrough/port_netbsd.go index 107e322..f664637 100644 --- a/examples/passthrough/port_netbsd.go +++ b/examples/passthrough/port_netbsd.go @@ -1,4 +1,3 @@ -//go:build netbsd // +build netbsd /* diff --git a/examples/passthrough/port_openbsd.go b/examples/passthrough/port_openbsd.go index 5d4515e..c309f0e 100644 --- a/examples/passthrough/port_openbsd.go +++ b/examples/passthrough/port_openbsd.go @@ -1,4 +1,3 @@ -//go:build openbsd // +build openbsd /* diff --git a/fuse/fsop.go b/fuse/fsop.go index c8b33a2..20b1176 100644 --- a/fuse/fsop.go +++ b/fuse/fsop.go @@ -313,25 +313,6 @@ type FileSystemInterface interface { Listxattr(path string, fill func(name string) bool) int } -// FileSystemFuse3 is the interface that wraps the fuse3 equivalent methods. -// -// ChmodFuse3, ChownFuse3, and UtimensFuse3 each similar to Chmod, Chown, and -// Utimens except they include a file handle that could be null and only work -// on with Fuse3. -// -// RenameFuse3 and ReaddirFuse3 are similar to Rename and Readir except that they -// include additional flags. -type FileSystemFuse3 interface { - ChmodFuse3(path string, mode uint32, fh uint64) int - ChownFuse3(path string, uid uint32, gid uint32, fh uint64) int - UtimensFuse3(path string, tmsp []Timespec, fh uint64) int - RenameFuse3(oldpath string, newpath string, flags uint32) int - ReaddirFuse3(path string, - fill func(name string, stat *Stat_t, ofst int64) bool, - ofst int64, - fh uint64, flags uint32) int -} - // FileSystemOpenEx is the interface that wraps the OpenEx and CreateEx methods. // // OpenEx and CreateEx are similar to Open and Create except that they allow @@ -370,6 +351,38 @@ type FileSystemSetchgtime interface { Setchgtime(path string, tmsp Timespec) int } +// FileSystemChmod3 is the interface that wraps the FUSE3 Chmod method. +// +// Chmod3 is similar to Chmod except that it includes a file handle that is +// available only under FUSE3. +type FileSystemChmod3 interface { + Chmod3(path string, mode uint32, fh uint64) int +} + +// FileSystemChown3 is the interface that wraps the FUSE3 Chown method. +// +// Chown3 is similar to Chown except that it includes a file handle that is +// available only under FUSE3. +type FileSystemChown3 interface { + Chown3(path string, uid uint32, gid uint32, fh uint64) int +} + +// FileSystemUtimens3 is the interface that wraps the FUSE3 Utimens method. +// +// Utimens3 is similar to Utimens except that it includes a file handle that is +// available only under FUSE3. +type FileSystemUtimens3 interface { + Utimens3(path string, tmsp []Timespec, fh uint64) int +} + +// FileSystemRename3 is the interface that wraps the FUSE3 Rename method. +// +// Rename3 is similar to Rename except that it includes flags that are +// available only under FUSE3. +type FileSystemRename3 interface { + Rename3(oldpath string, newpath string, flags uint32) 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 diff --git a/fuse/fsop_cgo.go b/fuse/fsop_cgo.go index 88c792f..7731095 100644 --- a/fuse/fsop_cgo.go +++ b/fuse/fsop_cgo.go @@ -303,6 +303,19 @@ const ( XATTR_REPLACE = int(C.XATTR_REPLACE) ) +// Flags used in Utimens and Utimens3. +const ( + UTIME_NOW = (1 << 30) - 1 + UTIME_OMIT = (1 << 30) - 2 +) + +// Flags used in FileSystemRename3.Rename3. +const ( + RENAME_NOREPLACE = 1 << 0 + RENAME_EXCHANGE = 1 << 1 + RENAME_WHITEOUT = 1 << 2 +) + // Notify actions. const ( NOTIFY_MKDIR = 0x0001 diff --git a/fuse/fsop_nocgo_windows.go b/fuse/fsop_nocgo_windows.go index 9be8d61..29be083 100644 --- a/fuse/fsop_nocgo_windows.go +++ b/fuse/fsop_nocgo_windows.go @@ -161,6 +161,19 @@ const ( XATTR_REPLACE = 2 ) +// Flags used in Utimens and Utimens3. +const ( + UTIME_NOW = (1 << 30) - 1 + UTIME_OMIT = (1 << 30) - 2 +) + +// Flags used in FileSystemRename3.Rename3. +const ( + RENAME_NOREPLACE = 1 << 0 + RENAME_EXCHANGE = 1 << 1 + RENAME_WHITEOUT = 1 << 2 +) + // Notify actions. const ( NOTIFY_MKDIR = 0x0001 diff --git a/fuse/host.go b/fuse/host.go index 17f57a4..083c03c 100644 --- a/fuse/host.go +++ b/fuse/host.go @@ -31,8 +31,12 @@ type FileSystemHost struct { mntp string sigc chan os.Signal - capCaseInsensitive, capReaddirPlus, capDeleteAccess bool - directIO, useIno bool + capCaseInsensitive bool + capReaddirPlus bool + capDeleteAccess bool + capOpenTrunc bool + directIO bool + useIno bool } var ( @@ -112,8 +116,7 @@ func recoverAsErrno(errc0 *c_int) { } } -func hostGetattr(path0 *c_char, stat0 *c_fuse_stat_t, - fi0 *c_struct_fuse_file_info) (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) @@ -185,11 +188,15 @@ func hostRename(oldpath0 *c_char, newpath0 *c_char, flags c_uint32_t) (errc0 c_i defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop oldpath, newpath := c_GoString(oldpath0), c_GoString(newpath0) - intf, ok := fsop.(FileSystemFuse3) + intf, ok := fsop.(FileSystemRename3) if ok { - errc := intf.RenameFuse3(oldpath, newpath, uint32(flags)) + errc := intf.Rename3(oldpath, newpath, uint32(flags)) return c_int(errc) } else { + if 0 != flags { + // man 2 rename: EINVAL when "the filesystem does not support one of the flags" + return -c_int(EINVAL) + } errc := fsop.Rename(oldpath, newpath) return c_int(errc) } @@ -207,13 +214,13 @@ func hostChmod(path0 *c_char, mode0 c_fuse_mode_t, fi0 *c_struct_fuse_file_info) defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop path := c_GoString(path0) - intf, ok := fsop.(FileSystemFuse3) + intf, ok := fsop.(FileSystemChmod3) if ok { fifh := ^uint64(0) if nil != fi0 { fifh = uint64(fi0.fh) } - errc := intf.ChmodFuse3(path, uint32(mode0), fifh) + errc := intf.Chmod3(path, uint32(mode0), fifh) return c_int(errc) } else { errc := fsop.Chmod(path, uint32(mode0)) @@ -225,13 +232,13 @@ func hostChown(path0 *c_char, uid0 c_fuse_uid_t, gid0 c_fuse_gid_t, fi0 *c_struc defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop path := c_GoString(path0) - intf, ok := fsop.(FileSystemFuse3) + intf, ok := fsop.(FileSystemChown3) if ok { fifh := ^uint64(0) if nil != fi0 { fifh = uint64(fi0.fh) } - errc := intf.ChownFuse3(path, uint32(uid0), uint32(gid0), fifh) + errc := intf.Chown3(path, uint32(uid0), uint32(gid0), fifh) return c_int(errc) } else { errc := fsop.Chown(path, uint32(uid0), uint32(gid0)) @@ -411,7 +418,7 @@ 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, flags c_fuse_readdir_flags_t) (errc0 c_int) { + 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) @@ -427,14 +434,8 @@ 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)) } } - intf, ok := fsop.(FileSystemFuse3) - if ok { - errc := intf.ReaddirFuse3(path, fill, int64(ofst0), uint64(fi0.fh), uint32(flags)) - return c_int(errc) - } else { - errc := fsop.Readdir(path, fill, int64(ofst0), uint64(fi0.fh)) - return c_int(errc) - } + errc := fsop.Readdir(path, fill, int64(ofst0), uint64(fi0.fh)) + return c_int(errc) } func hostReleasedir(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 c_int) { @@ -456,7 +457,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, cfg *c_struct_fuse_config) (user_data unsafe.Pointer) { +func hostInit(conn0 *c_struct_fuse_conn_info, conf0 *c_struct_fuse_config) (user_data unsafe.Pointer) { defer func() { recover() }() @@ -467,8 +468,9 @@ func hostInit(conn0 *c_struct_fuse_conn_info, cfg *c_struct_fuse_config) (user_d c_hostAsgnCconninfo(conn0, c_bool(host.capCaseInsensitive), c_bool(host.capReaddirPlus), - c_bool(host.capDeleteAccess)) - c_hostAsgnCconfig(cfg, + c_bool(host.capDeleteAccess), + c_bool(host.capOpenTrunc)) + c_hostAsgnCconfig(conf0, c_bool(host.directIO), c_bool(host.useIno)) if nil != host.sigc { @@ -557,35 +559,29 @@ func hostUtimens(path0 *c_char, tmsp0 *c_fuse_timespec_t, fi0 *c_struct_fuse_fil defer recoverAsErrno(&errc0) fsop := hostHandleGet(c_fuse_get_context().private_data).fsop path := c_GoString(path0) - intf, ok := fsop.(FileSystemFuse3) + tmsp := [2]Timespec{} + if nil == tmsp0 { + tmsp[0] = Now() + tmsp[1] = tmsp[0] + } else if tmsa := (*[2]c_fuse_timespec_t)(unsafe.Pointer(tmsp0)); UTIME_NOW == tmsa[0].tv_nsec && + UTIME_NOW == tmsa[1].tv_nsec { + tmsp[0] = Now() + tmsp[1] = tmsp[0] + } else { + copyFusetimespecFromCtimespec(&tmsp[0], &tmsa[0]) + copyFusetimespecFromCtimespec(&tmsp[1], &tmsa[1]) + } + intf, ok := fsop.(FileSystemUtimens3) if ok { fifh := ^uint64(0) if nil != fi0 { fifh = uint64(fi0.fh) } - if tmsp0 == nil { - errc := intf.UtimensFuse3(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 := intf.UtimensFuse3(path, tmsp[:], fifh) - return c_int(errc) - } + errc := intf.Utimens3(path, tmsp[:], fifh) + return c_int(errc) } else { - if tmsp0 == nil { - errc := fsop.Utimens(path, nil) - 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[:]) - return c_int(errc) - } + errc := fsop.Utimens(path, tmsp[:]) + return c_int(errc) } } @@ -682,13 +678,19 @@ func (host *FileSystemHost) SetCapDeleteAccess(value bool) { host.capDeleteAccess = value } -// SetDirectIO causes the file system to disable page caching [Fuse3 only]. Must be set +// SetCapOpenTrunc informs the host that the hosted file system can handle the O_TRUNC +// Open flag [Linux only]. +func (host *FileSystemHost) SetCapOpenTrunc(value bool) { + host.capOpenTrunc = 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 +// 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 @@ -699,10 +701,10 @@ func (host *FileSystemHost) SetUseIno(value bool) { // 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. // @@ -912,48 +914,49 @@ 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 34cda0b..3e05613 100644 --- a/fuse/host_cgo.go +++ b/fuse/host_cgo.go @@ -16,18 +16,14 @@ 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 !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 freebsd,!fuse3 CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -I/usr/local/include/fuse +#cgo freebsd,fuse3 CFLAGS: -DFUSE_USE_VERSION=39 -D_FILE_OFFSET_BITS=64 -I/usr/local/include/fuse3 +#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,!fuse3 CFLAGS: -DFUSE_USE_VERSION=28 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse +#cgo linux,fuse3 CFLAGS: -DFUSE_USE_VERSION=39 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3 +#cgo 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. @@ -120,11 +116,7 @@ static void cgofuse_init_fail(void) #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__linux__) -#if FUSE_USE_VERSION >= 30 - #include -#else - #include -#endif +#include #if defined(__OpenBSD__) static int (*pfn_fuse_main)(int argc, char *argv[], @@ -185,28 +177,20 @@ static void *cgofuse_init_fuse(void) if (0 == h) h = dlopen("/usr/local/lib/libfuse-t.dylib", RTLD_NOW); // FUSE-T #elif defined(__FreeBSD__) -#if FUSE_USE_VERSION >= 30 - h = dlopen("libfuse3.so.3", RTLD_NOW); +#if FUSE_USE_VERSION < 30 + h = dlopen("libfuse.so.2", RTLD_NOW); #else - h = dlopen("libfuse.so.2", RTLD_NOW); -#endif -#elif defined(__NetBSD__) -#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); #elif defined(__OpenBSD__) -#if FUSE_USE_VERSION >= 30 - h = dlopen("libfuse3.so.3", RTLD_NOW); -#else - h = dlopen("libfuse.so.2", RTLD_NOW); -#endif + h = dlopen("libfuse.so.2.0", RTLD_NOW); #elif defined(__linux__) -#if FUSE_USE_VERSION >= 30 - h = dlopen("libfuse3.so.3", RTLD_NOW); +#if FUSE_USE_VERSION < 30 + h = dlopen("libfuse.so.2", RTLD_NOW); #else - h = dlopen("libfuse.so.2", RTLD_NOW); + h = dlopen("libfuse3.so.3", RTLD_NOW); #endif #endif if (0 == h) @@ -347,19 +331,18 @@ typedef struct fuse_timespec fuse_timespec_t; typedef unsigned int fuse_opt_offset_t; #endif -#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; +#if FUSE_USE_VERSION < 30 struct fuse_config; + enum fuse_readdir_flags + { + fuse_readdir_flags_DUMMY + }; #endif -#if FUSE_USE_VERSION >= 30 -extern int go_hostGetattrFuse3(char *path, fuse_stat_t *stbuf, struct fuse_file_info *fi); +#if FUSE_USE_VERSION < 30 +extern int go_hostGetattr(char *path, fuse_stat_t *stbuf); #else -extern int go_hostGetattrFuse2(char *path, fuse_stat_t *stbuf); +extern int go_hostGetattr3(char *path, fuse_stat_t *stbuf, struct fuse_file_info *fi); #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); @@ -367,20 +350,20 @@ 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); -#if FUSE_USE_VERSION >= 30 -extern int go_hostRenameFuse3(char *oldpath, char *newpath, unsigned int flags); +#if FUSE_USE_VERSION < 30 +extern int go_hostRename(char *oldpath, char *newpath); #else -extern int go_hostRenameFuse2(char *oldpath, char *newpath); +extern int go_hostRename3(char *oldpath, char *newpath, unsigned int flags); #endif extern int go_hostLink(char *oldpath, char *newpath); -#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); +#if FUSE_USE_VERSION < 30 +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); #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); +extern int go_hostChmod3(char *path, fuse_mode_t mode, struct fuse_file_info *fi); +extern int go_hostChown3(char *path, fuse_uid_t uid, fuse_gid_t gid, struct fuse_file_info *fi); +extern int go_hostTruncate3(char *path, fuse_off_t size, struct fuse_file_info *fi); #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, @@ -396,19 +379,19 @@ 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); -#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, +#if FUSE_USE_VERSION < 30 +extern int go_hostReaddir(char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off, struct fuse_file_info *fi); +#else +extern int go_hostReaddir3(char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off, + struct fuse_file_info *fi, enum fuse_readdir_flags flags); #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); -#if FUSE_USE_VERSION >= 30 -extern void *go_hostInitFuse3(struct fuse_conn_info *conn, struct fuse_config *cfg); +#if FUSE_USE_VERSION < 30 +extern void *go_hostInit(struct fuse_conn_info *conn); #else -extern void *go_hostInitFuse2(struct fuse_conn_info *conn); +extern void *go_hostInit3(struct fuse_conn_info *conn, struct fuse_config *conf); #endif extern void go_hostDestroy(void *data); extern int go_hostAccess(char *path, int mask); @@ -418,10 +401,10 @@ extern int go_hostFtruncate(char *path, fuse_off_t off, struct fuse_file_info *f 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); -#if FUSE_USE_VERSION >= 30 -extern int go_hostUtimensFuse3(char *path, fuse_timespec_t tv[2], struct fuse_file_info *fi); +#if FUSE_USE_VERSION < 30 +extern int go_hostUtimens(char *path, fuse_timespec_t tv[2]); #else -extern int go_hostUtimensFuse2(char *path, fuse_timespec_t tv[2]); +extern int go_hostUtimens3(char *path, fuse_timespec_t tv[2], struct fuse_file_info *fi); #endif extern int go_hostGetpath(char *path, char *buf, size_t size, struct fuse_file_info *fi); @@ -432,12 +415,20 @@ extern int go_hostChflags(char *path, uint32_t flags); static inline void hostAsgnCconninfo(struct fuse_conn_info *conn, bool capCaseInsensitive, bool capReaddirPlus, - bool capDeleteAccess) + bool capDeleteAccess, + bool capOpenTrunc) { #if defined(__APPLE__) if (capCaseInsensitive) FUSE_ENABLE_CASE_INSENSITIVE(conn); -#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__linux__) +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#elif defined(__linux__) + // FUSE_CAP_ATOMIC_O_TRUNC was disabled in FUSE2 and is enabled in FUSE3. + // So disable it here, unless the user explicitly enables it. + if (capOpenTrunc) + conn->want |= conn->capable & FUSE_CAP_ATOMIC_O_TRUNC; + else + conn->want &= ~FUSE_CAP_ATOMIC_O_TRUNC; #elif defined(_WIN32) #if defined(FSP_FUSE_CAP_STAT_EX) conn->want |= conn->capable & FSP_FUSE_CAP_STAT_EX; @@ -452,21 +443,21 @@ static inline void hostAsgnCconninfo(struct fuse_conn_info *conn, #endif } -#if FUSE_USE_VERSION >= 30 -static inline void hostAsgnCconfig(struct fuse_config *cfg, +#if FUSE_USE_VERSION < 30 +static inline void hostAsgnCconfig(struct fuse_config *conf, 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, +static inline void hostAsgnCconfig(struct fuse_config *conf, bool direct_io, bool use_ino) -{} +{ + memset(conf, 0, sizeof *conf); + conf->direct_io = direct_io; + conf->use_ino = use_ino; +} #endif static inline void hostCstatvfsFromFusestatfs(fuse_statvfs_t *stbuf, @@ -581,10 +572,10 @@ 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 +#if FUSE_USE_VERSION < 30 return filler(buf, name, stbuf, off); +#else + return filler(buf, name, stbuf, off, FUSE_FILL_DIR_PLUS); #endif } @@ -627,10 +618,10 @@ static int hostMount(int argc, char *argv[], void *data) { static struct fuse_operations fsop = { -#if FUSE_USE_VERSION >= 30 - .getattr = (int (*)(const char *, fuse_stat_t *, struct fuse_file_info *))go_hostGetattrFuse3, +#if FUSE_USE_VERSION < 30 + .getattr = (int (*)(const char *, fuse_stat_t *))go_hostGetattr, #else - .getattr = (int (*)(const char *, fuse_stat_t *))go_hostGetattrFuse2, + .getattr = (int (*)(const char *, fuse_stat_t *, struct fuse_file_info *))go_hostGetattr3, #endif .readlink = (int (*)(const char *, char *, size_t))go_hostReadlink, .mknod = (int (*)(const char *, fuse_mode_t, fuse_dev_t))go_hostMknod, @@ -638,20 +629,20 @@ static int hostMount(int argc, char *argv[], void *data) .unlink = (int (*)(const char *))go_hostUnlink, .rmdir = (int (*)(const char *))go_hostRmdir, .symlink = (int (*)(const char *, const char *))go_hostSymlink, -#if FUSE_USE_VERSION >= 30 - .rename = (int (*)(const char *, const char *, unsigned int flags))go_hostRenameFuse3, +#if FUSE_USE_VERSION < 30 + .rename = (int (*)(const char *, const char *))go_hostRename, #else - .rename = (int (*)(const char *, const char *))go_hostRenameFuse2, + .rename = (int (*)(const char *, const char *, unsigned int flags))go_hostRename3, #endif .link = (int (*)(const char *, const char *))go_hostLink, -#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, +#if FUSE_USE_VERSION < 30 + .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, #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, + .chmod = (int (*)(const char *, fuse_mode_t, struct fuse_file_info *))go_hostChmod3, + .chown = (int (*)(const char *, fuse_uid_t, fuse_gid_t, struct fuse_file_info *))go_hostChown3, + .truncate = (int (*)(const char *, fuse_off_t, struct fuse_file_info *))go_hostTruncate3, #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 *)) @@ -674,19 +665,19 @@ 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 +#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, + struct fuse_file_info *))go_hostReaddir, #else .readdir = (int (*)(const char *, void *, fuse_fill_dir_t, fuse_off_t, - struct fuse_file_info *))go_hostReaddirFuse2, + struct fuse_file_info *, enum fuse_readdir_flags flags))go_hostReaddir3, #endif .releasedir = (int (*)(const char *, struct fuse_file_info *))go_hostReleasedir, .fsyncdir = (int (*)(const char *, int, struct fuse_file_info *))go_hostFsyncdir, -#if FUSE_USE_VERSION >= 30 - .init = (void *(*)(struct fuse_conn_info *, struct fuse_config *))go_hostInitFuse3, +#if FUSE_USE_VERSION < 30 + .init = (void *(*)(struct fuse_conn_info *))go_hostInit, #else - .init = (void *(*)(struct fuse_conn_info *))go_hostInitFuse2, + .init = (void *(*)(struct fuse_conn_info *, struct fuse_config *))go_hostInit3, #endif .destroy = (void (*)(void *))go_hostDestroy, .access = (int (*)(const char *, int))go_hostAccess, @@ -697,10 +688,10 @@ static int hostMount(int argc, char *argv[], void *data) #endif //.lock = (int (*)(const char *, struct fuse_file_info *, int, struct fuse_flock *)) // go_hostFlock, -#if FUSE_USE_VERSION >= 30 - .utimens = (int (*)(const char *, const fuse_timespec_t [2], struct fuse_file_info *))go_hostUtimensFuse3, +#if FUSE_USE_VERSION < 30 + .utimens = (int (*)(const char *, const fuse_timespec_t [2]))go_hostUtimens, #else - .utimens = (int (*)(const char *, const fuse_timespec_t [2]))go_hostUtimensFuse2, + .utimens = (int (*)(const char *, const fuse_timespec_t [2], struct fuse_file_info *))go_hostUtimens3, #endif #if defined(__APPLE__) || (defined(_WIN32) && defined(FSP_FUSE_CAP_STAT_EX)) .setchgtime = (int (*)(const char *, const fuse_timespec_t *))go_hostSetchgtime, @@ -829,39 +820,39 @@ import "C" import "unsafe" type ( - c_bool = C.bool - c_char = C.char - c_fuse_dev_t = C.fuse_dev_t - c_fuse_fill_dir_t = C.fuse_fill_dir_t - c_fuse_gid_t = C.fuse_gid_t - 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 - c_fuse_timespec_t = C.fuse_timespec_t - c_fuse_uid_t = C.fuse_uid_t - c_int = C.int - c_int16_t = C.int16_t - c_int32_t = C.int32_t - c_int64_t = C.int64_t - c_int8_t = C.int8_t - 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 - c_struct_fuse_opt = C.struct_fuse_opt - c_uint16_t = C.uint16_t - c_uint32_t = C.uint32_t - c_uint64_t = C.uint64_t - c_uint8_t = C.uint8_t - c_uintptr_t = C.uintptr_t - c_unsigned = C.unsigned + c_bool = C.bool + c_char = C.char + c_fuse_dev_t = C.fuse_dev_t + c_fuse_fill_dir_t = C.fuse_fill_dir_t + c_fuse_gid_t = C.fuse_gid_t + 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_enum_fuse_readdir_flags = C.enum_fuse_readdir_flags + 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 + c_fuse_timespec_t = C.fuse_timespec_t + c_fuse_uid_t = C.fuse_uid_t + c_int = C.int + c_int16_t = C.int16_t + c_int32_t = C.int32_t + c_int64_t = C.int64_t + c_int8_t = C.int8_t + 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 + c_struct_fuse_opt = C.struct_fuse_opt + c_uint16_t = C.uint16_t + c_uint32_t = C.uint32_t + c_uint64_t = C.uint64_t + c_uint8_t = C.uint8_t + c_uintptr_t = C.uintptr_t + c_unsigned = C.unsigned ) func c_GoString(s *c_char) string { @@ -891,13 +882,14 @@ func c_fuse_opt_free_args(args *c_struct_fuse_args) { func c_hostAsgnCconninfo(conn *c_struct_fuse_conn_info, capCaseInsensitive c_bool, capReaddirPlus c_bool, - capDeleteAccess c_bool) { - C.hostAsgnCconninfo(conn, capCaseInsensitive, capReaddirPlus, capDeleteAccess) + capDeleteAccess c_bool, + capOpenTrunc c_bool) { + C.hostAsgnCconninfo(conn, capCaseInsensitive, capReaddirPlus, capDeleteAccess, capOpenTrunc) } -func c_hostAsgnCconfig(cfg *c_struct_fuse_config, +func c_hostAsgnCconfig(conf *c_struct_fuse_config, directIO c_bool, useIno c_bool) { - C.hostAsgnCconfig(cfg, directIO, useIno) + C.hostAsgnCconfig(conf, directIO, useIno) } func c_hostCstatvfsFromFusestatfs(stbuf *c_fuse_statvfs_t, bsize c_uint64_t, @@ -1000,15 +992,15 @@ func c_hostOptParse(args *c_struct_fuse_args, data unsafe.Pointer, opts *c_struc return C.hostOptParse(args, data, opts, nonopts) } -//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_hostGetattr +func go_hostGetattr(path0 *c_char, stat0 *c_fuse_stat_t) (errc0 c_int) { + return hostGetattr(path0, stat0, nil) } -//export go_hostGetattrFuse2 -func go_hostGetattrFuse2(path0 *c_char, stat0 *c_fuse_stat_t) (errc0 c_int) { - return hostGetattr(path0, stat0, nil) +//export go_hostGetattr3 +func go_hostGetattr3(path0 *c_char, stat0 *c_fuse_stat_t, + fi0 *c_struct_fuse_file_info) (errc0 c_int) { + return hostGetattr(path0, stat0, fi0) } //export go_hostReadlink @@ -1041,14 +1033,14 @@ func go_hostSymlink(target0 *c_char, newpath0 *c_char) (errc0 c_int) { return hostSymlink(target0, 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_hostRename +func go_hostRename(oldpath0 *c_char, newpath0 *c_char) (errc0 c_int) { + return hostRename(oldpath0, newpath0, 0) } -//export go_hostRenameFuse2 -func go_hostRenameFuse2(oldpath0 *c_char, newpath0 *c_char) (errc0 c_int) { - return hostRename(oldpath0, newpath0, 0) +//export go_hostRename3 +func go_hostRename3(oldpath0 *c_char, newpath0 *c_char, flags c_uint32_t) (errc0 c_int) { + return hostRename(oldpath0, newpath0, flags) } //export go_hostLink @@ -1056,37 +1048,37 @@ func go_hostLink(oldpath0 *c_char, newpath0 *c_char) (errc0 c_int) { return hostLink(oldpath0, newpath0) } -//export go_hostChmodFuse3 -func go_hostChmodFuse3(path0 *c_char, mode0 c_fuse_mode_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { +//export go_hostChmod +func go_hostChmod(path0 *c_char, mode0 c_fuse_mode_t) (errc0 c_int) { + return hostChmod(path0, mode0, nil) +} + +//export go_hostChmod3 +func go_hostChmod3(path0 *c_char, mode0 c_fuse_mode_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { return hostChmod(path0, mode0, fi0) } -//export go_hostChmodFuse2 -func go_hostChmodFuse2(path0 *c_char, mode0 c_fuse_mode_t) (errc0 c_int) { - return hostChmod(path0, mode0, nil) +//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, nil) } -//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) { +//export go_hostChown3 +func go_hostChown3(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_hostTruncate +func go_hostTruncate(path0 *c_char, size0 c_fuse_off_t) (errc0 c_int) { + return hostTruncate(path0, size0, nil) } -//export go_hostTruncateFuse3 -func go_hostTruncateFuse3(path0 *c_char, size0 c_fuse_off_t, +//export go_hostTruncate3 +func go_hostTruncate3(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 func go_hostOpen(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 c_int) { return hostOpen(path0, fi0) @@ -1150,18 +1142,18 @@ func go_hostOpendir(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 c_int) { return hostOpendir(path0, fi0) } -//export go_hostReaddirFuse3 -func go_hostReaddirFuse3(path0 *c_char, +//export go_hostReaddir +func go_hostReaddir(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) + fi0 *c_struct_fuse_file_info) (errc0 c_int) { + return hostReaddir(path0, buff0, fill0, ofst0, fi0) } -//export go_hostReaddirFuse2 -func go_hostReaddirFuse2(path0 *c_char, +//export go_hostReaddir3 +func go_hostReaddir3(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, 0) + fi0 *c_struct_fuse_file_info, flags c_enum_fuse_readdir_flags) (errc0 c_int) { + return hostReaddir(path0, buff0, fill0, ofst0, fi0) } //export go_hostReleasedir @@ -1174,14 +1166,14 @@ func go_hostFsyncdir(path0 *c_char, datasync c_int, fi0 *c_struct_fuse_file_info return hostFsyncdir(path0, datasync, fi0) } -//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_hostInit +func go_hostInit(conn0 *c_struct_fuse_conn_info) (user_data unsafe.Pointer) { + return hostInit(conn0, nil) } -//export go_hostInitFuse2 -func go_hostInitFuse2(conn0 *c_struct_fuse_conn_info) (user_data unsafe.Pointer) { - return hostInit(conn0, nil) +//export go_hostInit3 +func go_hostInit3(conn0 *c_struct_fuse_conn_info, conf0 *c_struct_fuse_config) (user_data unsafe.Pointer) { + return hostInit(conn0, conf0) } //export go_hostDestroy @@ -1211,14 +1203,14 @@ func go_hostFgetattr(path0 *c_char, stat0 *c_fuse_stat_t, return hostFgetattr(path0, stat0, fi0) } -//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_hostUtimens +func go_hostUtimens(path0 *c_char, tmsp0 *c_fuse_timespec_t) (errc0 c_int) { + return hostUtimens(path0, tmsp0, nil) } -//export go_hostUtimensFuse2 -func go_hostUtimensFuse2(path0 *c_char, tmsp0 *c_fuse_timespec_t) (errc0 c_int) { - return hostUtimens(path0, tmsp0, nil) +//export go_hostUtimens3 +func go_hostUtimens3(path0 *c_char, tmsp0 *c_fuse_timespec_t, fi0 *c_struct_fuse_file_info) (errc0 c_int) { + return hostUtimens(path0, tmsp0, fi0) } //export go_hostGetpath diff --git a/fuse/host_nocgo_windows.go b/fuse/host_nocgo_windows.go index ed5d474..6d0b26f 100644 --- a/fuse/host_nocgo_windows.go +++ b/fuse/host_nocgo_windows.go @@ -86,26 +86,6 @@ 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 @@ -163,31 +143,6 @@ type struct_fuse_args struct { } 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 { @@ -228,7 +183,6 @@ 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 @@ -242,7 +196,6 @@ 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 @@ -356,7 +309,8 @@ func c_fuse_opt_free_args(args *c_struct_fuse_args) { func c_hostAsgnCconninfo(conn *c_struct_fuse_conn_info, capCaseInsensitive c_bool, capReaddirPlus c_bool, - capDeleteAccess c_bool) { + capDeleteAccess c_bool, + capOpenTrunc c_bool) { conn.want |= conn.capable & FSP_FUSE_CAP_STAT_EX cgofuse_stat_ex = 0 != conn.want&FSP_FUSE_CAP_STAT_EX // hack! if capCaseInsensitive { @@ -369,7 +323,7 @@ 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, +func c_hostAsgnCconfig(conf *c_struct_fuse_config, directIO c_bool, useIno c_bool) { } @@ -839,7 +793,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, 0))) + return uintptr(int(hostReaddir(path0, buff0, fill0, c_fuse_off_t(ofst0), fi0))) } func go_hostReleasedir64(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 uintptr) { @@ -1006,7 +960,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, 0))) + buff0, fill0, (c_fuse_off_t(hofst0)<<32)|c_fuse_off_t(lofst0), fi0))) } func go_hostReleasedir32(path0 *c_char, fi0 *c_struct_fuse_file_info) (errc0 uintptr) {