Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go-fuse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go-fuse
Commits
32016f39
Commit
32016f39
authored
Mar 13, 2019
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nodefs: documentation
parent
6d9ae31b
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
164 additions
and
93 deletions
+164
-93
nodefs/README.md
nodefs/README.md
+2
-0
nodefs/api.go
nodefs/api.go
+92
-19
nodefs/bridge.go
nodefs/bridge.go
+44
-42
nodefs/default.go
nodefs/default.go
+5
-4
nodefs/files.go
nodefs/files.go
+3
-2
nodefs/inode.go
nodefs/inode.go
+18
-26
No files found.
nodefs/README.md
View file @
32016f39
...
...
@@ -84,5 +84,7 @@ or
*
Should bridge.Lookup() add the child, bridge.Unlink remove the child, etc.?
*
Merge Fsync/FsyncDir?
*
Merge Release/ReleaseDir?
nodefs/api.go
View file @
32016f39
...
...
@@ -104,8 +104,15 @@ type Operations interface {
inode
()
*
Inode
setInode
(
*
Inode
)
bool
// StatFs implements statistics for the filesystem that holds
// this Inode. DefaultNode implements this, because OSX
// filesystem must have a valid StatFs implementation.
StatFs
(
ctx
context
.
Context
,
out
*
fuse
.
StatfsOut
)
fuse
.
Status
// Access should return if the caller can access the file with
// the given mode. In this case, the context has data about
// the real UID. For example a root-SUID binary called by user
// `susan` gets the UID and GID for `susan` here.
Access
(
ctx
context
.
Context
,
mask
uint32
)
fuse
.
Status
// File locking
...
...
@@ -115,34 +122,77 @@ type Operations interface {
// Extended attributes
// GetXAttr should read data for the given attribute into
// `dest` and return the number of bytes. If `dest` is too
// small, it should return ERANGE and the size of the attribute.
GetXAttr
(
ctx
context
.
Context
,
attr
string
,
dest
[]
byte
)
(
uint32
,
fuse
.
Status
)
// SetXAttr should store data for the given attribute.
// XXX flags.
SetXAttr
(
ctx
context
.
Context
,
attr
string
,
data
[]
byte
,
flags
uint32
)
fuse
.
Status
// RemoveXAttr should delete the given attribute.
RemoveXAttr
(
ctx
context
.
Context
,
attr
string
)
fuse
.
Status
// ListXAttr should read all attributes (null terminated) into
// `dest`. If the `dest` buffer is too small, it should return
// ERANGE and the correct size.
ListXAttr
(
ctx
context
.
Context
,
dest
[]
byte
)
(
uint32
,
fuse
.
Status
)
// The methods below may be called on closed files, due to
// concurrency.
GetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
// Lookup should find a direct child of the node by child name.
//
// VFS makes sure to call Lookup only once for particular
// (node, name) pair concurrently.
// Lookup should find a direct child of the node by child
// name. If the entry does not exist, it should return ENOENT
// and optionally set a NegativeTimeout in `out`. If it does
// exist, it should return attribute data in `out` and return
// the Inode for the child. A new inode can be created using
// `Inode.NewInode`. The new Inode will be added to the FS
// tree automatically if the return status is OK.
Lookup
(
ctx
context
.
Context
,
name
string
,
out
*
fuse
.
EntryOut
)
(
*
Inode
,
fuse
.
Status
)
// Mkdir is similar to Lookup, but must create a directory entry and Inode.
Mkdir
(
ctx
context
.
Context
,
name
string
,
mode
uint32
,
out
*
fuse
.
EntryOut
)
(
*
Inode
,
fuse
.
Status
)
// Mknod is similar to Lookup, but must create a device entry and Inode.
Mknod
(
ctx
context
.
Context
,
name
string
,
mode
uint32
,
dev
uint32
,
out
*
fuse
.
EntryOut
)
(
*
Inode
,
fuse
.
Status
)
Rmdir
(
ctx
context
.
Context
,
name
string
)
fuse
.
Status
Unlink
(
ctx
context
.
Context
,
name
string
)
fuse
.
Status
Rename
(
ctx
context
.
Context
,
name
string
,
newParent
Operations
,
newName
string
,
flags
uint32
)
fuse
.
Status
Create
(
ctx
context
.
Context
,
name
string
,
flags
uint32
,
mode
uint32
)
(
node
*
Inode
,
fh
FileHandle
,
fuseFlags
uint32
,
status
fuse
.
Status
)
// Link is similar to Lookup, but must create a new link to an existing Inode.
Link
(
ctx
context
.
Context
,
target
Operations
,
name
string
,
out
*
fuse
.
EntryOut
)
(
node
*
Inode
,
status
fuse
.
Status
)
// Symlink is similar to Lookup, but must create a new symbolic link.
Symlink
(
ctx
context
.
Context
,
target
,
name
string
,
out
*
fuse
.
EntryOut
)
(
node
*
Inode
,
status
fuse
.
Status
)
// Create is similar to Lookup, but should create a new
// child. It typically also returns a FileHandle as a
// reference for future reads/writes
Create
(
ctx
context
.
Context
,
name
string
,
flags
uint32
,
mode
uint32
)
(
node
*
Inode
,
fh
FileHandle
,
fuseFlags
uint32
,
status
fuse
.
Status
)
// Unlink should remove a child from this directory. If the
// return status is OK, the Inode is removed as child in the
// FS tree automatically.
Unlink
(
ctx
context
.
Context
,
name
string
)
fuse
.
Status
// Rmdir is like Unlink but for directories.
Rmdir
(
ctx
context
.
Context
,
name
string
)
fuse
.
Status
// Rename should move a child from one directory to a
// different one. The changes is effected in the FS tree if
// the return status is OK
Rename
(
ctx
context
.
Context
,
name
string
,
newParent
Operations
,
newName
string
,
flags
uint32
)
fuse
.
Status
// Readlink reads the content of a symlink.
Readlink
(
ctx
context
.
Context
)
(
string
,
fuse
.
Status
)
// Open opens an Inode (of regular file type) for reading. It
// is optional but recommended to return a FileHandle.
Open
(
ctx
context
.
Context
,
flags
uint32
)
(
fh
FileHandle
,
fuseFlags
uint32
,
status
fuse
.
Status
)
// OpenDir is called for sanity/permission checks on opening a
// directory.
// OpenDir opens a directory Inode for reading its
// contents. The actual reading is driven from ReadDir, so
// this method is just for performing sanity/permission
// checks.
OpenDir
(
ctx
context
.
Context
)
fuse
.
Status
// ReadDir opens a stream of directory entries.
...
...
@@ -150,26 +200,33 @@ type Operations interface {
// Reads data from a file. The data should be returned as
// ReadResult, which may be constructed from the incoming
// `dest` buffer.
// `dest` buffer. If the file was opened without FileHandle,
// the FileHandle argument here is nil. The default
// implementation forwards to the FileHandle.
Read
(
ctx
context
.
Context
,
f
FileHandle
,
dest
[]
byte
,
off
int64
)
(
fuse
.
ReadResult
,
fuse
.
Status
)
// Writes the data into the file handle at given offset. After
// returning, the data will be reused and may not referenced.
// The default implementation forwards to the FileHandle.
Write
(
ctx
context
.
Context
,
f
FileHandle
,
data
[]
byte
,
off
int64
)
(
written
uint32
,
status
fuse
.
Status
)
// Fsync is a signal to ensure writes to the Inode are flushed
// to stable storage. The default implementation forwards to the
// FileHandle.
Fsync
(
ctx
context
.
Context
,
f
FileHandle
,
flags
uint32
)
(
status
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.
// once for a file. The default implementation forwards to the
// FileHandle.
Flush
(
ctx
context
.
Context
,
f
FileHandle
)
fuse
.
Status
// This is called to before the file handle is forgotten. Th
is
//
method has no return value, so nothing can synchronize on
//
the call, and it cannot be canceled. Any cleanup that
//
requires specific synchronization or could fail with I/O
//
errors should happen in Flush instead
.
Release
(
f
FileHandle
)
// This is called to before the file handle is forgotten. Th
e
//
kernel ingores the return value of this method is ignored,
//
so any cleanup that requires specific synchronization or
//
could fail with I/O errors should happen in Flush instead.
//
The default implementation forwards to the FileHandle
.
Release
(
f
FileHandle
)
fuse
.
Status
/*
NOSUBMIT - fold into a setattr method, or expand methods?
...
...
@@ -178,13 +235,29 @@ type Operations interface {
types as args, we can't take apart SetAttr for the caller
*/
// Truncate sets the file length to the given size. The
// default implementation forwards to the FileHandle.
Truncate
(
ctx
context
.
Context
,
f
FileHandle
,
size
uint64
)
fuse
.
Status
// Chown changes the file owner . The default implementation
// forwards to the FileHandle.
Chown
(
ctx
context
.
Context
,
f
FileHandle
,
uid
uint32
,
gid
uint32
)
fuse
.
Status
// Chmod changes the file permissions. The default
// implementation forwards to the FileHandle.
Chmod
(
ctx
context
.
Context
,
f
FileHandle
,
perms
uint32
)
fuse
.
Status
// Utimens changes the files timestamps. The default
// implementation forwards to the FileHandle.
Utimens
(
ctx
context
.
Context
,
f
FileHandle
,
atime
*
time
.
Time
,
mtime
*
time
.
Time
)
fuse
.
Status
// Allocate preallocates space for future writes, so they will
// never encounter ESPACE. The default implementation
// forwards to the FileHandle.
Allocate
(
ctx
context
.
Context
,
f
FileHandle
,
off
uint64
,
size
uint64
,
mode
uint32
)
(
status
fuse
.
Status
)
}
// FileHandle is a resource identifier for opened files.
type
FileHandle
interface
{
Read
(
ctx
context
.
Context
,
dest
[]
byte
,
off
int64
)
(
fuse
.
ReadResult
,
fuse
.
Status
)
...
...
@@ -209,7 +282,7 @@ type FileHandle interface {
// the call, and it cannot be canceled. Any cleanup that
// requires specific synchronization or could fail with I/O
// errors should happen in Flush instead.
Release
()
Release
()
fuse
.
Status
// The methods below may be called on closed files, due to
// concurrency.
...
...
nodefs/bridge.go
View file @
32016f39
...
...
@@ -43,8 +43,8 @@ type rawBridge struct {
freeFiles
[]
uint32
}
// newInode creates creates new inode pointing to
node
.
func
(
b
*
rawBridge
)
newInode
(
node
Operations
,
mode
uint32
,
id
FileID
,
persistent
bool
)
*
Inode
{
// newInode creates creates new inode pointing to
ops
.
func
(
b
*
rawBridge
)
newInode
(
ops
Operations
,
mode
uint32
,
id
FileID
,
persistent
bool
)
*
Inode
{
b
.
mu
.
Lock
()
defer
b
.
mu
.
Unlock
()
...
...
@@ -75,7 +75,7 @@ func (b *rawBridge) newInode(node Operations, mode uint32, id FileID, persistent
mode
=
mode
&^
07777
inode
:=
&
Inode
{
mode
:
mode
,
node
:
node
,
ops
:
ops
,
nodeID
:
id
,
bridge
:
b
,
persistent
:
persistent
,
...
...
@@ -86,10 +86,12 @@ func (b *rawBridge) newInode(node Operations, mode uint32, id FileID, persistent
}
b
.
nodes
[
id
.
Ino
]
=
inode
node
.
setInode
(
inode
)
return
node
.
inode
()
ops
.
setInode
(
inode
)
return
ops
.
inode
()
}
// NewNodeFS creates a node based filesystem based on an Operations
// instance for the root.
func
NewNodeFS
(
root
Operations
,
opts
*
Options
)
fuse
.
RawFileSystem
{
bridge
:=
&
rawBridge
{
automaticIno
:
1
<<
63
,
...
...
@@ -108,7 +110,7 @@ func NewNodeFS(root Operations, opts *Options) fuse.RawFileSystem {
mode
:
fuse
.
S_IFDIR
,
children
:
make
(
map
[
string
]
*
Inode
),
parents
:
nil
,
node
:
root
,
ops
:
root
,
bridge
:
bridge
,
}
bridge
.
root
.
nodeID
.
Ino
=
1
...
...
@@ -139,7 +141,7 @@ func (b *rawBridge) inode(id uint64, fh uint64) (*Inode, *fileEntry) {
func
(
b
*
rawBridge
)
Lookup
(
cancel
<-
chan
struct
{},
header
*
fuse
.
InHeader
,
name
string
,
out
*
fuse
.
EntryOut
)
(
status
fuse
.
Status
)
{
parent
,
_
:=
b
.
inode
(
header
.
NodeId
,
0
)
child
,
status
:=
parent
.
node
.
Lookup
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
,
out
)
child
,
status
:=
parent
.
ops
.
Lookup
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
,
out
)
if
!
status
.
Ok
()
{
if
b
.
options
.
NegativeTimeout
!=
nil
{
out
.
SetEntryTimeout
(
*
b
.
options
.
NegativeTimeout
)
...
...
@@ -156,7 +158,7 @@ func (b *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name s
func
(
b
*
rawBridge
)
Rmdir
(
cancel
<-
chan
struct
{},
header
*
fuse
.
InHeader
,
name
string
)
fuse
.
Status
{
parent
,
_
:=
b
.
inode
(
header
.
NodeId
,
0
)
status
:=
parent
.
node
.
Rmdir
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
)
status
:=
parent
.
ops
.
Rmdir
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
)
if
status
.
Ok
()
{
parent
.
RmChild
(
name
)
}
...
...
@@ -166,7 +168,7 @@ func (b *rawBridge) Rmdir(cancel <-chan struct{}, header *fuse.InHeader, name st
func
(
b
*
rawBridge
)
Unlink
(
cancel
<-
chan
struct
{},
header
*
fuse
.
InHeader
,
name
string
)
fuse
.
Status
{
parent
,
_
:=
b
.
inode
(
header
.
NodeId
,
0
)
status
:=
parent
.
node
.
Unlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
)
status
:=
parent
.
ops
.
Unlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
)
if
status
.
Ok
()
{
parent
.
RmChild
(
name
)
}
...
...
@@ -176,7 +178,7 @@ func (b *rawBridge) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name s
func
(
b
*
rawBridge
)
Mkdir
(
cancel
<-
chan
struct
{},
input
*
fuse
.
MkdirIn
,
name
string
,
out
*
fuse
.
EntryOut
)
(
status
fuse
.
Status
)
{
parent
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
child
,
status
:=
parent
.
node
.
Mkdir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
name
,
input
.
Mode
,
out
)
child
,
status
:=
parent
.
ops
.
Mkdir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
name
,
input
.
Mode
,
out
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -193,7 +195,7 @@ func (b *rawBridge) Mkdir(cancel <-chan struct{}, input *fuse.MkdirIn, name stri
func
(
b
*
rawBridge
)
Mknod
(
cancel
<-
chan
struct
{},
input
*
fuse
.
MknodIn
,
name
string
,
out
*
fuse
.
EntryOut
)
(
status
fuse
.
Status
)
{
parent
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
child
,
status
:=
parent
.
node
.
Mknod
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
name
,
input
.
Mode
,
input
.
Rdev
,
out
)
child
,
status
:=
parent
.
ops
.
Mknod
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
name
,
input
.
Mode
,
input
.
Rdev
,
out
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -237,7 +239,7 @@ func (b *rawBridge) setEntryOutTimeout(out *fuse.EntryOut) {
func
(
b
*
rawBridge
)
Create
(
cancel
<-
chan
struct
{},
input
*
fuse
.
CreateIn
,
name
string
,
out
*
fuse
.
CreateOut
)
(
status
fuse
.
Status
)
{
ctx
:=
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
}
parent
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
child
,
f
,
flags
,
status
:=
parent
.
node
.
Create
(
ctx
,
name
,
input
.
Flags
,
input
.
Mode
)
child
,
f
,
flags
,
status
:=
parent
.
ops
.
Create
(
ctx
,
name
,
input
.
Flags
,
input
.
Mode
)
if
!
status
.
Ok
()
{
if
b
.
options
.
NegativeTimeout
!=
nil
{
out
.
SetEntryTimeout
(
*
b
.
options
.
NegativeTimeout
)
...
...
@@ -288,7 +290,7 @@ func (b *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *
b
.
mu
.
Unlock
()
}
status
:=
n
.
node
.
GetAttr
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
,
out
)
status
:=
n
.
ops
.
GetAttr
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
,
out
)
b
.
setAttrTimeout
(
out
)
out
.
Ino
=
input
.
NodeId
out
.
Mode
=
(
out
.
Attr
.
Mode
&
07777
)
|
n
.
mode
...
...
@@ -312,7 +314,7 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *
if
input
.
Valid
&
fuse
.
FATTR_MODE
!=
0
{
permissions
:=
uint32
(
07777
)
&
input
.
Mode
status
=
n
.
node
.
Chmod
(
ctx
,
f
,
permissions
)
status
=
n
.
ops
.
Chmod
(
ctx
,
f
,
permissions
)
}
if
status
.
Ok
()
&&
(
input
.
Valid
&
(
fuse
.
FATTR_UID
|
fuse
.
FATTR_GID
)
!=
0
)
{
...
...
@@ -324,11 +326,11 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *
if
input
.
Valid
&
fuse
.
FATTR_GID
!=
0
{
gid
=
input
.
Gid
}
status
=
n
.
node
.
Chown
(
ctx
,
f
,
uid
,
gid
)
status
=
n
.
ops
.
Chown
(
ctx
,
f
,
uid
,
gid
)
}
if
status
.
Ok
()
&&
input
.
Valid
&
fuse
.
FATTR_SIZE
!=
0
{
status
=
n
.
node
.
Truncate
(
ctx
,
f
,
input
.
Size
)
status
=
n
.
ops
.
Truncate
(
ctx
,
f
,
input
.
Size
)
}
if
status
.
Ok
()
&&
(
input
.
Valid
&
(
fuse
.
FATTR_ATIME
|
fuse
.
FATTR_MTIME
|
fuse
.
FATTR_ATIME_NOW
|
fuse
.
FATTR_MTIME_NOW
)
!=
0
)
{
...
...
@@ -354,7 +356,7 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *
}
}
status
=
n
.
node
.
Utimens
(
ctx
,
f
,
atime
,
mtime
)
status
=
n
.
ops
.
Utimens
(
ctx
,
f
,
atime
,
mtime
)
}
if
!
status
.
Ok
()
{
...
...
@@ -363,7 +365,7 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *
// Must call GetAttr(); the filesystem may override some of
// the changes we effect here.
status
=
n
.
node
.
GetAttr
(
ctx
,
f
,
out
)
status
=
n
.
ops
.
GetAttr
(
ctx
,
f
,
out
)
b
.
setAttrTimeout
(
out
)
out
.
Ino
=
n
.
nodeID
.
Ino
out
.
Mode
=
n
.
mode
|
(
out
.
Mode
&^
07777
)
...
...
@@ -374,7 +376,7 @@ func (b *rawBridge) Rename(cancel <-chan struct{}, input *fuse.RenameIn, oldName
p1
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
p2
,
_
:=
b
.
inode
(
input
.
Newdir
,
0
)
status
:=
p1
.
node
.
Rename
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
oldName
,
p2
.
node
,
newName
,
input
.
Flags
)
status
:=
p1
.
ops
.
Rename
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
oldName
,
p2
.
ops
,
newName
,
input
.
Flags
)
if
status
.
Ok
()
{
if
input
.
Flags
&
unix
.
RENAME_EXCHANGE
!=
0
{
p1
.
ExchangeChild
(
oldName
,
p2
,
newName
)
...
...
@@ -389,7 +391,7 @@ func (b *rawBridge) Link(cancel <-chan struct{}, input *fuse.LinkIn, name string
parent
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
target
,
_
:=
b
.
inode
(
input
.
Oldnodeid
,
0
)
child
,
status
:=
parent
.
node
.
Link
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
target
.
node
,
name
,
out
)
child
,
status
:=
parent
.
ops
.
Link
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
target
.
ops
,
name
,
out
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -401,7 +403,7 @@ func (b *rawBridge) Link(cancel <-chan struct{}, input *fuse.LinkIn, name string
func
(
b
*
rawBridge
)
Symlink
(
cancel
<-
chan
struct
{},
header
*
fuse
.
InHeader
,
target
string
,
name
string
,
out
*
fuse
.
EntryOut
)
(
status
fuse
.
Status
)
{
parent
,
_
:=
b
.
inode
(
header
.
NodeId
,
0
)
child
,
status
:=
parent
.
node
.
Symlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
target
,
name
,
out
)
child
,
status
:=
parent
.
ops
.
Symlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
target
,
name
,
out
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -413,7 +415,7 @@ func (b *rawBridge) Symlink(cancel <-chan struct{}, header *fuse.InHeader, targe
func
(
b
*
rawBridge
)
Readlink
(
cancel
<-
chan
struct
{},
header
*
fuse
.
InHeader
)
(
out
[]
byte
,
status
fuse
.
Status
)
{
n
,
_
:=
b
.
inode
(
header
.
NodeId
,
0
)
result
,
status
:=
n
.
node
.
Readlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
})
result
,
status
:=
n
.
ops
.
Readlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
})
if
!
status
.
Ok
()
{
return
nil
,
status
}
...
...
@@ -423,7 +425,7 @@ func (b *rawBridge) Readlink(cancel <-chan struct{}, header *fuse.InHeader) (out
func
(
b
*
rawBridge
)
Access
(
cancel
<-
chan
struct
{},
input
*
fuse
.
AccessIn
)
(
status
fuse
.
Status
)
{
n
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
return
n
.
node
.
Access
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
input
.
Mask
)
return
n
.
ops
.
Access
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
input
.
Mask
)
}
// Extended attributes.
...
...
@@ -431,28 +433,28 @@ func (b *rawBridge) Access(cancel <-chan struct{}, input *fuse.AccessIn) (status
func
(
b
*
rawBridge
)
GetXAttr
(
cancel
<-
chan
struct
{},
header
*
fuse
.
InHeader
,
attr
string
,
data
[]
byte
)
(
uint32
,
fuse
.
Status
)
{
n
,
_
:=
b
.
inode
(
header
.
NodeId
,
0
)
return
n
.
node
.
GetXAttr
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
attr
,
data
)
return
n
.
ops
.
GetXAttr
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
attr
,
data
)
}
func
(
b
*
rawBridge
)
ListXAttr
(
cancel
<-
chan
struct
{},
header
*
fuse
.
InHeader
,
dest
[]
byte
)
(
sz
uint32
,
status
fuse
.
Status
)
{
n
,
_
:=
b
.
inode
(
header
.
NodeId
,
0
)
return
n
.
node
.
ListXAttr
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
dest
)
return
n
.
ops
.
ListXAttr
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
dest
)
}
func
(
b
*
rawBridge
)
SetXAttr
(
cancel
<-
chan
struct
{},
input
*
fuse
.
SetXAttrIn
,
attr
string
,
data
[]
byte
)
fuse
.
Status
{
n
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
return
n
.
node
.
SetXAttr
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
attr
,
data
,
input
.
Flags
)
return
n
.
ops
.
SetXAttr
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
attr
,
data
,
input
.
Flags
)
}
func
(
b
*
rawBridge
)
RemoveXAttr
(
cancel
<-
chan
struct
{},
header
*
fuse
.
InHeader
,
attr
string
)
(
status
fuse
.
Status
)
{
n
,
_
:=
b
.
inode
(
header
.
NodeId
,
0
)
return
n
.
node
.
RemoveXAttr
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
attr
)
return
n
.
ops
.
RemoveXAttr
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
attr
)
}
func
(
b
*
rawBridge
)
Open
(
cancel
<-
chan
struct
{},
input
*
fuse
.
OpenIn
,
out
*
fuse
.
OpenOut
)
(
status
fuse
.
Status
)
{
n
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
// NOSUBMIT: what about the mode argument?
f
,
flags
,
status
:=
n
.
node
.
Open
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
input
.
Flags
)
f
,
flags
,
status
:=
n
.
ops
.
Open
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
input
.
Flags
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -486,28 +488,28 @@ func (b *rawBridge) registerFile(n *Inode, f FileHandle, flags uint32) uint32 {
func
(
b
*
rawBridge
)
Read
(
cancel
<-
chan
struct
{},
input
*
fuse
.
ReadIn
,
buf
[]
byte
)
(
fuse
.
ReadResult
,
fuse
.
Status
)
{
n
,
f
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
)
return
n
.
node
.
Read
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
buf
,
int64
(
input
.
Offset
))
return
n
.
ops
.
Read
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
buf
,
int64
(
input
.
Offset
))
}
func
(
b
*
rawBridge
)
GetLk
(
cancel
<-
chan
struct
{},
input
*
fuse
.
LkIn
,
out
*
fuse
.
LkOut
)
(
status
fuse
.
Status
)
{
n
,
f
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
)
return
n
.
node
.
GetLk
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
,
&
out
.
Lk
)
return
n
.
ops
.
GetLk
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
,
&
out
.
Lk
)
}
func
(
b
*
rawBridge
)
SetLk
(
cancel
<-
chan
struct
{},
input
*
fuse
.
LkIn
)
(
status
fuse
.
Status
)
{
n
,
f
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
)
return
n
.
node
.
SetLk
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
)
return
n
.
ops
.
SetLk
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
)
}
func
(
b
*
rawBridge
)
SetLkw
(
cancel
<-
chan
struct
{},
input
*
fuse
.
LkIn
)
(
status
fuse
.
Status
)
{
n
,
f
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
)
return
n
.
node
.
SetLkw
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
)
return
n
.
ops
.
SetLkw
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
)
}
func
(
b
*
rawBridge
)
Release
(
input
*
fuse
.
ReleaseIn
)
{
n
,
f
:=
b
.
releaseFileEntry
(
input
.
NodeId
,
input
.
Fh
)
f
.
wg
.
Wait
()
n
.
node
.
Release
(
f
.
file
)
n
.
ops
.
Release
(
f
.
file
)
b
.
mu
.
Lock
()
defer
b
.
mu
.
Unlock
()
...
...
@@ -547,27 +549,27 @@ func (b *rawBridge) releaseFileEntry(nid uint64, fh uint64) (*Inode, *fileEntry)
func
(
b
*
rawBridge
)
Write
(
cancel
<-
chan
struct
{},
input
*
fuse
.
WriteIn
,
data
[]
byte
)
(
written
uint32
,
status
fuse
.
Status
)
{
n
,
f
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
)
return
n
.
node
.
Write
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
data
,
int64
(
input
.
Offset
))
return
n
.
ops
.
Write
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
data
,
int64
(
input
.
Offset
))
}
func
(
b
*
rawBridge
)
Flush
(
cancel
<-
chan
struct
{},
input
*
fuse
.
FlushIn
)
fuse
.
Status
{
n
,
f
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
)
return
n
.
node
.
Flush
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
)
return
n
.
ops
.
Flush
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
)
}
func
(
b
*
rawBridge
)
Fsync
(
cancel
<-
chan
struct
{},
input
*
fuse
.
FsyncIn
)
(
status
fuse
.
Status
)
{
n
,
f
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
)
return
n
.
node
.
Fsync
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
FsyncFlags
)
return
n
.
ops
.
Fsync
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
FsyncFlags
)
}
func
(
b
*
rawBridge
)
Fallocate
(
cancel
<-
chan
struct
{},
input
*
fuse
.
FallocateIn
)
(
status
fuse
.
Status
)
{
n
,
f
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
)
return
n
.
node
.
Allocate
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Offset
,
input
.
Length
,
input
.
Mode
)
return
n
.
ops
.
Allocate
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Offset
,
input
.
Length
,
input
.
Mode
)
}
func
(
b
*
rawBridge
)
OpenDir
(
cancel
<-
chan
struct
{},
input
*
fuse
.
OpenIn
,
out
*
fuse
.
OpenOut
)
fuse
.
Status
{
n
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
status
:=
n
.
node
.
OpenDir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
})
status
:=
n
.
ops
.
OpenDir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
})
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -583,7 +585,7 @@ func (b *rawBridge) getStream(cancel <-chan struct{}, input *fuse.ReadIn, inode
f
.
dirStream
.
Close
()
f
.
dirStream
=
nil
}
str
,
status
:=
inode
.
node
.
ReadDir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
})
str
,
status
:=
inode
.
ops
.
ReadDir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
})
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -652,7 +654,7 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out
return
fuse
.
OK
}
child
,
status
:=
n
.
node
.
Lookup
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
e
.
Name
,
entryOut
)
child
,
status
:=
n
.
ops
.
Lookup
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
e
.
Name
,
entryOut
)
if
!
status
.
Ok
()
{
if
b
.
options
.
NegativeTimeout
!=
nil
{
entryOut
.
SetEntryTimeout
(
*
b
.
options
.
NegativeTimeout
)
...
...
@@ -674,12 +676,12 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out
func
(
b
*
rawBridge
)
FsyncDir
(
cancel
<-
chan
struct
{},
input
*
fuse
.
FsyncIn
)
(
status
fuse
.
Status
)
{
n
,
_
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
)
return
n
.
node
.
Fsync
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
nil
,
input
.
FsyncFlags
)
return
n
.
ops
.
Fsync
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
nil
,
input
.
FsyncFlags
)
}
func
(
b
*
rawBridge
)
StatFs
(
cancel
<-
chan
struct
{},
input
*
fuse
.
InHeader
,
out
*
fuse
.
StatfsOut
)
(
status
fuse
.
Status
)
{
n
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
return
n
.
node
.
StatFs
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
out
)
return
n
.
ops
.
StatFs
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
out
)
}
func
(
b
*
rawBridge
)
Init
(
s
*
fuse
.
Server
)
{
...
...
nodefs/default.go
View file @
32016f39
...
...
@@ -150,10 +150,11 @@ func (n *DefaultOperations) Flush(ctx context.Context, f FileHandle) fuse.Status
return
fuse
.
ENOSYS
}
func
(
n
*
DefaultOperations
)
Release
(
f
FileHandle
)
{
func
(
n
*
DefaultOperations
)
Release
(
f
FileHandle
)
fuse
.
Status
{
if
f
!=
nil
{
f
.
Release
()
return
f
.
Release
()
}
return
fuse
.
ENOSYS
}
func
(
n
*
DefaultOperations
)
Allocate
(
ctx
context
.
Context
,
f
FileHandle
,
off
uint64
,
size
uint64
,
mode
uint32
)
(
status
fuse
.
Status
)
{
...
...
@@ -264,8 +265,8 @@ func (f *DefaultFile) Flush(ctx context.Context) fuse.Status {
return
fuse
.
ENOSYS
}
func
(
f
*
DefaultFile
)
Release
()
{
func
(
f
*
DefaultFile
)
Release
()
fuse
.
Status
{
return
fuse
.
ENOSYS
}
func
(
f
*
DefaultFile
)
GetAttr
(
ctx
context
.
Context
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
...
...
nodefs/files.go
View file @
32016f39
...
...
@@ -46,10 +46,11 @@ func (f *loopbackFile) Write(ctx context.Context, data []byte, off int64) (uint3
return
uint32
(
n
),
fuse
.
ToStatus
(
err
)
}
func
(
f
*
loopbackFile
)
Release
()
{
func
(
f
*
loopbackFile
)
Release
()
fuse
.
Status
{
f
.
mu
.
Lock
()
syscall
.
Close
(
f
.
fd
)
err
:=
syscall
.
Close
(
f
.
fd
)
f
.
mu
.
Unlock
()
return
fuse
.
ToStatus
(
err
)
}
func
(
f
*
loopbackFile
)
Flush
(
ctx
context
.
Context
)
fuse
.
Status
{
...
...
nodefs/inode.go
View file @
32016f39
...
...
@@ -15,8 +15,6 @@ import (
"github.com/hanwen/go-fuse/fuse"
)
var
_
=
log
.
Println
type
parentData
struct
{
name
string
parent
*
Inode
...
...
@@ -54,7 +52,7 @@ type Inode struct {
nodeID
FileID
node
Operations
ops
Operations
bridge
*
rawBridge
// Following data is mutable.
...
...
@@ -90,10 +88,12 @@ type Inode struct {
parents
map
[
parentData
]
struct
{}
}
// FileID returns the (Ino, Gen) tuple for this node.
func
(
n
*
Inode
)
FileID
()
FileID
{
return
n
.
nodeID
}
// IsRoot returns true if this is the root of the FUSE mount.
func
(
n
*
Inode
)
IsRoot
()
bool
{
return
n
.
nodeID
.
Ino
==
fuse
.
FUSE_ROOT_ID
}
...
...
@@ -195,7 +195,7 @@ func (n *Inode) Forgotten() bool {
// Node returns the Node object implementing the file system operations.
func
(
n
*
Inode
)
Operations
()
Operations
{
return
n
.
node
return
n
.
ops
}
// Path returns a path string to the inode relative to the root.
...
...
@@ -238,23 +238,6 @@ func (n *Inode) Path(root *Inode) string {
return
path
}
// Finds a child with the given name and filetype. Returns nil if not
// found.
func
(
n
*
Inode
)
FindChildByMode
(
name
string
,
mode
uint32
)
*
Inode
{
mode
^=
07777
n
.
mu
.
Lock
()
defer
n
.
mu
.
Unlock
()
ch
:=
n
.
children
[
name
]
if
ch
!=
nil
&&
ch
.
mode
==
mode
{
return
ch
}
return
nil
}
// setEntry does `iparent[name] = ichild` linking.
//
// setEntry must not be called simultaneously for any of iparent or ichild.
...
...
@@ -420,7 +403,7 @@ retry:
}
// MvChild executes a rename. If overwrite is set, a child at the
// destination will be overwritten.
// destination will be overwritten
, should it exist
.
func
(
n
*
Inode
)
MvChild
(
old
string
,
newParent
*
Inode
,
newName
string
,
overwrite
bool
)
bool
{
retry
:
for
{
...
...
@@ -475,6 +458,8 @@ retry:
}
}
// ExchangeChild swaps the entries at (n, oldName) and (newParent,
// newName).
func
(
n
*
Inode
)
ExchangeChild
(
oldName
string
,
newParent
*
Inode
,
newName
string
)
{
oldParent
:=
n
retry
:
...
...
@@ -487,9 +472,6 @@ retry:
destChild
:=
newParent
.
children
[
newName
]
unlockNode2
(
oldParent
,
newParent
)
if
destChild
==
nil
&&
oldChild
==
nil
{
return
}
if
destChild
==
oldChild
{
return
}
...
...
@@ -536,26 +518,36 @@ retry:
}
}
// NotifyEntry notifies the kernel that data for a (directory, name)
// tuple should be invalidated. On next access, a LOOKUP operation
// will be started.
func
(
n
*
Inode
)
NotifyEntry
(
name
string
)
fuse
.
Status
{
return
n
.
bridge
.
server
.
EntryNotify
(
n
.
nodeID
.
Ino
,
name
)
}
// XXX naming: DeleteNotify ?
// NotifyDelete notifies the kernel that the given inode was removed
// from this directory as entry under the given name. It is equivalent
// to NotifyEntry, but also sends an event to inotify watchers.
func
(
n
*
Inode
)
NotifyDelete
(
name
string
,
child
*
Inode
)
fuse
.
Status
{
// XXX arg ordering?
return
n
.
bridge
.
server
.
DeleteNotify
(
n
.
nodeID
.
Ino
,
child
.
nodeID
.
Ino
,
name
)
}
// NotifyContent notifies the kernel that content under the given
// inode should be flushed from buffers.
func
(
n
*
Inode
)
NotifyContent
(
off
,
sz
int64
)
fuse
.
Status
{
// XXX how does this work for directories?
return
n
.
bridge
.
server
.
InodeNotify
(
n
.
nodeID
.
Ino
,
off
,
sz
)
}
// WriteCache stores data in the kernel cache.
func
(
n
*
Inode
)
WriteCache
(
offset
int64
,
data
[]
byte
)
fuse
.
Status
{
return
n
.
bridge
.
server
.
InodeNotifyStoreCache
(
n
.
nodeID
.
Ino
,
offset
,
data
)
}
// ReadCache reads data from the kernel cache.
func
(
n
*
Inode
)
ReadCache
(
offset
int64
,
dest
[]
byte
)
(
count
int
,
status
fuse
.
Status
)
{
return
n
.
bridge
.
server
.
InodeRetrieveCache
(
n
.
nodeID
.
Ino
,
offset
,
dest
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment