diff --git a/Godeps/_workspace/src/bazil.org/fuse/.gitattributes b/Godeps/_workspace/src/bazil.org/fuse/.gitattributes deleted file mode 100644 index b65f2a9ff..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -*.go filter=gofmt -*.cgo filter=gofmt diff --git a/Godeps/_workspace/src/bazil.org/fuse/.gitignore b/Godeps/_workspace/src/bazil.org/fuse/.gitignore deleted file mode 100644 index 2b286ca94..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -*~ -.#* -## the next line needs to start with a backslash to avoid looking like -## a comment -\#*# -.*.swp - -*.test diff --git a/Godeps/_workspace/src/bazil.org/fuse/LICENSE b/Godeps/_workspace/src/bazil.org/fuse/LICENSE deleted file mode 100644 index 4ac7cd838..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/LICENSE +++ /dev/null @@ -1,93 +0,0 @@ -Copyright (c) 2013-2015 Tommi Virtanen. -Copyright (c) 2009, 2011, 2012 The Go Authors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -The following included software components have additional copyright -notices and license terms that may differ from the above. - - -File fuse.go: - -// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c, -// which carries this notice: -// -// The files in this directory are subject to the following license. -// -// The author of this software is Russ Cox. -// -// Copyright (c) 2006 Russ Cox -// -// Permission to use, copy, modify, and distribute this software for any -// purpose without fee is hereby granted, provided that this entire notice -// is included in all copies of any software which is or includes a copy -// or modification of this software and in all copies of the supporting -// documentation for such software. -// -// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY -// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS -// FITNESS FOR ANY PARTICULAR PURPOSE. - - -File fuse_kernel.go: - -// Derived from FUSE's fuse_kernel.h -/* - This file defines the kernel interface of FUSE - Copyright (C) 2001-2007 Miklos Szeredi - - - This -- and only this -- header file may also be distributed under - the terms of the BSD Licence as follows: - - Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. -*/ diff --git a/Godeps/_workspace/src/bazil.org/fuse/README.md b/Godeps/_workspace/src/bazil.org/fuse/README.md deleted file mode 100644 index 8c6d556ee..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/README.md +++ /dev/null @@ -1,23 +0,0 @@ -bazil.org/fuse -- Filesystems in Go -=================================== - -`bazil.org/fuse` is a Go library for writing FUSE userspace -filesystems. - -It is a from-scratch implementation of the kernel-userspace -communication protocol, and does not use the C library from the -project called FUSE. `bazil.org/fuse` embraces Go fully for safety and -ease of programming. - -Here’s how to get going: - - go get bazil.org/fuse - -Website: http://bazil.org/fuse/ - -Github repository: https://github.com/bazil/fuse - -API docs: http://godoc.org/bazil.org/fuse - -Our thanks to Russ Cox for his fuse library, which this project is -based on. diff --git a/Godeps/_workspace/src/bazil.org/fuse/debug.go b/Godeps/_workspace/src/bazil.org/fuse/debug.go deleted file mode 100644 index be9f900d5..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/debug.go +++ /dev/null @@ -1,21 +0,0 @@ -package fuse - -import ( - "runtime" -) - -func stack() string { - buf := make([]byte, 1024) - return string(buf[:runtime.Stack(buf, false)]) -} - -func nop(msg interface{}) {} - -// Debug is called to output debug messages, including protocol -// traces. The default behavior is to do nothing. -// -// The messages have human-friendly string representations and are -// safe to marshal to JSON. -// -// Implementations must not retain msg. -var Debug func(msg interface{}) = nop diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/.gitignore b/Godeps/_workspace/src/bazil.org/fuse/doc/.gitignore deleted file mode 100644 index 6ebe2d170..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/doc/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/*.seq.svg - -# not ignoring *.seq.png; we want those committed to the repo -# for embedding on Github diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/README.md b/Godeps/_workspace/src/bazil.org/fuse/doc/README.md deleted file mode 100644 index 54ed0e590..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/doc/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# bazil.org/fuse documentation - -See also API docs at http://godoc.org/bazil.org/fuse - -- [The mount sequence](mount-sequence.md) -- [Writing documentation](writing-docs.md) diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux-error-init.seq b/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux-error-init.seq deleted file mode 100644 index 89cf15158..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux-error-init.seq +++ /dev/null @@ -1,32 +0,0 @@ -seqdiag { - app; - fuse [label="bazil.org/fuse"]; - fusermount; - kernel; - mounts; - - app; - fuse [label="bazil.org/fuse"]; - fusermount; - kernel; - mounts; - - app -> fuse [label="Mount"]; - fuse -> fusermount [label="spawn, pass socketpair fd"]; - fusermount -> kernel [label="open /dev/fuse"]; - fusermount -> kernel [label="mount(2)"]; - kernel ->> mounts [label="mount is visible"]; - fusermount <-- kernel [label="mount(2) returns"]; - fuse <<-- fusermount [diagonal, label="exit, receive /dev/fuse fd", leftnote="on Linux, successful exit here\nmeans the mount has happened,\nthough InitRequest might not have yet"]; - app <-- fuse [label="Mount returns\nConn.Ready is already closed"]; - - app -> fuse [label="fs.Serve"]; - fuse => kernel [label="read /dev/fuse fd", note="starts with InitRequest"]; - fuse -> app [label="Init"]; - fuse <-- app [color=red]; - fuse -> kernel [label="write /dev/fuse fd", color=red]; - kernel -> kernel [label="set connection\nstate to error", color=red]; - fuse <-- kernel; - ... conn.MountError == nil, so it is still mounted ... - ... call conn.Close to clean up ... -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux-error-init.seq.png b/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux-error-init.seq.png deleted file mode 100644 index fea214f71..000000000 Binary files a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux-error-init.seq.png and /dev/null differ diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux.seq b/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux.seq deleted file mode 100644 index a1cafc7a6..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux.seq +++ /dev/null @@ -1,41 +0,0 @@ -seqdiag { - // seqdiag -T svg -o doc/mount-osx.svg doc/mount-osx.seq - app; - fuse [label="bazil.org/fuse"]; - fusermount; - kernel; - mounts; - - app -> fuse [label="Mount"]; - fuse -> fusermount [label="spawn, pass socketpair fd"]; - fusermount -> kernel [label="open /dev/fuse"]; - fusermount -> kernel [label="mount(2)"]; - kernel ->> mounts [label="mount is visible"]; - fusermount <-- kernel [label="mount(2) returns"]; - fuse <<-- fusermount [diagonal, label="exit, receive /dev/fuse fd", leftnote="on Linux, successful exit here\nmeans the mount has happened,\nthough InitRequest might not have yet"]; - app <-- fuse [label="Mount returns\nConn.Ready is already closed", rightnote="InitRequest and StatfsRequest\nmay or may not be seen\nbefore Conn.Ready,\ndepending on platform"]; - - app -> fuse [label="fs.Serve"]; - fuse => kernel [label="read /dev/fuse fd", note="starts with InitRequest"]; - fuse => app [label="FS/Node/Handle methods"]; - fuse => kernel [label="write /dev/fuse fd"]; - ... repeat ... - - ... shutting down ... - app -> fuse [label="Unmount"]; - fuse -> fusermount [label="fusermount -u"]; - fusermount -> kernel; - kernel <<-- mounts; - fusermount <-- kernel; - fuse <<-- fusermount [diagonal]; - app <-- fuse [label="Unmount returns"]; - - // actually triggers before above - fuse <<-- kernel [diagonal, label="/dev/fuse EOF"]; - app <-- fuse [label="fs.Serve returns"]; - - app -> fuse [label="conn.Close"]; - fuse -> kernel [label="close /dev/fuse fd"]; - fuse <-- kernel; - app <-- fuse; -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux.seq.png b/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux.seq.png deleted file mode 100644 index af373dd28..000000000 Binary files a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-linux.seq.png and /dev/null differ diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx-error-init.seq b/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx-error-init.seq deleted file mode 100644 index 3bb2b39a0..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx-error-init.seq +++ /dev/null @@ -1,32 +0,0 @@ -seqdiag { - app; - fuse [label="bazil.org/fuse"]; - wait [label="callMount\nhelper goroutine"]; - mount_osxfusefs; - kernel; - - app -> fuse [label="Mount"]; - fuse -> kernel [label="open /dev/osxfuseN"]; - fuse -> mount_osxfusefs [label="spawn, pass fd"]; - fuse -> wait [label="goroutine", note="blocks on cmd.Wait"]; - app <-- fuse [label="Mount returns"]; - - mount_osxfusefs -> kernel [label="mount(2)"]; - - app -> fuse [label="fs.Serve"]; - fuse => kernel [label="read /dev/osxfuseN fd", note="starts with InitRequest,\nalso seen before mount exits:\ntwo StatfsRequest calls"]; - fuse -> app [label="Init"]; - fuse <-- app [color=red]; - fuse -> kernel [label="write /dev/osxfuseN fd", color=red]; - fuse <-- kernel; - - mount_osxfusefs <-- kernel [label="mount(2) returns", color=red]; - wait <<-- mount_osxfusefs [diagonal, label="exit", color=red]; - app <<-- wait [diagonal, label="mount has failed,\nclose Conn.Ready", color=red]; - - // actually triggers before above - fuse <<-- kernel [diagonal, label="/dev/osxfuseN EOF"]; - app <-- fuse [label="fs.Serve returns"]; - ... conn.MountError != nil, so it was was never mounted ... - ... call conn.Close to clean up ... -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx-error-init.seq.png b/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx-error-init.seq.png deleted file mode 100644 index e96589c13..000000000 Binary files a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx-error-init.seq.png and /dev/null differ diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx.seq b/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx.seq deleted file mode 100644 index c6914a840..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx.seq +++ /dev/null @@ -1,45 +0,0 @@ -seqdiag { - // seqdiag -T svg -o doc/mount-osx.svg doc/mount-osx.seq - app; - fuse [label="bazil.org/fuse"]; - wait [label="callMount\nhelper goroutine"]; - mount_osxfusefs; - kernel; - mounts; - - app -> fuse [label="Mount"]; - fuse -> kernel [label="open /dev/osxfuseN"]; - fuse -> mount_osxfusefs [label="spawn, pass fd"]; - fuse -> wait [label="goroutine", note="blocks on cmd.Wait"]; - app <-- fuse [label="Mount returns"]; - - mount_osxfusefs -> kernel [label="mount(2)"]; - - app -> fuse [label="fs.Serve"]; - fuse => kernel [label="read /dev/osxfuseN fd", note="starts with InitRequest,\nalso seen before mount exits:\ntwo StatfsRequest calls"]; - fuse => app [label="FS/Node/Handle methods"]; - fuse => kernel [label="write /dev/osxfuseN fd"]; - ... repeat ... - - kernel ->> mounts [label="mount is visible"]; - mount_osxfusefs <-- kernel [label="mount(2) returns"]; - wait <<-- mount_osxfusefs [diagonal, label="exit", leftnote="on OS X, successful exit\nhere means we finally know\nthe mount has happened\n(can't trust InitRequest,\nkernel might have timed out\nwaiting for InitResponse)"]; - - app <<-- wait [diagonal, label="mount is ready,\nclose Conn.Ready", rightnote="InitRequest and StatfsRequest\nmay or may not be seen\nbefore Conn.Ready,\ndepending on platform"]; - - ... shutting down ... - app -> fuse [label="Unmount"]; - fuse -> kernel [label="umount(2)"]; - kernel <<-- mounts; - fuse <-- kernel; - app <-- fuse [label="Unmount returns"]; - - // actually triggers before above - fuse <<-- kernel [diagonal, label="/dev/osxfuseN EOF"]; - app <-- fuse [label="fs.Serve returns"]; - - app -> fuse [label="conn.Close"]; - fuse -> kernel [label="close /dev/osxfuseN"]; - fuse <-- kernel; - app <-- fuse; -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx.seq.png b/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx.seq.png deleted file mode 100644 index 7e310f914..000000000 Binary files a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-osx.seq.png and /dev/null differ diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-sequence.md b/Godeps/_workspace/src/bazil.org/fuse/doc/mount-sequence.md deleted file mode 100644 index fb2a5224f..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/doc/mount-sequence.md +++ /dev/null @@ -1,30 +0,0 @@ -# The mount sequence - -FUSE mounting is a little bit tricky. There's a userspace helper tool -that performs the handshake with the kernel, and then steps out of the -way. This helper behaves differently on different platforms, forcing a -more complex API on us. - -## Successful runs - -On Linux, the mount is immediate and file system accesses wait until -the requests are served. - -![Diagram of Linux FUSE mount sequence](mount-linux.seq.png) - -On OS X, the mount becomes visible only after `InitRequest` (and maybe -more) have been served. - -![Diagram of OSXFUSE mount sequence](mount-osx.seq.png) - - -## Errors - -Let's see what happens if `InitRequest` gets an error response. On -Linux, the mountpoint is there but all operations will fail: - -![Diagram of Linux error handling](mount-linux-error-init.seq.png) - -On OS X, the mount never happened: - -![Diagram of OS X error handling](mount-osx-error-init.seq.png) diff --git a/Godeps/_workspace/src/bazil.org/fuse/doc/writing-docs.md b/Godeps/_workspace/src/bazil.org/fuse/doc/writing-docs.md deleted file mode 100644 index ab5dbf8c1..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/doc/writing-docs.md +++ /dev/null @@ -1,16 +0,0 @@ -# Writing documentation - -## Sequence diagrams - -The sequence diagrams are generated with `seqdiag`: -http://blockdiag.com/en/seqdiag/index.html - -An easy way to work on them is to automatically update the generated -files with https://github.com/cespare/reflex : - - reflex -g 'doc/[^.]*.seq' -- seqdiag -T svg -o '{}.svg' '{}' & - - reflex -g 'doc/[^.]*.seq' -- seqdiag -T png -o '{}.png' '{}' & - -The markdown files refer to PNG images because of Github limitations, -but the SVG is generally more pleasant to view. diff --git a/Godeps/_workspace/src/bazil.org/fuse/error_darwin.go b/Godeps/_workspace/src/bazil.org/fuse/error_darwin.go deleted file mode 100644 index a3fb89ca2..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/error_darwin.go +++ /dev/null @@ -1,17 +0,0 @@ -package fuse - -import ( - "syscall" -) - -const ( - ENOATTR = Errno(syscall.ENOATTR) -) - -const ( - errNoXattr = ENOATTR -) - -func init() { - errnoNames[errNoXattr] = "ENOATTR" -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/error_freebsd.go b/Godeps/_workspace/src/bazil.org/fuse/error_freebsd.go deleted file mode 100644 index c6ea6d6e7..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/error_freebsd.go +++ /dev/null @@ -1,15 +0,0 @@ -package fuse - -import "syscall" - -const ( - ENOATTR = Errno(syscall.ENOATTR) -) - -const ( - errNoXattr = ENOATTR -) - -func init() { - errnoNames[errNoXattr] = "ENOATTR" -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/error_linux.go b/Godeps/_workspace/src/bazil.org/fuse/error_linux.go deleted file mode 100644 index 6f113e71e..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/error_linux.go +++ /dev/null @@ -1,17 +0,0 @@ -package fuse - -import ( - "syscall" -) - -const ( - ENODATA = Errno(syscall.ENODATA) -) - -const ( - errNoXattr = ENODATA -) - -func init() { - errnoNames[errNoXattr] = "ENODATA" -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/error_std.go b/Godeps/_workspace/src/bazil.org/fuse/error_std.go deleted file mode 100644 index 398f43fbf..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/error_std.go +++ /dev/null @@ -1,31 +0,0 @@ -package fuse - -// There is very little commonality in extended attribute errors -// across platforms. -// -// getxattr return value for "extended attribute does not exist" is -// ENOATTR on OS X, and ENODATA on Linux and apparently at least -// NetBSD. There may be a #define ENOATTR on Linux too, but the value -// is ENODATA in the actual syscalls. FreeBSD and OpenBSD have no -// ENODATA, only ENOATTR. ENOATTR is not in any of the standards, -// ENODATA exists but is only used for STREAMs. -// -// Each platform will define it a errNoXattr constant, and this file -// will enforce that it implements the right interfaces and hide the -// implementation. -// -// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/getxattr.2.html -// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013090.html -// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013097.html -// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html -// http://www.freebsd.org/cgi/man.cgi?query=extattr_get_file&sektion=2 -// http://nixdoc.net/man-pages/openbsd/man2/extattr_get_file.2.html - -// ErrNoXattr is a platform-independent error value meaning the -// extended attribute was not found. It can be used to respond to -// GetxattrRequest and such. -const ErrNoXattr = errNoXattr - -var _ error = ErrNoXattr -var _ Errno = ErrNoXattr -var _ ErrorNumber = ErrNoXattr diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go b/Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go deleted file mode 100644 index bc3208009..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go +++ /dev/null @@ -1,273 +0,0 @@ -package bench_test - -import ( - "context" - "io" - "io/ioutil" - "os" - "path" - "testing" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" -) - -type benchConfig struct { - directIO bool -} - -type benchFS struct { - conf *benchConfig -} - -var _ = fs.FS(benchFS{}) -var _ = fs.FSIniter(benchFS{}) - -func (benchFS) Init(ctx context.Context, req *fuse.InitRequest, resp *fuse.InitResponse) error { - resp.MaxReadahead = 64 * 1024 * 1024 - resp.Flags |= fuse.InitAsyncRead - return nil -} - -func (f benchFS) Root() (fs.Node, error) { - return benchDir{conf: f.conf}, nil -} - -type benchDir struct { - conf *benchConfig -} - -var _ = fs.Node(benchDir{}) -var _ = fs.NodeStringLookuper(benchDir{}) -var _ = fs.Handle(benchDir{}) -var _ = fs.HandleReadDirAller(benchDir{}) - -func (benchDir) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 1 - a.Mode = os.ModeDir | 0555 - return nil -} - -func (d benchDir) Lookup(ctx context.Context, name string) (fs.Node, error) { - if name == "bench" { - return benchFile{conf: d.conf}, nil - } - return nil, fuse.ENOENT -} - -func (benchDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - l := []fuse.Dirent{ - {Inode: 2, Name: "bench", Type: fuse.DT_File}, - } - return l, nil -} - -type benchFile struct { - conf *benchConfig -} - -var _ = fs.Node(benchFile{}) -var _ = fs.NodeOpener(benchFile{}) -var _ = fs.NodeFsyncer(benchFile{}) -var _ = fs.Handle(benchFile{}) -var _ = fs.HandleReader(benchFile{}) -var _ = fs.HandleWriter(benchFile{}) - -func (benchFile) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 2 - a.Mode = 0644 - a.Size = 9999999999999999 - return nil -} - -func (f benchFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { - if f.conf.directIO { - resp.Flags |= fuse.OpenDirectIO - } - // TODO configurable? - resp.Flags |= fuse.OpenKeepCache - return f, nil -} - -func (benchFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - resp.Data = resp.Data[:cap(resp.Data)] - return nil -} - -func (benchFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error { - resp.Size = len(req.Data) - return nil -} - -func (benchFile) Fsync(ctx context.Context, req *fuse.FsyncRequest) error { - return nil -} - -func benchmark(b *testing.B, fn func(b *testing.B, mnt string), conf *benchConfig) { - srv := &fs.Server{ - FS: benchFS{ - conf: conf, - }, - } - mnt, err := fstestutil.Mounted(srv) - if err != nil { - b.Fatal(err) - } - defer mnt.Close() - - fn(b, mnt.Dir) -} - -type zero struct{} - -func (zero) Read(p []byte) (n int, err error) { - return len(p), nil -} - -var Zero io.Reader = zero{} - -func doWrites(size int64) func(b *testing.B, mnt string) { - return func(b *testing.B, mnt string) { - p := path.Join(mnt, "bench") - - f, err := os.Create(p) - if err != nil { - b.Fatalf("create: %v", err) - } - defer f.Close() - - b.ResetTimer() - b.SetBytes(size) - - for i := 0; i < b.N; i++ { - _, err = io.CopyN(f, Zero, size) - if err != nil { - b.Fatalf("write: %v", err) - } - } - } -} - -func BenchmarkWrite100(b *testing.B) { - benchmark(b, doWrites(100), &benchConfig{}) -} - -func BenchmarkWrite10MB(b *testing.B) { - benchmark(b, doWrites(10*1024*1024), &benchConfig{}) -} - -func BenchmarkWrite100MB(b *testing.B) { - benchmark(b, doWrites(100*1024*1024), &benchConfig{}) -} - -func BenchmarkDirectWrite100(b *testing.B) { - benchmark(b, doWrites(100), &benchConfig{ - directIO: true, - }) -} - -func BenchmarkDirectWrite10MB(b *testing.B) { - benchmark(b, doWrites(10*1024*1024), &benchConfig{ - directIO: true, - }) -} - -func BenchmarkDirectWrite100MB(b *testing.B) { - benchmark(b, doWrites(100*1024*1024), &benchConfig{ - directIO: true, - }) -} - -func doWritesSync(size int64) func(b *testing.B, mnt string) { - return func(b *testing.B, mnt string) { - p := path.Join(mnt, "bench") - - f, err := os.Create(p) - if err != nil { - b.Fatalf("create: %v", err) - } - defer f.Close() - - b.ResetTimer() - b.SetBytes(size) - - for i := 0; i < b.N; i++ { - _, err = io.CopyN(f, Zero, size) - if err != nil { - b.Fatalf("write: %v", err) - } - - if err := f.Sync(); err != nil { - b.Fatalf("sync: %v", err) - } - } - } -} - -func BenchmarkWriteSync100(b *testing.B) { - benchmark(b, doWritesSync(100), &benchConfig{}) -} - -func BenchmarkWriteSync10MB(b *testing.B) { - benchmark(b, doWritesSync(10*1024*1024), &benchConfig{}) -} - -func BenchmarkWriteSync100MB(b *testing.B) { - benchmark(b, doWritesSync(100*1024*1024), &benchConfig{}) -} - -func doReads(size int64) func(b *testing.B, mnt string) { - return func(b *testing.B, mnt string) { - p := path.Join(mnt, "bench") - - f, err := os.Open(p) - if err != nil { - b.Fatalf("close: %v", err) - } - defer f.Close() - - b.ResetTimer() - b.SetBytes(size) - - for i := 0; i < b.N; i++ { - n, err := io.CopyN(ioutil.Discard, f, size) - if err != nil { - b.Fatalf("read: %v", err) - } - if n != size { - b.Errorf("unexpected size: %d != %d", n, size) - } - } - } -} - -func BenchmarkRead100(b *testing.B) { - benchmark(b, doReads(100), &benchConfig{}) -} - -func BenchmarkRead10MB(b *testing.B) { - benchmark(b, doReads(10*1024*1024), &benchConfig{}) -} - -func BenchmarkRead100MB(b *testing.B) { - benchmark(b, doReads(100*1024*1024), &benchConfig{}) -} - -func BenchmarkDirectRead100(b *testing.B) { - benchmark(b, doReads(100), &benchConfig{ - directIO: true, - }) -} - -func BenchmarkDirectRead10MB(b *testing.B) { - benchmark(b, doReads(10*1024*1024), &benchConfig{ - directIO: true, - }) -} - -func BenchmarkDirectRead100MB(b *testing.B) { - benchmark(b, doReads(100*1024*1024), &benchConfig{ - directIO: true, - }) -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/bench/doc.go b/Godeps/_workspace/src/bazil.org/fuse/fs/bench/doc.go deleted file mode 100644 index f6da48d9e..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/bench/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package bench contains benchmarks. -// -// It is kept in a separate package to avoid conflicting with the -// debug-heavy defaults for the actual tests. -package bench diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/debug.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/debug.go deleted file mode 100644 index c06d7662d..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/debug.go +++ /dev/null @@ -1,65 +0,0 @@ -package fstestutil - -import ( - "flag" - "log" - "strconv" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" -) - -type flagDebug bool - -var debug flagDebug - -var _ = flag.Value(&debug) - -func (f *flagDebug) IsBoolFlag() bool { - return true -} - -func nop(msg interface{}) {} - -func (f *flagDebug) Set(s string) error { - v, err := strconv.ParseBool(s) - if err != nil { - return err - } - *f = flagDebug(v) - if v { - fuse.Debug = logMsg - } else { - fuse.Debug = nop - } - return nil -} - -func (f *flagDebug) String() string { - return strconv.FormatBool(bool(*f)) -} - -func logMsg(msg interface{}) { - log.Printf("FUSE: %s\n", msg) -} - -func init() { - flag.Var(&debug, "fuse.debug", "log FUSE processing details") -} - -// DebugByDefault changes the default of the `-fuse.debug` flag to -// true. -// -// This package registers a command line flag `-fuse.debug` and when -// run with that flag (and activated inside the tests), logs FUSE -// debug messages. -// -// This is disabled by default, as most callers probably won't care -// about FUSE details. Use DebugByDefault for tests where you'd -// normally be passing `-fuse.debug` all the time anyway. -// -// Call from an init function. -func DebugByDefault() { - f := flag.Lookup("fuse.debug") - f.DefValue = "true" - f.Value.Set(f.DefValue) -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/doc.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/doc.go deleted file mode 100644 index d4366cca5..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/doc.go +++ /dev/null @@ -1 +0,0 @@ -package fstestutil diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go deleted file mode 100644 index 9a1605603..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go +++ /dev/null @@ -1,113 +0,0 @@ -package fstestutil - -import ( - "errors" - "io/ioutil" - "log" - "os" - "testing" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" -) - -// Mount contains information about the mount for the test to use. -type Mount struct { - // Dir is the temporary directory where the filesystem is mounted. - Dir string - - Conn *fuse.Conn - - // Error will receive the return value of Serve. - Error <-chan error - - done <-chan struct{} - closed bool -} - -// Close unmounts the filesystem and waits for fs.Serve to return. Any -// returned error will be stored in Err. It is safe to call Close -// multiple times. -func (mnt *Mount) Close() { - if mnt.closed { - return - } - mnt.closed = true - for tries := 0; tries < 1000; tries++ { - err := fuse.Unmount(mnt.Dir) - if err != nil { - // TODO do more than log? - log.Printf("unmount error: %v", err) - time.Sleep(10 * time.Millisecond) - continue - } - break - } - <-mnt.done - mnt.Conn.Close() - os.Remove(mnt.Dir) -} - -// Mounted mounts the fuse.Server at a temporary directory. -// -// It also waits until the filesystem is known to be visible (OS X -// workaround). -// -// After successful return, caller must clean up by calling Close. -func Mounted(srv *fs.Server, options ...fuse.MountOption) (*Mount, error) { - dir, err := ioutil.TempDir("", "fusetest") - if err != nil { - return nil, err - } - c, err := fuse.Mount(dir, options...) - if err != nil { - return nil, err - } - - done := make(chan struct{}) - serveErr := make(chan error, 1) - mnt := &Mount{ - Dir: dir, - Conn: c, - Error: serveErr, - done: done, - } - go func() { - defer close(done) - serveErr <- srv.Serve(c) - }() - - select { - case <-mnt.Conn.Ready: - if mnt.Conn.MountError != nil { - return nil, err - } - return mnt, err - case err = <-mnt.Error: - // Serve quit early - if err != nil { - return nil, err - } - return nil, errors.New("Serve exited early") - } -} - -// MountedT mounts the filesystem at a temporary directory, -// directing it's debug log to the testing logger. -// -// See Mounted for usage. -// -// The debug log is not enabled by default. Use `-fuse.debug` or call -// DebugByDefault to enable. -func MountedT(t testing.TB, filesys fs.FS, options ...fuse.MountOption) (*Mount, error) { - srv := &fs.Server{ - FS: filesys, - } - if debug { - srv.Debug = func(msg interface{}) { - t.Logf("FUSE: %s", msg) - } - } - return Mounted(srv, options...) -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo.go deleted file mode 100644 index 654417bc4..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo.go +++ /dev/null @@ -1,26 +0,0 @@ -package fstestutil - -// MountInfo describes a mounted file system. -type MountInfo struct { - FSName string - Type string -} - -// GetMountInfo finds information about the mount at mnt. It is -// intended for use by tests only, and only fetches information -// relevant to the current tests. -func GetMountInfo(mnt string) (*MountInfo, error) { - return getMountInfo(mnt) -} - -// cstr converts a nil-terminated C string into a Go string -func cstr(ca []int8) string { - s := make([]byte, 0, len(ca)) - for _, c := range ca { - if c == 0x00 { - break - } - s = append(s, byte(c)) - } - return string(s) -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_darwin.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_darwin.go deleted file mode 100644 index f987bd8e7..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_darwin.go +++ /dev/null @@ -1,29 +0,0 @@ -package fstestutil - -import ( - "regexp" - "syscall" -) - -var re = regexp.MustCompile(`\\(.)`) - -// unescape removes backslash-escaping. The escaped characters are not -// mapped in any way; that is, unescape(`\n` ) == `n`. -func unescape(s string) string { - return re.ReplaceAllString(s, `$1`) -} - -func getMountInfo(mnt string) (*MountInfo, error) { - var st syscall.Statfs_t - err := syscall.Statfs(mnt, &st) - if err != nil { - return nil, err - } - i := &MountInfo{ - // osx getmntent(3) fails to un-escape the data, so we do it.. - // this might lead to double-unescaping in the future. fun. - // TestMountOptionFSNameEvilBackslashDouble checks for that. - FSName: unescape(cstr(st.Mntfromname[:])), - } - return i, nil -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_freebsd.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_freebsd.go deleted file mode 100644 index f70e9975e..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_freebsd.go +++ /dev/null @@ -1,7 +0,0 @@ -package fstestutil - -import "errors" - -func getMountInfo(mnt string) (*MountInfo, error) { - return nil, errors.New("FreeBSD has no useful mount information") -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_linux.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_linux.go deleted file mode 100644 index c502cf59b..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_linux.go +++ /dev/null @@ -1,51 +0,0 @@ -package fstestutil - -import ( - "errors" - "io/ioutil" - "strings" -) - -// Linux /proc/mounts shows current mounts. -// Same format as /etc/fstab. Quoting getmntent(3): -// -// Since fields in the mtab and fstab files are separated by whitespace, -// octal escapes are used to represent the four characters space (\040), -// tab (\011), newline (\012) and backslash (\134) in those files when -// they occur in one of the four strings in a mntent structure. -// -// http://linux.die.net/man/3/getmntent - -var fstabUnescape = strings.NewReplacer( - `\040`, "\040", - `\011`, "\011", - `\012`, "\012", - `\134`, "\134", -) - -var errNotFound = errors.New("mount not found") - -func getMountInfo(mnt string) (*MountInfo, error) { - data, err := ioutil.ReadFile("/proc/mounts") - if err != nil { - return nil, err - } - for _, line := range strings.Split(string(data), "\n") { - fields := strings.Fields(line) - if len(fields) < 3 { - continue - } - // Fields are: fsname dir type opts freq passno - fsname := fstabUnescape.Replace(fields[0]) - dir := fstabUnescape.Replace(fields[1]) - fstype := fstabUnescape.Replace(fields[2]) - if mnt == dir { - info := &MountInfo{ - FSName: fsname, - Type: fstype, - } - return info, nil - } - } - return nil, errNotFound -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/buffer.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/buffer.go deleted file mode 100644 index 2820459b0..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/buffer.go +++ /dev/null @@ -1,28 +0,0 @@ -package record - -import ( - "bytes" - "io" - "sync" -) - -// Buffer is like bytes.Buffer but safe to access from multiple -// goroutines. -type Buffer struct { - mu sync.Mutex - buf bytes.Buffer -} - -var _ = io.Writer(&Buffer{}) - -func (b *Buffer) Write(p []byte) (n int, err error) { - b.mu.Lock() - defer b.mu.Unlock() - return b.buf.Write(p) -} - -func (b *Buffer) Bytes() []byte { - b.mu.Lock() - defer b.mu.Unlock() - return b.buf.Bytes() -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go deleted file mode 100644 index 937ef16a5..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go +++ /dev/null @@ -1,381 +0,0 @@ -package record - -import ( - "context" - "sync" - "sync/atomic" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" -) - -// Writes gathers data from FUSE Write calls. -type Writes struct { - buf Buffer -} - -var _ = fs.HandleWriter(&Writes{}) - -func (w *Writes) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error { - n, err := w.buf.Write(req.Data) - resp.Size = n - if err != nil { - return err - } - return nil -} - -func (w *Writes) RecordedWriteData() []byte { - return w.buf.Bytes() -} - -// Counter records number of times a thing has occurred. -type Counter struct { - count uint32 -} - -func (r *Counter) Inc() { - atomic.StoreUint32(&r.count, 1) -} - -func (r *Counter) Count() uint32 { - return atomic.LoadUint32(&r.count) -} - -// MarkRecorder records whether a thing has occurred. -type MarkRecorder struct { - count Counter -} - -func (r *MarkRecorder) Mark() { - r.count.Inc() -} - -func (r *MarkRecorder) Recorded() bool { - return r.count.Count() > 0 -} - -// Flushes notes whether a FUSE Flush call has been seen. -type Flushes struct { - rec MarkRecorder -} - -var _ = fs.HandleFlusher(&Flushes{}) - -func (r *Flushes) Flush(ctx context.Context, req *fuse.FlushRequest) error { - r.rec.Mark() - return nil -} - -func (r *Flushes) RecordedFlush() bool { - return r.rec.Recorded() -} - -type Recorder struct { - mu sync.Mutex - val interface{} -} - -// Record that we've seen value. A nil value is indistinguishable from -// no value recorded. -func (r *Recorder) Record(value interface{}) { - r.mu.Lock() - r.val = value - r.mu.Unlock() -} - -func (r *Recorder) Recorded() interface{} { - r.mu.Lock() - val := r.val - r.mu.Unlock() - return val -} - -type RequestRecorder struct { - rec Recorder -} - -// Record a fuse.Request, after zeroing header fields that are hard to -// reproduce. -// -// Make sure to record a copy, not the original request. -func (r *RequestRecorder) RecordRequest(req fuse.Request) { - hdr := req.Hdr() - *hdr = fuse.Header{} - r.rec.Record(req) -} - -func (r *RequestRecorder) Recorded() fuse.Request { - val := r.rec.Recorded() - if val == nil { - return nil - } - return val.(fuse.Request) -} - -// Setattrs records a Setattr request and its fields. -type Setattrs struct { - rec RequestRecorder -} - -var _ = fs.NodeSetattrer(&Setattrs{}) - -func (r *Setattrs) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error { - tmp := *req - r.rec.RecordRequest(&tmp) - return nil -} - -func (r *Setattrs) RecordedSetattr() fuse.SetattrRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.SetattrRequest{} - } - return *(val.(*fuse.SetattrRequest)) -} - -// Fsyncs records an Fsync request and its fields. -type Fsyncs struct { - rec RequestRecorder -} - -var _ = fs.NodeFsyncer(&Fsyncs{}) - -func (r *Fsyncs) Fsync(ctx context.Context, req *fuse.FsyncRequest) error { - tmp := *req - r.rec.RecordRequest(&tmp) - return nil -} - -func (r *Fsyncs) RecordedFsync() fuse.FsyncRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.FsyncRequest{} - } - return *(val.(*fuse.FsyncRequest)) -} - -// Mkdirs records a Mkdir request and its fields. -type Mkdirs struct { - rec RequestRecorder -} - -var _ = fs.NodeMkdirer(&Mkdirs{}) - -// Mkdir records the request and returns an error. Most callers should -// wrap this call in a function that returns a more useful result. -func (r *Mkdirs) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { - tmp := *req - r.rec.RecordRequest(&tmp) - return nil, fuse.EIO -} - -// RecordedMkdir returns information about the Mkdir request. -// If no request was seen, returns a zero value. -func (r *Mkdirs) RecordedMkdir() fuse.MkdirRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.MkdirRequest{} - } - return *(val.(*fuse.MkdirRequest)) -} - -// Symlinks records a Symlink request and its fields. -type Symlinks struct { - rec RequestRecorder -} - -var _ = fs.NodeSymlinker(&Symlinks{}) - -// Symlink records the request and returns an error. Most callers should -// wrap this call in a function that returns a more useful result. -func (r *Symlinks) Symlink(ctx context.Context, req *fuse.SymlinkRequest) (fs.Node, error) { - tmp := *req - r.rec.RecordRequest(&tmp) - return nil, fuse.EIO -} - -// RecordedSymlink returns information about the Symlink request. -// If no request was seen, returns a zero value. -func (r *Symlinks) RecordedSymlink() fuse.SymlinkRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.SymlinkRequest{} - } - return *(val.(*fuse.SymlinkRequest)) -} - -// Links records a Link request and its fields. -type Links struct { - rec RequestRecorder -} - -var _ = fs.NodeLinker(&Links{}) - -// Link records the request and returns an error. Most callers should -// wrap this call in a function that returns a more useful result. -func (r *Links) Link(ctx context.Context, req *fuse.LinkRequest, old fs.Node) (fs.Node, error) { - tmp := *req - r.rec.RecordRequest(&tmp) - return nil, fuse.EIO -} - -// RecordedLink returns information about the Link request. -// If no request was seen, returns a zero value. -func (r *Links) RecordedLink() fuse.LinkRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.LinkRequest{} - } - return *(val.(*fuse.LinkRequest)) -} - -// Mknods records a Mknod request and its fields. -type Mknods struct { - rec RequestRecorder -} - -var _ = fs.NodeMknoder(&Mknods{}) - -// Mknod records the request and returns an error. Most callers should -// wrap this call in a function that returns a more useful result. -func (r *Mknods) Mknod(ctx context.Context, req *fuse.MknodRequest) (fs.Node, error) { - tmp := *req - r.rec.RecordRequest(&tmp) - return nil, fuse.EIO -} - -// RecordedMknod returns information about the Mknod request. -// If no request was seen, returns a zero value. -func (r *Mknods) RecordedMknod() fuse.MknodRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.MknodRequest{} - } - return *(val.(*fuse.MknodRequest)) -} - -// Opens records a Open request and its fields. -type Opens struct { - rec RequestRecorder -} - -var _ = fs.NodeOpener(&Opens{}) - -// Open records the request and returns an error. Most callers should -// wrap this call in a function that returns a more useful result. -func (r *Opens) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { - tmp := *req - r.rec.RecordRequest(&tmp) - return nil, fuse.EIO -} - -// RecordedOpen returns information about the Open request. -// If no request was seen, returns a zero value. -func (r *Opens) RecordedOpen() fuse.OpenRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.OpenRequest{} - } - return *(val.(*fuse.OpenRequest)) -} - -// Getxattrs records a Getxattr request and its fields. -type Getxattrs struct { - rec RequestRecorder -} - -var _ = fs.NodeGetxattrer(&Getxattrs{}) - -// Getxattr records the request and returns an error. Most callers should -// wrap this call in a function that returns a more useful result. -func (r *Getxattrs) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error { - tmp := *req - r.rec.RecordRequest(&tmp) - return fuse.ErrNoXattr -} - -// RecordedGetxattr returns information about the Getxattr request. -// If no request was seen, returns a zero value. -func (r *Getxattrs) RecordedGetxattr() fuse.GetxattrRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.GetxattrRequest{} - } - return *(val.(*fuse.GetxattrRequest)) -} - -// Listxattrs records a Listxattr request and its fields. -type Listxattrs struct { - rec RequestRecorder -} - -var _ = fs.NodeListxattrer(&Listxattrs{}) - -// Listxattr records the request and returns an error. Most callers should -// wrap this call in a function that returns a more useful result. -func (r *Listxattrs) Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error { - tmp := *req - r.rec.RecordRequest(&tmp) - return fuse.ErrNoXattr -} - -// RecordedListxattr returns information about the Listxattr request. -// If no request was seen, returns a zero value. -func (r *Listxattrs) RecordedListxattr() fuse.ListxattrRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.ListxattrRequest{} - } - return *(val.(*fuse.ListxattrRequest)) -} - -// Setxattrs records a Setxattr request and its fields. -type Setxattrs struct { - rec RequestRecorder -} - -var _ = fs.NodeSetxattrer(&Setxattrs{}) - -// Setxattr records the request and returns an error. Most callers should -// wrap this call in a function that returns a more useful result. -func (r *Setxattrs) Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error { - tmp := *req - r.rec.RecordRequest(&tmp) - return nil -} - -// RecordedSetxattr returns information about the Setxattr request. -// If no request was seen, returns a zero value. -func (r *Setxattrs) RecordedSetxattr() fuse.SetxattrRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.SetxattrRequest{} - } - return *(val.(*fuse.SetxattrRequest)) -} - -// Removexattrs records a Removexattr request and its fields. -type Removexattrs struct { - rec RequestRecorder -} - -var _ = fs.NodeRemovexattrer(&Removexattrs{}) - -// Removexattr records the request and returns an error. Most callers should -// wrap this call in a function that returns a more useful result. -func (r *Removexattrs) Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error { - tmp := *req - r.rec.RecordRequest(&tmp) - return nil -} - -// RecordedRemovexattr returns information about the Removexattr request. -// If no request was seen, returns a zero value. -func (r *Removexattrs) RecordedRemovexattr() fuse.RemovexattrRequest { - val := r.rec.Recorded() - if val == nil { - return fuse.RemovexattrRequest{} - } - return *(val.(*fuse.RemovexattrRequest)) -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/wait.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/wait.go deleted file mode 100644 index c0ebcd164..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/wait.go +++ /dev/null @@ -1,55 +0,0 @@ -package record - -import ( - "context" - "sync" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" -) - -type nothing struct{} - -// ReleaseWaiter notes whether a FUSE Release call has been seen. -// -// Releases are not guaranteed to happen synchronously with any client -// call, so they must be waited for. -type ReleaseWaiter struct { - once sync.Once - seen chan nothing -} - -var _ = fs.HandleReleaser(&ReleaseWaiter{}) - -func (r *ReleaseWaiter) init() { - r.once.Do(func() { - r.seen = make(chan nothing, 1) - }) -} - -func (r *ReleaseWaiter) Release(ctx context.Context, req *fuse.ReleaseRequest) error { - r.init() - close(r.seen) - return nil -} - -// WaitForRelease waits for Release to be called. -// -// With zero duration, wait forever. Otherwise, timeout early -// in a more controller way than `-test.timeout`. -// -// Returns whether a Release was seen. Always true if dur==0. -func (r *ReleaseWaiter) WaitForRelease(dur time.Duration) bool { - r.init() - var timeout <-chan time.Time - if dur > 0 { - timeout = time.After(dur) - } - select { - case <-r.seen: - return true - case <-timeout: - return false - } -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go deleted file mode 100644 index 215c4a625..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go +++ /dev/null @@ -1,55 +0,0 @@ -package fstestutil - -import ( - "context" - "os" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" -) - -// SimpleFS is a trivial FS that just implements the Root method. -type SimpleFS struct { - Node fs.Node -} - -var _ = fs.FS(SimpleFS{}) - -func (f SimpleFS) Root() (fs.Node, error) { - return f.Node, nil -} - -// File can be embedded in a struct to make it look like a file. -type File struct{} - -func (f File) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = 0666 - return nil -} - -// Dir can be embedded in a struct to make it look like a directory. -type Dir struct{} - -func (f Dir) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = os.ModeDir | 0777 - return nil -} - -// ChildMap is a directory with child nodes looked up from a map. -type ChildMap map[string]fs.Node - -var _ = fs.Node(ChildMap{}) -var _ = fs.NodeStringLookuper(ChildMap{}) - -func (f ChildMap) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = os.ModeDir | 0777 - return nil -} - -func (f ChildMap) Lookup(ctx context.Context, name string) (fs.Node, error) { - child, ok := f[name] - if !ok { - return nil, fuse.ENOENT - } - return child, nil -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/helpers_test.go b/Godeps/_workspace/src/bazil.org/fuse/fs/helpers_test.go deleted file mode 100644 index e37877c17..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/helpers_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package fs_test - -import ( - "errors" - "flag" - "os" - "os/exec" - "path/filepath" - "testing" -) - -var childHelpers = map[string]func(){} - -type childProcess struct { - name string - fn func() -} - -var _ flag.Value = (*childProcess)(nil) - -func (c *childProcess) String() string { - return c.name -} - -func (c *childProcess) Set(s string) error { - fn, ok := childHelpers[s] - if !ok { - return errors.New("helper not found") - } - c.name = s - c.fn = fn - return nil -} - -var childMode childProcess - -func init() { - flag.Var(&childMode, "fuse.internal.child", "internal use only") -} - -// childCmd prepares a test function to be run in a subprocess, with -// childMode set to true. Caller must still call Run or Start. -// -// Re-using the test executable as the subprocess is useful because -// now test executables can e.g. be cross-compiled, transferred -// between hosts, and run in settings where the whole Go development -// environment is not installed. -func childCmd(childName string) (*exec.Cmd, error) { - // caller may set cwd, so we can't rely on relative paths - executable, err := filepath.Abs(os.Args[0]) - if err != nil { - return nil, err - } - cmd := exec.Command(executable, "-fuse.internal.child="+childName) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd, nil -} - -func TestMain(m *testing.M) { - flag.Parse() - if childMode.fn != nil { - childMode.fn() - os.Exit(0) - } - os.Exit(m.Run()) -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go b/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go deleted file mode 100644 index b2cce7761..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go +++ /dev/null @@ -1,1422 +0,0 @@ -// FUSE service loop, for servers that wish to use it. - -package fs - -import ( - "encoding/binary" - "fmt" - "hash/fnv" - "io" - "log" - "reflect" - "runtime" - "strings" - "sync" - "time" - - "context" -) - -import ( - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fuseutil" -) - -const ( - attrValidTime = 1 * time.Minute - entryValidTime = 1 * time.Minute -) - -// TODO: FINISH DOCS - -// An FS is the interface required of a file system. -// -// Other FUSE requests can be handled by implementing methods from the -// FS* interfaces, for example FSIniter. -type FS interface { - // Root is called to obtain the Node for the file system root. - Root() (Node, error) -} - -type FSIniter interface { - // Init is called to initialize the FUSE connection. - // It can inspect the request and adjust the response as desired. - // Init must return promptly. - Init(ctx context.Context, req *fuse.InitRequest, resp *fuse.InitResponse) error -} - -type FSStatfser interface { - // Statfs is called to obtain file system metadata. - // It should write that data to resp. - Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error -} - -type FSDestroyer interface { - // Destroy is called when the file system is shutting down. - // - // Linux only sends this request for block device backed (fuseblk) - // filesystems, to allow them to flush writes to disk before the - // unmount completes. - Destroy() -} - -type FSInodeGenerator interface { - // GenerateInode is called to pick a dynamic inode number when it - // would otherwise be 0. - // - // Not all filesystems bother tracking inodes, but FUSE requires - // the inode to be set, and fewer duplicates in general makes UNIX - // tools work better. - // - // Operations where the nodes may return 0 inodes include Getattr, - // Setattr and ReadDir. - // - // If FS does not implement FSInodeGenerator, GenerateDynamicInode - // is used. - // - // Implementing this is useful to e.g. constrain the range of - // inode values used for dynamic inodes. - GenerateInode(parentInode uint64, name string) uint64 -} - -// A Node is the interface required of a file or directory. -// See the documentation for type FS for general information -// pertaining to all methods. -// -// Other FUSE requests can be handled by implementing methods from the -// Node* interfaces, for example NodeOpener. -type Node interface { - // Attr fills attr with the standard metadata for the node. - Attr(ctx context.Context, attr *fuse.Attr) error -} - -type NodeGetattrer interface { - // Getattr obtains the standard metadata for the receiver. - // It should store that metadata in resp. - // - // If this method is not implemented, the attributes will be - // generated based on Attr(), with zero values filled in. - Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error -} - -type NodeSetattrer interface { - // Setattr sets the standard metadata for the receiver. - // - // Note, this is also used to communicate changes in the size of - // the file. Not implementing Setattr causes writes to be unable - // to grow the file (except with OpenDirectIO, which bypasses that - // mechanism). - // - // req.Valid is a bitmask of what fields are actually being set. - // For example, the method should not change the mode of the file - // unless req.Valid.Mode() is true. - Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error -} - -type NodeSymlinker interface { - // Symlink creates a new symbolic link in the receiver, which must be a directory. - // - // TODO is the above true about directories? - Symlink(ctx context.Context, req *fuse.SymlinkRequest) (Node, error) -} - -// This optional request will be called only for symbolic link nodes. -type NodeReadlinker interface { - // Readlink reads a symbolic link. - Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) -} - -type NodeLinker interface { - // Link creates a new directory entry in the receiver based on an - // existing Node. Receiver must be a directory. - Link(ctx context.Context, req *fuse.LinkRequest, old Node) (Node, error) -} - -type NodeRemover interface { - // Remove removes the entry with the given name from - // the receiver, which must be a directory. The entry to be removed - // may correspond to a file (unlink) or to a directory (rmdir). - Remove(ctx context.Context, req *fuse.RemoveRequest) error -} - -type NodeAccesser interface { - // Access checks whether the calling context has permission for - // the given operations on the receiver. If so, Access should - // return nil. If not, Access should return EPERM. - // - // Note that this call affects the result of the access(2) system - // call but not the open(2) system call. If Access is not - // implemented, the Node behaves as if it always returns nil - // (permission granted), relying on checks in Open instead. - Access(ctx context.Context, req *fuse.AccessRequest) error -} - -type NodeStringLookuper interface { - // Lookup looks up a specific entry in the receiver, - // which must be a directory. Lookup should return a Node - // corresponding to the entry. If the name does not exist in - // the directory, Lookup should return nil, err. - // - // Lookup need not to handle the names "." and "..". - Lookup(ctx context.Context, name string) (Node, error) -} - -type NodeRequestLookuper interface { - // Lookup looks up a specific entry in the receiver. - // See NodeStringLookuper for more. - Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (Node, error) -} - -type NodeMkdirer interface { - Mkdir(ctx context.Context, req *fuse.MkdirRequest) (Node, error) -} - -type NodeOpener interface { - // Open opens the receiver. After a successful open, a client - // process has a file descriptor referring to this Handle. - // - // Open can also be also called on non-files. For example, - // directories are Opened for ReadDir or fchdir(2). - // - // If this method is not implemented, the open will always - // succeed, and the Node itself will be used as the Handle. - // - // XXX note about access. XXX OpenFlags. - Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (Handle, error) -} - -type NodeCreater interface { - // Create creates a new directory entry in the receiver, which - // must be a directory. - Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (Node, Handle, error) -} - -type NodeForgetter interface { - // Forget about this node. This node will not receive further - // method calls. - // - // Forget is not necessarily seen on unmount, as all nodes are - // implicitly forgotten as part part of the unmount. - Forget() -} - -type NodeRenamer interface { - Rename(ctx context.Context, req *fuse.RenameRequest, newDir Node) error -} - -type NodeMknoder interface { - Mknod(ctx context.Context, req *fuse.MknodRequest) (Node, error) -} - -// TODO this should be on Handle not Node -type NodeFsyncer interface { - Fsync(ctx context.Context, req *fuse.FsyncRequest) error -} - -type NodeGetxattrer interface { - // Getxattr gets an extended attribute by the given name from the - // node. - // - // If there is no xattr by that name, returns fuse.ErrNoXattr. - Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error -} - -type NodeListxattrer interface { - // Listxattr lists the extended attributes recorded for the node. - Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error -} - -type NodeSetxattrer interface { - // Setxattr sets an extended attribute with the given name and - // value for the node. - Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error -} - -type NodeRemovexattrer interface { - // Removexattr removes an extended attribute for the name. - // - // If there is no xattr by that name, returns fuse.ErrNoXattr. - Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error -} - -var startTime = time.Now() - -func nodeAttr(ctx context.Context, n Node, attr *fuse.Attr) error { - attr.Valid = attrValidTime - attr.Nlink = 1 - attr.Atime = startTime - attr.Mtime = startTime - attr.Ctime = startTime - attr.Crtime = startTime - if err := n.Attr(ctx, attr); err != nil { - return err - } - return nil -} - -// A Handle is the interface required of an opened file or directory. -// See the documentation for type FS for general information -// pertaining to all methods. -// -// Other FUSE requests can be handled by implementing methods from the -// Handle* interfaces. The most common to implement are HandleReader, -// HandleReadDirer, and HandleWriter. -// -// TODO implement methods: Getlk, Setlk, Setlkw -type Handle interface { -} - -type HandleFlusher interface { - // Flush is called each time the file or directory is closed. - // Because there can be multiple file descriptors referring to a - // single opened file, Flush can be called multiple times. - Flush(ctx context.Context, req *fuse.FlushRequest) error -} - -type HandleReadAller interface { - ReadAll(ctx context.Context) ([]byte, error) -} - -type HandleReadDirAller interface { - ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) -} - -type HandleReader interface { - // Read requests to read data from the handle. - // - // There is a page cache in the kernel that normally submits only - // page-aligned reads spanning one or more pages. However, you - // should not rely on this. To see individual requests as - // submitted by the file system clients, set OpenDirectIO. - // - // Note that reads beyond the size of the file as reported by Attr - // are not even attempted (except in OpenDirectIO mode). - Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error -} - -type HandleWriter interface { - // Write requests to write data into the handle. - // - // There is a writeback page cache in the kernel that normally submits - // only page-aligned writes spanning one or more pages. However, - // you should not rely on this. To see individual requests as - // submitted by the file system clients, set OpenDirectIO. - // - // Note that file size changes are communicated through Setattr. - // Writes beyond the size of the file as reported by Attr are not - // even attempted (except in OpenDirectIO mode). - Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error -} - -type HandleReleaser interface { - Release(ctx context.Context, req *fuse.ReleaseRequest) error -} - -type Server struct { - FS FS - - // Function to send debug log messages to. If nil, use fuse.Debug. - // Note that changing this or fuse.Debug may not affect existing - // calls to Serve. - // - // See fuse.Debug for the rules that log functions must follow. - Debug func(msg interface{}) - - // Used to ensure worker goroutines finish before Serve returns - wg sync.WaitGroup -} - -// Serve serves the FUSE connection by making calls to the methods -// of fs and the Nodes and Handles it makes available. It returns only -// when the connection has been closed or an unexpected error occurs. -func (s *Server) Serve(c *fuse.Conn) error { - defer s.wg.Wait() // Wait for worker goroutines to complete before return - - sc := serveConn{ - fs: s.FS, - debug: s.Debug, - req: map[fuse.RequestID]*serveRequest{}, - dynamicInode: GenerateDynamicInode, - } - if sc.debug == nil { - sc.debug = fuse.Debug - } - if dyn, ok := sc.fs.(FSInodeGenerator); ok { - sc.dynamicInode = dyn.GenerateInode - } - - root, err := sc.fs.Root() - if err != nil { - return fmt.Errorf("cannot obtain root node: %v", err) - } - sc.node = append(sc.node, nil, &serveNode{inode: 1, node: root, refs: 1}) - sc.handle = append(sc.handle, nil) - - for { - req, err := c.ReadRequest() - if err != nil { - if err == io.EOF { - break - } - return err - } - - s.wg.Add(1) - go func() { - defer s.wg.Done() - sc.serve(req) - }() - } - return nil -} - -// Serve serves a FUSE connection with the default settings. See -// Server.Serve. -func Serve(c *fuse.Conn, fs FS) error { - server := Server{ - FS: fs, - } - return server.Serve(c) -} - -type nothing struct{} - -type serveConn struct { - meta sync.Mutex - fs FS - req map[fuse.RequestID]*serveRequest - node []*serveNode - handle []*serveHandle - freeNode []fuse.NodeID - freeHandle []fuse.HandleID - nodeGen uint64 - debug func(msg interface{}) - dynamicInode func(parent uint64, name string) uint64 -} - -type serveRequest struct { - Request fuse.Request - cancel func() -} - -type serveNode struct { - inode uint64 - node Node - refs uint64 -} - -func (sn *serveNode) attr(ctx context.Context, attr *fuse.Attr) error { - err := nodeAttr(ctx, sn.node, attr) - if attr.Inode == 0 { - attr.Inode = sn.inode - } - return err -} - -type serveHandle struct { - handle Handle - readData []byte - nodeID fuse.NodeID -} - -// NodeRef can be embedded in a Node to recognize the same Node being -// returned from multiple Lookup, Create etc calls. -// -// Without this, each Node will get a new NodeID, causing spurious -// cache invalidations, extra lookups and aliasing anomalies. This may -// not matter for a simple, read-only filesystem. -type NodeRef struct { - id fuse.NodeID - generation uint64 -} - -// nodeRef is only ever accessed while holding serveConn.meta -func (n *NodeRef) nodeRef() *NodeRef { - return n -} - -type nodeRef interface { - nodeRef() *NodeRef -} - -func (c *serveConn) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint64) { - c.meta.Lock() - defer c.meta.Unlock() - - var ref *NodeRef - if nodeRef, ok := node.(nodeRef); ok { - ref = nodeRef.nodeRef() - - if ref.id != 0 { - // dropNode guarantees that NodeRef is zeroed at the same - // time as the NodeID is removed from serveConn.node, as - // guarded by c.meta; this means sn cannot be nil here - sn := c.node[ref.id] - sn.refs++ - return ref.id, ref.generation - } - } - - sn := &serveNode{inode: inode, node: node, refs: 1} - if n := len(c.freeNode); n > 0 { - id = c.freeNode[n-1] - c.freeNode = c.freeNode[:n-1] - c.node[id] = sn - c.nodeGen++ - } else { - id = fuse.NodeID(len(c.node)) - c.node = append(c.node, sn) - } - gen = c.nodeGen - if ref != nil { - ref.id = id - ref.generation = gen - } - return -} - -func (c *serveConn) saveHandle(handle Handle, nodeID fuse.NodeID) (id fuse.HandleID) { - c.meta.Lock() - shandle := &serveHandle{handle: handle, nodeID: nodeID} - if n := len(c.freeHandle); n > 0 { - id = c.freeHandle[n-1] - c.freeHandle = c.freeHandle[:n-1] - c.handle[id] = shandle - } else { - id = fuse.HandleID(len(c.handle)) - c.handle = append(c.handle, shandle) - } - c.meta.Unlock() - return -} - -type nodeRefcountDropBug struct { - N uint64 - Refs uint64 - Node fuse.NodeID -} - -func (n *nodeRefcountDropBug) String() string { - return fmt.Sprintf("bug: trying to drop %d of %d references to %v", n.N, n.Refs, n.Node) -} - -func (c *serveConn) dropNode(id fuse.NodeID, n uint64) (forget bool) { - c.meta.Lock() - defer c.meta.Unlock() - snode := c.node[id] - - if snode == nil { - // this should only happen if refcounts kernel<->us disagree - // *and* two ForgetRequests for the same node race each other; - // this indicates a bug somewhere - c.debug(nodeRefcountDropBug{N: n, Node: id}) - - // we may end up triggering Forget twice, but that's better - // than not even once, and that's the best we can do - return true - } - - if n > snode.refs { - c.debug(nodeRefcountDropBug{N: n, Refs: snode.refs, Node: id}) - n = snode.refs - } - - snode.refs -= n - if snode.refs == 0 { - c.node[id] = nil - if nodeRef, ok := snode.node.(nodeRef); ok { - ref := nodeRef.nodeRef() - *ref = NodeRef{} - } - c.freeNode = append(c.freeNode, id) - return true - } - return false -} - -func (c *serveConn) dropHandle(id fuse.HandleID) { - c.meta.Lock() - c.handle[id] = nil - c.freeHandle = append(c.freeHandle, id) - c.meta.Unlock() -} - -type missingHandle struct { - Handle fuse.HandleID - MaxHandle fuse.HandleID -} - -func (m missingHandle) String() string { - return fmt.Sprint("missing handle", m.Handle, m.MaxHandle) -} - -// Returns nil for invalid handles. -func (c *serveConn) getHandle(id fuse.HandleID) (shandle *serveHandle) { - c.meta.Lock() - defer c.meta.Unlock() - if id < fuse.HandleID(len(c.handle)) { - shandle = c.handle[uint(id)] - } - if shandle == nil { - c.debug(missingHandle{ - Handle: id, - MaxHandle: fuse.HandleID(len(c.handle)), - }) - } - return -} - -type request struct { - Op string - Request *fuse.Header - In interface{} `json:",omitempty"` -} - -func (r request) String() string { - return fmt.Sprintf("<- %s", r.In) -} - -type logResponseHeader struct { - ID fuse.RequestID -} - -func (m logResponseHeader) String() string { - return fmt.Sprintf("ID=%#x", m.ID) -} - -type response struct { - Op string - Request logResponseHeader - Out interface{} `json:",omitempty"` - // Errno contains the errno value as a string, for example "EPERM". - Errno string `json:",omitempty"` - // Error may contain a free form error message. - Error string `json:",omitempty"` -} - -func (r response) errstr() string { - s := r.Errno - if r.Error != "" { - // prefix the errno constant to the long form message - s = s + ": " + r.Error - } - return s -} - -func (r response) String() string { - switch { - case r.Errno != "" && r.Out != nil: - return fmt.Sprintf("-> %s error=%s %s", r.Request, r.errstr(), r.Out) - case r.Errno != "": - return fmt.Sprintf("-> %s error=%s", r.Request, r.errstr()) - case r.Out != nil: - // make sure (seemingly) empty values are readable - switch r.Out.(type) { - case string: - return fmt.Sprintf("-> %s %q", r.Request, r.Out) - case []byte: - return fmt.Sprintf("-> %s [% x]", r.Request, r.Out) - default: - return fmt.Sprintf("-> %s %s", r.Request, r.Out) - } - default: - return fmt.Sprintf("-> %s", r.Request) - } -} - -type logMissingNode struct { - MaxNode fuse.NodeID -} - -func opName(req fuse.Request) string { - t := reflect.Indirect(reflect.ValueOf(req)).Type() - s := t.Name() - s = strings.TrimSuffix(s, "Request") - return s -} - -type logLinkRequestOldNodeNotFound struct { - Request *fuse.Header - In *fuse.LinkRequest -} - -func (m *logLinkRequestOldNodeNotFound) String() string { - return fmt.Sprintf("In LinkRequest (request %#x), node %d not found", m.Request.Hdr().ID, m.In.OldNode) -} - -type renameNewDirNodeNotFound struct { - Request *fuse.Header - In *fuse.RenameRequest -} - -func (m *renameNewDirNodeNotFound) String() string { - return fmt.Sprintf("In RenameRequest (request %#x), node %d not found", m.Request.Hdr().ID, m.In.NewDir) -} - -type handlerPanickedError struct { - Request interface{} - Err interface{} -} - -var _ error = handlerPanickedError{} - -func (h handlerPanickedError) Error() string { - return fmt.Sprintf("handler panicked: %v", h.Err) -} - -var _ fuse.ErrorNumber = handlerPanickedError{} - -func (h handlerPanickedError) Errno() fuse.Errno { - if err, ok := h.Err.(fuse.ErrorNumber); ok { - return err.Errno() - } - return fuse.DefaultErrno -} - -func initLookupResponse(s *fuse.LookupResponse) { - s.EntryValid = entryValidTime -} - -func (c *serveConn) serve(r fuse.Request) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - req := &serveRequest{Request: r, cancel: cancel} - - c.debug(request{ - Op: opName(r), - Request: r.Hdr(), - In: r, - }) - var node Node - var snode *serveNode - c.meta.Lock() - hdr := r.Hdr() - if id := hdr.Node; id != 0 { - if id < fuse.NodeID(len(c.node)) { - snode = c.node[uint(id)] - } - if snode == nil { - c.meta.Unlock() - c.debug(response{ - Op: opName(r), - Request: logResponseHeader{ID: hdr.ID}, - Error: fuse.ESTALE.ErrnoName(), - // this is the only place that sets both Error and - // Out; not sure if i want to do that; might get rid - // of len(c.node) things altogether - Out: logMissingNode{ - MaxNode: fuse.NodeID(len(c.node)), - }, - }) - r.RespondError(fuse.ESTALE) - return - } - node = snode.node - } - if c.req[hdr.ID] != nil { - // This happens with OSXFUSE. Assume it's okay and - // that we'll never see an interrupt for this one. - // Otherwise everything wedges. TODO: Report to OSXFUSE? - // - // TODO this might have been because of missing done() calls - } else { - c.req[hdr.ID] = req - } - c.meta.Unlock() - - // Call this before responding. - // After responding is too late: we might get another request - // with the same ID and be very confused. - done := func(resp interface{}) { - msg := response{ - Op: opName(r), - Request: logResponseHeader{ID: hdr.ID}, - } - if err, ok := resp.(error); ok { - msg.Error = err.Error() - if ferr, ok := err.(fuse.ErrorNumber); ok { - errno := ferr.Errno() - msg.Errno = errno.ErrnoName() - if errno == err { - // it's just a fuse.Errno with no extra detail; - // skip the textual message for log readability - msg.Error = "" - } - } else { - msg.Errno = fuse.DefaultErrno.ErrnoName() - } - } else { - msg.Out = resp - } - c.debug(msg) - - c.meta.Lock() - delete(c.req, hdr.ID) - c.meta.Unlock() - } - - defer func() { - if rec := recover(); rec != nil { - const size = 1 << 16 - buf := make([]byte, size) - n := runtime.Stack(buf, false) - buf = buf[:n] - log.Printf("fuse: panic in handler for %v: %v\n%s", r, rec, buf) - err := handlerPanickedError{ - Request: r, - Err: rec, - } - done(err) - r.RespondError(err) - } - }() - - switch r := r.(type) { - default: - // NOTE: To FUSE, ENOSYS means "this server never implements this request." - // It would be inappropriate to return ENOSYS for other operations in this - // switch that might only be unavailable in some contexts, not all. - done(fuse.ENOSYS) - r.RespondError(fuse.ENOSYS) - - // FS operations. - case *fuse.InitRequest: - s := &fuse.InitResponse{ - MaxWrite: 128 * 1024, - Flags: fuse.InitBigWrites, - } - if fs, ok := c.fs.(FSIniter); ok { - if err := fs.Init(ctx, r, s); err != nil { - done(err) - r.RespondError(err) - break - } - } - done(s) - r.Respond(s) - - case *fuse.StatfsRequest: - s := &fuse.StatfsResponse{} - if fs, ok := c.fs.(FSStatfser); ok { - if err := fs.Statfs(ctx, r, s); err != nil { - done(err) - r.RespondError(err) - break - } - } - done(s) - r.Respond(s) - - // Node operations. - case *fuse.GetattrRequest: - s := &fuse.GetattrResponse{} - if n, ok := node.(NodeGetattrer); ok { - if err := n.Getattr(ctx, r, s); err != nil { - done(err) - r.RespondError(err) - break - } - } else { - if err := snode.attr(ctx, &s.Attr); err != nil { - done(err) - r.RespondError(err) - break - } - } - done(s) - r.Respond(s) - - case *fuse.SetattrRequest: - s := &fuse.SetattrResponse{} - if n, ok := node.(NodeSetattrer); ok { - if err := n.Setattr(ctx, r, s); err != nil { - done(err) - r.RespondError(err) - break - } - done(s) - r.Respond(s) - break - } - - if err := snode.attr(ctx, &s.Attr); err != nil { - done(err) - r.RespondError(err) - break - } - done(s) - r.Respond(s) - - case *fuse.SymlinkRequest: - s := &fuse.SymlinkResponse{} - initLookupResponse(&s.LookupResponse) - n, ok := node.(NodeSymlinker) - if !ok { - done(fuse.EIO) // XXX or EPERM like Mkdir? - r.RespondError(fuse.EIO) - break - } - n2, err := n.Symlink(ctx, r) - if err != nil { - done(err) - r.RespondError(err) - break - } - if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.NewName, n2); err != nil { - done(err) - r.RespondError(err) - break - } - done(s) - r.Respond(s) - - case *fuse.ReadlinkRequest: - n, ok := node.(NodeReadlinker) - if !ok { - done(fuse.EIO) /// XXX or EPERM? - r.RespondError(fuse.EIO) - break - } - target, err := n.Readlink(ctx, r) - if err != nil { - done(err) - r.RespondError(err) - break - } - done(target) - r.Respond(target) - - case *fuse.LinkRequest: - n, ok := node.(NodeLinker) - if !ok { - done(fuse.EIO) /// XXX or EPERM? - r.RespondError(fuse.EIO) - break - } - c.meta.Lock() - var oldNode *serveNode - if int(r.OldNode) < len(c.node) { - oldNode = c.node[r.OldNode] - } - c.meta.Unlock() - if oldNode == nil { - c.debug(logLinkRequestOldNodeNotFound{ - Request: r.Hdr(), - In: r, - }) - done(fuse.EIO) - r.RespondError(fuse.EIO) - break - } - n2, err := n.Link(ctx, r, oldNode.node) - if err != nil { - done(err) - r.RespondError(err) - break - } - s := &fuse.LookupResponse{} - initLookupResponse(s) - if err := c.saveLookup(ctx, s, snode, r.NewName, n2); err != nil { - done(err) - r.RespondError(err) - break - } - done(s) - r.Respond(s) - - case *fuse.RemoveRequest: - n, ok := node.(NodeRemover) - if !ok { - done(fuse.EIO) /// XXX or EPERM? - r.RespondError(fuse.EIO) - break - } - err := n.Remove(ctx, r) - if err != nil { - done(err) - r.RespondError(err) - break - } - done(nil) - r.Respond() - - case *fuse.AccessRequest: - if n, ok := node.(NodeAccesser); ok { - if err := n.Access(ctx, r); err != nil { - done(err) - r.RespondError(err) - break - } - } - done(nil) - r.Respond() - - case *fuse.LookupRequest: - var n2 Node - var err error - s := &fuse.LookupResponse{} - initLookupResponse(s) - if n, ok := node.(NodeStringLookuper); ok { - n2, err = n.Lookup(ctx, r.Name) - } else if n, ok := node.(NodeRequestLookuper); ok { - n2, err = n.Lookup(ctx, r, s) - } else { - done(fuse.ENOENT) - r.RespondError(fuse.ENOENT) - break - } - if err != nil { - done(err) - r.RespondError(err) - break - } - if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil { - done(err) - r.RespondError(err) - break - } - done(s) - r.Respond(s) - - case *fuse.MkdirRequest: - s := &fuse.MkdirResponse{} - initLookupResponse(&s.LookupResponse) - n, ok := node.(NodeMkdirer) - if !ok { - done(fuse.EPERM) - r.RespondError(fuse.EPERM) - break - } - n2, err := n.Mkdir(ctx, r) - if err != nil { - done(err) - r.RespondError(err) - break - } - if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil { - done(err) - r.RespondError(err) - break - } - done(s) - r.Respond(s) - - case *fuse.OpenRequest: - s := &fuse.OpenResponse{} - var h2 Handle - if n, ok := node.(NodeOpener); ok { - hh, err := n.Open(ctx, r, s) - if err != nil { - done(err) - r.RespondError(err) - break - } - h2 = hh - } else { - h2 = node - } - s.Handle = c.saveHandle(h2, hdr.Node) - done(s) - r.Respond(s) - - case *fuse.CreateRequest: - n, ok := node.(NodeCreater) - if !ok { - // If we send back ENOSYS, FUSE will try mknod+open. - done(fuse.EPERM) - r.RespondError(fuse.EPERM) - break - } - s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{}} - initLookupResponse(&s.LookupResponse) - n2, h2, err := n.Create(ctx, r, s) - if err != nil { - done(err) - r.RespondError(err) - break - } - if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil { - done(err) - r.RespondError(err) - break - } - s.Handle = c.saveHandle(h2, hdr.Node) - done(s) - r.Respond(s) - - case *fuse.GetxattrRequest: - n, ok := node.(NodeGetxattrer) - if !ok { - done(fuse.ENOTSUP) - r.RespondError(fuse.ENOTSUP) - break - } - s := &fuse.GetxattrResponse{} - err := n.Getxattr(ctx, r, s) - if err != nil { - done(err) - r.RespondError(err) - break - } - if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) { - done(fuse.ERANGE) - r.RespondError(fuse.ERANGE) - break - } - done(s) - r.Respond(s) - - case *fuse.ListxattrRequest: - n, ok := node.(NodeListxattrer) - if !ok { - done(fuse.ENOTSUP) - r.RespondError(fuse.ENOTSUP) - break - } - s := &fuse.ListxattrResponse{} - err := n.Listxattr(ctx, r, s) - if err != nil { - done(err) - r.RespondError(err) - break - } - if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) { - done(fuse.ERANGE) - r.RespondError(fuse.ERANGE) - break - } - done(s) - r.Respond(s) - - case *fuse.SetxattrRequest: - n, ok := node.(NodeSetxattrer) - if !ok { - done(fuse.ENOTSUP) - r.RespondError(fuse.ENOTSUP) - break - } - err := n.Setxattr(ctx, r) - if err != nil { - done(err) - r.RespondError(err) - break - } - done(nil) - r.Respond() - - case *fuse.RemovexattrRequest: - n, ok := node.(NodeRemovexattrer) - if !ok { - done(fuse.ENOTSUP) - r.RespondError(fuse.ENOTSUP) - break - } - err := n.Removexattr(ctx, r) - if err != nil { - done(err) - r.RespondError(err) - break - } - done(nil) - r.Respond() - - case *fuse.ForgetRequest: - forget := c.dropNode(hdr.Node, r.N) - if forget { - n, ok := node.(NodeForgetter) - if ok { - n.Forget() - } - } - done(nil) - r.Respond() - - // Handle operations. - case *fuse.ReadRequest: - shandle := c.getHandle(r.Handle) - if shandle == nil { - done(fuse.ESTALE) - r.RespondError(fuse.ESTALE) - return - } - handle := shandle.handle - - s := &fuse.ReadResponse{Data: make([]byte, 0, r.Size)} - if r.Dir { - if h, ok := handle.(HandleReadDirAller); ok { - if shandle.readData == nil { - dirs, err := h.ReadDirAll(ctx) - if err != nil { - done(err) - r.RespondError(err) - break - } - var data []byte - for _, dir := range dirs { - if dir.Inode == 0 { - dir.Inode = c.dynamicInode(snode.inode, dir.Name) - } - data = fuse.AppendDirent(data, dir) - } - shandle.readData = data - } - fuseutil.HandleRead(r, s, shandle.readData) - done(s) - r.Respond(s) - break - } - } else { - if h, ok := handle.(HandleReadAller); ok { - if shandle.readData == nil { - data, err := h.ReadAll(ctx) - if err != nil { - done(err) - r.RespondError(err) - break - } - if data == nil { - data = []byte{} - } - shandle.readData = data - } - fuseutil.HandleRead(r, s, shandle.readData) - done(s) - r.Respond(s) - break - } - h, ok := handle.(HandleReader) - if !ok { - fmt.Printf("NO READ FOR %T\n", handle) - done(fuse.EIO) - r.RespondError(fuse.EIO) - break - } - if err := h.Read(ctx, r, s); err != nil { - done(err) - r.RespondError(err) - break - } - } - done(s) - r.Respond(s) - - case *fuse.WriteRequest: - shandle := c.getHandle(r.Handle) - if shandle == nil { - done(fuse.ESTALE) - r.RespondError(fuse.ESTALE) - return - } - - s := &fuse.WriteResponse{} - if h, ok := shandle.handle.(HandleWriter); ok { - if err := h.Write(ctx, r, s); err != nil { - done(err) - r.RespondError(err) - break - } - done(s) - r.Respond(s) - break - } - done(fuse.EIO) - r.RespondError(fuse.EIO) - - case *fuse.FlushRequest: - shandle := c.getHandle(r.Handle) - if shandle == nil { - done(fuse.ESTALE) - r.RespondError(fuse.ESTALE) - return - } - handle := shandle.handle - - if h, ok := handle.(HandleFlusher); ok { - if err := h.Flush(ctx, r); err != nil { - done(err) - r.RespondError(err) - break - } - } - done(nil) - r.Respond() - - case *fuse.ReleaseRequest: - shandle := c.getHandle(r.Handle) - if shandle == nil { - done(fuse.ESTALE) - r.RespondError(fuse.ESTALE) - return - } - handle := shandle.handle - - // No matter what, release the handle. - c.dropHandle(r.Handle) - - if h, ok := handle.(HandleReleaser); ok { - if err := h.Release(ctx, r); err != nil { - done(err) - r.RespondError(err) - break - } - } - done(nil) - r.Respond() - - case *fuse.DestroyRequest: - if fs, ok := c.fs.(FSDestroyer); ok { - fs.Destroy() - } - done(nil) - r.Respond() - - case *fuse.RenameRequest: - c.meta.Lock() - var newDirNode *serveNode - if int(r.NewDir) < len(c.node) { - newDirNode = c.node[r.NewDir] - } - c.meta.Unlock() - if newDirNode == nil { - c.debug(renameNewDirNodeNotFound{ - Request: r.Hdr(), - In: r, - }) - done(fuse.EIO) - r.RespondError(fuse.EIO) - break - } - n, ok := node.(NodeRenamer) - if !ok { - done(fuse.EIO) // XXX or EPERM like Mkdir? - r.RespondError(fuse.EIO) - break - } - err := n.Rename(ctx, r, newDirNode.node) - if err != nil { - done(err) - r.RespondError(err) - break - } - done(nil) - r.Respond() - - case *fuse.MknodRequest: - n, ok := node.(NodeMknoder) - if !ok { - done(fuse.EIO) - r.RespondError(fuse.EIO) - break - } - n2, err := n.Mknod(ctx, r) - if err != nil { - done(err) - r.RespondError(err) - break - } - s := &fuse.LookupResponse{} - initLookupResponse(s) - if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil { - done(err) - r.RespondError(err) - break - } - done(s) - r.Respond(s) - - case *fuse.FsyncRequest: - n, ok := node.(NodeFsyncer) - if !ok { - done(fuse.EIO) - r.RespondError(fuse.EIO) - break - } - err := n.Fsync(ctx, r) - if err != nil { - done(err) - r.RespondError(err) - break - } - done(nil) - r.Respond() - - case *fuse.InterruptRequest: - c.meta.Lock() - ireq := c.req[r.IntrID] - if ireq != nil && ireq.cancel != nil { - ireq.cancel() - ireq.cancel = nil - } - c.meta.Unlock() - done(nil) - r.Respond() - - /* case *FsyncdirRequest: - done(ENOSYS) - r.RespondError(ENOSYS) - - case *GetlkRequest, *SetlkRequest, *SetlkwRequest: - done(ENOSYS) - r.RespondError(ENOSYS) - - case *BmapRequest: - done(ENOSYS) - r.RespondError(ENOSYS) - - case *SetvolnameRequest, *GetxtimesRequest, *ExchangeRequest: - done(ENOSYS) - r.RespondError(ENOSYS) - */ - } -} - -func (c *serveConn) saveLookup(ctx context.Context, s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) error { - if err := nodeAttr(ctx, n2, &s.Attr); err != nil { - return err - } - if s.Attr.Inode == 0 { - s.Attr.Inode = c.dynamicInode(snode.inode, elem) - } - - s.Node, s.Generation = c.saveNode(s.Attr.Inode, n2) - return nil -} - -// DataHandle returns a read-only Handle that satisfies reads -// using the given data. -func DataHandle(data []byte) Handle { - return &dataHandle{data} -} - -type dataHandle struct { - data []byte -} - -func (d *dataHandle) ReadAll(ctx context.Context) ([]byte, error) { - return d.data, nil -} - -// GenerateDynamicInode returns a dynamic inode. -// -// The parent inode and current entry name are used as the criteria -// for choosing a pseudorandom inode. This makes it likely the same -// entry will get the same inode on multiple runs. -func GenerateDynamicInode(parent uint64, name string) uint64 { - h := fnv.New64a() - var buf [8]byte - binary.LittleEndian.PutUint64(buf[:], parent) - _, _ = h.Write(buf[:]) - _, _ = h.Write([]byte(name)) - var inode uint64 - for { - inode = h.Sum64() - if inode != 0 { - break - } - // there's a tiny probability that result is zero; change the - // input a little and try again - _, _ = h.Write([]byte{'x'}) - } - return inode -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go b/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go deleted file mode 100644 index 919ab63b4..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go +++ /dev/null @@ -1,1919 +0,0 @@ -package fs_test - -import ( - "bytes" - "context" - "errors" - "io" - "io/ioutil" - "log" - "os" - "os/exec" - "runtime" - "strings" - "sync" - "syscall" - "testing" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fuseutil" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/syscallx" -) - -// TO TEST: -// Lookup(*LookupRequest, *LookupResponse) -// Getattr(*GetattrRequest, *GetattrResponse) -// Attr with explicit inode -// Setattr(*SetattrRequest, *SetattrResponse) -// Access(*AccessRequest) -// Open(*OpenRequest, *OpenResponse) -// Write(*WriteRequest, *WriteResponse) -// Flush(*FlushRequest, *FlushResponse) - -func init() { - fstestutil.DebugByDefault() -} - -// symlink can be embedded in a struct to make it look like a symlink. -type symlink struct { - target string -} - -func (f symlink) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = os.ModeSymlink | 0666 - return nil -} - -// fifo can be embedded in a struct to make it look like a named pipe. -type fifo struct{} - -func (f fifo) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = os.ModeNamedPipe | 0666 - return nil -} - -type badRootFS struct{} - -func (badRootFS) Root() (fs.Node, error) { - // pick a really distinct error, to identify it later - return nil, fuse.Errno(syscall.ENAMETOOLONG) -} - -func TestRootErr(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, badRootFS{}) - if err == nil { - // path for synchronous mounts (linux): started out fine, now - // wait for Serve to cycle through - err = <-mnt.Error - // without this, unmount will keep failing with EBUSY; nudge - // kernel into realizing InitResponse will not happen - mnt.Conn.Close() - mnt.Close() - } - - if err == nil { - t.Fatal("expected an error") - } - // TODO this should not be a textual comparison, Serve hides - // details - if err.Error() != "cannot obtain root node: file name too long" { - t.Errorf("Unexpected error: %v", err) - } -} - -type testPanic struct{} - -type panicSentinel struct{} - -var _ error = panicSentinel{} - -func (panicSentinel) Error() string { return "just a test" } - -var _ fuse.ErrorNumber = panicSentinel{} - -func (panicSentinel) Errno() fuse.Errno { - return fuse.Errno(syscall.ENAMETOOLONG) -} - -func (f testPanic) Root() (fs.Node, error) { - return f, nil -} - -func (f testPanic) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 1 - a.Mode = os.ModeDir | 0777 - return nil -} - -func (f testPanic) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error { - panic(panicSentinel{}) -} - -func TestPanic(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, testPanic{}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - var st syscall.Statfs_t - err = syscall.Statfs(mnt.Dir, &st) - if g, e := err, syscall.ENAMETOOLONG; g != e { - t.Fatalf("wrong error from panicking handler: %v != %v", g, e) - } -} - -type testStatFS struct{} - -func (f testStatFS) Root() (fs.Node, error) { - return f, nil -} - -func (f testStatFS) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 1 - a.Mode = os.ModeDir | 0777 - return nil -} - -func (f testStatFS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error { - resp.Blocks = 42 - resp.Files = 13 - return nil -} - -func TestStatfs(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, testStatFS{}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - { - var st syscall.Statfs_t - err = syscall.Statfs(mnt.Dir, &st) - if err != nil { - t.Errorf("Statfs failed: %v", err) - } - t.Logf("Statfs got: %#v", st) - if g, e := st.Blocks, uint64(42); g != e { - t.Errorf("got Blocks = %d; want %d", g, e) - } - if g, e := st.Files, uint64(13); g != e { - t.Errorf("got Files = %d; want %d", g, e) - } - } - - { - var st syscall.Statfs_t - f, err := os.Open(mnt.Dir) - if err != nil { - t.Errorf("Open for fstatfs failed: %v", err) - } - defer f.Close() - err = syscall.Fstatfs(int(f.Fd()), &st) - if err != nil { - t.Errorf("Fstatfs failed: %v", err) - } - t.Logf("Fstatfs got: %#v", st) - if g, e := st.Blocks, uint64(42); g != e { - t.Errorf("got Blocks = %d; want %d", g, e) - } - if g, e := st.Files, uint64(13); g != e { - t.Errorf("got Files = %d; want %d", g, e) - } - } - -} - -// Test Stat of root. - -type root struct{} - -func (f root) Root() (fs.Node, error) { - return f, nil -} - -func (root) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 1 - a.Mode = os.ModeDir | 0555 - return nil -} - -func TestStatRoot(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, root{}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - fi, err := os.Stat(mnt.Dir) - if err != nil { - t.Fatalf("root getattr failed with %v", err) - } - mode := fi.Mode() - if (mode & os.ModeType) != os.ModeDir { - t.Errorf("root is not a directory: %#v", fi) - } - if mode.Perm() != 0555 { - t.Errorf("root has weird access mode: %v", mode.Perm()) - } - switch stat := fi.Sys().(type) { - case *syscall.Stat_t: - if stat.Ino != 1 { - t.Errorf("root has wrong inode: %v", stat.Ino) - } - if stat.Nlink != 1 { - t.Errorf("root has wrong link count: %v", stat.Nlink) - } - if stat.Uid != 0 { - t.Errorf("root has wrong uid: %d", stat.Uid) - } - if stat.Gid != 0 { - t.Errorf("root has wrong gid: %d", stat.Gid) - } - } -} - -// Test Read calling ReadAll. - -type readAll struct { - fstestutil.File -} - -const hi = "hello, world" - -func (readAll) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = 0666 - a.Size = uint64(len(hi)) - return nil -} - -func (readAll) ReadAll(ctx context.Context) ([]byte, error) { - return []byte(hi), nil -} - -func testReadAll(t *testing.T, path string) { - data, err := ioutil.ReadFile(path) - if err != nil { - t.Fatalf("readAll: %v", err) - } - if string(data) != hi { - t.Errorf("readAll = %q, want %q", data, hi) - } -} - -func TestReadAll(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": readAll{}}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - testReadAll(t, mnt.Dir+"/child") -} - -// Test Read. - -type readWithHandleRead struct { - fstestutil.File -} - -func (readWithHandleRead) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = 0666 - a.Size = uint64(len(hi)) - return nil -} - -func (readWithHandleRead) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - fuseutil.HandleRead(req, resp, []byte(hi)) - return nil -} - -func TestReadAllWithHandleRead(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": readWithHandleRead{}}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - testReadAll(t, mnt.Dir+"/child") -} - -// Test Release. - -type release struct { - fstestutil.File - record.ReleaseWaiter -} - -func TestRelease(t *testing.T) { - t.Parallel() - r := &release{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": r}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - f, err := os.Open(mnt.Dir + "/child") - if err != nil { - t.Fatal(err) - } - f.Close() - if !r.WaitForRelease(1 * time.Second) { - t.Error("Close did not Release in time") - } -} - -// Test Write calling basic Write, with an fsync thrown in too. - -type write struct { - fstestutil.File - record.Writes - record.Fsyncs -} - -func TestWrite(t *testing.T) { - t.Parallel() - w := &write{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": w}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - f, err := os.Create(mnt.Dir + "/child") - if err != nil { - t.Fatalf("Create: %v", err) - } - defer f.Close() - n, err := f.Write([]byte(hi)) - if err != nil { - t.Fatalf("Write: %v", err) - } - if n != len(hi) { - t.Fatalf("short write; n=%d; hi=%d", n, len(hi)) - } - - err = syscall.Fsync(int(f.Fd())) - if err != nil { - t.Fatalf("Fsync = %v", err) - } - if w.RecordedFsync() == (fuse.FsyncRequest{}) { - t.Errorf("never received expected fsync call") - } - - err = f.Close() - if err != nil { - t.Fatalf("Close: %v", err) - } - - if got := string(w.RecordedWriteData()); got != hi { - t.Errorf("write = %q, want %q", got, hi) - } -} - -// Test Write of a larger buffer. - -type writeLarge struct { - fstestutil.File - record.Writes -} - -func TestWriteLarge(t *testing.T) { - t.Parallel() - w := &write{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": w}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - f, err := os.Create(mnt.Dir + "/child") - if err != nil { - t.Fatalf("Create: %v", err) - } - defer f.Close() - const one = "xyzzyfoo" - large := bytes.Repeat([]byte(one), 8192) - n, err := f.Write(large) - if err != nil { - t.Fatalf("Write: %v", err) - } - if g, e := n, len(large); g != e { - t.Fatalf("short write: %d != %d", g, e) - } - - err = f.Close() - if err != nil { - t.Fatalf("Close: %v", err) - } - - got := w.RecordedWriteData() - if g, e := len(got), len(large); g != e { - t.Errorf("write wrong length: %d != %d", g, e) - } - if g := strings.Replace(string(got), one, "", -1); g != "" { - t.Errorf("write wrong data: expected repeats of %q, also got %q", one, g) - } -} - -// Test Write calling Setattr+Write+Flush. - -type writeTruncateFlush struct { - fstestutil.File - record.Writes - record.Setattrs - record.Flushes -} - -func TestWriteTruncateFlush(t *testing.T) { - t.Parallel() - w := &writeTruncateFlush{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": w}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - err = ioutil.WriteFile(mnt.Dir+"/child", []byte(hi), 0666) - if err != nil { - t.Fatalf("WriteFile: %v", err) - } - if w.RecordedSetattr() == (fuse.SetattrRequest{}) { - t.Errorf("writeTruncateFlush expected Setattr") - } - if !w.RecordedFlush() { - t.Errorf("writeTruncateFlush expected Setattr") - } - if got := string(w.RecordedWriteData()); got != hi { - t.Errorf("writeTruncateFlush = %q, want %q", got, hi) - } -} - -// Test Mkdir. - -type mkdir1 struct { - fstestutil.Dir - record.Mkdirs -} - -func (f *mkdir1) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { - f.Mkdirs.Mkdir(ctx, req) - return &mkdir1{}, nil -} - -func TestMkdir(t *testing.T) { - t.Parallel() - f := &mkdir1{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - // uniform umask needed to make os.Mkdir's mode into something - // reproducible - defer syscall.Umask(syscall.Umask(0022)) - err = os.Mkdir(mnt.Dir+"/foo", 0771) - if err != nil { - t.Fatalf("mkdir: %v", err) - } - want := fuse.MkdirRequest{Name: "foo", Mode: os.ModeDir | 0751} - if g, e := f.RecordedMkdir(), want; g != e { - t.Errorf("mkdir saw %+v, want %+v", g, e) - } -} - -// Test Create (and fsync) - -type create1file struct { - fstestutil.File - record.Fsyncs -} - -type create1 struct { - fstestutil.Dir - f create1file -} - -func (f *create1) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) { - if req.Name != "foo" { - log.Printf("ERROR create1.Create unexpected name: %q\n", req.Name) - return nil, nil, fuse.EPERM - } - flags := req.Flags - - // OS X does not pass O_TRUNC here, Linux does; as this is a - // Create, that's acceptable - flags &^= fuse.OpenTruncate - - if runtime.GOOS == "linux" { - // Linux <3.7 accidentally leaks O_CLOEXEC through to FUSE; - // avoid spurious test failures - flags &^= fuse.OpenFlags(syscall.O_CLOEXEC) - } - - if g, e := flags, fuse.OpenReadWrite|fuse.OpenCreate; g != e { - log.Printf("ERROR create1.Create unexpected flags: %v != %v\n", g, e) - return nil, nil, fuse.EPERM - } - if g, e := req.Mode, os.FileMode(0644); g != e { - log.Printf("ERROR create1.Create unexpected mode: %v != %v\n", g, e) - return nil, nil, fuse.EPERM - } - return &f.f, &f.f, nil -} - -func TestCreate(t *testing.T) { - t.Parallel() - f := &create1{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - // uniform umask needed to make os.Create's 0666 into something - // reproducible - defer syscall.Umask(syscall.Umask(0022)) - ff, err := os.Create(mnt.Dir + "/foo") - if err != nil { - t.Fatalf("create1 WriteFile: %v", err) - } - defer ff.Close() - - err = syscall.Fsync(int(ff.Fd())) - if err != nil { - t.Fatalf("Fsync = %v", err) - } - - if f.f.RecordedFsync() == (fuse.FsyncRequest{}) { - t.Errorf("never received expected fsync call") - } - - ff.Close() -} - -// Test Create + Write + Remove - -type create3file struct { - fstestutil.File - record.Writes -} - -type create3 struct { - fstestutil.Dir - f create3file - fooCreated record.MarkRecorder - fooRemoved record.MarkRecorder -} - -func (f *create3) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) { - if req.Name != "foo" { - log.Printf("ERROR create3.Create unexpected name: %q\n", req.Name) - return nil, nil, fuse.EPERM - } - f.fooCreated.Mark() - return &f.f, &f.f, nil -} - -func (f *create3) Lookup(ctx context.Context, name string) (fs.Node, error) { - if f.fooCreated.Recorded() && !f.fooRemoved.Recorded() && name == "foo" { - return &f.f, nil - } - return nil, fuse.ENOENT -} - -func (f *create3) Remove(ctx context.Context, r *fuse.RemoveRequest) error { - if f.fooCreated.Recorded() && !f.fooRemoved.Recorded() && - r.Name == "foo" && !r.Dir { - f.fooRemoved.Mark() - return nil - } - return fuse.ENOENT -} - -func TestCreateWriteRemove(t *testing.T) { - t.Parallel() - f := &create3{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - err = ioutil.WriteFile(mnt.Dir+"/foo", []byte(hi), 0666) - if err != nil { - t.Fatalf("create3 WriteFile: %v", err) - } - if got := string(f.f.RecordedWriteData()); got != hi { - t.Fatalf("create3 write = %q, want %q", got, hi) - } - - err = os.Remove(mnt.Dir + "/foo") - if err != nil { - t.Fatalf("Remove: %v", err) - } - err = os.Remove(mnt.Dir + "/foo") - if err == nil { - t.Fatalf("second Remove = nil; want some error") - } -} - -// Test symlink + readlink - -// is a Node that is a symlink to target -type symlink1link struct { - symlink - target string -} - -func (f symlink1link) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) { - return f.target, nil -} - -type symlink1 struct { - fstestutil.Dir - record.Symlinks -} - -func (f *symlink1) Symlink(ctx context.Context, req *fuse.SymlinkRequest) (fs.Node, error) { - f.Symlinks.Symlink(ctx, req) - return symlink1link{target: req.Target}, nil -} - -func TestSymlink(t *testing.T) { - t.Parallel() - f := &symlink1{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - const target = "/some-target" - - err = os.Symlink(target, mnt.Dir+"/symlink.file") - if err != nil { - t.Fatalf("os.Symlink: %v", err) - } - - want := fuse.SymlinkRequest{NewName: "symlink.file", Target: target} - if g, e := f.RecordedSymlink(), want; g != e { - t.Errorf("symlink saw %+v, want %+v", g, e) - } - - gotName, err := os.Readlink(mnt.Dir + "/symlink.file") - if err != nil { - t.Fatalf("os.Readlink: %v", err) - } - if gotName != target { - t.Errorf("os.Readlink = %q; want %q", gotName, target) - } -} - -// Test link - -type link1 struct { - fstestutil.Dir - record.Links -} - -func (f *link1) Lookup(ctx context.Context, name string) (fs.Node, error) { - if name == "old" { - return fstestutil.File{}, nil - } - return nil, fuse.ENOENT -} - -func (f *link1) Link(ctx context.Context, r *fuse.LinkRequest, old fs.Node) (fs.Node, error) { - f.Links.Link(ctx, r, old) - return fstestutil.File{}, nil -} - -func TestLink(t *testing.T) { - t.Parallel() - f := &link1{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - err = os.Link(mnt.Dir+"/old", mnt.Dir+"/new") - if err != nil { - t.Fatalf("Link: %v", err) - } - - got := f.RecordedLink() - want := fuse.LinkRequest{ - NewName: "new", - // unpredictable - OldNode: got.OldNode, - } - if g, e := got, want; g != e { - t.Fatalf("link saw %+v, want %+v", g, e) - } -} - -// Test Rename - -type rename1 struct { - fstestutil.Dir - renamed record.Counter -} - -func (f *rename1) Lookup(ctx context.Context, name string) (fs.Node, error) { - if name == "old" { - return fstestutil.File{}, nil - } - return nil, fuse.ENOENT -} - -func (f *rename1) Rename(ctx context.Context, r *fuse.RenameRequest, newDir fs.Node) error { - if r.OldName == "old" && r.NewName == "new" && newDir == f { - f.renamed.Inc() - return nil - } - return fuse.EIO -} - -func TestRename(t *testing.T) { - t.Parallel() - f := &rename1{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - err = os.Rename(mnt.Dir+"/old", mnt.Dir+"/new") - if err != nil { - t.Fatalf("Rename: %v", err) - } - if g, e := f.renamed.Count(), uint32(1); g != e { - t.Fatalf("expected rename didn't happen: %d != %d", g, e) - } - err = os.Rename(mnt.Dir+"/old2", mnt.Dir+"/new2") - if err == nil { - t.Fatal("expected error on second Rename; got nil") - } -} - -// Test mknod - -type mknod1 struct { - fstestutil.Dir - record.Mknods -} - -func (f *mknod1) Mknod(ctx context.Context, r *fuse.MknodRequest) (fs.Node, error) { - f.Mknods.Mknod(ctx, r) - return fifo{}, nil -} - -func TestMknod(t *testing.T) { - t.Parallel() - if os.Getuid() != 0 { - t.Skip("skipping unless root") - } - - f := &mknod1{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - defer syscall.Umask(syscall.Umask(0)) - err = syscall.Mknod(mnt.Dir+"/node", syscall.S_IFIFO|0666, 123) - if err != nil { - t.Fatalf("Mknod: %v", err) - } - - want := fuse.MknodRequest{ - Name: "node", - Mode: os.FileMode(os.ModeNamedPipe | 0666), - Rdev: uint32(123), - } - if runtime.GOOS == "linux" { - // Linux fuse doesn't echo back the rdev if the node - // isn't a device (we're using a FIFO here, as that - // bit is portable.) - want.Rdev = 0 - } - if g, e := f.RecordedMknod(), want; g != e { - t.Fatalf("mknod saw %+v, want %+v", g, e) - } -} - -// Test Read served with DataHandle. - -type dataHandleTest struct { - fstestutil.File -} - -func (dataHandleTest) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = 0666 - a.Size = uint64(len(hi)) - return nil -} - -func (dataHandleTest) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { - return fs.DataHandle([]byte(hi)), nil -} - -func TestDataHandle(t *testing.T) { - t.Parallel() - f := &dataHandleTest{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - data, err := ioutil.ReadFile(mnt.Dir + "/child") - if err != nil { - t.Errorf("readAll: %v", err) - return - } - if string(data) != hi { - t.Errorf("readAll = %q, want %q", data, hi) - } -} - -// Test interrupt - -type interrupt struct { - fstestutil.File - - // strobes to signal we have a read hanging - hanging chan struct{} -} - -func (interrupt) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = 0666 - a.Size = 1 - return nil -} - -func (it *interrupt) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - select { - case it.hanging <- struct{}{}: - default: - } - <-ctx.Done() - return fuse.EINTR -} - -func TestInterrupt(t *testing.T) { - t.Parallel() - f := &interrupt{} - f.hanging = make(chan struct{}, 1) - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - // start a subprocess that can hang until signaled - cmd := exec.Command("cat", mnt.Dir+"/child") - - err = cmd.Start() - if err != nil { - t.Errorf("interrupt: cannot start cat: %v", err) - return - } - - // try to clean up if child is still alive when returning - defer cmd.Process.Kill() - - // wait till we're sure it's hanging in read - <-f.hanging - - err = cmd.Process.Signal(os.Interrupt) - if err != nil { - t.Errorf("interrupt: cannot interrupt cat: %v", err) - return - } - - p, err := cmd.Process.Wait() - if err != nil { - t.Errorf("interrupt: cat bork: %v", err) - return - } - switch ws := p.Sys().(type) { - case syscall.WaitStatus: - if ws.CoreDump() { - t.Errorf("interrupt: didn't expect cat to dump core: %v", ws) - } - - if ws.Exited() { - t.Errorf("interrupt: didn't expect cat to exit normally: %v", ws) - } - - if !ws.Signaled() { - t.Errorf("interrupt: expected cat to get a signal: %v", ws) - } else { - if ws.Signal() != os.Interrupt { - t.Errorf("interrupt: cat got wrong signal: %v", ws) - } - } - default: - t.Logf("interrupt: this platform has no test coverage") - } -} - -// Test truncate - -type truncate struct { - fstestutil.File - record.Setattrs -} - -func testTruncate(t *testing.T, toSize int64) { - t.Parallel() - f := &truncate{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - err = os.Truncate(mnt.Dir+"/child", toSize) - if err != nil { - t.Fatalf("Truncate: %v", err) - } - gotr := f.RecordedSetattr() - if gotr == (fuse.SetattrRequest{}) { - t.Fatalf("no recorded SetattrRequest") - } - if g, e := gotr.Size, uint64(toSize); g != e { - t.Errorf("got Size = %q; want %q", g, e) - } - if g, e := gotr.Valid&^fuse.SetattrLockOwner, fuse.SetattrSize; g != e { - t.Errorf("got Valid = %q; want %q", g, e) - } - t.Logf("Got request: %#v", gotr) -} - -func TestTruncate42(t *testing.T) { - testTruncate(t, 42) -} - -func TestTruncate0(t *testing.T) { - testTruncate(t, 0) -} - -// Test ftruncate - -type ftruncate struct { - fstestutil.File - record.Setattrs -} - -func testFtruncate(t *testing.T, toSize int64) { - t.Parallel() - f := &ftruncate{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - { - fil, err := os.OpenFile(mnt.Dir+"/child", os.O_WRONLY, 0666) - if err != nil { - t.Error(err) - return - } - defer fil.Close() - - err = fil.Truncate(toSize) - if err != nil { - t.Fatalf("Ftruncate: %v", err) - } - } - gotr := f.RecordedSetattr() - if gotr == (fuse.SetattrRequest{}) { - t.Fatalf("no recorded SetattrRequest") - } - if g, e := gotr.Size, uint64(toSize); g != e { - t.Errorf("got Size = %q; want %q", g, e) - } - if g, e := gotr.Valid&^fuse.SetattrLockOwner, fuse.SetattrHandle|fuse.SetattrSize; g != e { - t.Errorf("got Valid = %q; want %q", g, e) - } - t.Logf("Got request: %#v", gotr) -} - -func TestFtruncate42(t *testing.T) { - testFtruncate(t, 42) -} - -func TestFtruncate0(t *testing.T) { - testFtruncate(t, 0) -} - -// Test opening existing file truncates - -type truncateWithOpen struct { - fstestutil.File - record.Setattrs -} - -func TestTruncateWithOpen(t *testing.T) { - t.Parallel() - f := &truncateWithOpen{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - fil, err := os.OpenFile(mnt.Dir+"/child", os.O_WRONLY|os.O_TRUNC, 0666) - if err != nil { - t.Error(err) - return - } - fil.Close() - - gotr := f.RecordedSetattr() - if gotr == (fuse.SetattrRequest{}) { - t.Fatalf("no recorded SetattrRequest") - } - if g, e := gotr.Size, uint64(0); g != e { - t.Errorf("got Size = %q; want %q", g, e) - } - // osxfuse sets SetattrHandle here, linux does not - if g, e := gotr.Valid&^(fuse.SetattrLockOwner|fuse.SetattrHandle), fuse.SetattrSize; g != e { - t.Errorf("got Valid = %q; want %q", g, e) - } - t.Logf("Got request: %#v", gotr) -} - -// Test readdir calling ReadDirAll - -type readDirAll struct { - fstestutil.Dir -} - -func (d *readDirAll) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - return []fuse.Dirent{ - {Name: "one", Inode: 11, Type: fuse.DT_Dir}, - {Name: "three", Inode: 13}, - {Name: "two", Inode: 12, Type: fuse.DT_File}, - }, nil -} - -func TestReadDirAll(t *testing.T) { - t.Parallel() - f := &readDirAll{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - fil, err := os.Open(mnt.Dir) - if err != nil { - t.Error(err) - return - } - defer fil.Close() - - // go Readdir is just Readdirnames + Lstat, there's no point in - // testing that here; we have no consumption API for the real - // dirent data - names, err := fil.Readdirnames(100) - if err != nil { - t.Error(err) - return - } - - t.Logf("Got readdir: %q", names) - - if len(names) != 3 || - names[0] != "one" || - names[1] != "three" || - names[2] != "two" { - t.Errorf(`expected 3 entries of "one", "three", "two", got: %q`, names) - return - } -} - -// Test readdir without any ReadDir methods implemented. - -type readDirNotImplemented struct { - fstestutil.Dir -} - -func TestReadDirNotImplemented(t *testing.T) { - t.Parallel() - f := &readDirNotImplemented{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - fil, err := os.Open(mnt.Dir) - if err != nil { - t.Error(err) - return - } - defer fil.Close() - - // go Readdir is just Readdirnames + Lstat, there's no point in - // testing that here; we have no consumption API for the real - // dirent data - names, err := fil.Readdirnames(100) - if len(names) > 0 || err != io.EOF { - t.Fatalf("expected EOF got names=%v err=%v", names, err) - } -} - -// Test Chmod. - -type chmod struct { - fstestutil.File - record.Setattrs -} - -func (f *chmod) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error { - if !req.Valid.Mode() { - log.Printf("setattr not a chmod: %v", req.Valid) - return fuse.EIO - } - f.Setattrs.Setattr(ctx, req, resp) - return nil -} - -func TestChmod(t *testing.T) { - t.Parallel() - f := &chmod{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - err = os.Chmod(mnt.Dir+"/child", 0764) - if err != nil { - t.Errorf("chmod: %v", err) - return - } - got := f.RecordedSetattr() - if g, e := got.Mode, os.FileMode(0764); g != e { - t.Errorf("wrong mode: %v != %v", g, e) - } -} - -// Test open - -type open struct { - fstestutil.File - record.Opens -} - -func (f *open) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { - f.Opens.Open(ctx, req, resp) - // pick a really distinct error, to identify it later - return nil, fuse.Errno(syscall.ENAMETOOLONG) - -} - -func TestOpen(t *testing.T) { - t.Parallel() - f := &open{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - // node: mode only matters with O_CREATE - fil, err := os.OpenFile(mnt.Dir+"/child", os.O_WRONLY|os.O_APPEND, 0) - if err == nil { - t.Error("Open err == nil, expected ENAMETOOLONG") - fil.Close() - return - } - - switch err2 := err.(type) { - case *os.PathError: - if err2.Err == syscall.ENAMETOOLONG { - break - } - t.Errorf("unexpected inner error: %#v", err2) - default: - t.Errorf("unexpected error: %v", err) - } - - want := fuse.OpenRequest{Dir: false, Flags: fuse.OpenWriteOnly | fuse.OpenAppend} - if runtime.GOOS == "darwin" { - // osxfuse does not let O_APPEND through at all - // - // https://code.google.com/p/macfuse/issues/detail?id=233 - // https://code.google.com/p/macfuse/issues/detail?id=132 - // https://code.google.com/p/macfuse/issues/detail?id=133 - want.Flags &^= fuse.OpenAppend - } - got := f.RecordedOpen() - - if runtime.GOOS == "linux" { - // Linux <3.7 accidentally leaks O_CLOEXEC through to FUSE; - // avoid spurious test failures - got.Flags &^= fuse.OpenFlags(syscall.O_CLOEXEC) - } - - if g, e := got, want; g != e { - t.Errorf("open saw %v, want %v", g, e) - return - } -} - -// Test Fsync on a dir - -type fsyncDir struct { - fstestutil.Dir - record.Fsyncs -} - -func TestFsyncDir(t *testing.T) { - t.Parallel() - f := &fsyncDir{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - fil, err := os.Open(mnt.Dir) - if err != nil { - t.Errorf("fsyncDir open: %v", err) - return - } - defer fil.Close() - err = fil.Sync() - if err != nil { - t.Errorf("fsyncDir sync: %v", err) - return - } - - got := f.RecordedFsync() - want := fuse.FsyncRequest{ - Flags: 0, - Dir: true, - // unpredictable - Handle: got.Handle, - } - if runtime.GOOS == "darwin" { - // TODO document the meaning of these flags, figure out why - // they differ - want.Flags = 1 - } - if g, e := got, want; g != e { - t.Fatalf("fsyncDir saw %+v, want %+v", g, e) - } -} - -// Test Getxattr - -type getxattr struct { - fstestutil.File - record.Getxattrs -} - -func (f *getxattr) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error { - f.Getxattrs.Getxattr(ctx, req, resp) - resp.Xattr = []byte("hello, world") - return nil -} - -func TestGetxattr(t *testing.T) { - t.Parallel() - f := &getxattr{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - buf := make([]byte, 8192) - n, err := syscallx.Getxattr(mnt.Dir+"/child", "not-there", buf) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - buf = buf[:n] - if g, e := string(buf), "hello, world"; g != e { - t.Errorf("wrong getxattr content: %#v != %#v", g, e) - } - seen := f.RecordedGetxattr() - if g, e := seen.Name, "not-there"; g != e { - t.Errorf("wrong getxattr name: %#v != %#v", g, e) - } -} - -// Test Getxattr that has no space to return value - -type getxattrTooSmall struct { - fstestutil.File -} - -func (f *getxattrTooSmall) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error { - resp.Xattr = []byte("hello, world") - return nil -} - -func TestGetxattrTooSmall(t *testing.T) { - t.Parallel() - f := &getxattrTooSmall{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - buf := make([]byte, 3) - _, err = syscallx.Getxattr(mnt.Dir+"/child", "whatever", buf) - if err == nil { - t.Error("Getxattr = nil; want some error") - } - if err != syscall.ERANGE { - t.Errorf("unexpected error: %v", err) - return - } -} - -// Test Getxattr used to probe result size - -type getxattrSize struct { - fstestutil.File -} - -func (f *getxattrSize) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error { - resp.Xattr = []byte("hello, world") - return nil -} - -func TestGetxattrSize(t *testing.T) { - t.Parallel() - f := &getxattrSize{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - n, err := syscallx.Getxattr(mnt.Dir+"/child", "whatever", nil) - if err != nil { - t.Errorf("Getxattr unexpected error: %v", err) - return - } - if g, e := n, len("hello, world"); g != e { - t.Errorf("Getxattr incorrect size: %d != %d", g, e) - } -} - -// Test Listxattr - -type listxattr struct { - fstestutil.File - record.Listxattrs -} - -func (f *listxattr) Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error { - f.Listxattrs.Listxattr(ctx, req, resp) - resp.Append("one", "two") - return nil -} - -func TestListxattr(t *testing.T) { - t.Parallel() - f := &listxattr{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - buf := make([]byte, 8192) - n, err := syscallx.Listxattr(mnt.Dir+"/child", buf) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - buf = buf[:n] - if g, e := string(buf), "one\x00two\x00"; g != e { - t.Errorf("wrong listxattr content: %#v != %#v", g, e) - } - - want := fuse.ListxattrRequest{ - Size: 8192, - } - if g, e := f.RecordedListxattr(), want; g != e { - t.Fatalf("listxattr saw %+v, want %+v", g, e) - } -} - -// Test Listxattr that has no space to return value - -type listxattrTooSmall struct { - fstestutil.File -} - -func (f *listxattrTooSmall) Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error { - resp.Xattr = []byte("one\x00two\x00") - return nil -} - -func TestListxattrTooSmall(t *testing.T) { - t.Parallel() - f := &listxattrTooSmall{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - buf := make([]byte, 3) - _, err = syscallx.Listxattr(mnt.Dir+"/child", buf) - if err == nil { - t.Error("Listxattr = nil; want some error") - } - if err != syscall.ERANGE { - t.Errorf("unexpected error: %v", err) - return - } -} - -// Test Listxattr used to probe result size - -type listxattrSize struct { - fstestutil.File -} - -func (f *listxattrSize) Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error { - resp.Xattr = []byte("one\x00two\x00") - return nil -} - -func TestListxattrSize(t *testing.T) { - t.Parallel() - f := &listxattrSize{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - n, err := syscallx.Listxattr(mnt.Dir+"/child", nil) - if err != nil { - t.Errorf("Listxattr unexpected error: %v", err) - return - } - if g, e := n, len("one\x00two\x00"); g != e { - t.Errorf("Getxattr incorrect size: %d != %d", g, e) - } -} - -// Test Setxattr - -type setxattr struct { - fstestutil.File - record.Setxattrs -} - -func testSetxattr(t *testing.T, size int) { - const linux_XATTR_NAME_MAX = 64 * 1024 - if size > linux_XATTR_NAME_MAX && runtime.GOOS == "linux" { - t.Skip("large xattrs are not supported by linux") - } - - t.Parallel() - f := &setxattr{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - const g = "hello, world" - greeting := strings.Repeat(g, size/len(g)+1)[:size] - err = syscallx.Setxattr(mnt.Dir+"/child", "greeting", []byte(greeting), 0) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - // fuse.SetxattrRequest contains a byte slice and thus cannot be - // directly compared - got := f.RecordedSetxattr() - - if g, e := got.Name, "greeting"; g != e { - t.Errorf("Setxattr incorrect name: %q != %q", g, e) - } - - if g, e := got.Flags, uint32(0); g != e { - t.Errorf("Setxattr incorrect flags: %d != %d", g, e) - } - - if g, e := string(got.Xattr), greeting; g != e { - t.Errorf("Setxattr incorrect data: %q != %q", g, e) - } -} - -func TestSetxattr(t *testing.T) { - testSetxattr(t, 20) -} - -func TestSetxattr64kB(t *testing.T) { - testSetxattr(t, 64*1024) -} - -func TestSetxattr16MB(t *testing.T) { - testSetxattr(t, 16*1024*1024) -} - -// Test Removexattr - -type removexattr struct { - fstestutil.File - record.Removexattrs -} - -func TestRemovexattr(t *testing.T) { - t.Parallel() - f := &removexattr{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": f}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - err = syscallx.Removexattr(mnt.Dir+"/child", "greeting") - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - want := fuse.RemovexattrRequest{Name: "greeting"} - if g, e := f.RecordedRemovexattr(), want; g != e { - t.Errorf("removexattr saw %v, want %v", g, e) - } -} - -// Test default error. - -type defaultErrno struct { - fstestutil.Dir -} - -func (f defaultErrno) Lookup(ctx context.Context, name string) (fs.Node, error) { - return nil, errors.New("bork") -} - -func TestDefaultErrno(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{defaultErrno{}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - _, err = os.Stat(mnt.Dir + "/trigger") - if err == nil { - t.Fatalf("expected error") - } - - switch err2 := err.(type) { - case *os.PathError: - if err2.Err == syscall.EIO { - break - } - t.Errorf("unexpected inner error: Err=%v %#v", err2.Err, err2) - default: - t.Errorf("unexpected error: %v", err) - } -} - -// Test custom error. - -type customErrNode struct { - fstestutil.Dir -} - -type myCustomError struct { - fuse.ErrorNumber -} - -var _ = fuse.ErrorNumber(myCustomError{}) - -func (myCustomError) Error() string { - return "bork" -} - -func (f customErrNode) Lookup(ctx context.Context, name string) (fs.Node, error) { - return nil, myCustomError{ - ErrorNumber: fuse.Errno(syscall.ENAMETOOLONG), - } -} - -func TestCustomErrno(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{customErrNode{}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - _, err = os.Stat(mnt.Dir + "/trigger") - if err == nil { - t.Fatalf("expected error") - } - - switch err2 := err.(type) { - case *os.PathError: - if err2.Err == syscall.ENAMETOOLONG { - break - } - t.Errorf("unexpected inner error: %#v", err2) - default: - t.Errorf("unexpected error: %v", err) - } -} - -// Test Mmap writing - -type inMemoryFile struct { - mu sync.Mutex - data []byte -} - -func (f *inMemoryFile) bytes() []byte { - f.mu.Lock() - defer f.mu.Unlock() - - return f.data -} - -func (f *inMemoryFile) Attr(ctx context.Context, a *fuse.Attr) error { - f.mu.Lock() - defer f.mu.Unlock() - - a.Mode = 0666 - a.Size = uint64(len(f.data)) - return nil -} - -func (f *inMemoryFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - f.mu.Lock() - defer f.mu.Unlock() - - fuseutil.HandleRead(req, resp, f.data) - return nil -} - -func (f *inMemoryFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error { - f.mu.Lock() - defer f.mu.Unlock() - - resp.Size = copy(f.data[req.Offset:], req.Data) - return nil -} - -const mmapSize = 16 * 4096 - -var mmapWrites = map[int]byte{ - 10: 'a', - 4096: 'b', - 4097: 'c', - mmapSize - 4096: 'd', - mmapSize - 1: 'z', -} - -func helperMmap() { - f, err := os.Create("child") - if err != nil { - log.Fatalf("Create: %v", err) - } - defer f.Close() - - data, err := syscall.Mmap(int(f.Fd()), 0, mmapSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED) - if err != nil { - log.Fatalf("Mmap: %v", err) - } - - for i, b := range mmapWrites { - data[i] = b - } - - if err := syscallx.Msync(data, syscall.MS_SYNC); err != nil { - log.Fatalf("Msync: %v", err) - } - - if err := syscall.Munmap(data); err != nil { - log.Fatalf("Munmap: %v", err) - } - - if err := f.Sync(); err != nil { - log.Fatalf("Fsync = %v", err) - } - - err = f.Close() - if err != nil { - log.Fatalf("Close: %v", err) - } -} - -func init() { - childHelpers["mmap"] = helperMmap -} - -type mmap struct { - inMemoryFile - // We don't actually care about whether the fsync happened or not; - // this just lets us force the page cache to send the writes to - // FUSE, so we can reliably verify they came through. - record.Fsyncs -} - -func TestMmap(t *testing.T) { - - w := &mmap{} - w.data = make([]byte, mmapSize) - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": w}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - // Run the mmap-using parts of the test in a subprocess, to avoid - // an intentional page fault hanging the whole process (because it - // would need to be served by the same process, and there might - // not be a thread free to do that). Merely bumping GOMAXPROCS is - // not enough to prevent the hangs reliably. - child, err := childCmd("mmap") - if err != nil { - t.Fatal(err) - } - child.Dir = mnt.Dir - if err := child.Run(); err != nil { - t.Fatal(err) - } - - got := w.bytes() - if g, e := len(got), mmapSize; g != e { - t.Fatalf("bad write length: %d != %d", g, e) - } - for i, g := range got { - // default '\x00' for writes[i] is good here - if e := mmapWrites[i]; g != e { - t.Errorf("wrong byte at offset %d: %q != %q", i, g, e) - } - } -} - -// Test direct Read. - -type directRead struct { - fstestutil.File -} - -// explicitly not defining Attr and setting Size - -func (f directRead) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { - // do not allow the kernel to use page cache - resp.Flags |= fuse.OpenDirectIO - return f, nil -} - -func (directRead) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - fuseutil.HandleRead(req, resp, []byte(hi)) - return nil -} - -func TestDirectRead(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": directRead{}}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - testReadAll(t, mnt.Dir+"/child") -} - -// Test direct Write. - -type directWrite struct { - fstestutil.File - record.Writes -} - -// explicitly not defining Attr / Setattr and managing Size - -func (f *directWrite) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { - // do not allow the kernel to use page cache - resp.Flags |= fuse.OpenDirectIO - return f, nil -} - -func TestDirectWrite(t *testing.T) { - t.Parallel() - w := &directWrite{} - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": w}}) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - f, err := os.OpenFile(mnt.Dir+"/child", os.O_RDWR, 0666) - if err != nil { - t.Fatalf("Create: %v", err) - } - defer f.Close() - n, err := f.Write([]byte(hi)) - if err != nil { - t.Fatalf("Write: %v", err) - } - if n != len(hi) { - t.Fatalf("short write; n=%d; hi=%d", n, len(hi)) - } - - err = f.Close() - if err != nil { - t.Fatalf("Close: %v", err) - } - - if got := string(w.RecordedWriteData()); got != hi { - t.Errorf("write = %q, want %q", got, hi) - } -} - -// Test Attr - -// attrUnlinked is a file that is unlinked (Nlink==0). -type attrUnlinked struct { - fstestutil.File -} - -var _ fs.Node = attrUnlinked{} - -func (f attrUnlinked) Attr(ctx context.Context, a *fuse.Attr) error { - if err := f.File.Attr(ctx, a); err != nil { - return err - } - a.Nlink = 0 - return nil -} - -func TestAttrUnlinked(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": attrUnlinked{}}}) - - fi, err := os.Stat(mnt.Dir + "/child") - if err != nil { - t.Fatalf("Stat failed with %v", err) - } - switch stat := fi.Sys().(type) { - case *syscall.Stat_t: - if stat.Nlink != 0 { - t.Errorf("wrong link count: %v", stat.Nlink) - } - } -} - -// Test behavior when Attr method fails - -type attrBad struct { -} - -var _ fs.Node = attrBad{} - -func (attrBad) Attr(ctx context.Context, attr *fuse.Attr) error { - return fuse.Errno(syscall.ENAMETOOLONG) -} - -func TestAttrBad(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": attrBad{}}}) - - _, err = os.Stat(mnt.Dir + "/child") - if nerr, ok := err.(*os.PathError); !ok || nerr.Err != syscall.ENAMETOOLONG { - t.Fatalf("wrong error: %v", err) - } -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/tree.go b/Godeps/_workspace/src/bazil.org/fuse/fs/tree.go deleted file mode 100644 index dca33f266..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/tree.go +++ /dev/null @@ -1,99 +0,0 @@ -// FUSE directory tree, for servers that wish to use it with the service loop. - -package fs - -import ( - "os" - pathpkg "path" - "strings" - - "context" -) - -import ( - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" -) - -// A Tree implements a basic read-only directory tree for FUSE. -// The Nodes contained in it may still be writable. -type Tree struct { - tree -} - -func (t *Tree) Root() (Node, error) { - return &t.tree, nil -} - -// Add adds the path to the tree, resolving to the given node. -// If path or a prefix of path has already been added to the tree, -// Add panics. -// -// Add is only safe to call before starting to serve requests. -func (t *Tree) Add(path string, node Node) { - path = pathpkg.Clean("/" + path)[1:] - elems := strings.Split(path, "/") - dir := Node(&t.tree) - for i, elem := range elems { - dt, ok := dir.(*tree) - if !ok { - panic("fuse: Tree.Add for " + strings.Join(elems[:i], "/") + " and " + path) - } - n := dt.lookup(elem) - if n != nil { - if i+1 == len(elems) { - panic("fuse: Tree.Add for " + path + " conflicts with " + elem) - } - dir = n - } else { - if i+1 == len(elems) { - dt.add(elem, node) - } else { - dir = &tree{} - dt.add(elem, dir) - } - } - } -} - -type treeDir struct { - name string - node Node -} - -type tree struct { - dir []treeDir -} - -func (t *tree) lookup(name string) Node { - for _, d := range t.dir { - if d.name == name { - return d.node - } - } - return nil -} - -func (t *tree) add(name string, n Node) { - t.dir = append(t.dir, treeDir{name, n}) -} - -func (t *tree) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = os.ModeDir | 0555 - return nil -} - -func (t *tree) Lookup(ctx context.Context, name string) (Node, error) { - n := t.lookup(name) - if n != nil { - return n, nil - } - return nil, fuse.ENOENT -} - -func (t *tree) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - var out []fuse.Dirent - for _, d := range t.dir { - out = append(out, fuse.Dirent{Name: d.name}) - } - return out, nil -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuse.go b/Godeps/_workspace/src/bazil.org/fuse/fuse.go deleted file mode 100644 index 794ad91a2..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fuse.go +++ /dev/null @@ -1,2028 +0,0 @@ -// See the file LICENSE for copyright and licensing information. - -// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c, -// which carries this notice: -// -// The files in this directory are subject to the following license. -// -// The author of this software is Russ Cox. -// -// Copyright (c) 2006 Russ Cox -// -// Permission to use, copy, modify, and distribute this software for any -// purpose without fee is hereby granted, provided that this entire notice -// is included in all copies of any software which is or includes a copy -// or modification of this software and in all copies of the supporting -// documentation for such software. -// -// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY -// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS -// FITNESS FOR ANY PARTICULAR PURPOSE. - -// Package fuse enables writing FUSE file systems on Linux, OS X, and FreeBSD. -// -// On OS X, it requires OSXFUSE (http://osxfuse.github.com/). -// -// There are two approaches to writing a FUSE file system. The first is to speak -// the low-level message protocol, reading from a Conn using ReadRequest and -// writing using the various Respond methods. This approach is closest to -// the actual interaction with the kernel and can be the simplest one in contexts -// such as protocol translators. -// -// Servers of synthesized file systems tend to share common -// bookkeeping abstracted away by the second approach, which is to -// call fs.Serve to serve the FUSE protocol using an implementation of -// the service methods in the interfaces FS* (file system), Node* (file -// or directory), and Handle* (opened file or directory). -// There are a daunting number of such methods that can be written, -// but few are required. -// The specific methods are described in the documentation for those interfaces. -// -// The hellofs subdirectory contains a simple illustration of the fs.Serve approach. -// -// Service Methods -// -// The required and optional methods for the FS, Node, and Handle interfaces -// have the general form -// -// Op(ctx context.Context, req *OpRequest, resp *OpResponse) error -// -// where Op is the name of a FUSE operation. Op reads request -// parameters from req and writes results to resp. An operation whose -// only result is the error result omits the resp parameter. -// -// Multiple goroutines may call service methods simultaneously; the -// methods being called are responsible for appropriate -// synchronization. -// -// The operation must not hold on to the request or response, -// including any []byte fields such as WriteRequest.Data or -// SetxattrRequest.Xattr. -// -// Errors -// -// Operations can return errors. The FUSE interface can only -// communicate POSIX errno error numbers to file system clients, the -// message is not visible to file system clients. The returned error -// can implement ErrorNumber to control the errno returned. Without -// ErrorNumber, a generic errno (EIO) is returned. -// -// Error messages will be visible in the debug log as part of the -// response. -// -// Interrupted Operations -// -// In some file systems, some operations -// may take an undetermined amount of time. For example, a Read waiting for -// a network message or a matching Write might wait indefinitely. If the request -// is cancelled and no longer needed, the context will be cancelled. -// Blocking operations should select on a receive from ctx.Done() and attempt to -// abort the operation early if the receive succeeds (meaning the channel is closed). -// To indicate that the operation failed because it was aborted, return fuse.EINTR. -// -// If an operation does not block for an indefinite amount of time, supporting -// cancellation is not necessary. -// -// Authentication -// -// All requests types embed a Header, meaning that the method can -// inspect req.Pid, req.Uid, and req.Gid as necessary to implement -// permission checking. The kernel FUSE layer normally prevents other -// users from accessing the FUSE file system (to change this, see -// AllowOther, AllowRoot), but does not enforce access modes (to -// change this, see DefaultPermissions). -// -// Mount Options -// -// Behavior and metadata of the mounted file system can be changed by -// passing MountOption values to Mount. -// -package fuse - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "os" - "sync" - "syscall" - "time" - "unsafe" -) - -// A Conn represents a connection to a mounted FUSE file system. -type Conn struct { - // Ready is closed when the mount is complete or has failed. - Ready <-chan struct{} - - // MountError stores any error from the mount process. Only valid - // after Ready is closed. - MountError error - - // File handle for kernel communication. Only safe to access if - // rio or wio is held. - dev *os.File - buf []byte - wio sync.Mutex - rio sync.RWMutex -} - -// Mount mounts a new FUSE connection on the named directory -// and returns a connection for reading and writing FUSE messages. -// -// After a successful return, caller must call Close to free -// resources. -// -// Even on successful return, the new mount is not guaranteed to be -// visible until after Conn.Ready is closed. See Conn.MountError for -// possible errors. Incoming requests on Conn must be served to make -// progress. -func Mount(dir string, options ...MountOption) (*Conn, error) { - conf := MountConfig{ - options: make(map[string]string), - } - for _, option := range options { - if err := option(&conf); err != nil { - return nil, err - } - } - - ready := make(chan struct{}, 1) - c := &Conn{ - Ready: ready, - } - f, err := mount(dir, &conf, ready, &c.MountError) - if err != nil { - return nil, err - } - c.dev = f - return c, nil -} - -// A Request represents a single FUSE request received from the kernel. -// Use a type switch to determine the specific kind. -// A request of unrecognized type will have concrete type *Header. -type Request interface { - // Hdr returns the Header associated with this request. - Hdr() *Header - - // RespondError responds to the request with the given error. - RespondError(error) - - String() string -} - -// A RequestID identifies an active FUSE request. -type RequestID uint64 - -// A NodeID is a number identifying a directory or file. -// It must be unique among IDs returned in LookupResponses -// that have not yet been forgotten by ForgetRequests. -type NodeID uint64 - -// A HandleID is a number identifying an open directory or file. -// It only needs to be unique while the directory or file is open. -type HandleID uint64 - -// The RootID identifies the root directory of a FUSE file system. -const RootID NodeID = rootID - -// A Header describes the basic information sent in every request. -type Header struct { - Conn *Conn `json:"-"` // connection this request was received on - ID RequestID // unique ID for request - Node NodeID // file or directory the request is about - Uid uint32 // user ID of process making request - Gid uint32 // group ID of process making request - Pid uint32 // process ID of process making request - - // for returning to reqPool - msg *message -} - -func (h *Header) String() string { - return fmt.Sprintf("ID=%#x Node=%#x Uid=%d Gid=%d Pid=%d", h.ID, h.Node, h.Uid, h.Gid, h.Pid) -} - -func (h *Header) Hdr() *Header { - return h -} - -func (h *Header) noResponse() { - putMessage(h.msg) -} - -func (h *Header) respond(out *outHeader, n uintptr) { - h.Conn.respond(out, n) - putMessage(h.msg) -} - -func (h *Header) respondData(out *outHeader, n uintptr, data []byte) { - h.Conn.respondData(out, n, data) - putMessage(h.msg) -} - -// An ErrorNumber is an error with a specific error number. -// -// Operations may return an error value that implements ErrorNumber to -// control what specific error number (errno) to return. -type ErrorNumber interface { - // Errno returns the the error number (errno) for this error. - Errno() Errno -} - -const ( - // ENOSYS indicates that the call is not supported. - ENOSYS = Errno(syscall.ENOSYS) - - // ESTALE is used by Serve to respond to violations of the FUSE protocol. - ESTALE = Errno(syscall.ESTALE) - - ENOENT = Errno(syscall.ENOENT) - EIO = Errno(syscall.EIO) - EPERM = Errno(syscall.EPERM) - - // EINTR indicates request was interrupted by an InterruptRequest. - // See also fs.Intr. - EINTR = Errno(syscall.EINTR) - - ERANGE = Errno(syscall.ERANGE) - ENOTSUP = Errno(syscall.ENOTSUP) - EEXIST = Errno(syscall.EEXIST) -) - -// DefaultErrno is the errno used when error returned does not -// implement ErrorNumber. -const DefaultErrno = EIO - -var errnoNames = map[Errno]string{ - ENOSYS: "ENOSYS", - ESTALE: "ESTALE", - ENOENT: "ENOENT", - EIO: "EIO", - EPERM: "EPERM", - EINTR: "EINTR", - EEXIST: "EEXIST", -} - -// Errno implements Error and ErrorNumber using a syscall.Errno. -type Errno syscall.Errno - -var _ = ErrorNumber(Errno(0)) -var _ = error(Errno(0)) - -func (e Errno) Errno() Errno { - return e -} - -func (e Errno) String() string { - return syscall.Errno(e).Error() -} - -func (e Errno) Error() string { - return syscall.Errno(e).Error() -} - -// ErrnoName returns the short non-numeric identifier for this errno. -// For example, "EIO". -func (e Errno) ErrnoName() string { - s := errnoNames[e] - if s == "" { - s = fmt.Sprint(e.Errno()) - } - return s -} - -func (e Errno) MarshalText() ([]byte, error) { - s := e.ErrnoName() - return []byte(s), nil -} - -func (h *Header) RespondError(err error) { - errno := DefaultErrno - if ferr, ok := err.(ErrorNumber); ok { - errno = ferr.Errno() - } - // FUSE uses negative errors! - // TODO: File bug report against OSXFUSE: positive error causes kernel panic. - out := &outHeader{Error: -int32(errno), Unique: uint64(h.ID)} - h.respond(out, unsafe.Sizeof(*out)) -} - -// Maximum file write size we are prepared to receive from the kernel. -const maxWrite = 16 * 1024 * 1024 - -// All requests read from the kernel, without data, are shorter than -// this. -var maxRequestSize = syscall.Getpagesize() -var bufSize = maxRequestSize + maxWrite - -// reqPool is a pool of messages. -// -// Lifetime of a logical message is from getMessage to putMessage. -// getMessage is called by ReadRequest. putMessage is called by -// Conn.ReadRequest, Request.Respond, or Request.RespondError. -// -// Messages in the pool are guaranteed to have conn and off zeroed, -// buf allocated and len==bufSize, and hdr set. -var reqPool = sync.Pool{ - New: allocMessage, -} - -func allocMessage() interface{} { - m := &message{buf: make([]byte, bufSize)} - m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0])) - return m -} - -func getMessage(c *Conn) *message { - m := reqPool.Get().(*message) - m.conn = c - return m -} - -func putMessage(m *message) { - m.buf = m.buf[:bufSize] - m.conn = nil - m.off = 0 - reqPool.Put(m) -} - -// a message represents the bytes of a single FUSE message -type message struct { - conn *Conn - buf []byte // all bytes - hdr *inHeader // header - off int // offset for reading additional fields -} - -func (m *message) len() uintptr { - return uintptr(len(m.buf) - m.off) -} - -func (m *message) data() unsafe.Pointer { - var p unsafe.Pointer - if m.off < len(m.buf) { - p = unsafe.Pointer(&m.buf[m.off]) - } - return p -} - -func (m *message) bytes() []byte { - return m.buf[m.off:] -} - -func (m *message) Header() Header { - h := m.hdr - return Header{ - Conn: m.conn, - ID: RequestID(h.Unique), - Node: NodeID(h.Nodeid), - Uid: h.Uid, - Gid: h.Gid, - Pid: h.Pid, - - msg: m, - } -} - -// fileMode returns a Go os.FileMode from a Unix mode. -func fileMode(unixMode uint32) os.FileMode { - mode := os.FileMode(unixMode & 0777) - switch unixMode & syscall.S_IFMT { - case syscall.S_IFREG: - // nothing - case syscall.S_IFDIR: - mode |= os.ModeDir - case syscall.S_IFCHR: - mode |= os.ModeCharDevice | os.ModeDevice - case syscall.S_IFBLK: - mode |= os.ModeDevice - case syscall.S_IFIFO: - mode |= os.ModeNamedPipe - case syscall.S_IFLNK: - mode |= os.ModeSymlink - case syscall.S_IFSOCK: - mode |= os.ModeSocket - default: - // no idea - mode |= os.ModeDevice - } - if unixMode&syscall.S_ISUID != 0 { - mode |= os.ModeSetuid - } - if unixMode&syscall.S_ISGID != 0 { - mode |= os.ModeSetgid - } - return mode -} - -type noOpcode struct { - Opcode uint32 -} - -func (m noOpcode) String() string { - return fmt.Sprintf("No opcode %v", m.Opcode) -} - -type malformedMessage struct { -} - -func (malformedMessage) String() string { - return "malformed message" -} - -// Close closes the FUSE connection. -func (c *Conn) Close() error { - c.wio.Lock() - defer c.wio.Unlock() - c.rio.Lock() - defer c.rio.Unlock() - return c.dev.Close() -} - -// caller must hold wio or rio -func (c *Conn) fd() int { - return int(c.dev.Fd()) -} - -// ReadRequest returns the next FUSE request from the kernel. -// -// Caller must call either Request.Respond or Request.RespondError in -// a reasonable time. Caller must not retain Request after that call. -func (c *Conn) ReadRequest() (Request, error) { - m := getMessage(c) -loop: - c.rio.RLock() - n, err := syscall.Read(c.fd(), m.buf) - c.rio.RUnlock() - if err == syscall.EINTR { - // OSXFUSE sends EINTR to userspace when a request interrupt - // completed before it got sent to userspace? - goto loop - } - if err != nil && err != syscall.ENODEV { - putMessage(m) - return nil, err - } - if n <= 0 { - putMessage(m) - return nil, io.EOF - } - m.buf = m.buf[:n] - - if n < inHeaderSize { - putMessage(m) - return nil, errors.New("fuse: message too short") - } - - // FreeBSD FUSE sends a short length in the header - // for FUSE_INIT even though the actual read length is correct. - if n == inHeaderSize+initInSize && m.hdr.Opcode == opInit && m.hdr.Len < uint32(n) { - m.hdr.Len = uint32(n) - } - - // OSXFUSE sometimes sends the wrong m.hdr.Len in a FUSE_WRITE message. - if m.hdr.Len < uint32(n) && m.hdr.Len >= uint32(unsafe.Sizeof(writeIn{})) && m.hdr.Opcode == opWrite { - m.hdr.Len = uint32(n) - } - - if m.hdr.Len != uint32(n) { - // prepare error message before returning m to pool - err := fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len) - putMessage(m) - return nil, err - } - - m.off = inHeaderSize - - // Convert to data structures. - // Do not trust kernel to hand us well-formed data. - var req Request - switch m.hdr.Opcode { - default: - Debug(noOpcode{Opcode: m.hdr.Opcode}) - goto unrecognized - - case opLookup: - buf := m.bytes() - n := len(buf) - if n == 0 || buf[n-1] != '\x00' { - goto corrupt - } - req = &LookupRequest{ - Header: m.Header(), - Name: string(buf[:n-1]), - } - - case opForget: - in := (*forgetIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &ForgetRequest{ - Header: m.Header(), - N: in.Nlookup, - } - - case opGetattr: - req = &GetattrRequest{ - Header: m.Header(), - } - - case opSetattr: - in := (*setattrIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &SetattrRequest{ - Header: m.Header(), - Valid: SetattrValid(in.Valid), - Handle: HandleID(in.Fh), - Size: in.Size, - Atime: time.Unix(int64(in.Atime), int64(in.AtimeNsec)), - Mtime: time.Unix(int64(in.Mtime), int64(in.MtimeNsec)), - Mode: fileMode(in.Mode), - Uid: in.Uid, - Gid: in.Gid, - Bkuptime: in.BkupTime(), - Chgtime: in.Chgtime(), - Flags: in.Flags(), - } - - case opReadlink: - if len(m.bytes()) > 0 { - goto corrupt - } - req = &ReadlinkRequest{ - Header: m.Header(), - } - - case opSymlink: - // m.bytes() is "newName\0target\0" - names := m.bytes() - if len(names) == 0 || names[len(names)-1] != 0 { - goto corrupt - } - i := bytes.IndexByte(names, '\x00') - if i < 0 { - goto corrupt - } - newName, target := names[0:i], names[i+1:len(names)-1] - req = &SymlinkRequest{ - Header: m.Header(), - NewName: string(newName), - Target: string(target), - } - - case opLink: - in := (*linkIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - newName := m.bytes()[unsafe.Sizeof(*in):] - if len(newName) < 2 || newName[len(newName)-1] != 0 { - goto corrupt - } - newName = newName[:len(newName)-1] - req = &LinkRequest{ - Header: m.Header(), - OldNode: NodeID(in.Oldnodeid), - NewName: string(newName), - } - - case opMknod: - in := (*mknodIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - name := m.bytes()[unsafe.Sizeof(*in):] - if len(name) < 2 || name[len(name)-1] != '\x00' { - goto corrupt - } - name = name[:len(name)-1] - req = &MknodRequest{ - Header: m.Header(), - Mode: fileMode(in.Mode), - Rdev: in.Rdev, - Name: string(name), - } - - case opMkdir: - in := (*mkdirIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - name := m.bytes()[unsafe.Sizeof(*in):] - i := bytes.IndexByte(name, '\x00') - if i < 0 { - goto corrupt - } - req = &MkdirRequest{ - Header: m.Header(), - Name: string(name[:i]), - // observed on Linux: mkdirIn.Mode & syscall.S_IFMT == 0, - // and this causes fileMode to go into it's "no idea" - // code branch; enforce type to directory - Mode: fileMode((in.Mode &^ syscall.S_IFMT) | syscall.S_IFDIR), - } - - case opUnlink, opRmdir: - buf := m.bytes() - n := len(buf) - if n == 0 || buf[n-1] != '\x00' { - goto corrupt - } - req = &RemoveRequest{ - Header: m.Header(), - Name: string(buf[:n-1]), - Dir: m.hdr.Opcode == opRmdir, - } - - case opRename: - in := (*renameIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - newDirNodeID := NodeID(in.Newdir) - oldNew := m.bytes()[unsafe.Sizeof(*in):] - // oldNew should be "old\x00new\x00" - if len(oldNew) < 4 { - goto corrupt - } - if oldNew[len(oldNew)-1] != '\x00' { - goto corrupt - } - i := bytes.IndexByte(oldNew, '\x00') - if i < 0 { - goto corrupt - } - oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1]) - req = &RenameRequest{ - Header: m.Header(), - NewDir: newDirNodeID, - OldName: oldName, - NewName: newName, - } - - case opOpendir, opOpen: - in := (*openIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &OpenRequest{ - Header: m.Header(), - Dir: m.hdr.Opcode == opOpendir, - Flags: openFlags(in.Flags), - } - - case opRead, opReaddir: - in := (*readIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &ReadRequest{ - Header: m.Header(), - Dir: m.hdr.Opcode == opReaddir, - Handle: HandleID(in.Fh), - Offset: int64(in.Offset), - Size: int(in.Size), - } - - case opWrite: - in := (*writeIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - r := &WriteRequest{ - Header: m.Header(), - Handle: HandleID(in.Fh), - Offset: int64(in.Offset), - Flags: WriteFlags(in.WriteFlags), - } - buf := m.bytes()[unsafe.Sizeof(*in):] - if uint32(len(buf)) < in.Size { - goto corrupt - } - r.Data = buf - req = r - - case opStatfs: - req = &StatfsRequest{ - Header: m.Header(), - } - - case opRelease, opReleasedir: - in := (*releaseIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &ReleaseRequest{ - Header: m.Header(), - Dir: m.hdr.Opcode == opReleasedir, - Handle: HandleID(in.Fh), - Flags: openFlags(in.Flags), - ReleaseFlags: ReleaseFlags(in.ReleaseFlags), - LockOwner: in.LockOwner, - } - - case opFsync, opFsyncdir: - in := (*fsyncIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &FsyncRequest{ - Dir: m.hdr.Opcode == opFsyncdir, - Header: m.Header(), - Handle: HandleID(in.Fh), - Flags: in.FsyncFlags, - } - - case opSetxattr: - in := (*setxattrIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - m.off += int(unsafe.Sizeof(*in)) - name := m.bytes() - i := bytes.IndexByte(name, '\x00') - if i < 0 { - goto corrupt - } - xattr := name[i+1:] - if uint32(len(xattr)) < in.Size { - goto corrupt - } - xattr = xattr[:in.Size] - req = &SetxattrRequest{ - Header: m.Header(), - Flags: in.Flags, - Position: in.position(), - Name: string(name[:i]), - Xattr: xattr, - } - - case opGetxattr: - in := (*getxattrIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - name := m.bytes()[unsafe.Sizeof(*in):] - i := bytes.IndexByte(name, '\x00') - if i < 0 { - goto corrupt - } - req = &GetxattrRequest{ - Header: m.Header(), - Name: string(name[:i]), - Size: in.Size, - Position: in.position(), - } - - case opListxattr: - in := (*getxattrIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &ListxattrRequest{ - Header: m.Header(), - Size: in.Size, - Position: in.position(), - } - - case opRemovexattr: - buf := m.bytes() - n := len(buf) - if n == 0 || buf[n-1] != '\x00' { - goto corrupt - } - req = &RemovexattrRequest{ - Header: m.Header(), - Name: string(buf[:n-1]), - } - - case opFlush: - in := (*flushIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &FlushRequest{ - Header: m.Header(), - Handle: HandleID(in.Fh), - Flags: in.FlushFlags, - LockOwner: in.LockOwner, - } - - case opInit: - in := (*initIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &InitRequest{ - Header: m.Header(), - Major: in.Major, - Minor: in.Minor, - MaxReadahead: in.MaxReadahead, - Flags: InitFlags(in.Flags), - } - - case opGetlk: - panic("opGetlk") - case opSetlk: - panic("opSetlk") - case opSetlkw: - panic("opSetlkw") - - case opAccess: - in := (*accessIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &AccessRequest{ - Header: m.Header(), - Mask: in.Mask, - } - - case opCreate: - in := (*createIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - name := m.bytes()[unsafe.Sizeof(*in):] - i := bytes.IndexByte(name, '\x00') - if i < 0 { - goto corrupt - } - req = &CreateRequest{ - Header: m.Header(), - Flags: openFlags(in.Flags), - Mode: fileMode(in.Mode), - Name: string(name[:i]), - } - - case opInterrupt: - in := (*interruptIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &InterruptRequest{ - Header: m.Header(), - IntrID: RequestID(in.Unique), - } - - case opBmap: - panic("opBmap") - - case opDestroy: - req = &DestroyRequest{ - Header: m.Header(), - } - - // OS X - case opSetvolname: - panic("opSetvolname") - case opGetxtimes: - panic("opGetxtimes") - case opExchange: - panic("opExchange") - } - - return req, nil - -corrupt: - Debug(malformedMessage{}) - putMessage(m) - return nil, fmt.Errorf("fuse: malformed message") - -unrecognized: - // Unrecognized message. - // Assume higher-level code will send a "no idea what you mean" error. - h := m.Header() - return &h, nil -} - -type bugShortKernelWrite struct { - Written int64 - Length int64 - Error string - Stack string -} - -func (b bugShortKernelWrite) String() string { - return fmt.Sprintf("short kernel write: written=%d/%d error=%q stack=\n%s", b.Written, b.Length, b.Error, b.Stack) -} - -// safe to call even with nil error -func errorString(err error) string { - if err == nil { - return "" - } - return err.Error() -} - -func (c *Conn) respond(out *outHeader, n uintptr) { - c.wio.Lock() - defer c.wio.Unlock() - out.Len = uint32(n) - msg := (*[1 << 30]byte)(unsafe.Pointer(out))[:n] - nn, err := syscall.Write(c.fd(), msg) - if nn != len(msg) || err != nil { - Debug(bugShortKernelWrite{ - Written: int64(nn), - Length: int64(len(msg)), - Error: errorString(err), - Stack: stack(), - }) - } -} - -func (c *Conn) respondData(out *outHeader, n uintptr, data []byte) { - c.wio.Lock() - defer c.wio.Unlock() - // TODO: use writev - out.Len = uint32(n + uintptr(len(data))) - msg := make([]byte, out.Len) - copy(msg, (*[1 << 30]byte)(unsafe.Pointer(out))[:n]) - copy(msg[n:], data) - syscall.Write(c.fd(), msg) -} - -// An InitRequest is the first request sent on a FUSE file system. -type InitRequest struct { - Header `json:"-"` - Major uint32 - Minor uint32 - // Maximum readahead in bytes that the kernel plans to use. - MaxReadahead uint32 - Flags InitFlags -} - -var _ = Request(&InitRequest{}) - -func (r *InitRequest) String() string { - return fmt.Sprintf("Init [%s] %d.%d ra=%d fl=%v", &r.Header, r.Major, r.Minor, r.MaxReadahead, r.Flags) -} - -// An InitResponse is the response to an InitRequest. -type InitResponse struct { - // Maximum readahead in bytes that the kernel can use. Ignored if - // greater than InitRequest.MaxReadahead. - MaxReadahead uint32 - Flags InitFlags - // Maximum size of a single write operation. - // Linux enforces a minimum of 4 KiB. - MaxWrite uint32 -} - -func (r *InitResponse) String() string { - return fmt.Sprintf("Init %+v", *r) -} - -// Respond replies to the request with the given response. -func (r *InitRequest) Respond(resp *InitResponse) { - out := &initOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Major: kernelVersion, - Minor: kernelMinorVersion, - MaxReadahead: resp.MaxReadahead, - Flags: uint32(resp.Flags), - MaxWrite: resp.MaxWrite, - } - // MaxWrite larger than our receive buffer would just lead to - // errors on large writes. - if out.MaxWrite > maxWrite { - out.MaxWrite = maxWrite - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A StatfsRequest requests information about the mounted file system. -type StatfsRequest struct { - Header `json:"-"` -} - -var _ = Request(&StatfsRequest{}) - -func (r *StatfsRequest) String() string { - return fmt.Sprintf("Statfs [%s]", &r.Header) -} - -// Respond replies to the request with the given response. -func (r *StatfsRequest) Respond(resp *StatfsResponse) { - out := &statfsOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - St: kstatfs{ - Blocks: resp.Blocks, - Bfree: resp.Bfree, - Bavail: resp.Bavail, - Files: resp.Files, - Bsize: resp.Bsize, - Namelen: resp.Namelen, - Frsize: resp.Frsize, - }, - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A StatfsResponse is the response to a StatfsRequest. -type StatfsResponse struct { - Blocks uint64 // Total data blocks in file system. - Bfree uint64 // Free blocks in file system. - Bavail uint64 // Free blocks in file system if you're not root. - Files uint64 // Total files in file system. - Ffree uint64 // Free files in file system. - Bsize uint32 // Block size - Namelen uint32 // Maximum file name length? - Frsize uint32 // Fragment size, smallest addressable data size in the file system. -} - -func (r *StatfsResponse) String() string { - return fmt.Sprintf("Statfs %+v", *r) -} - -// An AccessRequest asks whether the file can be accessed -// for the purpose specified by the mask. -type AccessRequest struct { - Header `json:"-"` - Mask uint32 -} - -var _ = Request(&AccessRequest{}) - -func (r *AccessRequest) String() string { - return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask) -} - -// Respond replies to the request indicating that access is allowed. -// To deny access, use RespondError. -func (r *AccessRequest) Respond() { - out := &outHeader{Unique: uint64(r.ID)} - r.respond(out, unsafe.Sizeof(*out)) -} - -// An Attr is the metadata for a single file or directory. -type Attr struct { - Valid time.Duration // how long Attr can be cached - - Inode uint64 // inode number - Size uint64 // size in bytes - Blocks uint64 // size in blocks - Atime time.Time // time of last access - Mtime time.Time // time of last modification - Ctime time.Time // time of last inode change - Crtime time.Time // time of creation (OS X only) - Mode os.FileMode // file mode - Nlink uint32 // number of links - Uid uint32 // owner uid - Gid uint32 // group gid - Rdev uint32 // device numbers - Flags uint32 // chflags(2) flags (OS X only) -} - -func unix(t time.Time) (sec uint64, nsec uint32) { - nano := t.UnixNano() - sec = uint64(nano / 1e9) - nsec = uint32(nano % 1e9) - return -} - -func (a *Attr) attr() (out attr) { - out.Ino = a.Inode - out.Size = a.Size - out.Blocks = a.Blocks - out.Atime, out.AtimeNsec = unix(a.Atime) - out.Mtime, out.MtimeNsec = unix(a.Mtime) - out.Ctime, out.CtimeNsec = unix(a.Ctime) - out.SetCrtime(unix(a.Crtime)) - out.Mode = uint32(a.Mode) & 0777 - switch { - default: - out.Mode |= syscall.S_IFREG - case a.Mode&os.ModeDir != 0: - out.Mode |= syscall.S_IFDIR - case a.Mode&os.ModeDevice != 0: - if a.Mode&os.ModeCharDevice != 0 { - out.Mode |= syscall.S_IFCHR - } else { - out.Mode |= syscall.S_IFBLK - } - case a.Mode&os.ModeNamedPipe != 0: - out.Mode |= syscall.S_IFIFO - case a.Mode&os.ModeSymlink != 0: - out.Mode |= syscall.S_IFLNK - case a.Mode&os.ModeSocket != 0: - out.Mode |= syscall.S_IFSOCK - } - if a.Mode&os.ModeSetuid != 0 { - out.Mode |= syscall.S_ISUID - } - if a.Mode&os.ModeSetgid != 0 { - out.Mode |= syscall.S_ISGID - } - out.Nlink = a.Nlink - out.Uid = a.Uid - out.Gid = a.Gid - out.Rdev = a.Rdev - out.SetFlags(a.Flags) - - return -} - -// A GetattrRequest asks for the metadata for the file denoted by r.Node. -type GetattrRequest struct { - Header `json:"-"` -} - -var _ = Request(&GetattrRequest{}) - -func (r *GetattrRequest) String() string { - return fmt.Sprintf("Getattr [%s]", &r.Header) -} - -// Respond replies to the request with the given response. -func (r *GetattrRequest) Respond(resp *GetattrResponse) { - out := &attrOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - AttrValid: uint64(resp.Attr.Valid / time.Second), - AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond), - Attr: resp.Attr.attr(), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A GetattrResponse is the response to a GetattrRequest. -type GetattrResponse struct { - Attr Attr // file attributes -} - -func (r *GetattrResponse) String() string { - return fmt.Sprintf("Getattr %+v", *r) -} - -// A GetxattrRequest asks for the extended attributes associated with r.Node. -type GetxattrRequest struct { - Header `json:"-"` - - // Maximum size to return. - Size uint32 - - // Name of the attribute requested. - Name string - - // Offset within extended attributes. - // - // Only valid for OS X, and then only with the resource fork - // attribute. - Position uint32 -} - -var _ = Request(&GetxattrRequest{}) - -func (r *GetxattrRequest) String() string { - return fmt.Sprintf("Getxattr [%s] %q %d @%d", &r.Header, r.Name, r.Size, r.Position) -} - -// Respond replies to the request with the given response. -func (r *GetxattrRequest) Respond(resp *GetxattrResponse) { - if r.Size == 0 { - out := &getxattrOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Size: uint32(len(resp.Xattr)), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) - } else { - out := &outHeader{Unique: uint64(r.ID)} - r.respondData(out, unsafe.Sizeof(*out), resp.Xattr) - } -} - -// A GetxattrResponse is the response to a GetxattrRequest. -type GetxattrResponse struct { - Xattr []byte -} - -func (r *GetxattrResponse) String() string { - return fmt.Sprintf("Getxattr %x", r.Xattr) -} - -// A ListxattrRequest asks to list the extended attributes associated with r.Node. -type ListxattrRequest struct { - Header `json:"-"` - Size uint32 // maximum size to return - Position uint32 // offset within attribute list -} - -var _ = Request(&ListxattrRequest{}) - -func (r *ListxattrRequest) String() string { - return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position) -} - -// Respond replies to the request with the given response. -func (r *ListxattrRequest) Respond(resp *ListxattrResponse) { - if r.Size == 0 { - out := &getxattrOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Size: uint32(len(resp.Xattr)), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) - } else { - out := &outHeader{Unique: uint64(r.ID)} - r.respondData(out, unsafe.Sizeof(*out), resp.Xattr) - } -} - -// A ListxattrResponse is the response to a ListxattrRequest. -type ListxattrResponse struct { - Xattr []byte -} - -func (r *ListxattrResponse) String() string { - return fmt.Sprintf("Listxattr %x", r.Xattr) -} - -// Append adds an extended attribute name to the response. -func (r *ListxattrResponse) Append(names ...string) { - for _, name := range names { - r.Xattr = append(r.Xattr, name...) - r.Xattr = append(r.Xattr, '\x00') - } -} - -// A RemovexattrRequest asks to remove an extended attribute associated with r.Node. -type RemovexattrRequest struct { - Header `json:"-"` - Name string // name of extended attribute -} - -var _ = Request(&RemovexattrRequest{}) - -func (r *RemovexattrRequest) String() string { - return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name) -} - -// Respond replies to the request, indicating that the attribute was removed. -func (r *RemovexattrRequest) Respond() { - out := &outHeader{Unique: uint64(r.ID)} - r.respond(out, unsafe.Sizeof(*out)) -} - -// A SetxattrRequest asks to set an extended attribute associated with a file. -type SetxattrRequest struct { - Header `json:"-"` - - // Flags can make the request fail if attribute does/not already - // exist. Unfortunately, the constants are platform-specific and - // not exposed by Go1.2. Look for XATTR_CREATE, XATTR_REPLACE. - // - // TODO improve this later - // - // TODO XATTR_CREATE and exist -> EEXIST - // - // TODO XATTR_REPLACE and not exist -> ENODATA - Flags uint32 - - // Offset within extended attributes. - // - // Only valid for OS X, and then only with the resource fork - // attribute. - Position uint32 - - Name string - Xattr []byte -} - -var _ = Request(&SetxattrRequest{}) - -func trunc(b []byte, max int) ([]byte, string) { - if len(b) > max { - return b[:max], "..." - } - return b, "" -} - -func (r *SetxattrRequest) String() string { - xattr, tail := trunc(r.Xattr, 16) - return fmt.Sprintf("Setxattr [%s] %q %x%s fl=%v @%#x", &r.Header, r.Name, xattr, tail, r.Flags, r.Position) -} - -// Respond replies to the request, indicating that the extended attribute was set. -func (r *SetxattrRequest) Respond() { - out := &outHeader{Unique: uint64(r.ID)} - r.respond(out, unsafe.Sizeof(*out)) -} - -// A LookupRequest asks to look up the given name in the directory named by r.Node. -type LookupRequest struct { - Header `json:"-"` - Name string -} - -var _ = Request(&LookupRequest{}) - -func (r *LookupRequest) String() string { - return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name) -} - -// Respond replies to the request with the given response. -func (r *LookupRequest) Respond(resp *LookupResponse) { - out := &entryOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Nodeid: uint64(resp.Node), - Generation: resp.Generation, - EntryValid: uint64(resp.EntryValid / time.Second), - EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond), - AttrValid: uint64(resp.Attr.Valid / time.Second), - AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond), - Attr: resp.Attr.attr(), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A LookupResponse is the response to a LookupRequest. -type LookupResponse struct { - Node NodeID - Generation uint64 - EntryValid time.Duration - Attr Attr -} - -func (r *LookupResponse) String() string { - return fmt.Sprintf("Lookup %+v", *r) -} - -// An OpenRequest asks to open a file or directory -type OpenRequest struct { - Header `json:"-"` - Dir bool // is this Opendir? - Flags OpenFlags -} - -var _ = Request(&OpenRequest{}) - -func (r *OpenRequest) String() string { - return fmt.Sprintf("Open [%s] dir=%v fl=%v", &r.Header, r.Dir, r.Flags) -} - -// Respond replies to the request with the given response. -func (r *OpenRequest) Respond(resp *OpenResponse) { - out := &openOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Fh: uint64(resp.Handle), - OpenFlags: uint32(resp.Flags), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A OpenResponse is the response to a OpenRequest. -type OpenResponse struct { - Handle HandleID - Flags OpenResponseFlags -} - -func (r *OpenResponse) String() string { - return fmt.Sprintf("Open %+v", *r) -} - -// A CreateRequest asks to create and open a file (not a directory). -type CreateRequest struct { - Header `json:"-"` - Name string - Flags OpenFlags - Mode os.FileMode -} - -var _ = Request(&CreateRequest{}) - -func (r *CreateRequest) String() string { - return fmt.Sprintf("Create [%s] %q fl=%v mode=%v", &r.Header, r.Name, r.Flags, r.Mode) -} - -// Respond replies to the request with the given response. -func (r *CreateRequest) Respond(resp *CreateResponse) { - out := &createOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - - Nodeid: uint64(resp.Node), - Generation: resp.Generation, - EntryValid: uint64(resp.EntryValid / time.Second), - EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond), - AttrValid: uint64(resp.Attr.Valid / time.Second), - AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond), - Attr: resp.Attr.attr(), - - Fh: uint64(resp.Handle), - OpenFlags: uint32(resp.Flags), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A CreateResponse is the response to a CreateRequest. -// It describes the created node and opened handle. -type CreateResponse struct { - LookupResponse - OpenResponse -} - -func (r *CreateResponse) String() string { - return fmt.Sprintf("Create %+v", *r) -} - -// A MkdirRequest asks to create (but not open) a directory. -type MkdirRequest struct { - Header `json:"-"` - Name string - Mode os.FileMode -} - -var _ = Request(&MkdirRequest{}) - -func (r *MkdirRequest) String() string { - return fmt.Sprintf("Mkdir [%s] %q mode=%v", &r.Header, r.Name, r.Mode) -} - -// Respond replies to the request with the given response. -func (r *MkdirRequest) Respond(resp *MkdirResponse) { - out := &entryOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Nodeid: uint64(resp.Node), - Generation: resp.Generation, - EntryValid: uint64(resp.EntryValid / time.Second), - EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond), - AttrValid: uint64(resp.Attr.Valid / time.Second), - AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond), - Attr: resp.Attr.attr(), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A MkdirResponse is the response to a MkdirRequest. -type MkdirResponse struct { - LookupResponse -} - -func (r *MkdirResponse) String() string { - return fmt.Sprintf("Mkdir %+v", *r) -} - -// A ReadRequest asks to read from an open file. -type ReadRequest struct { - Header `json:"-"` - Dir bool // is this Readdir? - Handle HandleID - Offset int64 - Size int -} - -var _ = Request(&ReadRequest{}) - -func (r *ReadRequest) String() string { - return fmt.Sprintf("Read [%s] %#x %d @%#x dir=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir) -} - -// Respond replies to the request with the given response. -func (r *ReadRequest) Respond(resp *ReadResponse) { - out := &outHeader{Unique: uint64(r.ID)} - r.respondData(out, unsafe.Sizeof(*out), resp.Data) -} - -// A ReadResponse is the response to a ReadRequest. -type ReadResponse struct { - Data []byte -} - -func (r *ReadResponse) String() string { - return fmt.Sprintf("Read %d", len(r.Data)) -} - -type jsonReadResponse struct { - Len uint64 -} - -func (r *ReadResponse) MarshalJSON() ([]byte, error) { - j := jsonReadResponse{ - Len: uint64(len(r.Data)), - } - return json.Marshal(j) -} - -// A ReleaseRequest asks to release (close) an open file handle. -type ReleaseRequest struct { - Header `json:"-"` - Dir bool // is this Releasedir? - Handle HandleID - Flags OpenFlags // flags from OpenRequest - ReleaseFlags ReleaseFlags - LockOwner uint32 -} - -var _ = Request(&ReleaseRequest{}) - -func (r *ReleaseRequest) String() string { - return fmt.Sprintf("Release [%s] %#x fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner) -} - -// Respond replies to the request, indicating that the handle has been released. -func (r *ReleaseRequest) Respond() { - out := &outHeader{Unique: uint64(r.ID)} - r.respond(out, unsafe.Sizeof(*out)) -} - -// A DestroyRequest is sent by the kernel when unmounting the file system. -// No more requests will be received after this one, but it should still be -// responded to. -type DestroyRequest struct { - Header `json:"-"` -} - -var _ = Request(&DestroyRequest{}) - -func (r *DestroyRequest) String() string { - return fmt.Sprintf("Destroy [%s]", &r.Header) -} - -// Respond replies to the request. -func (r *DestroyRequest) Respond() { - out := &outHeader{Unique: uint64(r.ID)} - r.respond(out, unsafe.Sizeof(*out)) -} - -// A ForgetRequest is sent by the kernel when forgetting about r.Node -// as returned by r.N lookup requests. -type ForgetRequest struct { - Header `json:"-"` - N uint64 -} - -var _ = Request(&ForgetRequest{}) - -func (r *ForgetRequest) String() string { - return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N) -} - -// Respond replies to the request, indicating that the forgetfulness has been recorded. -func (r *ForgetRequest) Respond() { - // Don't reply to forget messages. - r.noResponse() -} - -// A Dirent represents a single directory entry. -type Dirent struct { - // Inode this entry names. - Inode uint64 - - // Type of the entry, for example DT_File. - // - // Setting this is optional. The zero value (DT_Unknown) means - // callers will just need to do a Getattr when the type is - // needed. Providing a type can speed up operations - // significantly. - Type DirentType - - // Name of the entry - Name string -} - -// Type of an entry in a directory listing. -type DirentType uint32 - -const ( - // These don't quite match os.FileMode; especially there's an - // explicit unknown, instead of zero value meaning file. They - // are also not quite syscall.DT_*; nothing says the FUSE - // protocol follows those, and even if they were, we don't - // want each fs to fiddle with syscall. - - // The shift by 12 is hardcoded in the FUSE userspace - // low-level C library, so it's safe here. - - DT_Unknown DirentType = 0 - DT_Socket DirentType = syscall.S_IFSOCK >> 12 - DT_Link DirentType = syscall.S_IFLNK >> 12 - DT_File DirentType = syscall.S_IFREG >> 12 - DT_Block DirentType = syscall.S_IFBLK >> 12 - DT_Dir DirentType = syscall.S_IFDIR >> 12 - DT_Char DirentType = syscall.S_IFCHR >> 12 - DT_FIFO DirentType = syscall.S_IFIFO >> 12 -) - -func (t DirentType) String() string { - switch t { - case DT_Unknown: - return "unknown" - case DT_Socket: - return "socket" - case DT_Link: - return "link" - case DT_File: - return "file" - case DT_Block: - return "block" - case DT_Dir: - return "dir" - case DT_Char: - return "char" - case DT_FIFO: - return "fifo" - } - return "invalid" -} - -// AppendDirent appends the encoded form of a directory entry to data -// and returns the resulting slice. -func AppendDirent(data []byte, dir Dirent) []byte { - de := dirent{ - Ino: dir.Inode, - Namelen: uint32(len(dir.Name)), - Type: uint32(dir.Type), - } - de.Off = uint64(len(data) + direntSize + (len(dir.Name)+7)&^7) - data = append(data, (*[direntSize]byte)(unsafe.Pointer(&de))[:]...) - data = append(data, dir.Name...) - n := direntSize + uintptr(len(dir.Name)) - if n%8 != 0 { - var pad [8]byte - data = append(data, pad[:8-n%8]...) - } - return data -} - -// A WriteRequest asks to write to an open file. -type WriteRequest struct { - Header - Handle HandleID - Offset int64 - Data []byte - Flags WriteFlags -} - -var _ = Request(&WriteRequest{}) - -func (r *WriteRequest) String() string { - return fmt.Sprintf("Write [%s] %#x %d @%d fl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags) -} - -type jsonWriteRequest struct { - Handle HandleID - Offset int64 - Len uint64 - Flags WriteFlags -} - -func (r *WriteRequest) MarshalJSON() ([]byte, error) { - j := jsonWriteRequest{ - Handle: r.Handle, - Offset: r.Offset, - Len: uint64(len(r.Data)), - Flags: r.Flags, - } - return json.Marshal(j) -} - -// Respond replies to the request with the given response. -func (r *WriteRequest) Respond(resp *WriteResponse) { - out := &writeOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Size: uint32(resp.Size), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A WriteResponse replies to a write indicating how many bytes were written. -type WriteResponse struct { - Size int -} - -func (r *WriteResponse) String() string { - return fmt.Sprintf("Write %+v", *r) -} - -// A SetattrRequest asks to change one or more attributes associated with a file, -// as indicated by Valid. -type SetattrRequest struct { - Header `json:"-"` - Valid SetattrValid - Handle HandleID - Size uint64 - Atime time.Time - Mtime time.Time - Mode os.FileMode - Uid uint32 - Gid uint32 - - // OS X only - Bkuptime time.Time - Chgtime time.Time - Crtime time.Time - Flags uint32 // see chflags(2) -} - -var _ = Request(&SetattrRequest{}) - -func (r *SetattrRequest) String() string { - var buf bytes.Buffer - fmt.Fprintf(&buf, "Setattr [%s]", &r.Header) - if r.Valid.Mode() { - fmt.Fprintf(&buf, " mode=%v", r.Mode) - } - if r.Valid.Uid() { - fmt.Fprintf(&buf, " uid=%d", r.Uid) - } - if r.Valid.Gid() { - fmt.Fprintf(&buf, " gid=%d", r.Gid) - } - if r.Valid.Size() { - fmt.Fprintf(&buf, " size=%d", r.Size) - } - if r.Valid.Atime() { - fmt.Fprintf(&buf, " atime=%v", r.Atime) - } - if r.Valid.AtimeNow() { - fmt.Fprintf(&buf, " atime=now") - } - if r.Valid.Mtime() { - fmt.Fprintf(&buf, " mtime=%v", r.Mtime) - } - if r.Valid.MtimeNow() { - fmt.Fprintf(&buf, " mtime=now") - } - if r.Valid.Handle() { - fmt.Fprintf(&buf, " handle=%#x", r.Handle) - } else { - fmt.Fprintf(&buf, " handle=INVALID-%#x", r.Handle) - } - if r.Valid.LockOwner() { - fmt.Fprintf(&buf, " lockowner") - } - if r.Valid.Crtime() { - fmt.Fprintf(&buf, " crtime=%v", r.Crtime) - } - if r.Valid.Chgtime() { - fmt.Fprintf(&buf, " chgtime=%v", r.Chgtime) - } - if r.Valid.Bkuptime() { - fmt.Fprintf(&buf, " bkuptime=%v", r.Bkuptime) - } - if r.Valid.Flags() { - fmt.Fprintf(&buf, " flags=%#x", r.Flags) - } - return buf.String() -} - -// Respond replies to the request with the given response, -// giving the updated attributes. -func (r *SetattrRequest) Respond(resp *SetattrResponse) { - out := &attrOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - AttrValid: uint64(resp.Attr.Valid / time.Second), - AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond), - Attr: resp.Attr.attr(), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A SetattrResponse is the response to a SetattrRequest. -type SetattrResponse struct { - Attr Attr // file attributes -} - -func (r *SetattrResponse) String() string { - return fmt.Sprintf("Setattr %+v", *r) -} - -// A FlushRequest asks for the current state of an open file to be flushed -// to storage, as when a file descriptor is being closed. A single opened Handle -// may receive multiple FlushRequests over its lifetime. -type FlushRequest struct { - Header `json:"-"` - Handle HandleID - Flags uint32 - LockOwner uint64 -} - -var _ = Request(&FlushRequest{}) - -func (r *FlushRequest) String() string { - return fmt.Sprintf("Flush [%s] %#x fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner) -} - -// Respond replies to the request, indicating that the flush succeeded. -func (r *FlushRequest) Respond() { - out := &outHeader{Unique: uint64(r.ID)} - r.respond(out, unsafe.Sizeof(*out)) -} - -// A RemoveRequest asks to remove a file or directory from the -// directory r.Node. -type RemoveRequest struct { - Header `json:"-"` - Name string // name of the entry to remove - Dir bool // is this rmdir? -} - -var _ = Request(&RemoveRequest{}) - -func (r *RemoveRequest) String() string { - return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir) -} - -// Respond replies to the request, indicating that the file was removed. -func (r *RemoveRequest) Respond() { - out := &outHeader{Unique: uint64(r.ID)} - r.respond(out, unsafe.Sizeof(*out)) -} - -// A SymlinkRequest is a request to create a symlink making NewName point to Target. -type SymlinkRequest struct { - Header `json:"-"` - NewName, Target string -} - -var _ = Request(&SymlinkRequest{}) - -func (r *SymlinkRequest) String() string { - return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target) -} - -// Respond replies to the request, indicating that the symlink was created. -func (r *SymlinkRequest) Respond(resp *SymlinkResponse) { - out := &entryOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Nodeid: uint64(resp.Node), - Generation: resp.Generation, - EntryValid: uint64(resp.EntryValid / time.Second), - EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond), - AttrValid: uint64(resp.Attr.Valid / time.Second), - AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond), - Attr: resp.Attr.attr(), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A SymlinkResponse is the response to a SymlinkRequest. -type SymlinkResponse struct { - LookupResponse -} - -// A ReadlinkRequest is a request to read a symlink's target. -type ReadlinkRequest struct { - Header `json:"-"` -} - -var _ = Request(&ReadlinkRequest{}) - -func (r *ReadlinkRequest) String() string { - return fmt.Sprintf("Readlink [%s]", &r.Header) -} - -func (r *ReadlinkRequest) Respond(target string) { - out := &outHeader{Unique: uint64(r.ID)} - r.respondData(out, unsafe.Sizeof(*out), []byte(target)) -} - -// A LinkRequest is a request to create a hard link. -type LinkRequest struct { - Header `json:"-"` - OldNode NodeID - NewName string -} - -var _ = Request(&LinkRequest{}) - -func (r *LinkRequest) String() string { - return fmt.Sprintf("Link [%s] node %d to %q", &r.Header, r.OldNode, r.NewName) -} - -func (r *LinkRequest) Respond(resp *LookupResponse) { - out := &entryOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Nodeid: uint64(resp.Node), - Generation: resp.Generation, - EntryValid: uint64(resp.EntryValid / time.Second), - EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond), - AttrValid: uint64(resp.Attr.Valid / time.Second), - AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond), - Attr: resp.Attr.attr(), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A RenameRequest is a request to rename a file. -type RenameRequest struct { - Header `json:"-"` - NewDir NodeID - OldName, NewName string -} - -var _ = Request(&RenameRequest{}) - -func (r *RenameRequest) String() string { - return fmt.Sprintf("Rename [%s] from %q to dirnode %d %q", &r.Header, r.OldName, r.NewDir, r.NewName) -} - -func (r *RenameRequest) Respond() { - out := &outHeader{Unique: uint64(r.ID)} - r.respond(out, unsafe.Sizeof(*out)) -} - -type MknodRequest struct { - Header `json:"-"` - Name string - Mode os.FileMode - Rdev uint32 -} - -var _ = Request(&MknodRequest{}) - -func (r *MknodRequest) String() string { - return fmt.Sprintf("Mknod [%s] Name %q mode %v rdev %d", &r.Header, r.Name, r.Mode, r.Rdev) -} - -func (r *MknodRequest) Respond(resp *LookupResponse) { - out := &entryOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - Nodeid: uint64(resp.Node), - Generation: resp.Generation, - EntryValid: uint64(resp.EntryValid / time.Second), - EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond), - AttrValid: uint64(resp.Attr.Valid / time.Second), - AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond), - Attr: resp.Attr.attr(), - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -type FsyncRequest struct { - Header `json:"-"` - Handle HandleID - // TODO bit 1 is datasync, not well documented upstream - Flags uint32 - Dir bool -} - -var _ = Request(&FsyncRequest{}) - -func (r *FsyncRequest) String() string { - return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags) -} - -func (r *FsyncRequest) Respond() { - out := &outHeader{Unique: uint64(r.ID)} - r.respond(out, unsafe.Sizeof(*out)) -} - -// An InterruptRequest is a request to interrupt another pending request. The -// response to that request should return an error status of EINTR. -type InterruptRequest struct { - Header `json:"-"` - IntrID RequestID // ID of the request to be interrupt. -} - -var _ = Request(&InterruptRequest{}) - -func (r *InterruptRequest) Respond() { - // nothing to do here - r.noResponse() -} - -func (r *InterruptRequest) String() string { - return fmt.Sprintf("Interrupt [%s] ID %v", &r.Header, r.IntrID) -} - -/*{ - -// A XXXRequest xxx. -type XXXRequest struct { - Header `json:"-"` - xxx -} - -var _ = Request(&XXXRequest{}) - -func (r *XXXRequest) String() string { - return fmt.Sprintf("XXX [%s] xxx", &r.Header) -} - -// Respond replies to the request with the given response. -func (r *XXXRequest) Respond(resp *XXXResponse) { - out := &xxxOut{ - outHeader: outHeader{Unique: uint64(r.ID)}, - xxx, - } - r.respond(&out.outHeader, unsafe.Sizeof(*out)) -} - -// A XXXResponse is the response to a XXXRequest. -type XXXResponse struct { - xxx -} - -func (r *XXXResponse) String() string { - return fmt.Sprintf("XXX %+v", *r) -} - - } -*/ diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go b/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go deleted file mode 100644 index b04c89a9e..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go +++ /dev/null @@ -1,639 +0,0 @@ -// See the file LICENSE for copyright and licensing information. - -// Derived from FUSE's fuse_kernel.h, which carries this notice: -/* - This file defines the kernel interface of FUSE - Copyright (C) 2001-2007 Miklos Szeredi - - - This -- and only this -- header file may also be distributed under - the terms of the BSD Licence as follows: - - Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. -*/ - -package fuse - -import ( - "fmt" - "syscall" - "unsafe" -) - -// Version is the FUSE version implemented by the package. -const Version = "7.8" - -const ( - kernelVersion = 7 - kernelMinorVersion = 8 - rootID = 1 -) - -type kstatfs struct { - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Bsize uint32 - Namelen uint32 - Frsize uint32 - Padding uint32 - Spare [6]uint32 -} - -type fileLock struct { - Start uint64 - End uint64 - Type uint32 - Pid uint32 -} - -// The SetattrValid are bit flags describing which fields in the SetattrRequest -// are included in the change. -type SetattrValid uint32 - -const ( - SetattrMode SetattrValid = 1 << 0 - SetattrUid SetattrValid = 1 << 1 - SetattrGid SetattrValid = 1 << 2 - SetattrSize SetattrValid = 1 << 3 - SetattrAtime SetattrValid = 1 << 4 - SetattrMtime SetattrValid = 1 << 5 - SetattrHandle SetattrValid = 1 << 6 - - // Linux only(?) - SetattrAtimeNow SetattrValid = 1 << 7 - SetattrMtimeNow SetattrValid = 1 << 8 - SetattrLockOwner SetattrValid = 1 << 9 // http://www.mail-archive.com/git-commits-head@vger.kernel.org/msg27852.html - - // OS X only - SetattrCrtime SetattrValid = 1 << 28 - SetattrChgtime SetattrValid = 1 << 29 - SetattrBkuptime SetattrValid = 1 << 30 - SetattrFlags SetattrValid = 1 << 31 -) - -func (fl SetattrValid) Mode() bool { return fl&SetattrMode != 0 } -func (fl SetattrValid) Uid() bool { return fl&SetattrUid != 0 } -func (fl SetattrValid) Gid() bool { return fl&SetattrGid != 0 } -func (fl SetattrValid) Size() bool { return fl&SetattrSize != 0 } -func (fl SetattrValid) Atime() bool { return fl&SetattrAtime != 0 } -func (fl SetattrValid) Mtime() bool { return fl&SetattrMtime != 0 } -func (fl SetattrValid) Handle() bool { return fl&SetattrHandle != 0 } -func (fl SetattrValid) AtimeNow() bool { return fl&SetattrAtimeNow != 0 } -func (fl SetattrValid) MtimeNow() bool { return fl&SetattrMtimeNow != 0 } -func (fl SetattrValid) LockOwner() bool { return fl&SetattrLockOwner != 0 } -func (fl SetattrValid) Crtime() bool { return fl&SetattrCrtime != 0 } -func (fl SetattrValid) Chgtime() bool { return fl&SetattrChgtime != 0 } -func (fl SetattrValid) Bkuptime() bool { return fl&SetattrBkuptime != 0 } -func (fl SetattrValid) Flags() bool { return fl&SetattrFlags != 0 } - -func (fl SetattrValid) String() string { - return flagString(uint32(fl), setattrValidNames) -} - -var setattrValidNames = []flagName{ - {uint32(SetattrMode), "SetattrMode"}, - {uint32(SetattrUid), "SetattrUid"}, - {uint32(SetattrGid), "SetattrGid"}, - {uint32(SetattrSize), "SetattrSize"}, - {uint32(SetattrAtime), "SetattrAtime"}, - {uint32(SetattrMtime), "SetattrMtime"}, - {uint32(SetattrHandle), "SetattrHandle"}, - {uint32(SetattrAtimeNow), "SetattrAtimeNow"}, - {uint32(SetattrMtimeNow), "SetattrMtimeNow"}, - {uint32(SetattrLockOwner), "SetattrLockOwner"}, - {uint32(SetattrCrtime), "SetattrCrtime"}, - {uint32(SetattrChgtime), "SetattrChgtime"}, - {uint32(SetattrBkuptime), "SetattrBkuptime"}, - {uint32(SetattrFlags), "SetattrFlags"}, -} - -// Flags that can be seen in OpenRequest.Flags. -const ( - // Access modes. These are not 1-bit flags, but alternatives where - // only one can be chosen. See the IsReadOnly etc convenience - // methods. - OpenReadOnly OpenFlags = syscall.O_RDONLY - OpenWriteOnly OpenFlags = syscall.O_WRONLY - OpenReadWrite OpenFlags = syscall.O_RDWR - - OpenAppend OpenFlags = syscall.O_APPEND - OpenCreate OpenFlags = syscall.O_CREAT - OpenExclusive OpenFlags = syscall.O_EXCL - OpenSync OpenFlags = syscall.O_SYNC - OpenTruncate OpenFlags = syscall.O_TRUNC -) - -// OpenAccessModeMask is a bitmask that separates the access mode -// from the other flags in OpenFlags. -const OpenAccessModeMask OpenFlags = syscall.O_ACCMODE - -// OpenFlags are the O_FOO flags passed to open/create/etc calls. For -// example, os.O_WRONLY | os.O_APPEND. -type OpenFlags uint32 - -func (fl OpenFlags) String() string { - // O_RDONLY, O_RWONLY, O_RDWR are not flags - s := accModeName(fl & OpenAccessModeMask) - flags := uint32(fl &^ OpenAccessModeMask) - if flags != 0 { - s = s + "+" + flagString(flags, openFlagNames) - } - return s -} - -// Return true if OpenReadOnly is set. -func (fl OpenFlags) IsReadOnly() bool { - return fl&OpenAccessModeMask == OpenReadOnly -} - -// Return true if OpenWriteOnly is set. -func (fl OpenFlags) IsWriteOnly() bool { - return fl&OpenAccessModeMask == OpenWriteOnly -} - -// Return true if OpenReadWrite is set. -func (fl OpenFlags) IsReadWrite() bool { - return fl&OpenAccessModeMask == OpenReadWrite -} - -func accModeName(flags OpenFlags) string { - switch flags { - case OpenReadOnly: - return "OpenReadOnly" - case OpenWriteOnly: - return "OpenWriteOnly" - case OpenReadWrite: - return "OpenReadWrite" - default: - return "" - } -} - -var openFlagNames = []flagName{ - {uint32(OpenCreate), "OpenCreate"}, - {uint32(OpenExclusive), "OpenExclusive"}, - {uint32(OpenTruncate), "OpenTruncate"}, - {uint32(OpenAppend), "OpenAppend"}, - {uint32(OpenSync), "OpenSync"}, -} - -// The OpenResponseFlags are returned in the OpenResponse. -type OpenResponseFlags uint32 - -const ( - OpenDirectIO OpenResponseFlags = 1 << 0 // bypass page cache for this open file - OpenKeepCache OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open - OpenNonSeekable OpenResponseFlags = 1 << 2 // (Linux?) - - OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X - OpenPurgeUBC OpenResponseFlags = 1 << 31 // OS X -) - -func (fl OpenResponseFlags) String() string { - return flagString(uint32(fl), openResponseFlagNames) -} - -var openResponseFlagNames = []flagName{ - {uint32(OpenDirectIO), "OpenDirectIO"}, - {uint32(OpenKeepCache), "OpenKeepCache"}, - {uint32(OpenPurgeAttr), "OpenPurgeAttr"}, - {uint32(OpenPurgeUBC), "OpenPurgeUBC"}, -} - -// The InitFlags are used in the Init exchange. -type InitFlags uint32 - -const ( - InitAsyncRead InitFlags = 1 << 0 - InitPosixLocks InitFlags = 1 << 1 - InitFileOps InitFlags = 1 << 2 - InitAtomicTrunc InitFlags = 1 << 3 - InitExportSupport InitFlags = 1 << 4 - InitBigWrites InitFlags = 1 << 5 - InitDontMask InitFlags = 1 << 6 - InitSpliceWrite InitFlags = 1 << 7 - InitSpliceMove InitFlags = 1 << 8 - InitSpliceRead InitFlags = 1 << 9 - InitFlockLocks InitFlags = 1 << 10 - InitHasIoctlDir InitFlags = 1 << 11 - InitAutoInvalData InitFlags = 1 << 12 - InitDoReaddirplus InitFlags = 1 << 13 - InitReaddirplusAuto InitFlags = 1 << 14 - InitAsyncDIO InitFlags = 1 << 15 - InitWritebackCache InitFlags = 1 << 16 - InitNoOpenSupport InitFlags = 1 << 17 - - InitCaseSensitive InitFlags = 1 << 29 // OS X only - InitVolRename InitFlags = 1 << 30 // OS X only - InitXtimes InitFlags = 1 << 31 // OS X only -) - -type flagName struct { - bit uint32 - name string -} - -var initFlagNames = []flagName{ - {uint32(InitAsyncRead), "InitAsyncRead"}, - {uint32(InitPosixLocks), "InitPosixLocks"}, - {uint32(InitFileOps), "InitFileOps"}, - {uint32(InitAtomicTrunc), "InitAtomicTrunc"}, - {uint32(InitExportSupport), "InitExportSupport"}, - {uint32(InitBigWrites), "InitBigWrites"}, - {uint32(InitDontMask), "InitDontMask"}, - {uint32(InitSpliceWrite), "InitSpliceWrite"}, - {uint32(InitSpliceMove), "InitSpliceMove"}, - {uint32(InitSpliceRead), "InitSpliceRead"}, - {uint32(InitFlockLocks), "InitFlockLocks"}, - {uint32(InitHasIoctlDir), "InitHasIoctlDir"}, - {uint32(InitAutoInvalData), "InitAutoInvalData"}, - {uint32(InitDoReaddirplus), "InitDoReaddirplus"}, - {uint32(InitReaddirplusAuto), "InitReaddirplusAuto"}, - {uint32(InitAsyncDIO), "InitAsyncDIO"}, - {uint32(InitWritebackCache), "InitWritebackCache"}, - {uint32(InitNoOpenSupport), "InitNoOpenSupport"}, - - {uint32(InitCaseSensitive), "InitCaseSensitive"}, - {uint32(InitVolRename), "InitVolRename"}, - {uint32(InitXtimes), "InitXtimes"}, -} - -func (fl InitFlags) String() string { - return flagString(uint32(fl), initFlagNames) -} - -func flagString(f uint32, names []flagName) string { - var s string - - if f == 0 { - return "0" - } - - for _, n := range names { - if f&n.bit != 0 { - s += "+" + n.name - f &^= n.bit - } - } - if f != 0 { - s += fmt.Sprintf("%+#x", f) - } - return s[1:] -} - -// The ReleaseFlags are used in the Release exchange. -type ReleaseFlags uint32 - -const ( - ReleaseFlush ReleaseFlags = 1 << 0 -) - -func (fl ReleaseFlags) String() string { - return flagString(uint32(fl), releaseFlagNames) -} - -var releaseFlagNames = []flagName{ - {uint32(ReleaseFlush), "ReleaseFlush"}, -} - -// Opcodes -const ( - opLookup = 1 - opForget = 2 // no reply - opGetattr = 3 - opSetattr = 4 - opReadlink = 5 - opSymlink = 6 - opMknod = 8 - opMkdir = 9 - opUnlink = 10 - opRmdir = 11 - opRename = 12 - opLink = 13 - opOpen = 14 - opRead = 15 - opWrite = 16 - opStatfs = 17 - opRelease = 18 - opFsync = 20 - opSetxattr = 21 - opGetxattr = 22 - opListxattr = 23 - opRemovexattr = 24 - opFlush = 25 - opInit = 26 - opOpendir = 27 - opReaddir = 28 - opReleasedir = 29 - opFsyncdir = 30 - opGetlk = 31 - opSetlk = 32 - opSetlkw = 33 - opAccess = 34 - opCreate = 35 - opInterrupt = 36 - opBmap = 37 - opDestroy = 38 - opIoctl = 39 // Linux? - opPoll = 40 // Linux? - - // OS X - opSetvolname = 61 - opGetxtimes = 62 - opExchange = 63 -) - -type entryOut struct { - outHeader - Nodeid uint64 // Inode ID - Generation uint64 // Inode generation - EntryValid uint64 // Cache timeout for the name - AttrValid uint64 // Cache timeout for the attributes - EntryValidNsec uint32 - AttrValidNsec uint32 - Attr attr -} - -type forgetIn struct { - Nlookup uint64 -} - -type attrOut struct { - outHeader - AttrValid uint64 // Cache timeout for the attributes - AttrValidNsec uint32 - Dummy uint32 - Attr attr -} - -// OS X -type getxtimesOut struct { - outHeader - Bkuptime uint64 - Crtime uint64 - BkuptimeNsec uint32 - CrtimeNsec uint32 -} - -type mknodIn struct { - Mode uint32 - Rdev uint32 - // "filename\x00" follows. -} - -type mkdirIn struct { - Mode uint32 - Padding uint32 - // filename follows -} - -type renameIn struct { - Newdir uint64 - // "oldname\x00newname\x00" follows -} - -// OS X -type exchangeIn struct { - Olddir uint64 - Newdir uint64 - Options uint64 -} - -type linkIn struct { - Oldnodeid uint64 -} - -type setattrInCommon struct { - Valid uint32 - Padding uint32 - Fh uint64 - Size uint64 - LockOwner uint64 // unused on OS X? - Atime uint64 - Mtime uint64 - Unused2 uint64 - AtimeNsec uint32 - MtimeNsec uint32 - Unused3 uint32 - Mode uint32 - Unused4 uint32 - Uid uint32 - Gid uint32 - Unused5 uint32 -} - -type openIn struct { - Flags uint32 - Unused uint32 -} - -type openOut struct { - outHeader - Fh uint64 - OpenFlags uint32 - Padding uint32 -} - -type createIn struct { - Flags uint32 - Mode uint32 -} - -type createOut struct { - outHeader - - Nodeid uint64 // Inode ID - Generation uint64 // Inode generation - EntryValid uint64 // Cache timeout for the name - AttrValid uint64 // Cache timeout for the attributes - EntryValidNsec uint32 - AttrValidNsec uint32 - Attr attr - - Fh uint64 - OpenFlags uint32 - Padding uint32 -} - -type releaseIn struct { - Fh uint64 - Flags uint32 - ReleaseFlags uint32 - LockOwner uint32 -} - -type flushIn struct { - Fh uint64 - FlushFlags uint32 - Padding uint32 - LockOwner uint64 -} - -type readIn struct { - Fh uint64 - Offset uint64 - Size uint32 - Padding uint32 -} - -type writeIn struct { - Fh uint64 - Offset uint64 - Size uint32 - WriteFlags uint32 -} - -type writeOut struct { - outHeader - Size uint32 - Padding uint32 -} - -// The WriteFlags are passed in WriteRequest. -type WriteFlags uint32 - -func (fl WriteFlags) String() string { - return flagString(uint32(fl), writeFlagNames) -} - -var writeFlagNames = []flagName{} - -const compatStatfsSize = 48 - -type statfsOut struct { - outHeader - St kstatfs -} - -type fsyncIn struct { - Fh uint64 - FsyncFlags uint32 - Padding uint32 -} - -type setxattrInCommon struct { - Size uint32 - Flags uint32 -} - -func (setxattrInCommon) position() uint32 { - return 0 -} - -type getxattrInCommon struct { - Size uint32 - Padding uint32 -} - -func (getxattrInCommon) position() uint32 { - return 0 -} - -type getxattrOut struct { - outHeader - Size uint32 - Padding uint32 -} - -type lkIn struct { - Fh uint64 - Owner uint64 - Lk fileLock -} - -type lkOut struct { - outHeader - Lk fileLock -} - -type accessIn struct { - Mask uint32 - Padding uint32 -} - -type initIn struct { - Major uint32 - Minor uint32 - MaxReadahead uint32 - Flags uint32 -} - -const initInSize = int(unsafe.Sizeof(initIn{})) - -type initOut struct { - outHeader - Major uint32 - Minor uint32 - MaxReadahead uint32 - Flags uint32 - Unused uint32 - MaxWrite uint32 -} - -type interruptIn struct { - Unique uint64 -} - -type bmapIn struct { - Block uint64 - BlockSize uint32 - Padding uint32 -} - -type bmapOut struct { - outHeader - Block uint64 -} - -type inHeader struct { - Len uint32 - Opcode uint32 - Unique uint64 - Nodeid uint64 - Uid uint32 - Gid uint32 - Pid uint32 - Padding uint32 -} - -const inHeaderSize = int(unsafe.Sizeof(inHeader{})) - -type outHeader struct { - Len uint32 - Error int32 - Unique uint64 -} - -type dirent struct { - Ino uint64 - Off uint64 - Namelen uint32 - Type uint32 - Name [0]byte -} - -const direntSize = 8 + 8 + 4 + 4 diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_darwin.go b/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_darwin.go deleted file mode 100644 index 4f9347d03..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_darwin.go +++ /dev/null @@ -1,86 +0,0 @@ -package fuse - -import ( - "time" -) - -type attr struct { - Ino uint64 - Size uint64 - Blocks uint64 - Atime uint64 - Mtime uint64 - Ctime uint64 - Crtime_ uint64 // OS X only - AtimeNsec uint32 - MtimeNsec uint32 - CtimeNsec uint32 - CrtimeNsec uint32 // OS X only - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint32 - Flags_ uint32 // OS X only; see chflags(2) -} - -func (a *attr) SetCrtime(s uint64, ns uint32) { - a.Crtime_, a.CrtimeNsec = s, ns -} - -func (a *attr) SetFlags(f uint32) { - a.Flags_ = f -} - -type setattrIn struct { - setattrInCommon - - // OS X only - Bkuptime_ uint64 - Chgtime_ uint64 - Crtime uint64 - BkuptimeNsec uint32 - ChgtimeNsec uint32 - CrtimeNsec uint32 - Flags_ uint32 // see chflags(2) -} - -func (in *setattrIn) BkupTime() time.Time { - return time.Unix(int64(in.Bkuptime_), int64(in.BkuptimeNsec)) -} - -func (in *setattrIn) Chgtime() time.Time { - return time.Unix(int64(in.Chgtime_), int64(in.ChgtimeNsec)) -} - -func (in *setattrIn) Flags() uint32 { - return in.Flags_ -} - -func openFlags(flags uint32) OpenFlags { - return OpenFlags(flags) -} - -type getxattrIn struct { - getxattrInCommon - - // OS X only - Position uint32 - Padding uint32 -} - -func (g *getxattrIn) position() uint32 { - return g.Position -} - -type setxattrIn struct { - setxattrInCommon - - // OS X only - Position uint32 - Padding uint32 -} - -func (s *setxattrIn) position() uint32 { - return s.Position -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_freebsd.go b/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_freebsd.go deleted file mode 100644 index 7636878c3..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_freebsd.go +++ /dev/null @@ -1,60 +0,0 @@ -package fuse - -import "time" - -type attr struct { - Ino uint64 - Size uint64 - Blocks uint64 - Atime uint64 - Mtime uint64 - Ctime uint64 - AtimeNsec uint32 - MtimeNsec uint32 - CtimeNsec uint32 - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint32 -} - -func (a *attr) Crtime() time.Time { - return time.Time{} -} - -func (a *attr) SetCrtime(s uint64, ns uint32) { - // ignored on freebsd -} - -func (a *attr) SetFlags(f uint32) { - // ignored on freebsd -} - -type setattrIn struct { - setattrInCommon -} - -func (in *setattrIn) BkupTime() time.Time { - return time.Time{} -} - -func (in *setattrIn) Chgtime() time.Time { - return time.Time{} -} - -func (in *setattrIn) Flags() uint32 { - return 0 -} - -func openFlags(flags uint32) OpenFlags { - return OpenFlags(flags) -} - -type getxattrIn struct { - getxattrInCommon -} - -type setxattrIn struct { - setxattrInCommon -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_linux.go b/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_linux.go deleted file mode 100644 index 6a752457a..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_linux.go +++ /dev/null @@ -1,70 +0,0 @@ -package fuse - -import "time" - -type attr struct { - Ino uint64 - Size uint64 - Blocks uint64 - Atime uint64 - Mtime uint64 - Ctime uint64 - AtimeNsec uint32 - MtimeNsec uint32 - CtimeNsec uint32 - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint32 - // Blksize uint32 // Only in protocol 7.9 - // padding_ uint32 // Only in protocol 7.9 -} - -func (a *attr) Crtime() time.Time { - return time.Time{} -} - -func (a *attr) SetCrtime(s uint64, ns uint32) { - // Ignored on Linux. -} - -func (a *attr) SetFlags(f uint32) { - // Ignored on Linux. -} - -type setattrIn struct { - setattrInCommon -} - -func (in *setattrIn) BkupTime() time.Time { - return time.Time{} -} - -func (in *setattrIn) Chgtime() time.Time { - return time.Time{} -} - -func (in *setattrIn) Flags() uint32 { - return 0 -} - -func openFlags(flags uint32) OpenFlags { - // on amd64, the 32-bit O_LARGEFILE flag is always seen; - // on i386, the flag probably depends on the app - // requesting, but in any case should be utterly - // uninteresting to us here; our kernel protocol messages - // are not directly related to the client app's kernel - // API/ABI - flags &^= 0x8000 - - return OpenFlags(flags) -} - -type getxattrIn struct { - getxattrInCommon -} - -type setxattrIn struct { - setxattrInCommon -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_std.go b/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_std.go deleted file mode 100644 index 074cfd322..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_std.go +++ /dev/null @@ -1 +0,0 @@ -package fuse diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_test.go b/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_test.go deleted file mode 100644 index 8d74ea727..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package fuse_test - -import ( - "os" - "testing" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" -) - -func TestOpenFlagsAccmodeMask(t *testing.T) { - var f = fuse.OpenFlags(os.O_RDWR | os.O_SYNC) - if g, e := f&fuse.OpenAccessModeMask, fuse.OpenReadWrite; g != e { - t.Fatalf("OpenAccessModeMask behaves wrong: %v: %o != %o", f, g, e) - } - if f.IsReadOnly() { - t.Fatalf("IsReadOnly is wrong: %v", f) - } - if f.IsWriteOnly() { - t.Fatalf("IsWriteOnly is wrong: %v", f) - } - if !f.IsReadWrite() { - t.Fatalf("IsReadWrite is wrong: %v", f) - } -} - -func TestOpenFlagsString(t *testing.T) { - var f = fuse.OpenFlags(os.O_RDWR | os.O_SYNC | os.O_APPEND) - if g, e := f.String(), "OpenReadWrite+OpenAppend+OpenSync"; g != e { - t.Fatalf("OpenFlags.String: %q != %q", g, e) - } -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuseutil/fuseutil.go b/Godeps/_workspace/src/bazil.org/fuse/fuseutil/fuseutil.go deleted file mode 100644 index 9da753559..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/fuseutil/fuseutil.go +++ /dev/null @@ -1,20 +0,0 @@ -package fuseutil - -import ( - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" -) - -// HandleRead handles a read request assuming that data is the entire file content. -// It adjusts the amount returned in resp according to req.Offset and req.Size. -func HandleRead(req *fuse.ReadRequest, resp *fuse.ReadResponse, data []byte) { - if req.Offset >= int64(len(data)) { - data = nil - } else { - data = data[req.Offset:] - } - if len(data) > req.Size { - data = data[:req.Size] - } - n := copy(resp.Data[:req.Size], data) - resp.Data = resp.Data[:n] -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go b/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go deleted file mode 100644 index 3a6a688fa..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go +++ /dev/null @@ -1,101 +0,0 @@ -// Hellofs implements a simple "hello world" file system. -package main - -import ( - "context" - "flag" - "fmt" - "log" - "os" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" - _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" -) - -var Usage = func() { - fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) - fmt.Fprintf(os.Stderr, " %s MOUNTPOINT\n", os.Args[0]) - flag.PrintDefaults() -} - -func main() { - flag.Usage = Usage - flag.Parse() - - if flag.NArg() != 1 { - Usage() - os.Exit(2) - } - mountpoint := flag.Arg(0) - - c, err := fuse.Mount( - mountpoint, - fuse.FSName("helloworld"), - fuse.Subtype("hellofs"), - fuse.LocalVolume(), - fuse.VolumeName("Hello world!"), - ) - if err != nil { - log.Fatal(err) - } - defer c.Close() - - err = fs.Serve(c, FS{}) - if err != nil { - log.Fatal(err) - } - - // check if the mount process has an error to report - <-c.Ready - if err := c.MountError; err != nil { - log.Fatal(err) - } -} - -// FS implements the hello world file system. -type FS struct{} - -func (FS) Root() (fs.Node, error) { - return Dir{}, nil -} - -// Dir implements both Node and Handle for the root directory. -type Dir struct{} - -func (Dir) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 1 - a.Mode = os.ModeDir | 0555 - return nil -} - -func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) { - if name == "hello" { - return File{}, nil - } - return nil, fuse.ENOENT -} - -var dirDirs = []fuse.Dirent{ - {Inode: 2, Name: "hello", Type: fuse.DT_File}, -} - -func (Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - return dirDirs, nil -} - -// File implements both Node and Handle for the hello file. -type File struct{} - -const greeting = "hello, world\n" - -func (File) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 2 - a.Mode = 0444 - a.Size = uint64(len(greeting)) - return nil -} - -func (File) ReadAll(ctx context.Context) ([]byte, error) { - return []byte(greeting), nil -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go b/Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go deleted file mode 100644 index 742b084c2..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go +++ /dev/null @@ -1,126 +0,0 @@ -package fuse - -import ( - "bytes" - "errors" - "fmt" - "os" - "os/exec" - "strconv" - "strings" - "syscall" -) - -var errNoAvail = errors.New("no available fuse devices") - -var errNotLoaded = errors.New("osxfusefs is not loaded") - -func loadOSXFUSE() error { - cmd := exec.Command("/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs") - cmd.Dir = "/" - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - return err -} - -func openOSXFUSEDev() (*os.File, error) { - var f *os.File - var err error - for i := uint64(0); ; i++ { - path := "/dev/osxfuse" + strconv.FormatUint(i, 10) - f, err = os.OpenFile(path, os.O_RDWR, 0000) - if os.IsNotExist(err) { - if i == 0 { - // not even the first device was found -> fuse is not loaded - return nil, errNotLoaded - } - - // we've run out of kernel-provided devices - return nil, errNoAvail - } - - if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY { - // try the next one - continue - } - - if err != nil { - return nil, err - } - return f, nil - } -} - -func callMount(dir string, conf *MountConfig, f *os.File, ready chan<- struct{}, errp *error) error { - bin := "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs" - - for k, v := range conf.options { - if strings.Contains(k, ",") || strings.Contains(v, ",") { - // Silly limitation but the mount helper does not - // understand any escaping. See TestMountOptionCommaError. - return fmt.Errorf("mount options cannot contain commas on darwin: %q=%q", k, v) - } - } - cmd := exec.Command( - bin, - "-o", conf.getOptions(), - // Tell osxfuse-kext how large our buffer is. It must split - // writes larger than this into multiple writes. - // - // OSXFUSE seems to ignore InitResponse.MaxWrite, and uses - // this instead. - "-o", "iosize="+strconv.FormatUint(maxWrite, 10), - // refers to fd passed in cmd.ExtraFiles - "3", - dir, - ) - cmd.ExtraFiles = []*os.File{f} - cmd.Env = os.Environ() - cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_CALL_BY_LIB=") - // TODO this is used for fs typenames etc, let app influence it - cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_DAEMON_PATH="+bin) - var buf bytes.Buffer - cmd.Stdout = &buf - cmd.Stderr = &buf - - err := cmd.Start() - if err != nil { - return err - } - go func() { - err := cmd.Wait() - if err != nil { - if buf.Len() > 0 { - output := buf.Bytes() - output = bytes.TrimRight(output, "\n") - msg := err.Error() + ": " + string(output) - err = errors.New(msg) - } - } - *errp = err - close(ready) - }() - return err -} - -func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (*os.File, error) { - f, err := openOSXFUSEDev() - if err == errNotLoaded { - err = loadOSXFUSE() - if err != nil { - return nil, err - } - // try again - f, err = openOSXFUSEDev() - } - if err != nil { - return nil, err - } - err = callMount(dir, conf, f, ready, errp) - if err != nil { - f.Close() - return nil, err - } - return f, nil -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/mount_freebsd.go b/Godeps/_workspace/src/bazil.org/fuse/mount_freebsd.go deleted file mode 100644 index 951dcf10c..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/mount_freebsd.go +++ /dev/null @@ -1,41 +0,0 @@ -package fuse - -import ( - "fmt" - "os" - "os/exec" - "strings" -) - -func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (*os.File, error) { - for k, v := range conf.options { - if strings.Contains(k, ",") || strings.Contains(v, ",") { - // Silly limitation but the mount helper does not - // understand any escaping. See TestMountOptionCommaError. - return nil, fmt.Errorf("mount options cannot contain commas on FreeBSD: %q=%q", k, v) - } - } - - f, err := os.OpenFile("/dev/fuse", os.O_RDWR, 0000) - if err != nil { - *errp = err - return nil, err - } - - cmd := exec.Command( - "/sbin/mount_fusefs", - "--safe", - "-o", conf.getOptions(), - "3", - dir, - ) - cmd.ExtraFiles = []*os.File{f} - - out, err := cmd.CombinedOutput() - if err != nil { - return nil, fmt.Errorf("mount_fusefs: %q, %v", out, err) - } - - close(ready) - return f, nil -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/mount_linux.go b/Godeps/_workspace/src/bazil.org/fuse/mount_linux.go deleted file mode 100644 index 36b81dbeb..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/mount_linux.go +++ /dev/null @@ -1,112 +0,0 @@ -package fuse - -import ( - "bufio" - "fmt" - "io" - "log" - "net" - "os" - "os/exec" - "sync" - "syscall" -) - -func lineLogger(wg *sync.WaitGroup, prefix string, r io.ReadCloser) { - defer wg.Done() - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - switch line := scanner.Text(); line { - case `fusermount: failed to open /etc/fuse.conf: Permission denied`: - // Silence this particular message, it occurs way too - // commonly and isn't very relevant to whether the mount - // succeeds or not. - continue - default: - log.Printf("%s: %s", prefix, line) - } - } - if err := scanner.Err(); err != nil { - log.Printf("%s, error reading: %v", prefix, err) - } -} - -func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) { - // linux mount is never delayed - close(ready) - - fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0) - if err != nil { - return nil, fmt.Errorf("socketpair error: %v", err) - } - defer syscall.Close(fds[0]) - defer syscall.Close(fds[1]) - - cmd := exec.Command( - "fusermount", - "-o", conf.getOptions(), - "--", - dir, - ) - cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3") - - writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes") - defer writeFile.Close() - cmd.ExtraFiles = []*os.File{writeFile} - - var wg sync.WaitGroup - stdout, err := cmd.StdoutPipe() - if err != nil { - return nil, fmt.Errorf("setting up fusermount stderr: %v", err) - } - stderr, err := cmd.StderrPipe() - if err != nil { - return nil, fmt.Errorf("setting up fusermount stderr: %v", err) - } - - if err := cmd.Start(); err != nil { - return nil, fmt.Errorf("fusermount: %v", err) - } - wg.Add(2) - go lineLogger(&wg, "mount helper output", stdout) - go lineLogger(&wg, "mount helper error", stderr) - wg.Wait() - if err := cmd.Wait(); err != nil { - return nil, fmt.Errorf("fusermount: %v", err) - } - - readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads") - defer readFile.Close() - c, err := net.FileConn(readFile) - if err != nil { - return nil, fmt.Errorf("FileConn from fusermount socket: %v", err) - } - defer c.Close() - - uc, ok := c.(*net.UnixConn) - if !ok { - return nil, fmt.Errorf("unexpected FileConn type; expected UnixConn, got %T", c) - } - - buf := make([]byte, 32) // expect 1 byte - oob := make([]byte, 32) // expect 24 bytes - _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) - scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) - if err != nil { - return nil, fmt.Errorf("ParseSocketControlMessage: %v", err) - } - if len(scms) != 1 { - return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms) - } - scm := scms[0] - gotFds, err := syscall.ParseUnixRights(&scm) - if err != nil { - return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err) - } - if len(gotFds) != 1 { - return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds) - } - f := os.NewFile(uintptr(gotFds[0]), "/dev/fuse") - return f, nil -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/options.go b/Godeps/_workspace/src/bazil.org/fuse/options.go deleted file mode 100644 index 5a0b7f180..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/options.go +++ /dev/null @@ -1,132 +0,0 @@ -package fuse - -import ( - "errors" - "strings" -) - -func dummyOption(conf *MountConfig) error { - return nil -} - -// MountConfig holds the configuration for a mount operation. -// Use it by passing MountOption values to Mount. -type MountConfig struct { - options map[string]string -} - -func escapeComma(s string) string { - s = strings.Replace(s, `\`, `\\`, -1) - s = strings.Replace(s, `,`, `\,`, -1) - return s -} - -// getOptions makes a string of options suitable for passing to FUSE -// mount flag `-o`. Returns an empty string if no options were set. -// Any platform specific adjustments should happen before the call. -func (m *MountConfig) getOptions() string { - var opts []string - for k, v := range m.options { - k = escapeComma(k) - if v != "" { - k += "=" + escapeComma(v) - } - opts = append(opts, k) - } - return strings.Join(opts, ",") -} - -// MountOption is passed to Mount to change the behavior of the mount. -type MountOption func(*MountConfig) error - -// FSName sets the file system name (also called source) that is -// visible in the list of mounted file systems. -// -// FreeBSD ignores this option. -func FSName(name string) MountOption { - return func(conf *MountConfig) error { - conf.options["fsname"] = name - return nil - } -} - -// Subtype sets the subtype of the mount. The main type is always -// `fuse`. The type in a list of mounted file systems will look like -// `fuse.foo`. -// -// OS X ignores this option. -// FreeBSD ignores this option. -func Subtype(fstype string) MountOption { - return func(conf *MountConfig) error { - conf.options["subtype"] = fstype - return nil - } -} - -// LocalVolume sets the volume to be local (instead of network), -// changing the behavior of Finder, Spotlight, and such. -// -// OS X only. Others ignore this option. -func LocalVolume() MountOption { - return localVolume -} - -// VolumeName sets the volume name shown in Finder. -// -// OS X only. Others ignore this option. -func VolumeName(name string) MountOption { - return volumeName(name) -} - -var ErrCannotCombineAllowOtherAndAllowRoot = errors.New("cannot combine AllowOther and AllowRoot") - -// AllowOther allows other users to access the file system. -// -// Only one of AllowOther or AllowRoot can be used. -func AllowOther() MountOption { - return func(conf *MountConfig) error { - if _, ok := conf.options["allow_root"]; ok { - return ErrCannotCombineAllowOtherAndAllowRoot - } - conf.options["allow_other"] = "" - return nil - } -} - -// AllowRoot allows other users to access the file system. -// -// Only one of AllowOther or AllowRoot can be used. -// -// FreeBSD ignores this option. -func AllowRoot() MountOption { - return func(conf *MountConfig) error { - if _, ok := conf.options["allow_other"]; ok { - return ErrCannotCombineAllowOtherAndAllowRoot - } - conf.options["allow_root"] = "" - return nil - } -} - -// DefaultPermissions makes the kernel enforce access control based on -// the file mode (as in chmod). -// -// Without this option, the Node itself decides what is and is not -// allowed. This is normally ok because FUSE file systems cannot be -// accessed by other users without AllowOther/AllowRoot. -// -// FreeBSD ignores this option. -func DefaultPermissions() MountOption { - return func(conf *MountConfig) error { - conf.options["default_permissions"] = "" - return nil - } -} - -// ReadOnly makes the mount read-only. -func ReadOnly() MountOption { - return func(conf *MountConfig) error { - conf.options["ro"] = "" - return nil - } -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_darwin.go b/Godeps/_workspace/src/bazil.org/fuse/options_darwin.go deleted file mode 100644 index 15aedbcfc..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/options_darwin.go +++ /dev/null @@ -1,13 +0,0 @@ -package fuse - -func localVolume(conf *MountConfig) error { - conf.options["local"] = "" - return nil -} - -func volumeName(name string) MountOption { - return func(conf *MountConfig) error { - conf.options["volname"] = name - return nil - } -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_freebsd.go b/Godeps/_workspace/src/bazil.org/fuse/options_freebsd.go deleted file mode 100644 index 8eb07e009..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/options_freebsd.go +++ /dev/null @@ -1,9 +0,0 @@ -package fuse - -func localVolume(conf *MountConfig) error { - return nil -} - -func volumeName(name string) MountOption { - return dummyOption -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_helper_test.go b/Godeps/_workspace/src/bazil.org/fuse/options_helper_test.go deleted file mode 100644 index f9c90e8bf..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/options_helper_test.go +++ /dev/null @@ -1,6 +0,0 @@ -package fuse - -// for TestMountOptionCommaError -func ForTestSetMountOption(conf *MountConfig, k, v string) { - conf.options[k] = v -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_linux.go b/Godeps/_workspace/src/bazil.org/fuse/options_linux.go deleted file mode 100644 index 8eb07e009..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/options_linux.go +++ /dev/null @@ -1,9 +0,0 @@ -package fuse - -func localVolume(conf *MountConfig) error { - return nil -} - -func volumeName(name string) MountOption { - return dummyOption -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_nocomma_test.go b/Godeps/_workspace/src/bazil.org/fuse/options_nocomma_test.go deleted file mode 100644 index b3d7bdad0..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/options_nocomma_test.go +++ /dev/null @@ -1,34 +0,0 @@ -// This file contains tests for platforms that have no escape -// mechanism for including commas in mount options. -// -// +build darwin - -package fuse_test - -import ( - "runtime" - "testing" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" -) - -func TestMountOptionCommaError(t *testing.T) { - t.Parallel() - // this test is not tied to any specific option, it just needs - // some string content - var evil = "FuseTest,Marker" - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, - func(conf *fuse.MountConfig) error { - fuse.ForTestSetMountOption(conf, "fusetest", evil) - return nil - }, - ) - if err == nil { - mnt.Close() - t.Fatal("expected an error about commas") - } - if g, e := err.Error(), `mount options cannot contain commas on `+runtime.GOOS+`: "fusetest"="FuseTest,Marker"`; g != e { - t.Fatalf("wrong error: %q != %q", g, e) - } -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_test.go b/Godeps/_workspace/src/bazil.org/fuse/options_test.go deleted file mode 100644 index 6096ec031..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/options_test.go +++ /dev/null @@ -1,229 +0,0 @@ -package fuse_test - -import ( - "context" - "os" - "runtime" - "syscall" - "testing" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" -) - -func init() { - fstestutil.DebugByDefault() -} - -func TestMountOptionFSName(t *testing.T) { - if runtime.GOOS == "freebsd" { - t.Skip("FreeBSD does not support FSName") - } - t.Parallel() - const name = "FuseTestMarker" - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, - fuse.FSName(name), - ) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - info, err := fstestutil.GetMountInfo(mnt.Dir) - if err != nil { - t.Fatal(err) - } - if g, e := info.FSName, name; g != e { - t.Errorf("wrong FSName: %q != %q", g, e) - } -} - -func testMountOptionFSNameEvil(t *testing.T, evil string) { - if runtime.GOOS == "freebsd" { - t.Skip("FreeBSD does not support FSName") - } - t.Parallel() - var name = "FuseTest" + evil + "Marker" - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, - fuse.FSName(name), - ) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - info, err := fstestutil.GetMountInfo(mnt.Dir) - if err != nil { - t.Fatal(err) - } - if g, e := info.FSName, name; g != e { - t.Errorf("wrong FSName: %q != %q", g, e) - } -} - -func TestMountOptionFSNameEvilComma(t *testing.T) { - if runtime.GOOS == "darwin" { - // see TestMountOptionCommaError for a test that enforces we - // at least give a nice error, instead of corrupting the mount - // options - t.Skip("TODO: OS X gets this wrong, commas in mount options cannot be escaped at all") - } - testMountOptionFSNameEvil(t, ",") -} - -func TestMountOptionFSNameEvilSpace(t *testing.T) { - testMountOptionFSNameEvil(t, " ") -} - -func TestMountOptionFSNameEvilTab(t *testing.T) { - testMountOptionFSNameEvil(t, "\t") -} - -func TestMountOptionFSNameEvilNewline(t *testing.T) { - testMountOptionFSNameEvil(t, "\n") -} - -func TestMountOptionFSNameEvilBackslash(t *testing.T) { - testMountOptionFSNameEvil(t, `\`) -} - -func TestMountOptionFSNameEvilBackslashDouble(t *testing.T) { - // catch double-unescaping, if it were to happen - testMountOptionFSNameEvil(t, `\\`) -} - -func TestMountOptionSubtype(t *testing.T) { - if runtime.GOOS == "darwin" { - t.Skip("OS X does not support Subtype") - } - if runtime.GOOS == "freebsd" { - t.Skip("FreeBSD does not support Subtype") - } - t.Parallel() - const name = "FuseTestMarker" - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, - fuse.Subtype(name), - ) - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - info, err := fstestutil.GetMountInfo(mnt.Dir) - if err != nil { - t.Fatal(err) - } - if g, e := info.Type, "fuse."+name; g != e { - t.Errorf("wrong Subtype: %q != %q", g, e) - } -} - -// TODO test LocalVolume - -// TODO test AllowOther; hard because needs system-level authorization - -func TestMountOptionAllowOtherThenAllowRoot(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, - fuse.AllowOther(), - fuse.AllowRoot(), - ) - if err == nil { - mnt.Close() - } - if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e { - t.Fatalf("wrong error: %v != %v", g, e) - } -} - -// TODO test AllowRoot; hard because needs system-level authorization - -func TestMountOptionAllowRootThenAllowOther(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, - fuse.AllowRoot(), - fuse.AllowOther(), - ) - if err == nil { - mnt.Close() - } - if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e { - t.Fatalf("wrong error: %v != %v", g, e) - } -} - -type unwritableFile struct{} - -func (f unwritableFile) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = 0000 - return nil -} - -func TestMountOptionDefaultPermissions(t *testing.T) { - if runtime.GOOS == "freebsd" { - t.Skip("FreeBSD does not support DefaultPermissions") - } - t.Parallel() - mnt, err := fstestutil.MountedT(t, - fstestutil.SimpleFS{ - fstestutil.ChildMap{"child": unwritableFile{}}, - }, - fuse.DefaultPermissions(), - ) - - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - // This will be prevented by kernel-level access checking when - // DefaultPermissions is used. - f, err := os.OpenFile(mnt.Dir+"/child", os.O_WRONLY, 0000) - if err == nil { - f.Close() - t.Fatal("expected an error") - } - if !os.IsPermission(err) { - t.Fatalf("expected a permission error, got %T: %v", err, err) - } -} - -type createrDir struct { - fstestutil.Dir -} - -var _ fs.NodeCreater = createrDir{} - -func (createrDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) { - // pick a really distinct error, to identify it later - return nil, nil, fuse.Errno(syscall.ENAMETOOLONG) -} - -func TestMountOptionReadOnly(t *testing.T) { - t.Parallel() - mnt, err := fstestutil.MountedT(t, - fstestutil.SimpleFS{createrDir{}}, - fuse.ReadOnly(), - ) - - if err != nil { - t.Fatal(err) - } - defer mnt.Close() - - // This will be prevented by kernel-level access checking when - // ReadOnly is used. - f, err := os.Create(mnt.Dir + "/child") - if err == nil { - f.Close() - t.Fatal("expected an error") - } - perr, ok := err.(*os.PathError) - if !ok { - t.Fatalf("expected PathError, got %T: %v", err, err) - } - if perr.Err != syscall.EROFS { - t.Fatalf("expected EROFS, got %T: %v", err, err) - } -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/doc.go b/Godeps/_workspace/src/bazil.org/fuse/syscallx/doc.go deleted file mode 100644 index 8ceee43b0..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/doc.go +++ /dev/null @@ -1,13 +0,0 @@ -// Package syscallx provides wrappers that make syscalls on various -// platforms more interoperable. -// -// The API intentionally omits the OS X-specific position and option -// arguments for extended attribute calls. -// -// Not having position means it might not be useful for accessing the -// resource fork. If that's needed by code inside fuse, a function -// with a different name may be added on the side. -// -// Options can be implemented with separate wrappers, in the style of -// Linux getxattr/lgetxattr/fgetxattr. -package syscallx diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/generate b/Godeps/_workspace/src/bazil.org/fuse/syscallx/generate deleted file mode 100644 index 476a282b1..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/generate +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -set -e - -mksys="$(go env GOROOT)/src/pkg/syscall/mksyscall.pl" - -fix() { - sed 's,^package syscall$,&x\nimport "syscall",' \ - | gofmt -r='BytePtrFromString -> syscall.BytePtrFromString' \ - | gofmt -r='Syscall6 -> syscall.Syscall6' \ - | gofmt -r='Syscall -> syscall.Syscall' \ - | gofmt -r='SYS_GETXATTR -> syscall.SYS_GETXATTR' \ - | gofmt -r='SYS_LISTXATTR -> syscall.SYS_LISTXATTR' \ - | gofmt -r='SYS_SETXATTR -> syscall.SYS_SETXATTR' \ - | gofmt -r='SYS_REMOVEXATTR -> syscall.SYS_REMOVEXATTR' \ - | gofmt -r='SYS_MSYNC -> syscall.SYS_MSYNC' -} - -cd "$(dirname "$0")" - -$mksys xattr_darwin.go \ - | fix \ - >xattr_darwin_amd64.go - -$mksys -l32 xattr_darwin.go \ - | fix \ - >xattr_darwin_386.go - -$mksys msync.go \ - | fix \ - >msync_amd64.go - -$mksys -l32 msync.go \ - | fix \ - >msync_386.go diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/msync.go b/Godeps/_workspace/src/bazil.org/fuse/syscallx/msync.go deleted file mode 100644 index 30737e6d4..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/msync.go +++ /dev/null @@ -1,9 +0,0 @@ -package syscallx - -/* This is the source file for msync_*.go, to regenerate run - - ./generate - -*/ - -//sys Msync(b []byte, flags int) (err error) diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/msync_386.go b/Godeps/_workspace/src/bazil.org/fuse/syscallx/msync_386.go deleted file mode 100644 index 672599423..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/msync_386.go +++ /dev/null @@ -1,24 +0,0 @@ -// mksyscall.pl -l32 msync.go -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -package syscallx - -import "syscall" - -import "unsafe" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Msync(b []byte, flags int) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall.Syscall(syscall.SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) - if e1 != 0 { - err = e1 - } - return -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/msync_amd64.go b/Godeps/_workspace/src/bazil.org/fuse/syscallx/msync_amd64.go deleted file mode 100644 index 0bbe1ab85..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/msync_amd64.go +++ /dev/null @@ -1,24 +0,0 @@ -// mksyscall.pl msync.go -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -package syscallx - -import "syscall" - -import "unsafe" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Msync(b []byte, flags int) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall.Syscall(syscall.SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) - if e1 != 0 { - err = e1 - } - return -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/syscallx.go b/Godeps/_workspace/src/bazil.org/fuse/syscallx/syscallx.go deleted file mode 100644 index eb099129e..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/syscallx.go +++ /dev/null @@ -1,4 +0,0 @@ -package syscallx - -// make us look more like package syscall, so mksyscall.pl output works -var _zero uintptr diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/syscallx_std.go b/Godeps/_workspace/src/bazil.org/fuse/syscallx/syscallx_std.go deleted file mode 100644 index d12713cd0..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/syscallx_std.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build !darwin - -package syscallx - -// This file just contains wrappers for platforms that already have -// the right stuff in golang.org/x/sys/unix. - -import ( - "gx/ipfs/QmXPKMT5cT8ajqamSD1YaeEpfeaHvs9AU4MQzte4Bkr6V4/sys/unix" -) - -func Getxattr(path string, attr string, dest []byte) (sz int, err error) { - return unix.Getxattr(path, attr, dest) -} - -func Listxattr(path string, dest []byte) (sz int, err error) { - return unix.Listxattr(path, dest) -} - -func Setxattr(path string, attr string, data []byte, flags int) (err error) { - return unix.Setxattr(path, attr, data, flags) -} - -func Removexattr(path string, attr string) (err error) { - return unix.Removexattr(path, attr) -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/xattr_darwin.go b/Godeps/_workspace/src/bazil.org/fuse/syscallx/xattr_darwin.go deleted file mode 100644 index b00f90203..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/xattr_darwin.go +++ /dev/null @@ -1,38 +0,0 @@ -package syscallx - -/* This is the source file for syscallx_darwin_*.go, to regenerate run - - ./generate - -*/ - -// cannot use dest []byte here because OS X getxattr really wants a -// NULL to trigger size probing, size==0 is not enough -// -//sys getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) - -func Getxattr(path string, attr string, dest []byte) (sz int, err error) { - var destp *byte - if len(dest) > 0 { - destp = &dest[0] - } - return getxattr(path, attr, destp, len(dest), 0, 0) -} - -//sys listxattr(path string, dest []byte, options int) (sz int, err error) - -func Listxattr(path string, dest []byte) (sz int, err error) { - return listxattr(path, dest, 0) -} - -//sys setxattr(path string, attr string, data []byte, position uint32, flags int) (err error) - -func Setxattr(path string, attr string, data []byte, flags int) (err error) { - return setxattr(path, attr, data, 0, flags) -} - -//sys removexattr(path string, attr string, options int) (err error) - -func Removexattr(path string, attr string) (err error) { - return removexattr(path, attr, 0) -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/xattr_darwin_386.go b/Godeps/_workspace/src/bazil.org/fuse/syscallx/xattr_darwin_386.go deleted file mode 100644 index ffc357aef..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/xattr_darwin_386.go +++ /dev/null @@ -1,97 +0,0 @@ -// mksyscall.pl -l32 xattr_darwin.go -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -package syscallx - -import "syscall" - -import "unsafe" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = syscall.BytePtrFromString(attr) - if err != nil { - return - } - r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) - sz = int(r0) - if e1 != 0 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func listxattr(path string, dest []byte, options int) (sz int, err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(dest) > 0 { - _p1 = unsafe.Pointer(&dest[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(options), 0, 0) - sz = int(r0) - if e1 != 0 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setxattr(path string, attr string, data []byte, position uint32, flags int) (err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = syscall.BytePtrFromString(attr) - if err != nil { - return - } - var _p2 unsafe.Pointer - if len(data) > 0 { - _p2 = unsafe.Pointer(&data[0]) - } else { - _p2 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(position), uintptr(flags)) - if e1 != 0 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func removexattr(path string, attr string, options int) (err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = syscall.BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) - if e1 != 0 { - err = e1 - } - return -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/syscallx/xattr_darwin_amd64.go b/Godeps/_workspace/src/bazil.org/fuse/syscallx/xattr_darwin_amd64.go deleted file mode 100644 index 864c4c1d4..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/syscallx/xattr_darwin_amd64.go +++ /dev/null @@ -1,97 +0,0 @@ -// mksyscall.pl xattr_darwin.go -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -package syscallx - -import "syscall" - -import "unsafe" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = syscall.BytePtrFromString(attr) - if err != nil { - return - } - r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) - sz = int(r0) - if e1 != 0 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func listxattr(path string, dest []byte, options int) (sz int, err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(dest) > 0 { - _p1 = unsafe.Pointer(&dest[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(options), 0, 0) - sz = int(r0) - if e1 != 0 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setxattr(path string, attr string, data []byte, position uint32, flags int) (err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = syscall.BytePtrFromString(attr) - if err != nil { - return - } - var _p2 unsafe.Pointer - if len(data) > 0 { - _p2 = unsafe.Pointer(&data[0]) - } else { - _p2 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(position), uintptr(flags)) - if e1 != 0 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func removexattr(path string, attr string, options int) (err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = syscall.BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) - if e1 != 0 { - err = e1 - } - return -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/unmount.go b/Godeps/_workspace/src/bazil.org/fuse/unmount.go deleted file mode 100644 index ffe3f155c..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/unmount.go +++ /dev/null @@ -1,6 +0,0 @@ -package fuse - -// Unmount tries to unmount the filesystem mounted at dir. -func Unmount(dir string) error { - return unmount(dir) -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/unmount_linux.go b/Godeps/_workspace/src/bazil.org/fuse/unmount_linux.go deleted file mode 100644 index 088f0cfee..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/unmount_linux.go +++ /dev/null @@ -1,21 +0,0 @@ -package fuse - -import ( - "bytes" - "errors" - "os/exec" -) - -func unmount(dir string) error { - cmd := exec.Command("fusermount", "-u", dir) - output, err := cmd.CombinedOutput() - if err != nil { - if len(output) > 0 { - output = bytes.TrimRight(output, "\n") - msg := err.Error() + ": " + string(output) - err = errors.New(msg) - } - return err - } - return nil -} diff --git a/Godeps/_workspace/src/bazil.org/fuse/unmount_std.go b/Godeps/_workspace/src/bazil.org/fuse/unmount_std.go deleted file mode 100644 index d6efe276f..000000000 --- a/Godeps/_workspace/src/bazil.org/fuse/unmount_std.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build !linux - -package fuse - -import ( - "os" - "syscall" -) - -func unmount(dir string) error { - err := syscall.Unmount(dir, 0) - if err != nil { - err = &os.PathError{Op: "unmount", Path: dir, Err: err} - return err - } - return nil -}