dep ensure
This commit is contained in:
parent
1158ac4760
commit
c8c18403e4
371 changed files with 168673 additions and 1 deletions
190
vendor/github.com/hanwen/go-fuse/fuse/nodefs/api.go
generated
vendored
Normal file
190
vendor/github.com/hanwen/go-fuse/fuse/nodefs/api.go
generated
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The nodefs package offers a high level API that resembles the
|
||||
// kernel's idea of what an FS looks like. File systems can have
|
||||
// multiple hard-links to one file, for example. It is also suited if
|
||||
// the data to represent fits in memory: you can construct the
|
||||
// complete file system tree at mount time
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
// The Node interface implements the user-defined file system
|
||||
// functionality
|
||||
type Node interface {
|
||||
// Inode and SetInode are basic getter/setters. They are
|
||||
// called by the FileSystemConnector. You get them for free by
|
||||
// embedding the result of NewDefaultNode() in your node
|
||||
// struct.
|
||||
Inode() *Inode
|
||||
SetInode(node *Inode)
|
||||
|
||||
// OnMount is called on the root node just after a mount is
|
||||
// executed, either when the actual root is mounted, or when a
|
||||
// filesystem is mounted in-process. The passed-in
|
||||
// FileSystemConnector gives access to Notify methods and
|
||||
// Debug settings.
|
||||
OnMount(conn *FileSystemConnector)
|
||||
|
||||
// OnUnmount is executed just before a submount is removed,
|
||||
// and when the process receives a forget for the FUSE root
|
||||
// node.
|
||||
OnUnmount()
|
||||
|
||||
// Lookup finds a child node to this node; it is only called
|
||||
// for directory Nodes.
|
||||
Lookup(out *fuse.Attr, name string, context *fuse.Context) (*Inode, fuse.Status)
|
||||
|
||||
// Deletable() should return true if this node may be discarded once
|
||||
// the kernel forgets its reference.
|
||||
// If it returns false, OnForget will never get called for this node. This
|
||||
// is appropriate if the filesystem has no persistent backing store
|
||||
// (in-memory filesystems) where discarding the node loses the stored data.
|
||||
// Deletable will be called from within the treeLock critical section, so you
|
||||
// cannot look at other nodes.
|
||||
Deletable() bool
|
||||
|
||||
// OnForget is called when the kernel forgets its reference to this node and
|
||||
// sends a FORGET request. It should perform cleanup and free memory as
|
||||
// appropriate for the filesystem.
|
||||
// OnForget is not called if the node is a directory and has children.
|
||||
// This is called from within a treeLock critical section.
|
||||
OnForget()
|
||||
|
||||
// Misc.
|
||||
Access(mode uint32, context *fuse.Context) (code fuse.Status)
|
||||
Readlink(c *fuse.Context) ([]byte, fuse.Status)
|
||||
|
||||
// Namespace operations; these are only called on directory Nodes.
|
||||
|
||||
// Mknod should create the node, add it to the receiver's
|
||||
// inode, and return it
|
||||
Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (newNode *Inode, code fuse.Status)
|
||||
|
||||
// Mkdir should create the directory Inode, add it to the
|
||||
// receiver's Inode, and return it
|
||||
Mkdir(name string, mode uint32, context *fuse.Context) (newNode *Inode, code fuse.Status)
|
||||
Unlink(name string, context *fuse.Context) (code fuse.Status)
|
||||
Rmdir(name string, context *fuse.Context) (code fuse.Status)
|
||||
|
||||
// Symlink should create a child inode to the receiver, and
|
||||
// return it.
|
||||
Symlink(name string, content string, context *fuse.Context) (*Inode, fuse.Status)
|
||||
Rename(oldName string, newParent Node, newName string, context *fuse.Context) (code fuse.Status)
|
||||
|
||||
// Link should return the Inode of the resulting link. In
|
||||
// a POSIX conformant file system, this should add 'existing'
|
||||
// to the receiver, and return the Inode corresponding to
|
||||
// 'existing'.
|
||||
Link(name string, existing Node, context *fuse.Context) (newNode *Inode, code fuse.Status)
|
||||
|
||||
// Create should return an open file, and the Inode for that file.
|
||||
Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, child *Inode, code fuse.Status)
|
||||
|
||||
// Open opens a file, and returns a File which is associated
|
||||
// with a file handle. It is OK to return (nil, OK) here. In
|
||||
// that case, the Node should implement Read or Write
|
||||
// directly.
|
||||
Open(flags uint32, context *fuse.Context) (file File, code fuse.Status)
|
||||
OpenDir(context *fuse.Context) ([]fuse.DirEntry, fuse.Status)
|
||||
Read(file File, dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status)
|
||||
Write(file File, data []byte, off int64, context *fuse.Context) (written uint32, code fuse.Status)
|
||||
|
||||
// XAttrs
|
||||
GetXAttr(attribute string, context *fuse.Context) (data []byte, code fuse.Status)
|
||||
RemoveXAttr(attr string, context *fuse.Context) fuse.Status
|
||||
SetXAttr(attr string, data []byte, flags int, context *fuse.Context) fuse.Status
|
||||
ListXAttr(context *fuse.Context) (attrs []string, code fuse.Status)
|
||||
|
||||
// Attributes
|
||||
GetAttr(out *fuse.Attr, file File, context *fuse.Context) (code fuse.Status)
|
||||
Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status)
|
||||
Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status)
|
||||
Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status)
|
||||
Utimens(file File, atime *time.Time, mtime *time.Time, context *fuse.Context) (code fuse.Status)
|
||||
Fallocate(file File, off uint64, size uint64, mode uint32, context *fuse.Context) (code fuse.Status)
|
||||
|
||||
StatFs() *fuse.StatfsOut
|
||||
}
|
||||
|
||||
// A File object is returned from FileSystem.Open and
|
||||
// FileSystem.Create. Include the NewDefaultFile return value into
|
||||
// the struct to inherit a null implementation.
|
||||
type File interface {
|
||||
// Called upon registering the filehandle in the inode.
|
||||
SetInode(*Inode)
|
||||
|
||||
// The String method is for debug printing.
|
||||
String() string
|
||||
|
||||
// Wrappers around other File implementations, should return
|
||||
// the inner file here.
|
||||
InnerFile() File
|
||||
|
||||
Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status)
|
||||
Write(data []byte, off int64) (written uint32, code fuse.Status)
|
||||
|
||||
Flock(flags int) fuse.Status
|
||||
|
||||
// Flush is called for close() call on a file descriptor. In
|
||||
// case of duplicated descriptor, it may be called more than
|
||||
// once for a file.
|
||||
Flush() fuse.Status
|
||||
|
||||
// This is called to before the file handle is forgotten. This
|
||||
// method has no return value, so nothing can synchronizes on
|
||||
// the call. Any cleanup that requires specific synchronization or
|
||||
// could fail with I/O errors should happen in Flush instead.
|
||||
Release()
|
||||
Fsync(flags int) (code fuse.Status)
|
||||
|
||||
// The methods below may be called on closed files, due to
|
||||
// concurrency. In that case, you should return EBADF.
|
||||
Truncate(size uint64) fuse.Status
|
||||
GetAttr(out *fuse.Attr) fuse.Status
|
||||
Chown(uid uint32, gid uint32) fuse.Status
|
||||
Chmod(perms uint32) fuse.Status
|
||||
Utimens(atime *time.Time, mtime *time.Time) fuse.Status
|
||||
Allocate(off uint64, size uint64, mode uint32) (code fuse.Status)
|
||||
}
|
||||
|
||||
// Wrap a File return in this to set FUSE flags. Also used internally
|
||||
// to store open file data.
|
||||
type WithFlags struct {
|
||||
File
|
||||
|
||||
// For debugging.
|
||||
Description string
|
||||
|
||||
// Put FOPEN_* flags here.
|
||||
FuseFlags uint32
|
||||
|
||||
// O_RDWR, O_TRUNCATE, etc.
|
||||
OpenFlags uint32
|
||||
}
|
||||
|
||||
// Options contains time out options for a node FileSystem. The
|
||||
// default copied from libfuse and set in NewMountOptions() is
|
||||
// (1s,1s,0s).
|
||||
type Options struct {
|
||||
EntryTimeout time.Duration
|
||||
AttrTimeout time.Duration
|
||||
NegativeTimeout time.Duration
|
||||
|
||||
// If set, replace all uids with given UID.
|
||||
// NewOptions() will set this to the daemon's
|
||||
// uid/gid.
|
||||
*fuse.Owner
|
||||
|
||||
// This option exists for compatibility and is ignored.
|
||||
PortableInodes bool
|
||||
|
||||
// If set, print debug information.
|
||||
Debug bool
|
||||
}
|
||||
75
vendor/github.com/hanwen/go-fuse/fuse/nodefs/defaultfile.go
generated
vendored
Normal file
75
vendor/github.com/hanwen/go-fuse/fuse/nodefs/defaultfile.go
generated
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
type defaultFile struct{}
|
||||
|
||||
// NewDefaultFile returns a File instance that returns ENOSYS for
|
||||
// every operation.
|
||||
func NewDefaultFile() File {
|
||||
return (*defaultFile)(nil)
|
||||
}
|
||||
|
||||
func (f *defaultFile) SetInode(*Inode) {
|
||||
}
|
||||
|
||||
func (f *defaultFile) InnerFile() File {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *defaultFile) String() string {
|
||||
return "defaultFile"
|
||||
}
|
||||
|
||||
func (f *defaultFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
|
||||
return nil, fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (f *defaultFile) Write(data []byte, off int64) (uint32, fuse.Status) {
|
||||
return 0, fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (f *defaultFile) Flock(flags int) fuse.Status { return fuse.ENOSYS }
|
||||
func (f *defaultFile) Flush() fuse.Status {
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (f *defaultFile) Release() {
|
||||
|
||||
}
|
||||
|
||||
func (f *defaultFile) GetAttr(*fuse.Attr) fuse.Status {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (f *defaultFile) Fsync(flags int) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (f *defaultFile) Utimens(atime *time.Time, mtime *time.Time) fuse.Status {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (f *defaultFile) Truncate(size uint64) fuse.Status {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (f *defaultFile) Chown(uid uint32, gid uint32) fuse.Status {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (f *defaultFile) Chmod(perms uint32) fuse.Status {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (f *defaultFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
172
vendor/github.com/hanwen/go-fuse/fuse/nodefs/defaultnode.go
generated
vendored
Normal file
172
vendor/github.com/hanwen/go-fuse/fuse/nodefs/defaultnode.go
generated
vendored
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
// NewDefaultNode returns an implementation of Node that returns
|
||||
// ENOSYS for all operations.
|
||||
func NewDefaultNode() Node {
|
||||
return &defaultNode{}
|
||||
}
|
||||
|
||||
type defaultNode struct {
|
||||
inode *Inode
|
||||
}
|
||||
|
||||
func (fs *defaultNode) OnUnmount() {
|
||||
}
|
||||
|
||||
func (fs *defaultNode) OnMount(conn *FileSystemConnector) {
|
||||
}
|
||||
|
||||
func (n *defaultNode) StatFs() *fuse.StatfsOut {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *defaultNode) SetInode(node *Inode) {
|
||||
n.inode = node
|
||||
}
|
||||
|
||||
func (n *defaultNode) Deletable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (n *defaultNode) Inode() *Inode {
|
||||
return n.inode
|
||||
}
|
||||
|
||||
func (n *defaultNode) OnForget() {
|
||||
}
|
||||
|
||||
func (n *defaultNode) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node *Inode, code fuse.Status) {
|
||||
return nil, fuse.ENOENT
|
||||
}
|
||||
|
||||
func (n *defaultNode) Access(mode uint32, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Readlink(c *fuse.Context) ([]byte, fuse.Status) {
|
||||
return nil, fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (newNode *Inode, code fuse.Status) {
|
||||
return nil, fuse.ENOSYS
|
||||
}
|
||||
func (n *defaultNode) Mkdir(name string, mode uint32, context *fuse.Context) (newNode *Inode, code fuse.Status) {
|
||||
return nil, fuse.ENOSYS
|
||||
}
|
||||
func (n *defaultNode) Unlink(name string, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
func (n *defaultNode) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
func (n *defaultNode) Symlink(name string, content string, context *fuse.Context) (newNode *Inode, code fuse.Status) {
|
||||
return nil, fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Rename(oldName string, newParent Node, newName string, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Link(name string, existing Node, context *fuse.Context) (newNode *Inode, code fuse.Status) {
|
||||
return nil, fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, newNode *Inode, code fuse.Status) {
|
||||
return nil, nil, fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Open(flags uint32, context *fuse.Context) (file File, code fuse.Status) {
|
||||
return nil, fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Flush(file File, openFlags uint32, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) OpenDir(context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
|
||||
ch := n.Inode().Children()
|
||||
s := make([]fuse.DirEntry, 0, len(ch))
|
||||
for name, child := range ch {
|
||||
if child.mountPoint != nil {
|
||||
continue
|
||||
}
|
||||
var a fuse.Attr
|
||||
code := child.Node().GetAttr(&a, nil, context)
|
||||
if code.Ok() {
|
||||
s = append(s, fuse.DirEntry{Name: name, Mode: a.Mode})
|
||||
}
|
||||
}
|
||||
return s, fuse.OK
|
||||
}
|
||||
|
||||
func (n *defaultNode) GetXAttr(attribute string, context *fuse.Context) (data []byte, code fuse.Status) {
|
||||
return nil, fuse.ENOATTR
|
||||
}
|
||||
|
||||
func (n *defaultNode) RemoveXAttr(attr string, context *fuse.Context) fuse.Status {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) SetXAttr(attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) ListXAttr(context *fuse.Context) (attrs []string, code fuse.Status) {
|
||||
return nil, fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) GetAttr(out *fuse.Attr, file File, context *fuse.Context) (code fuse.Status) {
|
||||
if file != nil {
|
||||
return file.GetAttr(out)
|
||||
}
|
||||
if n.Inode().IsDir() {
|
||||
out.Mode = fuse.S_IFDIR | 0755
|
||||
} else {
|
||||
out.Mode = fuse.S_IFREG | 0644
|
||||
}
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (n *defaultNode) Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Utimens(file File, atime *time.Time, mtime *time.Time, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Fallocate(file File, off uint64, size uint64, mode uint32, context *fuse.Context) (code fuse.Status) {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Read(file File, dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status) {
|
||||
if file != nil {
|
||||
return file.Read(dest, off)
|
||||
}
|
||||
return nil, fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (n *defaultNode) Write(file File, data []byte, off int64, context *fuse.Context) (written uint32, code fuse.Status) {
|
||||
if file != nil {
|
||||
return file.Write(data, off)
|
||||
}
|
||||
return 0, fuse.ENOSYS
|
||||
}
|
||||
118
vendor/github.com/hanwen/go-fuse/fuse/nodefs/dir.go
generated
vendored
Normal file
118
vendor/github.com/hanwen/go-fuse/fuse/nodefs/dir.go
generated
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
type connectorDir struct {
|
||||
node Node
|
||||
rawFS fuse.RawFileSystem
|
||||
|
||||
// Protect stream and lastOffset. These are written in case
|
||||
// there is a seek on the directory.
|
||||
mu sync.Mutex
|
||||
stream []fuse.DirEntry
|
||||
|
||||
// lastOffset stores the last offset for a readdir. This lets
|
||||
// readdir pick up changes to the directory made after opening
|
||||
// it.
|
||||
lastOffset uint64
|
||||
}
|
||||
|
||||
func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if d.stream == nil {
|
||||
return fuse.OK
|
||||
}
|
||||
// rewinddir() should be as if reopening directory.
|
||||
// TODO - test this.
|
||||
if d.lastOffset > 0 && input.Offset == 0 {
|
||||
d.stream, code = d.node.OpenDir((*fuse.Context)(&input.Context))
|
||||
if !code.Ok() {
|
||||
return code
|
||||
}
|
||||
}
|
||||
|
||||
if input.Offset > uint64(len(d.stream)) {
|
||||
// This shouldn't happen, but let's not crash.
|
||||
return fuse.EINVAL
|
||||
}
|
||||
|
||||
todo := d.stream[input.Offset:]
|
||||
for _, e := range todo {
|
||||
if e.Name == "" {
|
||||
log.Printf("got empty directory entry, mode %o.", e.Mode)
|
||||
continue
|
||||
}
|
||||
ok, off := out.AddDirEntry(e)
|
||||
d.lastOffset = off
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if d.stream == nil {
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
// rewinddir() should be as if reopening directory.
|
||||
if d.lastOffset > 0 && input.Offset == 0 {
|
||||
d.stream, code = d.node.OpenDir((*fuse.Context)(&input.Context))
|
||||
if !code.Ok() {
|
||||
return code
|
||||
}
|
||||
}
|
||||
|
||||
if input.Offset > uint64(len(d.stream)) {
|
||||
// This shouldn't happen, but let's not crash.
|
||||
return fuse.EINVAL
|
||||
}
|
||||
todo := d.stream[input.Offset:]
|
||||
for _, e := range todo {
|
||||
if e.Name == "" {
|
||||
log.Printf("got empty directory entry, mode %o.", e.Mode)
|
||||
continue
|
||||
}
|
||||
|
||||
// we have to be sure entry will fit if we try to add
|
||||
// it, or we'll mess up the lookup counts.
|
||||
entryDest, off := out.AddDirLookupEntry(e)
|
||||
if entryDest == nil {
|
||||
break
|
||||
}
|
||||
entryDest.Ino = uint64(fuse.FUSE_UNKNOWN_INO)
|
||||
|
||||
// No need to fill attributes for . and ..
|
||||
if e.Name == "." || e.Name == ".." {
|
||||
continue
|
||||
}
|
||||
|
||||
// Clear entryDest before use it, some fields can be corrupted if does not set all fields in rawFS.Lookup
|
||||
*entryDest = fuse.EntryOut{}
|
||||
|
||||
d.rawFS.Lookup(&input.InHeader, e.Name, entryDest)
|
||||
d.lastOffset = off
|
||||
}
|
||||
return fuse.OK
|
||||
|
||||
}
|
||||
|
||||
type rawDir interface {
|
||||
ReadDir(out *fuse.DirEntryList, input *fuse.ReadIn, c *fuse.Context) fuse.Status
|
||||
ReadDirPlus(out *fuse.DirEntryList, input *fuse.ReadIn, c *fuse.Context) fuse.Status
|
||||
}
|
||||
261
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files.go
generated
vendored
Normal file
261
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files.go
generated
vendored
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
// DataFile is for implementing read-only filesystems. This
|
||||
// assumes we already have the data in memory.
|
||||
type dataFile struct {
|
||||
data []byte
|
||||
|
||||
File
|
||||
}
|
||||
|
||||
func (f *dataFile) String() string {
|
||||
l := len(f.data)
|
||||
if l > 10 {
|
||||
l = 10
|
||||
}
|
||||
|
||||
return fmt.Sprintf("dataFile(%x)", f.data[:l])
|
||||
}
|
||||
|
||||
func (f *dataFile) GetAttr(out *fuse.Attr) fuse.Status {
|
||||
out.Mode = fuse.S_IFREG | 0644
|
||||
out.Size = uint64(len(f.data))
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func NewDataFile(data []byte) File {
|
||||
f := new(dataFile)
|
||||
f.data = data
|
||||
f.File = NewDefaultFile()
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *dataFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) {
|
||||
end := int(off) + int(len(buf))
|
||||
if end > len(f.data) {
|
||||
end = len(f.data)
|
||||
}
|
||||
|
||||
return fuse.ReadResultData(f.data[off:end]), fuse.OK
|
||||
}
|
||||
|
||||
type devNullFile struct {
|
||||
File
|
||||
}
|
||||
|
||||
// NewDevNullFile returns a file that accepts any write, and always
|
||||
// returns EOF for reads.
|
||||
func NewDevNullFile() File {
|
||||
return &devNullFile{
|
||||
File: NewDefaultFile(),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *devNullFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) {
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (f *devNullFile) String() string {
|
||||
return "devNullFile"
|
||||
}
|
||||
|
||||
func (f *devNullFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
|
||||
return fuse.ReadResultData(nil), fuse.OK
|
||||
}
|
||||
|
||||
func (f *devNullFile) Write(content []byte, off int64) (uint32, fuse.Status) {
|
||||
return uint32(len(content)), fuse.OK
|
||||
}
|
||||
|
||||
func (f *devNullFile) Flush() fuse.Status {
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (f *devNullFile) Fsync(flags int) (code fuse.Status) {
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (f *devNullFile) Truncate(size uint64) (code fuse.Status) {
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
////////////////
|
||||
|
||||
// LoopbackFile delegates all operations back to an underlying os.File.
|
||||
func NewLoopbackFile(f *os.File) File {
|
||||
return &loopbackFile{File: f}
|
||||
}
|
||||
|
||||
type loopbackFile struct {
|
||||
File *os.File
|
||||
|
||||
// os.File is not threadsafe. Although fd themselves are
|
||||
// constant during the lifetime of an open file, the OS may
|
||||
// reuse the fd number after it is closed. When open races
|
||||
// with another close, they may lead to confusion as which
|
||||
// file gets written in the end.
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func (f *loopbackFile) InnerFile() File {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *loopbackFile) SetInode(n *Inode) {
|
||||
}
|
||||
|
||||
func (f *loopbackFile) String() string {
|
||||
return fmt.Sprintf("loopbackFile(%s)", f.File.Name())
|
||||
}
|
||||
|
||||
func (f *loopbackFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) {
|
||||
f.lock.Lock()
|
||||
// This is not racy by virtue of the kernel properly
|
||||
// synchronizing the open/write/close.
|
||||
r := fuse.ReadResultFd(f.File.Fd(), off, len(buf))
|
||||
f.lock.Unlock()
|
||||
return r, fuse.OK
|
||||
}
|
||||
|
||||
func (f *loopbackFile) Write(data []byte, off int64) (uint32, fuse.Status) {
|
||||
f.lock.Lock()
|
||||
n, err := f.File.WriteAt(data, off)
|
||||
f.lock.Unlock()
|
||||
return uint32(n), fuse.ToStatus(err)
|
||||
}
|
||||
|
||||
func (f *loopbackFile) Release() {
|
||||
f.lock.Lock()
|
||||
f.File.Close()
|
||||
f.lock.Unlock()
|
||||
}
|
||||
|
||||
func (f *loopbackFile) Flush() fuse.Status {
|
||||
f.lock.Lock()
|
||||
|
||||
// Since Flush() may be called for each dup'd fd, we don't
|
||||
// want to really close the file, we just want to flush. This
|
||||
// is achieved by closing a dup'd fd.
|
||||
newFd, err := syscall.Dup(int(f.File.Fd()))
|
||||
f.lock.Unlock()
|
||||
|
||||
if err != nil {
|
||||
return fuse.ToStatus(err)
|
||||
}
|
||||
err = syscall.Close(newFd)
|
||||
return fuse.ToStatus(err)
|
||||
}
|
||||
|
||||
func (f *loopbackFile) Fsync(flags int) (code fuse.Status) {
|
||||
f.lock.Lock()
|
||||
r := fuse.ToStatus(syscall.Fsync(int(f.File.Fd())))
|
||||
f.lock.Unlock()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (f *loopbackFile) Flock(flags int) fuse.Status {
|
||||
f.lock.Lock()
|
||||
r := fuse.ToStatus(syscall.Flock(int(f.File.Fd()), flags))
|
||||
f.lock.Unlock()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (f *loopbackFile) Truncate(size uint64) fuse.Status {
|
||||
f.lock.Lock()
|
||||
r := fuse.ToStatus(syscall.Ftruncate(int(f.File.Fd()), int64(size)))
|
||||
f.lock.Unlock()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (f *loopbackFile) Chmod(mode uint32) fuse.Status {
|
||||
f.lock.Lock()
|
||||
r := fuse.ToStatus(f.File.Chmod(os.FileMode(mode)))
|
||||
f.lock.Unlock()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (f *loopbackFile) Chown(uid uint32, gid uint32) fuse.Status {
|
||||
f.lock.Lock()
|
||||
r := fuse.ToStatus(f.File.Chown(int(uid), int(gid)))
|
||||
f.lock.Unlock()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (f *loopbackFile) GetAttr(a *fuse.Attr) fuse.Status {
|
||||
st := syscall.Stat_t{}
|
||||
f.lock.Lock()
|
||||
err := syscall.Fstat(int(f.File.Fd()), &st)
|
||||
f.lock.Unlock()
|
||||
if err != nil {
|
||||
return fuse.ToStatus(err)
|
||||
}
|
||||
a.FromStat(&st)
|
||||
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
// Utimens implemented in files_linux.go
|
||||
|
||||
// Allocate implemented in files_linux.go
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// NewReadOnlyFile wraps a File so all read/write operations are
|
||||
// denied.
|
||||
func NewReadOnlyFile(f File) File {
|
||||
return &readOnlyFile{File: f}
|
||||
}
|
||||
|
||||
type readOnlyFile struct {
|
||||
File
|
||||
}
|
||||
|
||||
func (f *readOnlyFile) InnerFile() File {
|
||||
return f.File
|
||||
}
|
||||
|
||||
func (f *readOnlyFile) String() string {
|
||||
return fmt.Sprintf("readOnlyFile(%s)", f.File.String())
|
||||
}
|
||||
|
||||
func (f *readOnlyFile) Write(data []byte, off int64) (uint32, fuse.Status) {
|
||||
return 0, fuse.EPERM
|
||||
}
|
||||
|
||||
func (f *readOnlyFile) Fsync(flag int) (code fuse.Status) {
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (f *readOnlyFile) Truncate(size uint64) fuse.Status {
|
||||
return fuse.EPERM
|
||||
}
|
||||
|
||||
func (f *readOnlyFile) Chmod(mode uint32) fuse.Status {
|
||||
return fuse.EPERM
|
||||
}
|
||||
|
||||
func (f *readOnlyFile) Chown(uid uint32, gid uint32) fuse.Status {
|
||||
return fuse.EPERM
|
||||
}
|
||||
|
||||
func (f *readOnlyFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
|
||||
return fuse.EPERM
|
||||
}
|
||||
102
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files_darwin.go
generated
vendored
Normal file
102
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files_darwin.go
generated
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
|
||||
// TODO: Handle `mode` parameter.
|
||||
|
||||
// From `man fcntl` on OSX:
|
||||
// The F_PREALLOCATE command operates on the following structure:
|
||||
//
|
||||
// typedef struct fstore {
|
||||
// u_int32_t fst_flags; /* IN: flags word */
|
||||
// int fst_posmode; /* IN: indicates offset field */
|
||||
// off_t fst_offset; /* IN: start of the region */
|
||||
// off_t fst_length; /* IN: size of the region */
|
||||
// off_t fst_bytesalloc; /* OUT: number of bytes allocated */
|
||||
// } fstore_t;
|
||||
//
|
||||
// The flags (fst_flags) for the F_PREALLOCATE command are as follows:
|
||||
//
|
||||
// F_ALLOCATECONTIG Allocate contiguous space.
|
||||
//
|
||||
// F_ALLOCATEALL Allocate all requested space or no space at all.
|
||||
//
|
||||
// The position modes (fst_posmode) for the F_PREALLOCATE command indicate how to use the offset field. The modes are as fol-
|
||||
// lows:
|
||||
//
|
||||
// F_PEOFPOSMODE Allocate from the physical end of file.
|
||||
//
|
||||
// F_VOLPOSMODE Allocate from the volume offset.
|
||||
|
||||
k := struct {
|
||||
Flags uint32 // u_int32_t
|
||||
Posmode int64 // int
|
||||
Offset int64 // off_t
|
||||
Length int64 // off_t
|
||||
Bytesalloc int64 // off_t
|
||||
}{
|
||||
0,
|
||||
0,
|
||||
int64(off),
|
||||
int64(sz),
|
||||
0,
|
||||
}
|
||||
|
||||
// Linux version for reference:
|
||||
// err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz))
|
||||
|
||||
f.lock.Lock()
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.File.Fd(), uintptr(syscall.F_PREALLOCATE), uintptr(unsafe.Pointer(&k)))
|
||||
f.lock.Unlock()
|
||||
if errno != 0 {
|
||||
return fuse.ToStatus(errno)
|
||||
}
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
const _UTIME_OMIT = ((1 << 30) - 2)
|
||||
|
||||
// timeToTimeval - Convert time.Time to syscall.Timeval
|
||||
//
|
||||
// Note: This does not use syscall.NsecToTimespec because
|
||||
// that does not work properly for times before 1970,
|
||||
// see https://github.com/golang/go/issues/12777
|
||||
func timeToTimeval(t *time.Time) syscall.Timeval {
|
||||
var tv syscall.Timeval
|
||||
tv.Usec = int32(t.Nanosecond() / 1000)
|
||||
tv.Sec = t.Unix()
|
||||
return tv
|
||||
}
|
||||
|
||||
// OSX does not have the utimensat syscall neded to implement this properly.
|
||||
// We do our best to emulate it using futimes.
|
||||
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status {
|
||||
tv := make([]syscall.Timeval, 2)
|
||||
if a == nil {
|
||||
tv[0].Usec = _UTIME_OMIT
|
||||
} else {
|
||||
tv[0] = timeToTimeval(a)
|
||||
}
|
||||
|
||||
if m == nil {
|
||||
tv[1].Usec = _UTIME_OMIT
|
||||
} else {
|
||||
tv[1] = timeToTimeval(m)
|
||||
}
|
||||
|
||||
f.lock.Lock()
|
||||
err := syscall.Futimes(int(f.File.Fd()), tv)
|
||||
f.lock.Unlock()
|
||||
return fuse.ToStatus(err)
|
||||
}
|
||||
33
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files_linux.go
generated
vendored
Normal file
33
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
|
||||
f.lock.Lock()
|
||||
err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz))
|
||||
f.lock.Unlock()
|
||||
if err != nil {
|
||||
return fuse.ToStatus(err)
|
||||
}
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
// Utimens - file handle based version of loopbackFileSystem.Utimens()
|
||||
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status {
|
||||
var ts [2]syscall.Timespec
|
||||
ts[0] = fuse.UtimeToTimespec(a)
|
||||
ts[1] = fuse.UtimeToTimespec(m)
|
||||
f.lock.Lock()
|
||||
err := futimens(int(f.File.Fd()), &ts)
|
||||
f.lock.Unlock()
|
||||
return fuse.ToStatus(err)
|
||||
}
|
||||
424
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsconnector.go
generated
vendored
Normal file
424
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsconnector.go
generated
vendored
Normal file
|
|
@ -0,0 +1,424 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
// This file contains the internal logic of the
|
||||
// FileSystemConnector. The functions for satisfying the raw interface
|
||||
// are in fsops.go
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
// Tests should set to true.
|
||||
var paranoia = false
|
||||
|
||||
// FilesystemConnector translates the raw FUSE protocol (serialized
|
||||
// structs of uint32/uint64) to operations on Go objects representing
|
||||
// files and directories.
|
||||
type FileSystemConnector struct {
|
||||
debug bool
|
||||
|
||||
// Callbacks for talking back to the kernel.
|
||||
server *fuse.Server
|
||||
|
||||
// Translate between uint64 handles and *Inode.
|
||||
inodeMap handleMap
|
||||
|
||||
// The root of the FUSE file system.
|
||||
rootNode *Inode
|
||||
}
|
||||
|
||||
// NewOptions generates FUSE options that correspond to libfuse's
|
||||
// defaults.
|
||||
func NewOptions() *Options {
|
||||
return &Options{
|
||||
NegativeTimeout: 0,
|
||||
AttrTimeout: time.Second,
|
||||
EntryTimeout: time.Second,
|
||||
Owner: fuse.CurrentOwner(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewFileSystemConnector creates a FileSystemConnector with the given
|
||||
// options.
|
||||
func NewFileSystemConnector(root Node, opts *Options) (c *FileSystemConnector) {
|
||||
c = new(FileSystemConnector)
|
||||
if opts == nil {
|
||||
opts = NewOptions()
|
||||
}
|
||||
c.inodeMap = newPortableHandleMap()
|
||||
c.rootNode = newInode(true, root)
|
||||
|
||||
c.verify()
|
||||
c.mountRoot(opts)
|
||||
|
||||
// FUSE does not issue a LOOKUP for 1 (obviously), but it does
|
||||
// issue a forget. This lookupUpdate is to make the counts match.
|
||||
c.lookupUpdate(c.rootNode)
|
||||
c.debug = opts.Debug
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Server returns the fuse.Server that talking to the kernel.
|
||||
func (c *FileSystemConnector) Server() *fuse.Server {
|
||||
return c.server
|
||||
}
|
||||
|
||||
// SetDebug toggles printing of debug information. This function is
|
||||
// deprecated. Set the Debug option in the Options struct instead.
|
||||
func (c *FileSystemConnector) SetDebug(debug bool) {
|
||||
c.debug = debug
|
||||
}
|
||||
|
||||
// This verifies invariants of the data structure. This routine
|
||||
// acquires tree locks as it walks the inode tree.
|
||||
func (c *FileSystemConnector) verify() {
|
||||
if !paranoia {
|
||||
return
|
||||
}
|
||||
root := c.rootNode
|
||||
root.verify(c.rootNode.mountPoint)
|
||||
}
|
||||
|
||||
// childLookup fills entry information for a newly created child inode
|
||||
func (c *rawBridge) childLookup(out *fuse.EntryOut, n *Inode, context *fuse.Context) {
|
||||
n.Node().GetAttr((*fuse.Attr)(&out.Attr), nil, context)
|
||||
n.mount.fillEntry(out)
|
||||
out.NodeId, out.Generation = c.fsConn().lookupUpdate(n)
|
||||
if out.Ino == 0 {
|
||||
out.Ino = out.NodeId
|
||||
}
|
||||
if out.Nlink == 0 {
|
||||
// With Nlink == 0, newer kernels will refuse link
|
||||
// operations.
|
||||
out.Nlink = 1
|
||||
}
|
||||
}
|
||||
|
||||
func (c *rawBridge) toInode(nodeid uint64) *Inode {
|
||||
if nodeid == fuse.FUSE_ROOT_ID {
|
||||
return c.rootNode
|
||||
}
|
||||
i := (*Inode)(unsafe.Pointer(c.inodeMap.Decode(nodeid)))
|
||||
return i
|
||||
}
|
||||
|
||||
// Must run outside treeLock. Returns the nodeId and generation.
|
||||
func (c *FileSystemConnector) lookupUpdate(node *Inode) (id, generation uint64) {
|
||||
id, generation = c.inodeMap.Register(&node.handled)
|
||||
c.verify()
|
||||
return
|
||||
}
|
||||
|
||||
// forgetUpdate decrements the reference counter for "nodeID" by "forgetCount".
|
||||
// Must run outside treeLock.
|
||||
func (c *FileSystemConnector) forgetUpdate(nodeID uint64, forgetCount int) {
|
||||
if nodeID == fuse.FUSE_ROOT_ID {
|
||||
c.rootNode.Node().OnUnmount()
|
||||
|
||||
// We never got a lookup for root, so don't try to
|
||||
// forget root.
|
||||
return
|
||||
}
|
||||
|
||||
// Prevent concurrent modification of the tree while we are processing
|
||||
// the FORGET
|
||||
node := (*Inode)(unsafe.Pointer(c.inodeMap.Decode(nodeID)))
|
||||
node.mount.treeLock.Lock()
|
||||
defer node.mount.treeLock.Unlock()
|
||||
|
||||
if forgotten, _ := c.inodeMap.Forget(nodeID, forgetCount); forgotten {
|
||||
if len(node.children) > 0 || !node.Node().Deletable() ||
|
||||
node == c.rootNode || node.mountPoint != nil {
|
||||
// We cannot forget a directory that still has children as these
|
||||
// would become unreachable.
|
||||
return
|
||||
}
|
||||
// We have to remove ourself from all parents.
|
||||
// Create a copy of node.parents so we can safely iterate over it
|
||||
// while modifying the original.
|
||||
parents := make(map[parentData]struct{}, len(node.parents))
|
||||
for k, v := range node.parents {
|
||||
parents[k] = v
|
||||
}
|
||||
|
||||
for p := range parents {
|
||||
// This also modifies node.parents
|
||||
p.parent.rmChild(p.name)
|
||||
}
|
||||
|
||||
node.fsInode.OnForget()
|
||||
}
|
||||
// TODO - try to drop children even forget was not successful.
|
||||
c.verify()
|
||||
}
|
||||
|
||||
// InodeCount returns the number of inodes registered with the kernel.
|
||||
func (c *FileSystemConnector) InodeHandleCount() int {
|
||||
return c.inodeMap.Count()
|
||||
}
|
||||
|
||||
// Finds a node within the currently known inodes, returns the last
|
||||
// known node and the remaining unknown path components. If parent is
|
||||
// nil, start from FUSE mountpoint.
|
||||
func (c *FileSystemConnector) Node(parent *Inode, fullPath string) (*Inode, []string) {
|
||||
if parent == nil {
|
||||
parent = c.rootNode
|
||||
}
|
||||
if fullPath == "" {
|
||||
return parent, nil
|
||||
}
|
||||
|
||||
sep := string(filepath.Separator)
|
||||
fullPath = strings.TrimLeft(filepath.Clean(fullPath), sep)
|
||||
comps := strings.Split(fullPath, sep)
|
||||
|
||||
node := parent
|
||||
if node.mountPoint == nil {
|
||||
node.mount.treeLock.RLock()
|
||||
defer node.mount.treeLock.RUnlock()
|
||||
}
|
||||
|
||||
for i, component := range comps {
|
||||
if len(component) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if node.mountPoint != nil {
|
||||
node.mount.treeLock.RLock()
|
||||
defer node.mount.treeLock.RUnlock()
|
||||
}
|
||||
|
||||
next := node.children[component]
|
||||
if next == nil {
|
||||
return node, comps[i:]
|
||||
}
|
||||
node = next
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// Follows the path from the given parent, doing lookups as
|
||||
// necessary. The path should be '/' separated without leading slash.
|
||||
func (c *FileSystemConnector) LookupNode(parent *Inode, path string) *Inode {
|
||||
if path == "" {
|
||||
return parent
|
||||
}
|
||||
|
||||
components := strings.Split(path, "/")
|
||||
for _, r := range components {
|
||||
var a fuse.Attr
|
||||
// This will not affect inode ID lookup counts, which
|
||||
// are only update in response to kernel requests.
|
||||
var dummy fuse.InHeader
|
||||
child, _ := c.internalLookup(&a, parent, r, &dummy)
|
||||
if child == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
parent = child
|
||||
}
|
||||
|
||||
return parent
|
||||
}
|
||||
|
||||
func (c *FileSystemConnector) mountRoot(opts *Options) {
|
||||
c.rootNode.mountFs(opts)
|
||||
c.rootNode.mount.connector = c
|
||||
c.verify()
|
||||
}
|
||||
|
||||
// Mount() generates a synthetic directory node, and mounts the file
|
||||
// system there. If opts is nil, the mount options of the root file
|
||||
// system are inherited. The encompassing filesystem should pretend
|
||||
// the mount point does not exist.
|
||||
//
|
||||
// It returns ENOENT if the directory containing the mount point does
|
||||
// not exist, and EBUSY if the intended mount point already exists.
|
||||
func (c *FileSystemConnector) Mount(parent *Inode, name string, root Node, opts *Options) fuse.Status {
|
||||
node, code := c.lockMount(parent, name, root, opts)
|
||||
if !code.Ok() {
|
||||
return code
|
||||
}
|
||||
|
||||
node.Node().OnMount(c)
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *FileSystemConnector) lockMount(parent *Inode, name string, root Node, opts *Options) (*Inode, fuse.Status) {
|
||||
defer c.verify()
|
||||
parent.mount.treeLock.Lock()
|
||||
defer parent.mount.treeLock.Unlock()
|
||||
node := parent.children[name]
|
||||
if node != nil {
|
||||
return nil, fuse.EBUSY
|
||||
}
|
||||
|
||||
node = newInode(true, root)
|
||||
if opts == nil {
|
||||
opts = c.rootNode.mountPoint.options
|
||||
}
|
||||
|
||||
node.mountFs(opts)
|
||||
node.mount.connector = c
|
||||
parent.addChild(name, node)
|
||||
|
||||
node.mountPoint.parentInode = parent
|
||||
if c.debug {
|
||||
log.Printf("Mount %T on subdir %s, parent %d", node,
|
||||
name, c.inodeMap.Handle(&parent.handled))
|
||||
}
|
||||
return node, fuse.OK
|
||||
}
|
||||
|
||||
// Unmount() tries to unmount the given inode. It returns EINVAL if the
|
||||
// path does not exist, or is not a mount point, and EBUSY if there
|
||||
// are open files or submounts below this node.
|
||||
func (c *FileSystemConnector) Unmount(node *Inode) fuse.Status {
|
||||
// TODO - racy.
|
||||
if node.mountPoint == nil {
|
||||
log.Println("not a mountpoint:", c.inodeMap.Handle(&node.handled))
|
||||
return fuse.EINVAL
|
||||
}
|
||||
|
||||
nodeID := c.inodeMap.Handle(&node.handled)
|
||||
|
||||
// Must lock parent to update tree structure.
|
||||
parentNode := node.mountPoint.parentInode
|
||||
parentNode.mount.treeLock.Lock()
|
||||
defer parentNode.mount.treeLock.Unlock()
|
||||
|
||||
mount := node.mountPoint
|
||||
name := node.mountPoint.mountName()
|
||||
if mount.openFiles.Count() > 0 {
|
||||
return fuse.EBUSY
|
||||
}
|
||||
|
||||
node.mount.treeLock.Lock()
|
||||
defer node.mount.treeLock.Unlock()
|
||||
|
||||
if mount.mountInode != node {
|
||||
log.Panicf("got two different mount inodes %v vs %v",
|
||||
c.inodeMap.Handle(&mount.mountInode.handled),
|
||||
c.inodeMap.Handle(&node.handled))
|
||||
}
|
||||
|
||||
if !node.canUnmount() {
|
||||
return fuse.EBUSY
|
||||
}
|
||||
|
||||
delete(parentNode.children, name)
|
||||
node.Node().OnUnmount()
|
||||
|
||||
parentId := c.inodeMap.Handle(&parentNode.handled)
|
||||
if parentNode == c.rootNode {
|
||||
// TODO - test coverage. Currently covered by zipfs/multizip_test.go
|
||||
parentId = fuse.FUSE_ROOT_ID
|
||||
}
|
||||
|
||||
// We have to wait until the kernel has forgotten the
|
||||
// mountpoint, so the write to node.mountPoint is no longer
|
||||
// racy.
|
||||
mount.treeLock.Unlock()
|
||||
parentNode.mount.treeLock.Unlock()
|
||||
code := c.server.DeleteNotify(parentId, nodeID, name)
|
||||
|
||||
if code.Ok() {
|
||||
delay := 100 * time.Microsecond
|
||||
|
||||
for {
|
||||
// This operation is rare, so we kludge it to avoid
|
||||
// contention.
|
||||
time.Sleep(delay)
|
||||
delay = delay * 2
|
||||
if !c.inodeMap.Has(nodeID) {
|
||||
break
|
||||
}
|
||||
|
||||
if delay >= time.Second {
|
||||
// We limit the wait at one second. If
|
||||
// it takes longer, something else is
|
||||
// amiss, and we would be waiting forever.
|
||||
log.Println("kernel did not issue FORGET for node on Unmount.")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
parentNode.mount.treeLock.Lock()
|
||||
mount.treeLock.Lock()
|
||||
mount.mountInode = nil
|
||||
node.mountPoint = nil
|
||||
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
// FileNotify notifies the kernel that data and metadata of this inode
|
||||
// has changed. After this call completes, the kernel will issue a
|
||||
// new GetAttr requests for metadata and new Read calls for content.
|
||||
// Use negative offset for metadata-only invalidation, and zero-length
|
||||
// for invalidating all content.
|
||||
func (c *FileSystemConnector) FileNotify(node *Inode, off int64, length int64) fuse.Status {
|
||||
var nId uint64
|
||||
if node == c.rootNode {
|
||||
nId = fuse.FUSE_ROOT_ID
|
||||
} else {
|
||||
nId = c.inodeMap.Handle(&node.handled)
|
||||
}
|
||||
|
||||
if nId == 0 {
|
||||
return fuse.OK
|
||||
}
|
||||
return c.server.InodeNotify(nId, off, length)
|
||||
}
|
||||
|
||||
// EntryNotify makes the kernel forget the entry data from the given
|
||||
// name from a directory. After this call, the kernel will issue a
|
||||
// new lookup request for the given name when necessary. No filesystem
|
||||
// related locks should be held when calling this.
|
||||
func (c *FileSystemConnector) EntryNotify(node *Inode, name string) fuse.Status {
|
||||
var nId uint64
|
||||
if node == c.rootNode {
|
||||
nId = fuse.FUSE_ROOT_ID
|
||||
} else {
|
||||
nId = c.inodeMap.Handle(&node.handled)
|
||||
}
|
||||
|
||||
if nId == 0 {
|
||||
return fuse.OK
|
||||
}
|
||||
return c.server.EntryNotify(nId, name)
|
||||
}
|
||||
|
||||
// DeleteNotify signals to the kernel that the named entry in dir for
|
||||
// the child disappeared. No filesystem related locks should be held
|
||||
// when calling this.
|
||||
func (c *FileSystemConnector) DeleteNotify(dir *Inode, child *Inode, name string) fuse.Status {
|
||||
var nId uint64
|
||||
|
||||
if dir == c.rootNode {
|
||||
nId = fuse.FUSE_ROOT_ID
|
||||
} else {
|
||||
nId = c.inodeMap.Handle(&dir.handled)
|
||||
}
|
||||
|
||||
if nId == 0 {
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
chId := c.inodeMap.Handle(&child.handled)
|
||||
|
||||
return c.server.DeleteNotify(nId, chId, name)
|
||||
}
|
||||
158
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsmount.go
generated
vendored
Normal file
158
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsmount.go
generated
vendored
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
// openedFile stores either an open dir or an open file.
|
||||
type openedFile struct {
|
||||
handled
|
||||
|
||||
WithFlags
|
||||
|
||||
dir *connectorDir
|
||||
}
|
||||
|
||||
type fileSystemMount struct {
|
||||
// Node that we were mounted on.
|
||||
mountInode *Inode
|
||||
|
||||
// Parent to the mountInode.
|
||||
parentInode *Inode
|
||||
|
||||
// Options for the mount.
|
||||
options *Options
|
||||
|
||||
// Protects the "children" and "parents" hashmaps of the inodes
|
||||
// within the mount.
|
||||
// treeLock should be acquired before openFilesLock.
|
||||
//
|
||||
// If multiple treeLocks must be acquired, the treeLocks
|
||||
// closer to the root must be acquired first.
|
||||
treeLock sync.RWMutex
|
||||
|
||||
// Manage filehandles of open files.
|
||||
openFiles handleMap
|
||||
|
||||
Debug bool
|
||||
|
||||
connector *FileSystemConnector
|
||||
}
|
||||
|
||||
// Must called with lock for parent held.
|
||||
func (m *fileSystemMount) mountName() string {
|
||||
for k, v := range m.parentInode.children {
|
||||
if m.mountInode == v {
|
||||
return k
|
||||
}
|
||||
}
|
||||
panic("not found")
|
||||
}
|
||||
|
||||
func (m *fileSystemMount) setOwner(attr *fuse.Attr) {
|
||||
if m.options.Owner != nil {
|
||||
attr.Owner = *(*fuse.Owner)(m.options.Owner)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *fileSystemMount) fillEntry(out *fuse.EntryOut) {
|
||||
splitDuration(m.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
|
||||
splitDuration(m.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
|
||||
m.setOwner(&out.Attr)
|
||||
if out.Mode&fuse.S_IFDIR == 0 && out.Nlink == 0 {
|
||||
out.Nlink = 1
|
||||
}
|
||||
}
|
||||
|
||||
func (m *fileSystemMount) fillAttr(out *fuse.AttrOut, nodeId uint64) {
|
||||
splitDuration(m.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
|
||||
m.setOwner(&out.Attr)
|
||||
if out.Ino == 0 {
|
||||
out.Ino = nodeId
|
||||
}
|
||||
}
|
||||
|
||||
func (m *fileSystemMount) getOpenedFile(h uint64) *openedFile {
|
||||
var b *openedFile
|
||||
if h != 0 {
|
||||
b = (*openedFile)(unsafe.Pointer(m.openFiles.Decode(h)))
|
||||
}
|
||||
|
||||
if b != nil && m.connector.debug && b.WithFlags.Description != "" {
|
||||
log.Printf("File %d = %q", h, b.WithFlags.Description)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (m *fileSystemMount) unregisterFileHandle(handle uint64, node *Inode) *openedFile {
|
||||
_, obj := m.openFiles.Forget(handle, 1)
|
||||
opened := (*openedFile)(unsafe.Pointer(obj))
|
||||
node.openFilesMutex.Lock()
|
||||
idx := -1
|
||||
for i, v := range node.openFiles {
|
||||
if v == opened {
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
l := len(node.openFiles)
|
||||
if idx == l-1 {
|
||||
node.openFiles[idx] = nil
|
||||
} else {
|
||||
node.openFiles[idx] = node.openFiles[l-1]
|
||||
}
|
||||
node.openFiles = node.openFiles[:l-1]
|
||||
node.openFilesMutex.Unlock()
|
||||
|
||||
return opened
|
||||
}
|
||||
|
||||
func (m *fileSystemMount) registerFileHandle(node *Inode, dir *connectorDir, f File, flags uint32) (uint64, *openedFile) {
|
||||
node.openFilesMutex.Lock()
|
||||
b := &openedFile{
|
||||
dir: dir,
|
||||
WithFlags: WithFlags{
|
||||
File: f,
|
||||
OpenFlags: flags,
|
||||
},
|
||||
}
|
||||
|
||||
for {
|
||||
withFlags, ok := f.(*WithFlags)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
b.WithFlags.File = withFlags.File
|
||||
b.WithFlags.FuseFlags |= withFlags.FuseFlags
|
||||
b.WithFlags.Description += withFlags.Description
|
||||
f = withFlags.File
|
||||
}
|
||||
|
||||
if b.WithFlags.File != nil {
|
||||
b.WithFlags.File.SetInode(node)
|
||||
}
|
||||
node.openFiles = append(node.openFiles, b)
|
||||
handle, _ := m.openFiles.Register(&b.handled)
|
||||
node.openFilesMutex.Unlock()
|
||||
return handle, b
|
||||
}
|
||||
|
||||
// Creates a return entry for a non-existent path.
|
||||
func (m *fileSystemMount) negativeEntry(out *fuse.EntryOut) bool {
|
||||
if m.options.NegativeTimeout > 0.0 {
|
||||
out.NodeId = 0
|
||||
splitDuration(m.options.NegativeTimeout, &out.EntryValid, &out.EntryValidNsec)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
487
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsops.go
generated
vendored
Normal file
487
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsops.go
generated
vendored
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
// This file contains FileSystemConnector's implementation of
|
||||
// RawFileSystem
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
// Returns the RawFileSystem so it can be mounted.
|
||||
func (c *FileSystemConnector) RawFS() fuse.RawFileSystem {
|
||||
return (*rawBridge)(c)
|
||||
}
|
||||
|
||||
type rawBridge FileSystemConnector
|
||||
|
||||
func (c *rawBridge) Fsync(input *fuse.FsyncIn) fuse.Status {
|
||||
node := c.toInode(input.NodeId)
|
||||
opened := node.mount.getOpenedFile(input.Fh)
|
||||
|
||||
if opened != nil {
|
||||
return opened.WithFlags.File.Fsync(int(input.FsyncFlags))
|
||||
}
|
||||
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (c *rawBridge) SetDebug(debug bool) {
|
||||
c.fsConn().SetDebug(debug)
|
||||
}
|
||||
|
||||
func (c *rawBridge) FsyncDir(input *fuse.FsyncIn) fuse.Status {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
|
||||
func (c *rawBridge) fsConn() *FileSystemConnector {
|
||||
return (*FileSystemConnector)(c)
|
||||
}
|
||||
|
||||
func (c *rawBridge) String() string {
|
||||
if c.rootNode == nil || c.rootNode.mount == nil {
|
||||
return "go-fuse:unmounted"
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%T", c.rootNode.Node())
|
||||
name = strings.TrimLeft(name, "*")
|
||||
return name
|
||||
}
|
||||
|
||||
func (c *rawBridge) Init(s *fuse.Server) {
|
||||
c.server = s
|
||||
c.rootNode.Node().OnMount((*FileSystemConnector)(c))
|
||||
}
|
||||
|
||||
func (c *FileSystemConnector) lookupMountUpdate(out *fuse.Attr, mount *fileSystemMount) (node *Inode, code fuse.Status) {
|
||||
code = mount.mountInode.Node().GetAttr(out, nil, nil)
|
||||
if !code.Ok() {
|
||||
log.Println("Root getattr should not return error", code)
|
||||
out.Mode = fuse.S_IFDIR | 0755
|
||||
return mount.mountInode, fuse.OK
|
||||
}
|
||||
|
||||
return mount.mountInode, fuse.OK
|
||||
}
|
||||
|
||||
// internalLookup executes a lookup without affecting NodeId reference counts.
|
||||
func (c *FileSystemConnector) internalLookup(out *fuse.Attr, parent *Inode, name string, header *fuse.InHeader) (node *Inode, code fuse.Status) {
|
||||
|
||||
// We may already know the child because it was created using Create or Mkdir,
|
||||
// from an earlier lookup, or because the nodes were created in advance
|
||||
// (in-memory filesystems).
|
||||
child := parent.GetChild(name)
|
||||
|
||||
if child != nil && child.mountPoint != nil {
|
||||
return c.lookupMountUpdate(out, child.mountPoint)
|
||||
}
|
||||
|
||||
if child != nil {
|
||||
parent = nil
|
||||
}
|
||||
if child != nil {
|
||||
code = child.fsInode.GetAttr(out, nil, &header.Context)
|
||||
} else {
|
||||
child, code = parent.fsInode.Lookup(out, name, &header.Context)
|
||||
}
|
||||
|
||||
return child, code
|
||||
}
|
||||
|
||||
func (c *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOut) (code fuse.Status) {
|
||||
parent := c.toInode(header.NodeId)
|
||||
if !parent.IsDir() {
|
||||
log.Printf("Lookup %q called on non-Directory node %d", name, header.NodeId)
|
||||
return fuse.ENOTDIR
|
||||
}
|
||||
outAttr := (*fuse.Attr)(&out.Attr)
|
||||
child, code := c.fsConn().internalLookup(outAttr, parent, name, header)
|
||||
if code == fuse.ENOENT && parent.mount.negativeEntry(out) {
|
||||
return fuse.OK
|
||||
}
|
||||
if !code.Ok() {
|
||||
return code
|
||||
}
|
||||
if child == nil {
|
||||
log.Println("Lookup returned fuse.OK with nil child", name)
|
||||
}
|
||||
|
||||
child.mount.fillEntry(out)
|
||||
out.NodeId, out.Generation = c.fsConn().lookupUpdate(child)
|
||||
if out.Ino == 0 {
|
||||
out.Ino = out.NodeId
|
||||
}
|
||||
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (c *rawBridge) Forget(nodeID, nlookup uint64) {
|
||||
c.fsConn().forgetUpdate(nodeID, int(nlookup))
|
||||
}
|
||||
|
||||
func (c *rawBridge) GetAttr(input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
|
||||
node := c.toInode(input.NodeId)
|
||||
|
||||
var f File
|
||||
if input.Flags()&fuse.FUSE_GETATTR_FH != 0 {
|
||||
if opened := node.mount.getOpenedFile(input.Fh()); opened != nil {
|
||||
f = opened.WithFlags.File
|
||||
}
|
||||
}
|
||||
|
||||
dest := (*fuse.Attr)(&out.Attr)
|
||||
code = node.fsInode.GetAttr(dest, f, &input.Context)
|
||||
if !code.Ok() {
|
||||
return code
|
||||
}
|
||||
|
||||
if out.Nlink == 0 {
|
||||
// With Nlink == 0, newer kernels will refuse link
|
||||
// operations.
|
||||
out.Nlink = 1
|
||||
}
|
||||
|
||||
node.mount.fillAttr(out, input.NodeId)
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (c *rawBridge) OpenDir(input *fuse.OpenIn, out *fuse.OpenOut) (code fuse.Status) {
|
||||
node := c.toInode(input.NodeId)
|
||||
stream, err := node.fsInode.OpenDir(&input.Context)
|
||||
if err != fuse.OK {
|
||||
return err
|
||||
}
|
||||
stream = append(stream, node.getMountDirEntries()...)
|
||||
de := &connectorDir{
|
||||
node: node.Node(),
|
||||
stream: append(stream,
|
||||
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."},
|
||||
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."}),
|
||||
rawFS: c,
|
||||
}
|
||||
h, opened := node.mount.registerFileHandle(node, de, nil, input.Flags)
|
||||
out.OpenFlags = opened.FuseFlags
|
||||
out.Fh = h
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (c *rawBridge) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status {
|
||||
node := c.toInode(input.NodeId)
|
||||
opened := node.mount.getOpenedFile(input.Fh)
|
||||
return opened.dir.ReadDir(input, out)
|
||||
}
|
||||
|
||||
func (c *rawBridge) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status {
|
||||
node := c.toInode(input.NodeId)
|
||||
opened := node.mount.getOpenedFile(input.Fh)
|
||||
return opened.dir.ReadDirPlus(input, out)
|
||||
}
|
||||
|
||||
func (c *rawBridge) Open(input *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) {
|
||||
node := c.toInode(input.NodeId)
|
||||
f, code := node.fsInode.Open(input.Flags, &input.Context)
|
||||
if !code.Ok() || f == nil {
|
||||
return code
|
||||
}
|
||||
h, opened := node.mount.registerFileHandle(node, nil, f, input.Flags)
|
||||
out.OpenFlags = opened.FuseFlags
|
||||
out.Fh = h
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (c *rawBridge) SetAttr(input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
|
||||
node := c.toInode(input.NodeId)
|
||||
|
||||
var f File
|
||||
if input.Valid&fuse.FATTR_FH != 0 {
|
||||
opened := node.mount.getOpenedFile(input.Fh)
|
||||
f = opened.WithFlags.File
|
||||
}
|
||||
|
||||
if code.Ok() && input.Valid&fuse.FATTR_MODE != 0 {
|
||||
permissions := uint32(07777) & input.Mode
|
||||
code = node.fsInode.Chmod(f, permissions, &input.Context)
|
||||
}
|
||||
if code.Ok() && (input.Valid&(fuse.FATTR_UID|fuse.FATTR_GID) != 0) {
|
||||
var uid uint32 = ^uint32(0) // means "do not change" in chown(2)
|
||||
var gid uint32 = ^uint32(0)
|
||||
if input.Valid&fuse.FATTR_UID != 0 {
|
||||
uid = input.Uid
|
||||
}
|
||||
if input.Valid&fuse.FATTR_GID != 0 {
|
||||
gid = input.Gid
|
||||
}
|
||||
code = node.fsInode.Chown(f, uid, gid, &input.Context)
|
||||
}
|
||||
if code.Ok() && input.Valid&fuse.FATTR_SIZE != 0 {
|
||||
code = node.fsInode.Truncate(f, input.Size, &input.Context)
|
||||
}
|
||||
if code.Ok() && (input.Valid&(fuse.FATTR_ATIME|fuse.FATTR_MTIME|fuse.FATTR_ATIME_NOW|fuse.FATTR_MTIME_NOW) != 0) {
|
||||
now := time.Now()
|
||||
var atime *time.Time
|
||||
var mtime *time.Time
|
||||
|
||||
if input.Valid&fuse.FATTR_ATIME != 0 {
|
||||
if input.Valid&fuse.FATTR_ATIME_NOW != 0 {
|
||||
atime = &now
|
||||
} else {
|
||||
t := time.Unix(int64(input.Atime), int64(input.Atimensec))
|
||||
atime = &t
|
||||
}
|
||||
}
|
||||
|
||||
if input.Valid&fuse.FATTR_MTIME != 0 {
|
||||
if input.Valid&fuse.FATTR_MTIME_NOW != 0 {
|
||||
mtime = &now
|
||||
} else {
|
||||
t := time.Unix(int64(input.Mtime), int64(input.Mtimensec))
|
||||
mtime = &t
|
||||
}
|
||||
}
|
||||
|
||||
code = node.fsInode.Utimens(f, atime, mtime, &input.Context)
|
||||
}
|
||||
|
||||
if !code.Ok() {
|
||||
return code
|
||||
}
|
||||
|
||||
// Must call GetAttr(); the filesystem may override some of
|
||||
// the changes we effect here.
|
||||
attr := (*fuse.Attr)(&out.Attr)
|
||||
code = node.fsInode.GetAttr(attr, nil, &input.Context)
|
||||
if code.Ok() {
|
||||
node.mount.fillAttr(out, input.NodeId)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *rawBridge) Fallocate(input *fuse.FallocateIn) (code fuse.Status) {
|
||||
n := c.toInode(input.NodeId)
|
||||
opened := n.mount.getOpenedFile(input.Fh)
|
||||
|
||||
return n.fsInode.Fallocate(opened, input.Offset, input.Length, input.Mode, &input.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) Readlink(header *fuse.InHeader) (out []byte, code fuse.Status) {
|
||||
n := c.toInode(header.NodeId)
|
||||
return n.fsInode.Readlink(&header.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) Mknod(input *fuse.MknodIn, name string, out *fuse.EntryOut) (code fuse.Status) {
|
||||
parent := c.toInode(input.NodeId)
|
||||
|
||||
child, code := parent.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &input.Context)
|
||||
if code.Ok() {
|
||||
c.childLookup(out, child, &input.Context)
|
||||
code = child.fsInode.GetAttr((*fuse.Attr)(&out.Attr), nil, &input.Context)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *rawBridge) Mkdir(input *fuse.MkdirIn, name string, out *fuse.EntryOut) (code fuse.Status) {
|
||||
parent := c.toInode(input.NodeId)
|
||||
|
||||
child, code := parent.fsInode.Mkdir(name, input.Mode, &input.Context)
|
||||
if code.Ok() {
|
||||
c.childLookup(out, child, &input.Context)
|
||||
code = child.fsInode.GetAttr((*fuse.Attr)(&out.Attr), nil, &input.Context)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *rawBridge) Unlink(header *fuse.InHeader, name string) (code fuse.Status) {
|
||||
parent := c.toInode(header.NodeId)
|
||||
return parent.fsInode.Unlink(name, &header.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) Rmdir(header *fuse.InHeader, name string) (code fuse.Status) {
|
||||
parent := c.toInode(header.NodeId)
|
||||
return parent.fsInode.Rmdir(name, &header.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) Symlink(header *fuse.InHeader, pointedTo string, linkName string, out *fuse.EntryOut) (code fuse.Status) {
|
||||
parent := c.toInode(header.NodeId)
|
||||
|
||||
child, code := parent.fsInode.Symlink(linkName, pointedTo, &header.Context)
|
||||
if code.Ok() {
|
||||
c.childLookup(out, child, &header.Context)
|
||||
code = child.fsInode.GetAttr((*fuse.Attr)(&out.Attr), nil, &header.Context)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *rawBridge) Rename(input *fuse.RenameIn, oldName string, newName string) (code fuse.Status) {
|
||||
oldParent := c.toInode(input.NodeId)
|
||||
|
||||
child := oldParent.GetChild(oldName)
|
||||
if child == nil {
|
||||
return fuse.ENOENT
|
||||
}
|
||||
if child.mountPoint != nil {
|
||||
return fuse.EBUSY
|
||||
}
|
||||
|
||||
newParent := c.toInode(input.Newdir)
|
||||
if oldParent.mount != newParent.mount {
|
||||
return fuse.EXDEV
|
||||
}
|
||||
|
||||
return oldParent.fsInode.Rename(oldName, newParent.fsInode, newName, &input.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) Link(input *fuse.LinkIn, name string, out *fuse.EntryOut) (code fuse.Status) {
|
||||
existing := c.toInode(input.Oldnodeid)
|
||||
parent := c.toInode(input.NodeId)
|
||||
|
||||
if existing.mount != parent.mount {
|
||||
return fuse.EXDEV
|
||||
}
|
||||
|
||||
child, code := parent.fsInode.Link(name, existing.fsInode, &input.Context)
|
||||
if code.Ok() {
|
||||
c.childLookup(out, child, &input.Context)
|
||||
code = child.fsInode.GetAttr((*fuse.Attr)(&out.Attr), nil, &input.Context)
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *rawBridge) Access(input *fuse.AccessIn) (code fuse.Status) {
|
||||
n := c.toInode(input.NodeId)
|
||||
return n.fsInode.Access(input.Mask, &input.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) Create(input *fuse.CreateIn, name string, out *fuse.CreateOut) (code fuse.Status) {
|
||||
parent := c.toInode(input.NodeId)
|
||||
f, child, code := parent.fsInode.Create(name, uint32(input.Flags), input.Mode, &input.Context)
|
||||
if !code.Ok() {
|
||||
return code
|
||||
}
|
||||
|
||||
c.childLookup(&out.EntryOut, child, &input.Context)
|
||||
handle, opened := parent.mount.registerFileHandle(child, nil, f, input.Flags)
|
||||
|
||||
out.OpenOut.OpenFlags = opened.FuseFlags
|
||||
out.OpenOut.Fh = handle
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *rawBridge) Release(input *fuse.ReleaseIn) {
|
||||
if input.Fh != 0 {
|
||||
node := c.toInode(input.NodeId)
|
||||
opened := node.mount.unregisterFileHandle(input.Fh, node)
|
||||
opened.WithFlags.File.Release()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *rawBridge) ReleaseDir(input *fuse.ReleaseIn) {
|
||||
if input.Fh != 0 {
|
||||
node := c.toInode(input.NodeId)
|
||||
node.mount.unregisterFileHandle(input.Fh, node)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *rawBridge) GetXAttrSize(header *fuse.InHeader, attribute string) (sz int, code fuse.Status) {
|
||||
node := c.toInode(header.NodeId)
|
||||
data, errno := node.fsInode.GetXAttr(attribute, &header.Context)
|
||||
return len(data), errno
|
||||
}
|
||||
|
||||
func (c *rawBridge) GetXAttrData(header *fuse.InHeader, attribute string) (data []byte, code fuse.Status) {
|
||||
node := c.toInode(header.NodeId)
|
||||
return node.fsInode.GetXAttr(attribute, &header.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) RemoveXAttr(header *fuse.InHeader, attr string) fuse.Status {
|
||||
node := c.toInode(header.NodeId)
|
||||
return node.fsInode.RemoveXAttr(attr, &header.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) SetXAttr(input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
|
||||
node := c.toInode(input.NodeId)
|
||||
return node.fsInode.SetXAttr(attr, data, int(input.Flags), &input.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) ListXAttr(header *fuse.InHeader) (data []byte, code fuse.Status) {
|
||||
node := c.toInode(header.NodeId)
|
||||
attrs, code := node.fsInode.ListXAttr(&header.Context)
|
||||
if code != fuse.OK {
|
||||
return nil, code
|
||||
}
|
||||
|
||||
b := bytes.NewBuffer([]byte{})
|
||||
for _, v := range attrs {
|
||||
b.Write([]byte(v))
|
||||
b.WriteByte(0)
|
||||
}
|
||||
|
||||
return b.Bytes(), code
|
||||
}
|
||||
|
||||
////////////////
|
||||
// files.
|
||||
|
||||
func (c *rawBridge) Write(input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) {
|
||||
node := c.toInode(input.NodeId)
|
||||
opened := node.mount.getOpenedFile(input.Fh)
|
||||
|
||||
var f File
|
||||
if opened != nil {
|
||||
f = opened.WithFlags.File
|
||||
}
|
||||
|
||||
return node.Node().Write(f, data, int64(input.Offset), &input.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) Read(input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
|
||||
node := c.toInode(input.NodeId)
|
||||
opened := node.mount.getOpenedFile(input.Fh)
|
||||
|
||||
var f File
|
||||
if opened != nil {
|
||||
f = opened.WithFlags.File
|
||||
}
|
||||
|
||||
return node.Node().Read(f, buf, int64(input.Offset), &input.Context)
|
||||
}
|
||||
|
||||
func (c *rawBridge) Flock(input *fuse.FlockIn, flags int) fuse.Status {
|
||||
node := c.toInode(input.NodeId)
|
||||
opened := node.mount.getOpenedFile(input.Fh)
|
||||
|
||||
if opened != nil {
|
||||
return opened.WithFlags.File.Flock(flags)
|
||||
}
|
||||
|
||||
return fuse.EBADF
|
||||
}
|
||||
|
||||
func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status {
|
||||
node := c.toInode(header.NodeId)
|
||||
s := node.Node().StatFs()
|
||||
if s == nil {
|
||||
return fuse.ENOSYS
|
||||
}
|
||||
*out = *s
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (c *rawBridge) Flush(input *fuse.FlushIn) fuse.Status {
|
||||
node := c.toInode(input.NodeId)
|
||||
opened := node.mount.getOpenedFile(input.Fh)
|
||||
|
||||
if opened != nil {
|
||||
return opened.WithFlags.File.Flush()
|
||||
}
|
||||
return fuse.OK
|
||||
}
|
||||
24
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fuse.go
generated
vendored
Normal file
24
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fuse.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
// Mounts a filesystem with the given root node on the given directory
|
||||
func MountRoot(mountpoint string, root Node, opts *Options) (*fuse.Server, *FileSystemConnector, error) {
|
||||
conn := NewFileSystemConnector(root, opts)
|
||||
|
||||
mountOpts := fuse.MountOptions{}
|
||||
if opts != nil && opts.Debug {
|
||||
mountOpts.Debug = opts.Debug
|
||||
}
|
||||
s, err := fuse.NewServer(conn.RawFS(), mountpoint, &mountOpts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return s, conn, nil
|
||||
}
|
||||
151
vendor/github.com/hanwen/go-fuse/fuse/nodefs/handle.go
generated
vendored
Normal file
151
vendor/github.com/hanwen/go-fuse/fuse/nodefs/handle.go
generated
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// HandleMap translates objects in Go space to 64-bit handles that can
|
||||
// be given out to -say- the linux kernel as NodeIds.
|
||||
//
|
||||
// The 32 bits version of this is a threadsafe wrapper around a map.
|
||||
//
|
||||
// To use it, include "handled" as first member of the structure
|
||||
// you wish to export.
|
||||
//
|
||||
// This structure is thread-safe.
|
||||
type handleMap interface {
|
||||
// Register stores "obj" and returns a unique (NodeId, generation) tuple.
|
||||
Register(obj *handled) (handle, generation uint64)
|
||||
Count() int
|
||||
// Decode retrieves a stored object from its 64-bit handle.
|
||||
Decode(uint64) *handled
|
||||
// Forget decrements the reference counter for "handle" by "count" and drops
|
||||
// the object if the refcount reaches zero.
|
||||
// Returns a boolean whether the object was dropped and the object itself.
|
||||
Forget(handle uint64, count int) (bool, *handled)
|
||||
// Handle gets the object's NodeId.
|
||||
Handle(obj *handled) uint64
|
||||
// Has checks if NodeId is stored.
|
||||
Has(uint64) bool
|
||||
}
|
||||
|
||||
type handled struct {
|
||||
check uint32
|
||||
handle uint64
|
||||
count int
|
||||
}
|
||||
|
||||
func (h *handled) verify() {
|
||||
if h.count < 0 {
|
||||
log.Panicf("negative lookup count %d", h.count)
|
||||
}
|
||||
if (h.count == 0) != (h.handle == 0) {
|
||||
log.Panicf("registration mismatch: lookup %d id %d", h.count, h.handle)
|
||||
}
|
||||
}
|
||||
|
||||
const _ALREADY_MSG = "Object already has a handle"
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// portable version using 32 bit integers.
|
||||
|
||||
type portableHandleMap struct {
|
||||
sync.RWMutex
|
||||
// The generation counter is incremented each time a NodeId is reused,
|
||||
// hence the (NodeId, Generation) tuple is always unique.
|
||||
generation uint64
|
||||
// Number of currently used handles
|
||||
used int
|
||||
// Array of Go objects indexed by NodeId
|
||||
handles []*handled
|
||||
// Free slots in the "handles" array
|
||||
freeIds []uint64
|
||||
}
|
||||
|
||||
func newPortableHandleMap() *portableHandleMap {
|
||||
return &portableHandleMap{
|
||||
// Avoid handing out ID 0 and 1.
|
||||
handles: []*handled{nil, nil},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *portableHandleMap) Register(obj *handled) (handle, generation uint64) {
|
||||
m.Lock()
|
||||
if obj.count == 0 {
|
||||
if obj.check != 0 {
|
||||
panic(_ALREADY_MSG)
|
||||
}
|
||||
|
||||
if len(m.freeIds) == 0 {
|
||||
handle = uint64(len(m.handles))
|
||||
m.handles = append(m.handles, obj)
|
||||
} else {
|
||||
handle = m.freeIds[len(m.freeIds)-1]
|
||||
m.freeIds = m.freeIds[:len(m.freeIds)-1]
|
||||
m.generation++
|
||||
m.handles[handle] = obj
|
||||
}
|
||||
m.used++
|
||||
obj.handle = handle
|
||||
} else {
|
||||
handle = obj.handle
|
||||
}
|
||||
obj.count++
|
||||
generation = m.generation
|
||||
m.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (m *portableHandleMap) Handle(obj *handled) (h uint64) {
|
||||
m.RLock()
|
||||
if obj.count == 0 {
|
||||
h = 0
|
||||
} else {
|
||||
h = obj.handle
|
||||
}
|
||||
m.RUnlock()
|
||||
return h
|
||||
}
|
||||
|
||||
func (m *portableHandleMap) Count() int {
|
||||
m.RLock()
|
||||
c := m.used
|
||||
m.RUnlock()
|
||||
return c
|
||||
}
|
||||
|
||||
func (m *portableHandleMap) Decode(h uint64) *handled {
|
||||
m.RLock()
|
||||
v := m.handles[h]
|
||||
m.RUnlock()
|
||||
return v
|
||||
}
|
||||
|
||||
func (m *portableHandleMap) Forget(h uint64, count int) (forgotten bool, obj *handled) {
|
||||
m.Lock()
|
||||
obj = m.handles[h]
|
||||
obj.count -= count
|
||||
if obj.count < 0 {
|
||||
log.Panicf("underflow: handle %d, count %d, object %d", h, count, obj.count)
|
||||
} else if obj.count == 0 {
|
||||
m.handles[h] = nil
|
||||
m.freeIds = append(m.freeIds, h)
|
||||
m.used--
|
||||
forgotten = true
|
||||
obj.handle = 0
|
||||
}
|
||||
m.Unlock()
|
||||
return forgotten, obj
|
||||
}
|
||||
|
||||
func (m *portableHandleMap) Has(h uint64) bool {
|
||||
m.RLock()
|
||||
ok := m.handles[h] != nil
|
||||
m.RUnlock()
|
||||
return ok
|
||||
}
|
||||
289
vendor/github.com/hanwen/go-fuse/fuse/nodefs/inode.go
generated
vendored
Normal file
289
vendor/github.com/hanwen/go-fuse/fuse/nodefs/inode.go
generated
vendored
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
type parentData struct {
|
||||
parent *Inode
|
||||
name string
|
||||
}
|
||||
|
||||
// An Inode reflects the kernel's idea of the inode. Inodes have IDs
|
||||
// that are communicated to the kernel, and they have a tree
|
||||
// structure: a directory Inode may contain named children. Each
|
||||
// Inode object is paired with a Node object, which file system
|
||||
// implementers should supply.
|
||||
type Inode struct {
|
||||
handled handled
|
||||
|
||||
// Generation number of the inode. Each (re)use of an inode
|
||||
// should have a unique generation number.
|
||||
generation uint64
|
||||
|
||||
// Number of open files and its protection.
|
||||
openFilesMutex sync.Mutex
|
||||
openFiles []*openedFile
|
||||
|
||||
fsInode Node
|
||||
|
||||
// Each inode belongs to exactly one fileSystemMount. This
|
||||
// pointer is constant during the lifetime, except upon
|
||||
// Unmount() when it is set to nil.
|
||||
mount *fileSystemMount
|
||||
|
||||
// All data below is protected by treeLock.
|
||||
children map[string]*Inode
|
||||
// Due to hard links, an Inode can have many parents.
|
||||
parents map[parentData]struct{}
|
||||
|
||||
// Non-nil if this inode is a mountpoint, ie. the Root of a
|
||||
// NodeFileSystem.
|
||||
mountPoint *fileSystemMount
|
||||
}
|
||||
|
||||
func newInode(isDir bool, fsNode Node) *Inode {
|
||||
me := new(Inode)
|
||||
me.parents = map[parentData]struct{}{}
|
||||
if isDir {
|
||||
me.children = make(map[string]*Inode, initDirSize)
|
||||
}
|
||||
me.fsInode = fsNode
|
||||
me.fsInode.SetInode(me)
|
||||
return me
|
||||
}
|
||||
|
||||
// public methods.
|
||||
|
||||
// Returns any open file, preferably a r/w one.
|
||||
func (n *Inode) AnyFile() (file File) {
|
||||
n.openFilesMutex.Lock()
|
||||
for _, f := range n.openFiles {
|
||||
if file == nil || f.WithFlags.OpenFlags&fuse.O_ANYWRITE != 0 {
|
||||
file = f.WithFlags.File
|
||||
}
|
||||
}
|
||||
n.openFilesMutex.Unlock()
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
// Children returns all children of this inode.
|
||||
func (n *Inode) Children() (out map[string]*Inode) {
|
||||
n.mount.treeLock.RLock()
|
||||
out = make(map[string]*Inode, len(n.children))
|
||||
for k, v := range n.children {
|
||||
out[k] = v
|
||||
}
|
||||
n.mount.treeLock.RUnlock()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Parent returns a random parent and the name this inode has under this parent.
|
||||
// This function can be used to walk up the directory tree. It will not cross
|
||||
// sub-mounts.
|
||||
func (n *Inode) Parent() (parent *Inode, name string) {
|
||||
if n.mountPoint != nil {
|
||||
return nil, ""
|
||||
}
|
||||
for k := range n.parents {
|
||||
return k.parent, k.name
|
||||
}
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// FsChildren returns all the children from the same filesystem. It
|
||||
// will skip mountpoints.
|
||||
func (n *Inode) FsChildren() (out map[string]*Inode) {
|
||||
n.mount.treeLock.RLock()
|
||||
out = map[string]*Inode{}
|
||||
for k, v := range n.children {
|
||||
if v.mount == n.mount {
|
||||
out[k] = v
|
||||
}
|
||||
}
|
||||
n.mount.treeLock.RUnlock()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Node returns the file-system specific node.
|
||||
func (n *Inode) Node() Node {
|
||||
return n.fsInode
|
||||
}
|
||||
|
||||
// Files() returns an opens file that have bits in common with the
|
||||
// give mask. Use mask==0 to return all files.
|
||||
func (n *Inode) Files(mask uint32) (files []WithFlags) {
|
||||
n.openFilesMutex.Lock()
|
||||
for _, f := range n.openFiles {
|
||||
if mask == 0 || f.WithFlags.OpenFlags&mask != 0 {
|
||||
files = append(files, f.WithFlags)
|
||||
}
|
||||
}
|
||||
n.openFilesMutex.Unlock()
|
||||
return files
|
||||
}
|
||||
|
||||
// IsDir returns true if this is a directory.
|
||||
func (n *Inode) IsDir() bool {
|
||||
return n.children != nil
|
||||
}
|
||||
|
||||
// NewChild adds a new child inode to this inode.
|
||||
func (n *Inode) NewChild(name string, isDir bool, fsi Node) *Inode {
|
||||
ch := newInode(isDir, fsi)
|
||||
ch.mount = n.mount
|
||||
n.AddChild(name, ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
// GetChild returns a child inode with the given name, or nil if it
|
||||
// does not exist.
|
||||
func (n *Inode) GetChild(name string) (child *Inode) {
|
||||
n.mount.treeLock.RLock()
|
||||
child = n.children[name]
|
||||
n.mount.treeLock.RUnlock()
|
||||
|
||||
return child
|
||||
}
|
||||
|
||||
// AddChild adds a child inode. The parent inode must be a directory
|
||||
// node.
|
||||
func (n *Inode) AddChild(name string, child *Inode) {
|
||||
if child == nil {
|
||||
log.Panicf("adding nil child as %q", name)
|
||||
}
|
||||
n.mount.treeLock.Lock()
|
||||
n.addChild(name, child)
|
||||
n.mount.treeLock.Unlock()
|
||||
}
|
||||
|
||||
// TreeWatcher is an additional interface that Nodes can implement.
|
||||
// If they do, the OnAdd and OnRemove are called for operations on the
|
||||
// file system tree. These functions run under a lock, so they should
|
||||
// not do blocking operations.
|
||||
type TreeWatcher interface {
|
||||
OnAdd(parent *Inode, name string)
|
||||
OnRemove(parent *Inode, name string)
|
||||
}
|
||||
|
||||
// RmChild removes an inode by name, and returns it. It returns nil if
|
||||
// child does not exist.
|
||||
func (n *Inode) RmChild(name string) (ch *Inode) {
|
||||
n.mount.treeLock.Lock()
|
||||
ch = n.rmChild(name)
|
||||
n.mount.treeLock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// private
|
||||
|
||||
// addChild adds "child" to our children under name "name".
|
||||
// Must be called with treeLock for the mount held.
|
||||
func (n *Inode) addChild(name string, child *Inode) {
|
||||
if paranoia {
|
||||
ch := n.children[name]
|
||||
if ch != nil {
|
||||
log.Panicf("Already have an Inode with same name: %v: %v", name, ch)
|
||||
}
|
||||
}
|
||||
n.children[name] = child
|
||||
child.parents[parentData{n, name}] = struct{}{}
|
||||
if w, ok := child.Node().(TreeWatcher); ok && child.mountPoint == nil {
|
||||
w.OnAdd(n, name)
|
||||
}
|
||||
}
|
||||
|
||||
// rmChild throws out child "name". This means (1) deleting "name" from our
|
||||
// "children" map and (2) deleting ourself from the child's "parents" map.
|
||||
// Must be called with treeLock for the mount held.
|
||||
func (n *Inode) rmChild(name string) *Inode {
|
||||
ch := n.children[name]
|
||||
if ch != nil {
|
||||
delete(n.children, name)
|
||||
delete(ch.parents, parentData{n, name})
|
||||
if w, ok := ch.Node().(TreeWatcher); ok && ch.mountPoint == nil {
|
||||
w.OnRemove(n, name)
|
||||
}
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
// Can only be called on untouched root inodes.
|
||||
func (n *Inode) mountFs(opts *Options) {
|
||||
n.mountPoint = &fileSystemMount{
|
||||
openFiles: newPortableHandleMap(),
|
||||
mountInode: n,
|
||||
options: opts,
|
||||
}
|
||||
n.mount = n.mountPoint
|
||||
}
|
||||
|
||||
// Must be called with treeLock held.
|
||||
func (n *Inode) canUnmount() bool {
|
||||
for _, v := range n.children {
|
||||
if v.mountPoint != nil {
|
||||
// This access may be out of date, but it is no
|
||||
// problem to err on the safe side.
|
||||
return false
|
||||
}
|
||||
if !v.canUnmount() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
n.openFilesMutex.Lock()
|
||||
ok := len(n.openFiles) == 0
|
||||
n.openFilesMutex.Unlock()
|
||||
return ok
|
||||
}
|
||||
|
||||
func (n *Inode) getMountDirEntries() (out []fuse.DirEntry) {
|
||||
n.mount.treeLock.RLock()
|
||||
for k, v := range n.children {
|
||||
if v.mountPoint != nil {
|
||||
out = append(out, fuse.DirEntry{
|
||||
Name: k,
|
||||
Mode: fuse.S_IFDIR,
|
||||
})
|
||||
}
|
||||
}
|
||||
n.mount.treeLock.RUnlock()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
const initDirSize = 20
|
||||
|
||||
func (n *Inode) verify(cur *fileSystemMount) {
|
||||
n.handled.verify()
|
||||
if n.mountPoint != nil {
|
||||
if n != n.mountPoint.mountInode {
|
||||
log.Panicf("mountpoint mismatch %v %v", n, n.mountPoint.mountInode)
|
||||
}
|
||||
cur = n.mountPoint
|
||||
|
||||
cur.treeLock.Lock()
|
||||
defer cur.treeLock.Unlock()
|
||||
}
|
||||
if n.mount != cur {
|
||||
log.Panicf("n.mount not set correctly %v %v", n.mount, cur)
|
||||
}
|
||||
|
||||
for nm, ch := range n.children {
|
||||
if ch == nil {
|
||||
log.Panicf("Found nil child: %q", nm)
|
||||
}
|
||||
ch.verify(cur)
|
||||
}
|
||||
}
|
||||
109
vendor/github.com/hanwen/go-fuse/fuse/nodefs/lockingfile.go
generated
vendored
Normal file
109
vendor/github.com/hanwen/go-fuse/fuse/nodefs/lockingfile.go
generated
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
type lockingFile struct {
|
||||
mu *sync.Mutex
|
||||
file File
|
||||
}
|
||||
|
||||
// NewLockingFile serializes operations an existing File.
|
||||
func NewLockingFile(mu *sync.Mutex, f File) File {
|
||||
return &lockingFile{
|
||||
mu: mu,
|
||||
file: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *lockingFile) SetInode(*Inode) {
|
||||
}
|
||||
|
||||
func (f *lockingFile) InnerFile() File {
|
||||
return f.file
|
||||
}
|
||||
|
||||
func (f *lockingFile) String() string {
|
||||
return fmt.Sprintf("lockingFile(%s)", f.file.String())
|
||||
}
|
||||
|
||||
func (f *lockingFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Read(buf, off)
|
||||
}
|
||||
|
||||
func (f *lockingFile) Write(data []byte, off int64) (uint32, fuse.Status) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Write(data, off)
|
||||
}
|
||||
|
||||
func (f *lockingFile) Flush() fuse.Status {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Flush()
|
||||
}
|
||||
|
||||
func (f *lockingFile) Flock(flags int) fuse.Status {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Flock(flags)
|
||||
}
|
||||
|
||||
func (f *lockingFile) Release() {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.file.Release()
|
||||
}
|
||||
|
||||
func (f *lockingFile) GetAttr(a *fuse.Attr) fuse.Status {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.GetAttr(a)
|
||||
}
|
||||
|
||||
func (f *lockingFile) Fsync(flags int) (code fuse.Status) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Fsync(flags)
|
||||
}
|
||||
|
||||
func (f *lockingFile) Utimens(atime *time.Time, mtime *time.Time) fuse.Status {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Utimens(atime, mtime)
|
||||
}
|
||||
|
||||
func (f *lockingFile) Truncate(size uint64) fuse.Status {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Truncate(size)
|
||||
}
|
||||
|
||||
func (f *lockingFile) Chown(uid uint32, gid uint32) fuse.Status {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Chown(uid, gid)
|
||||
}
|
||||
|
||||
func (f *lockingFile) Chmod(perms uint32) fuse.Status {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Chmod(perms)
|
||||
}
|
||||
|
||||
func (f *lockingFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.file.Allocate(off, size, mode)
|
||||
}
|
||||
232
vendor/github.com/hanwen/go-fuse/fuse/nodefs/memnode.go
generated
vendored
Normal file
232
vendor/github.com/hanwen/go-fuse/fuse/nodefs/memnode.go
generated
vendored
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
// NewMemNodeFSRoot creates an in-memory node-based filesystem. Files
|
||||
// are written into a backing store under the given prefix.
|
||||
func NewMemNodeFSRoot(prefix string) Node {
|
||||
fs := &memNodeFs{
|
||||
backingStorePrefix: prefix,
|
||||
}
|
||||
fs.root = fs.newNode()
|
||||
return fs.root
|
||||
}
|
||||
|
||||
type memNodeFs struct {
|
||||
backingStorePrefix string
|
||||
root *memNode
|
||||
|
||||
mutex sync.Mutex
|
||||
nextFree int
|
||||
}
|
||||
|
||||
func (fs *memNodeFs) String() string {
|
||||
return fmt.Sprintf("MemNodeFs(%s)", fs.backingStorePrefix)
|
||||
}
|
||||
|
||||
func (fs *memNodeFs) Root() Node {
|
||||
return fs.root
|
||||
}
|
||||
|
||||
func (fs *memNodeFs) SetDebug(bool) {
|
||||
}
|
||||
|
||||
func (fs *memNodeFs) OnMount(*FileSystemConnector) {
|
||||
}
|
||||
|
||||
func (fs *memNodeFs) OnUnmount() {
|
||||
}
|
||||
|
||||
func (fs *memNodeFs) newNode() *memNode {
|
||||
fs.mutex.Lock()
|
||||
id := fs.nextFree
|
||||
fs.nextFree++
|
||||
fs.mutex.Unlock()
|
||||
n := &memNode{
|
||||
Node: NewDefaultNode(),
|
||||
fs: fs,
|
||||
id: id,
|
||||
}
|
||||
now := time.Now()
|
||||
n.info.SetTimes(&now, &now, &now)
|
||||
n.info.Mode = fuse.S_IFDIR | 0777
|
||||
return n
|
||||
}
|
||||
|
||||
func (fs *memNodeFs) Filename(n *Inode) string {
|
||||
mn := n.Node().(*memNode)
|
||||
return mn.filename()
|
||||
}
|
||||
|
||||
type memNode struct {
|
||||
Node
|
||||
fs *memNodeFs
|
||||
id int
|
||||
|
||||
link string
|
||||
info fuse.Attr
|
||||
}
|
||||
|
||||
func (n *memNode) filename() string {
|
||||
return fmt.Sprintf("%s%d", n.fs.backingStorePrefix, n.id)
|
||||
}
|
||||
|
||||
func (n *memNode) Deletable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *memNode) Readlink(c *fuse.Context) ([]byte, fuse.Status) {
|
||||
return []byte(n.link), fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) StatFs() *fuse.StatfsOut {
|
||||
return &fuse.StatfsOut{}
|
||||
}
|
||||
|
||||
func (n *memNode) Mkdir(name string, mode uint32, context *fuse.Context) (newNode *Inode, code fuse.Status) {
|
||||
ch := n.fs.newNode()
|
||||
ch.info.Mode = mode | fuse.S_IFDIR
|
||||
n.Inode().NewChild(name, true, ch)
|
||||
return ch.Inode(), fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) Unlink(name string, context *fuse.Context) (code fuse.Status) {
|
||||
ch := n.Inode().RmChild(name)
|
||||
if ch == nil {
|
||||
return fuse.ENOENT
|
||||
}
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
|
||||
return n.Unlink(name, context)
|
||||
}
|
||||
|
||||
func (n *memNode) Symlink(name string, content string, context *fuse.Context) (newNode *Inode, code fuse.Status) {
|
||||
ch := n.fs.newNode()
|
||||
ch.info.Mode = fuse.S_IFLNK | 0777
|
||||
ch.link = content
|
||||
n.Inode().NewChild(name, false, ch)
|
||||
return ch.Inode(), fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) Rename(oldName string, newParent Node, newName string, context *fuse.Context) (code fuse.Status) {
|
||||
ch := n.Inode().RmChild(oldName)
|
||||
newParent.Inode().RmChild(newName)
|
||||
newParent.Inode().AddChild(newName, ch)
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) Link(name string, existing Node, context *fuse.Context) (*Inode, fuse.Status) {
|
||||
n.Inode().AddChild(name, existing.Inode())
|
||||
return existing.Inode(), fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, node *Inode, code fuse.Status) {
|
||||
ch := n.fs.newNode()
|
||||
ch.info.Mode = mode | fuse.S_IFREG
|
||||
|
||||
f, err := os.Create(ch.filename())
|
||||
if err != nil {
|
||||
return nil, nil, fuse.ToStatus(err)
|
||||
}
|
||||
n.Inode().NewChild(name, false, ch)
|
||||
return ch.newFile(f), ch.Inode(), fuse.OK
|
||||
}
|
||||
|
||||
type memNodeFile struct {
|
||||
File
|
||||
node *memNode
|
||||
}
|
||||
|
||||
func (n *memNodeFile) String() string {
|
||||
return fmt.Sprintf("memNodeFile(%s)", n.File.String())
|
||||
}
|
||||
|
||||
func (n *memNodeFile) InnerFile() File {
|
||||
return n.File
|
||||
}
|
||||
|
||||
func (n *memNodeFile) Flush() fuse.Status {
|
||||
code := n.File.Flush()
|
||||
|
||||
if !code.Ok() {
|
||||
return code
|
||||
}
|
||||
|
||||
st := syscall.Stat_t{}
|
||||
err := syscall.Stat(n.node.filename(), &st)
|
||||
n.node.info.Size = uint64(st.Size)
|
||||
n.node.info.Blocks = uint64(st.Blocks)
|
||||
return fuse.ToStatus(err)
|
||||
}
|
||||
|
||||
func (n *memNode) newFile(f *os.File) File {
|
||||
return &memNodeFile{
|
||||
File: NewLoopbackFile(f),
|
||||
node: n,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *memNode) Open(flags uint32, context *fuse.Context) (file File, code fuse.Status) {
|
||||
f, err := os.OpenFile(n.filename(), int(flags), 0666)
|
||||
if err != nil {
|
||||
return nil, fuse.ToStatus(err)
|
||||
}
|
||||
|
||||
return n.newFile(f), fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) GetAttr(fi *fuse.Attr, file File, context *fuse.Context) (code fuse.Status) {
|
||||
*fi = n.info
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status) {
|
||||
if file != nil {
|
||||
code = file.Truncate(size)
|
||||
} else {
|
||||
err := os.Truncate(n.filename(), int64(size))
|
||||
code = fuse.ToStatus(err)
|
||||
}
|
||||
if code.Ok() {
|
||||
now := time.Now()
|
||||
n.info.SetTimes(nil, nil, &now)
|
||||
// TODO - should update mtime too?
|
||||
n.info.Size = size
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func (n *memNode) Utimens(file File, atime *time.Time, mtime *time.Time, context *fuse.Context) (code fuse.Status) {
|
||||
c := time.Now()
|
||||
n.info.SetTimes(atime, mtime, &c)
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status) {
|
||||
n.info.Mode = (n.info.Mode &^ 07777) | perms
|
||||
now := time.Now()
|
||||
n.info.SetTimes(nil, nil, &now)
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
func (n *memNode) Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
|
||||
n.info.Uid = uid
|
||||
n.info.Gid = gid
|
||||
now := time.Now()
|
||||
n.info.SetTimes(nil, nil, &now)
|
||||
return fuse.OK
|
||||
}
|
||||
13
vendor/github.com/hanwen/go-fuse/fuse/nodefs/nodefs.go
generated
vendored
Normal file
13
vendor/github.com/hanwen/go-fuse/fuse/nodefs/nodefs.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import "time"
|
||||
|
||||
func splitDuration(dt time.Duration, secs *uint64, nsecs *uint32) {
|
||||
ns := int64(dt)
|
||||
*nsecs = uint32(ns % 1e9)
|
||||
*secs = uint64(ns / 1e9)
|
||||
}
|
||||
18
vendor/github.com/hanwen/go-fuse/fuse/nodefs/print.go
generated
vendored
Normal file
18
vendor/github.com/hanwen/go-fuse/fuse/nodefs/print.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
)
|
||||
|
||||
// String provides a debug string for the given file.
|
||||
func (f *WithFlags) String() string {
|
||||
return fmt.Sprintf("File %s (%s) %s %s",
|
||||
f.File, f.Description, fuse.FlagString(fuse.OpenFlagNames, int64(f.OpenFlags), "O_RDONLY"),
|
||||
fuse.FlagString(fuse.FuseOpenFlagNames, int64(f.FuseFlags), ""))
|
||||
}
|
||||
20
vendor/github.com/hanwen/go-fuse/fuse/nodefs/syscall_linux.go
generated
vendored
Normal file
20
vendor/github.com/hanwen/go-fuse/fuse/nodefs/syscall_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nodefs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// futimens - futimens(3) calls utimensat(2) with "pathname" set to null and
|
||||
// "flags" set to zero
|
||||
func futimens(fd int, times *[2]syscall.Timespec) (err error) {
|
||||
_, _, e1 := syscall.Syscall6(syscall.SYS_UTIMENSAT, uintptr(fd), 0, uintptr(unsafe.Pointer(times)), uintptr(0), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = syscall.Errno(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue