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
Levin Zimmermann
go-fuse
Commits
4f60fdad
Commit
4f60fdad
authored
Mar 14, 2019
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nodefs: separate interfaces for File/Symlink/Dir
parent
70326fc5
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
260 additions
and
243 deletions
+260
-243
fuse/types.go
fuse/types.go
+4
-0
nodefs/README.md
nodefs/README.md
+0
-2
nodefs/api.go
nodefs/api.go
+101
-91
nodefs/bridge.go
nodefs/bridge.go
+67
-103
nodefs/default.go
nodefs/default.go
+13
-26
nodefs/files.go
nodefs/files.go
+56
-16
nodefs/files_linux.go
nodefs/files_linux.go
+1
-1
nodefs/inode.go
nodefs/inode.go
+12
-0
nodefs/loopback.go
nodefs/loopback.go
+5
-3
nodefs/simple_test.go
nodefs/simple_test.go
+1
-1
No files found.
fuse/types.go
View file @
4f60fdad
...
...
@@ -527,6 +527,10 @@ type CopyFileRangeIn struct {
Flags
uint64
}
// EntryOut holds the result of a (directory,name) lookup. It has two
// TTLs, one for the (directory, name) lookup itself, and one for the
// attributes (eg. size, mode). The entry TTL also applies if the
// lookup result is ENOENT ("negative entry lookup")
type
EntryOut
struct
{
NodeId
uint64
Generation
uint64
...
...
nodefs/README.md
View file @
4f60fdad
...
...
@@ -55,8 +55,6 @@ To decide
*
One giant interface with many methods, or many one-method
interfaces? Or some interface (file, dir, symlink, etc).
*
one SetAttr method, or many (Chown, Truncate, etc.)
*
function signatures, or types? The latter is easier to remember?
Easier to extend? The latter less efficient (indirections/copies)
...
...
nodefs/api.go
View file @
4f60fdad
...
...
@@ -115,11 +115,6 @@ type Operations interface {
// `susan` gets the UID and GID for `susan` here.
Access
(
ctx
context
.
Context
,
mask
uint32
)
fuse
.
Status
// File locking
GetLk
(
ctx
context
.
Context
,
f
FileHandle
,
owner
uint64
,
lk
*
fuse
.
FileLock
,
flags
uint32
,
out
*
fuse
.
FileLock
)
(
status
fuse
.
Status
)
SetLk
(
ctx
context
.
Context
,
f
FileHandle
,
owner
uint64
,
lk
*
fuse
.
FileLock
,
flags
uint32
)
(
status
fuse
.
Status
)
SetLkw
(
ctx
context
.
Context
,
f
FileHandle
,
owner
uint64
,
lk
*
fuse
.
FileLock
,
flags
uint32
)
(
status
fuse
.
Status
)
// Extended attributes
// GetXAttr should read data for the given attribute into
...
...
@@ -139,7 +134,88 @@ type Operations interface {
// ERANGE and the correct size.
ListXAttr
(
ctx
context
.
Context
,
dest
[]
byte
)
(
uint32
,
fuse
.
Status
)
GetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
GetAttr
(
ctx
context
.
Context
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
SetAttr
(
ctx
context
.
Context
,
in
*
fuse
.
SetAttrIn
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
}
// SymlinkOperations holds operations specific to symlinks.
type
SymlinkOperations
interface
{
Operations
// Readlink reads the content of a symlink.
Readlink
(
ctx
context
.
Context
)
(
string
,
fuse
.
Status
)
}
// FileOperations holds operations that apply to regular files. The
// default implementation, as returned from NewFileOperations forwards
// to the passed-in FileHandle.
//
// XXX Mknod output too?
type
FileOperations
interface
{
Operations
// 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
)
// File locking
// GetLk returns locks that would conflict with the given
// input lock. If no locks conflict, the output has type
// L_UNLCK. See fcntl(2) for more information.
GetLk
(
ctx
context
.
Context
,
f
FileHandle
,
owner
uint64
,
lk
*
fuse
.
FileLock
,
flags
uint32
,
out
*
fuse
.
FileLock
)
(
status
fuse
.
Status
)
// Obtain a lock on a file, or fail if the lock could not
// obtained. See fcntl(2) for more information.
SetLk
(
ctx
context
.
Context
,
f
FileHandle
,
owner
uint64
,
lk
*
fuse
.
FileLock
,
flags
uint32
)
(
status
fuse
.
Status
)
// Obtain a lock on a file, waiting if necessary. See fcntl(2)
// for more information.
SetLkw
(
ctx
context
.
Context
,
f
FileHandle
,
owner
uint64
,
lk
*
fuse
.
FileLock
,
flags
uint32
)
(
status
fuse
.
Status
)
// Reads data from a file. The data should be returned as
// ReadResult, which may be constructed from the incoming
// `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. 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. The
// kernel ingores the return value of this method,
// 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
(
ctx
context
.
Context
,
f
FileHandle
)
fuse
.
Status
// Allocate preallocates space for future writes, so they will
// never encounter ESPACE.
Allocate
(
ctx
context
.
Context
,
f
FileHandle
,
off
uint64
,
size
uint64
,
mode
uint32
)
(
status
fuse
.
Status
)
FGetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
FSetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
in
*
fuse
.
SetAttrIn
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
}
// DirOperations are operations for directory nodes in the filesystem.
type
DirOperations
interface
{
Operations
// Lookup should find a direct child of the node by child
// name. If the entry does not exist, it should return ENOENT
...
...
@@ -180,13 +256,6 @@ type Operations interface {
// 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 opens a directory Inode for reading its
// contents. The actual reading is driven from ReadDir, so
// this method is just for performing sanity/permission
...
...
@@ -195,105 +264,46 @@ type Operations interface {
// ReadDir opens a stream of directory entries.
ReadDir
(
ctx
context
.
Context
)
(
DirStream
,
fuse
.
Status
)
// Reads data from a file. The data should be returned as
// ReadResult, which may be constructed from the incoming
// `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. 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. The
// 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?
Decoding SetAttr is a bit of a PITA, but if we use fuse
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.
// FileHandle is a resource identifier for opened files. For a
// description, see the equivalent operations in FileOperations.
type
FileHandle
interface
{
Read
(
ctx
context
.
Context
,
dest
[]
byte
,
off
int64
)
(
fuse
.
ReadResult
,
fuse
.
Status
)
// Writes the data at given offset. After returning, the data
// will be reused and may not referenced.
Write
(
ctx
context
.
Context
,
data
[]
byte
,
off
int64
)
(
written
uint32
,
status
fuse
.
Status
)
// File locking
GetLk
(
ctx
context
.
Context
,
owner
uint64
,
lk
*
fuse
.
FileLock
,
flags
uint32
,
out
*
fuse
.
FileLock
)
(
status
fuse
.
Status
)
SetLk
(
ctx
context
.
Context
,
owner
uint64
,
lk
*
fuse
.
FileLock
,
flags
uint32
)
(
status
fuse
.
Status
)
SetLkw
(
ctx
context
.
Context
,
owner
uint64
,
lk
*
fuse
.
FileLock
,
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.
Flush
(
ctx
context
.
Context
)
fuse
.
Status
Fsync
(
ctx
context
.
Context
,
flags
uint32
)
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, and it cannot be canceled. Any cleanup that
// requires specific synchronization or could fail with I/O
// errors should happen in Flush instead.
Release
()
fuse
.
Status
Release
(
ctx
context
.
Context
)
fuse
.
Status
GetAttr
(
ctx
context
.
Context
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
Truncate
(
ctx
context
.
Context
,
size
uint64
)
fuse
.
Status
Chown
(
ctx
context
.
Context
,
uid
uint32
,
gid
uint32
)
fuse
.
Status
Chmod
(
ctx
context
.
Context
,
perms
uint32
)
fuse
.
Status
Utimens
(
ctx
context
.
Context
,
atime
*
time
.
Time
,
mtime
*
time
.
Time
)
fuse
.
Status
SetAttr
(
ctx
context
.
Context
,
in
*
fuse
.
SetAttrIn
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
Allocate
(
ctx
context
.
Context
,
off
uint64
,
size
uint64
,
mode
uint32
)
(
status
fuse
.
Status
)
}
// Options sets options for the entire filesystem
type
Options
struct
{
// Debug toggles debug output
Debug
bool
// If set to nonnil, this defines the overall entry timeout
// for the file system. See fuse.EntryOut for more information.
EntryTimeout
*
time
.
Duration
// If set to nonnil, this defines the overall attribute
// timeout for the file system. See fuse.EntryOut for more
// information.
AttrTimeout
*
time
.
Duration
// If set to nonnil, this defines the overall entry timeout
// for failed lookups (fuse.ENOENT). See fuse.EntryOut for
// more information.
NegativeTimeout
*
time
.
Duration
}
nodefs/bridge.go
View file @
4f60fdad
...
...
@@ -73,6 +73,17 @@ func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent
return
old
}
mode
=
mode
&^
07777
switch
mode
{
case
fuse
.
S_IFDIR
:
_
=
ops
.
(
DirOperations
)
case
fuse
.
S_IFLNK
:
_
=
ops
.
(
SymlinkOperations
)
case
fuse
.
S_IFREG
:
_
=
ops
.
(
FileOperations
)
default
:
log
.
Panicf
(
"filetype %o unimplemented"
,
mode
)
}
inode
:=
&
Inode
{
mode
:
mode
,
ops
:
ops
,
...
...
@@ -92,7 +103,7 @@ func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent
// NewNodeFS creates a node based filesystem based on an Operations
// instance for the root.
func
NewNodeFS
(
root
Operations
,
opts
*
Options
)
fuse
.
RawFileSystem
{
func
NewNodeFS
(
root
Dir
Operations
,
opts
*
Options
)
fuse
.
RawFileSystem
{
bridge
:=
&
rawBridge
{
automaticIno
:
1
<<
63
,
}
...
...
@@ -141,7 +152,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
.
ops
.
Lookup
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
,
out
)
child
,
status
:=
parent
.
dirOps
()
.
Lookup
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
,
out
)
if
!
status
.
Ok
()
{
if
b
.
options
.
NegativeTimeout
!=
nil
{
out
.
SetEntryTimeout
(
*
b
.
options
.
NegativeTimeout
)
...
...
@@ -158,7 +169,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
.
ops
.
Rmdir
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
)
status
:=
parent
.
dirOps
()
.
Rmdir
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
)
if
status
.
Ok
()
{
parent
.
RmChild
(
name
)
}
...
...
@@ -168,7 +179,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
.
ops
.
Unlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
)
status
:=
parent
.
dirOps
()
.
Unlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
name
)
if
status
.
Ok
()
{
parent
.
RmChild
(
name
)
}
...
...
@@ -178,7 +189,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
.
ops
.
Mkdir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
name
,
input
.
Mode
,
out
)
child
,
status
:=
parent
.
dirOps
()
.
Mkdir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
name
,
input
.
Mode
,
out
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -195,7 +206,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
.
ops
.
Mknod
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
name
,
input
.
Mode
,
input
.
Rdev
,
out
)
child
,
status
:=
parent
.
dirOps
()
.
Mknod
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
name
,
input
.
Mode
,
input
.
Rdev
,
out
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -239,7 +250,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
.
ops
.
Create
(
ctx
,
name
,
input
.
Flags
,
input
.
Mode
)
child
,
f
,
flags
,
status
:=
parent
.
dirOps
()
.
Create
(
ctx
,
name
,
input
.
Flags
,
input
.
Mode
)
if
!
status
.
Ok
()
{
if
b
.
options
.
NegativeTimeout
!=
nil
{
out
.
SetEntryTimeout
(
*
b
.
options
.
NegativeTimeout
)
...
...
@@ -275,6 +286,9 @@ func (b *rawBridge) SetDebug(debug bool) {}
func
(
b
*
rawBridge
)
GetAttr
(
cancel
<-
chan
struct
{},
input
*
fuse
.
GetAttrIn
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
n
,
fEntry
:=
b
.
inode
(
input
.
NodeId
,
input
.
Fh
())
ctx
:=
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
}
if
fops
,
ok
:=
n
.
ops
.
(
FileOperations
);
ok
{
f
:=
fEntry
.
file
if
input
.
Flags
()
&
fuse
.
FUSE_GETATTR_FH
==
0
{
// The linux kernel doesnt pass along the file
...
...
@@ -290,11 +304,13 @@ func (b *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *
b
.
mu
.
Unlock
()
}
status
:=
n
.
ops
.
GetAttr
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
}
,
f
,
out
)
status
:=
fops
.
FGetAttr
(
ctx
,
f
,
out
)
b
.
setAttrTimeout
(
out
)
out
.
Ino
=
input
.
NodeId
out
.
Mode
=
(
out
.
Attr
.
Mode
&
07777
)
|
n
.
mode
return
status
}
return
n
.
ops
.
GetAttr
(
ctx
,
out
)
}
func
(
b
*
rawBridge
)
setAttrTimeout
(
out
*
fuse
.
AttrOut
)
{
...
...
@@ -303,80 +319,27 @@ func (b *rawBridge) setAttrTimeout(out *fuse.AttrOut) {
}
}
func
(
b
*
rawBridge
)
SetAttr
(
cancel
<-
chan
struct
{},
in
put
*
fuse
.
SetAttrIn
,
out
*
fuse
.
AttrOut
)
(
status
fuse
.
Status
)
{
ctx
:=
&
fuse
.
Context
{
Caller
:
in
put
.
Caller
,
Cancel
:
cancel
}
func
(
b
*
rawBridge
)
SetAttr
(
cancel
<-
chan
struct
{},
in
*
fuse
.
SetAttrIn
,
out
*
fuse
.
AttrOut
)
(
status
fuse
.
Status
)
{
ctx
:=
&
fuse
.
Context
{
Caller
:
in
.
Caller
,
Cancel
:
cancel
}
n
,
fEntry
:=
b
.
inode
(
in
put
.
NodeId
,
input
.
Fh
)
n
,
fEntry
:=
b
.
inode
(
in
.
NodeId
,
in
.
Fh
)
f
:=
fEntry
.
file
if
in
put
.
Valid
&
fuse
.
FATTR_FH
==
0
{
if
in
.
Valid
&
fuse
.
FATTR_FH
==
0
{
f
=
nil
}
if
input
.
Valid
&
fuse
.
FATTR_MODE
!=
0
{
permissions
:=
uint32
(
07777
)
&
input
.
Mode
status
=
n
.
ops
.
Chmod
(
ctx
,
f
,
permissions
)
if
fops
,
ok
:=
n
.
ops
.
(
FileOperations
);
ok
{
return
fops
.
FSetAttr
(
ctx
,
f
,
in
,
out
)
}
if
status
.
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
}
status
=
n
.
ops
.
Chown
(
ctx
,
f
,
uid
,
gid
)
}
if
status
.
Ok
()
&&
input
.
Valid
&
fuse
.
FATTR_SIZE
!=
0
{
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
)
{
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
}
}
status
=
n
.
ops
.
Utimens
(
ctx
,
f
,
atime
,
mtime
)
}
if
!
status
.
Ok
()
{
return
status
}
// Must call GetAttr(); the filesystem may override some of
// the changes we effect here.
status
=
n
.
ops
.
GetAttr
(
ctx
,
f
,
out
)
b
.
setAttrTimeout
(
out
)
out
.
Ino
=
n
.
nodeID
.
Ino
out
.
Mode
=
n
.
mode
|
(
out
.
Mode
&^
07777
)
return
status
return
n
.
ops
.
SetAttr
(
ctx
,
in
,
out
)
}
func
(
b
*
rawBridge
)
Rename
(
cancel
<-
chan
struct
{},
input
*
fuse
.
RenameIn
,
oldName
string
,
newName
string
)
fuse
.
Status
{
p1
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
p2
,
_
:=
b
.
inode
(
input
.
Newdir
,
0
)
status
:=
p1
.
ops
.
Rename
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
oldName
,
p2
.
ops
,
newName
,
input
.
Flags
)
status
:=
p1
.
dirOps
()
.
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
)
...
...
@@ -391,7 +354,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
.
ops
.
Link
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
target
.
ops
,
name
,
out
)
child
,
status
:=
parent
.
dirOps
()
.
Link
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
target
.
ops
,
name
,
out
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -403,7 +366,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
.
ops
.
Symlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
target
,
name
,
out
)
child
,
status
:=
parent
.
dirOps
()
.
Symlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
},
target
,
name
,
out
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -415,7 +378,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
.
ops
.
Readlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
})
result
,
status
:=
n
.
linkOps
()
.
Readlink
(
&
fuse
.
Context
{
Caller
:
header
.
Caller
,
Cancel
:
cancel
})
if
!
status
.
Ok
()
{
return
nil
,
status
}
...
...
@@ -454,7 +417,7 @@ func (b *rawBridge) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, a
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
.
ops
.
Open
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
input
.
Flags
)
f
,
flags
,
status
:=
n
.
fileOps
()
.
Open
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
input
.
Flags
)
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -488,28 +451,29 @@ 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
.
ops
.
Read
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
buf
,
int64
(
input
.
Offset
))
return
n
.
fileOps
()
.
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
.
ops
.
GetLk
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
,
&
out
.
Lk
)
return
n
.
fileOps
()
.
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
.
ops
.
SetLk
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
)
return
n
.
fileOps
()
.
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
.
ops
.
SetLkw
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
)
return
n
.
fileOps
()
.
SetLkw
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Owner
,
&
input
.
Lk
,
input
.
LkFlags
)
}
func
(
b
*
rawBridge
)
Release
(
input
*
fuse
.
ReleaseIn
)
{
// XXX should have cancel channel too.
n
,
f
:=
b
.
releaseFileEntry
(
input
.
NodeId
,
input
.
Fh
)
f
.
wg
.
Wait
()
n
.
ops
.
Release
(
f
.
file
)
n
.
fileOps
()
.
Release
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
nil
},
f
.
file
)
b
.
mu
.
Lock
()
defer
b
.
mu
.
Unlock
()
...
...
@@ -549,27 +513,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
.
ops
.
Write
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
data
,
int64
(
input
.
Offset
))
return
n
.
fileOps
()
.
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
.
ops
.
Flush
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
)
return
n
.
fileOps
()
.
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
.
ops
.
Fsync
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
FsyncFlags
)
return
n
.
fileOps
()
.
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
.
ops
.
Allocate
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
f
.
file
,
input
.
Offset
,
input
.
Length
,
input
.
Mode
)
return
n
.
fileOps
()
.
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
.
ops
.
OpenDir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
})
status
:=
n
.
dirOps
()
.
OpenDir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
})
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -585,7 +549,7 @@ func (b *rawBridge) getStream(cancel <-chan struct{}, input *fuse.ReadIn, inode
f
.
dirStream
.
Close
()
f
.
dirStream
=
nil
}
str
,
status
:=
inode
.
ops
.
ReadDir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
})
str
,
status
:=
inode
.
dirOps
()
.
ReadDir
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
})
if
!
status
.
Ok
()
{
return
status
}
...
...
@@ -654,7 +618,7 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out
return
fuse
.
OK
}
child
,
status
:=
n
.
ops
.
Lookup
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
e
.
Name
,
entryOut
)
child
,
status
:=
n
.
dirOps
()
.
Lookup
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
e
.
Name
,
entryOut
)
if
!
status
.
Ok
()
{
if
b
.
options
.
NegativeTimeout
!=
nil
{
entryOut
.
SetEntryTimeout
(
*
b
.
options
.
NegativeTimeout
)
...
...
@@ -676,7 +640,7 @@ 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
.
ops
.
Fsync
(
&
fuse
.
Context
{
Caller
:
input
.
Caller
,
Cancel
:
cancel
},
nil
,
input
.
FsyncFlags
)
return
n
.
fileOps
()
.
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
)
{
...
...
nodefs/default.go
View file @
4f60fdad
...
...
@@ -150,9 +150,9 @@ func (n *DefaultOperations) Flush(ctx context.Context, f FileHandle) fuse.Status
return
fuse
.
ENOSYS
}
func
(
n
*
DefaultOperations
)
Release
(
f
FileHandle
)
fuse
.
Status
{
func
(
n
*
DefaultOperations
)
Release
(
ctx
context
.
Context
,
f
FileHandle
)
fuse
.
Status
{
if
f
!=
nil
{
return
f
.
Release
()
return
f
.
Release
(
ctx
)
}
return
fuse
.
ENOSYS
}
...
...
@@ -165,41 +165,24 @@ func (n *DefaultOperations) Allocate(ctx context.Context, f FileHandle, off uint
return
fuse
.
ENOSYS
}
func
(
n
*
DefaultOperations
)
GetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
if
f
!=
nil
{
f
.
GetAttr
(
ctx
,
out
)
}
return
fuse
.
ENOSYS
}
func
(
n
*
DefaultOperations
)
Truncate
(
ctx
context
.
Context
,
f
FileHandle
,
size
uint64
)
fuse
.
Status
{
if
f
!=
nil
{
return
f
.
Truncate
(
ctx
,
size
)
}
func
(
n
*
DefaultOperations
)
GetAttr
(
ctx
context
.
Context
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
return
fuse
.
ENOSYS
}
func
(
n
*
DefaultOperations
)
Chown
(
ctx
context
.
Context
,
f
FileHandle
,
uid
uint32
,
gid
uint32
)
fuse
.
Status
{
func
(
n
*
DefaultOperations
)
FGetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
if
f
!=
nil
{
return
f
.
Chown
(
ctx
,
uid
,
gid
)
f
.
GetAttr
(
ctx
,
out
)
}
return
fuse
.
ENOSYS
}
func
(
n
*
DefaultOperations
)
Chmod
(
ctx
context
.
Context
,
f
FileHandle
,
perms
uint32
)
fuse
.
Status
{
if
f
!=
nil
{
return
f
.
Chmod
(
ctx
,
perms
)
}
func
(
n
*
DefaultOperations
)
SetAttr
(
ctx
context
.
Context
,
in
*
fuse
.
SetAttrIn
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
return
fuse
.
ENOSYS
}
func
(
n
*
DefaultOperations
)
Utimens
(
ctx
context
.
Context
,
f
FileHandle
,
atime
*
time
.
Time
,
mtime
*
time
.
Time
)
fuse
.
Status
{
func
(
n
*
DefaultOperations
)
FSetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
in
*
fuse
.
SetAttrIn
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
if
f
!=
nil
{
return
f
.
Utimens
(
ctx
,
atime
,
mtime
)
return
f
.
SetAttr
(
ctx
,
in
,
out
)
}
return
fuse
.
ENOSYS
...
...
@@ -265,7 +248,7 @@ func (f *DefaultFile) Flush(ctx context.Context) fuse.Status {
return
fuse
.
ENOSYS
}
func
(
f
*
DefaultFile
)
Release
()
fuse
.
Status
{
func
(
f
*
DefaultFile
)
Release
(
ctx
context
.
Context
)
fuse
.
Status
{
return
fuse
.
ENOSYS
}
...
...
@@ -273,6 +256,10 @@ func (f *DefaultFile) GetAttr(ctx context.Context, out *fuse.AttrOut) fuse.Statu
return
fuse
.
ENOSYS
}
func
(
f
*
DefaultFile
)
SetAttr
(
ctx
context
.
Context
,
in
*
fuse
.
SetAttrIn
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
return
fuse
.
ENOSYS
}
func
(
f
*
DefaultFile
)
Truncate
(
ctx
context
.
Context
,
size
uint64
)
fuse
.
Status
{
return
fuse
.
ENOSYS
}
...
...
nodefs/files.go
View file @
4f60fdad
...
...
@@ -45,7 +45,7 @@ func (f *loopbackFile) Write(ctx context.Context, data []byte, off int64) (uint3
return
uint32
(
n
),
fuse
.
ToStatus
(
err
)
}
func
(
f
*
loopbackFile
)
Release
()
fuse
.
Status
{
func
(
f
*
loopbackFile
)
Release
(
ctx
context
.
Context
)
fuse
.
Status
{
f
.
mu
.
Lock
()
err
:=
syscall
.
Close
(
f
.
fd
)
f
.
mu
.
Unlock
()
...
...
@@ -128,28 +128,68 @@ func (f *loopbackFile) setLock(ctx context.Context, owner uint64, lk *fuse.FileL
}
}
func
(
f
*
loopbackFile
)
Truncate
(
ctx
context
.
Context
,
size
uint64
)
fuse
.
Status
{
f
.
mu
.
Lock
()
r
:=
fuse
.
ToStatus
(
syscall
.
Ftruncate
(
f
.
fd
,
int64
(
size
)))
f
.
mu
.
Unlock
()
func
(
f
*
loopbackFile
)
SetAttr
(
ctx
context
.
Context
,
in
*
fuse
.
SetAttrIn
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
if
status
:=
f
.
setAttr
(
ctx
,
in
);
!
status
.
Ok
()
{
return
status
}
return
r
return
f
.
GetAttr
(
ctx
,
out
)
}
func
(
f
*
loopbackFile
)
Chmod
(
ctx
context
.
Context
,
mode
uint32
)
fuse
.
Status
{
func
(
f
*
loopbackFile
)
setAttr
(
ctx
context
.
Context
,
in
*
fuse
.
SetAttrIn
)
fuse
.
Status
{
f
.
mu
.
Lock
()
r
:=
fuse
.
ToStatus
(
syscall
.
Fchmod
(
f
.
fd
,
mode
))
f
.
mu
.
Unlock
()
defer
f
.
mu
.
Unlock
()
var
status
fuse
.
Status
if
mode
,
ok
:=
in
.
GetMode
();
ok
{
status
=
fuse
.
ToStatus
(
syscall
.
Fchmod
(
f
.
fd
,
mode
))
if
!
status
.
Ok
()
{
return
status
}
}
return
r
}
uid32
,
uOk
:=
in
.
GetUID
()
gid32
,
gOk
:=
in
.
GetGID
()
if
uOk
||
gOk
{
uid
:=
-
1
gid
:=
-
1
func
(
f
*
loopbackFile
)
Chown
(
ctx
context
.
Context
,
uid
uint32
,
gid
uint32
)
fuse
.
Status
{
f
.
mu
.
Lock
()
r
:=
fuse
.
ToStatus
(
syscall
.
Fchown
(
f
.
fd
,
int
(
uid
),
int
(
gid
)))
f
.
mu
.
Unlock
()
if
uOk
{
uid
=
int
(
uid32
)
}
if
gOk
{
gid
=
int
(
gid32
)
}
status
=
fuse
.
ToStatus
(
syscall
.
Fchown
(
f
.
fd
,
uid
,
gid
))
if
!
status
.
Ok
()
{
return
status
}
}
return
r
mtime
,
mok
:=
in
.
GetMTime
()
atime
,
aok
:=
in
.
GetATime
()
if
mok
||
aok
{
ap
:=
&
atime
mp
:=
&
mtime
if
!
aok
{
ap
=
nil
}
if
!
mok
{
mp
=
nil
}
status
=
f
.
utimens
(
ap
,
mp
)
if
!
status
.
Ok
()
{
return
status
}
}
if
sz
,
ok
:=
in
.
GetSize
();
ok
{
status
=
fuse
.
ToStatus
(
syscall
.
Ftruncate
(
f
.
fd
,
int64
(
sz
)))
if
!
status
.
Ok
()
{
return
status
}
}
return
fuse
.
OK
}
func
(
f
*
loopbackFile
)
GetAttr
(
ctx
context
.
Context
,
a
*
fuse
.
AttrOut
)
fuse
.
Status
{
...
...
nodefs/files_linux.go
View file @
4f60fdad
...
...
@@ -23,7 +23,7 @@ func (f *loopbackFile) Allocate(ctx context.Context, off uint64, sz uint64, mode
}
// Utimens - file handle based version of loopbackFileSystem.Utimens()
func
(
f
*
loopbackFile
)
Utimens
(
ctx
context
.
Context
,
a
*
time
.
Time
,
m
*
time
.
Time
)
fuse
.
Status
{
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
)
...
...
nodefs/inode.go
View file @
4f60fdad
...
...
@@ -88,6 +88,18 @@ type Inode struct {
parents
map
[
parentData
]
struct
{}
}
func
(
n
*
Inode
)
dirOps
()
DirOperations
{
return
n
.
ops
.
(
DirOperations
)
}
func
(
n
*
Inode
)
fileOps
()
FileOperations
{
return
n
.
ops
.
(
FileOperations
)
}
func
(
n
*
Inode
)
linkOps
()
SymlinkOperations
{
return
n
.
ops
.
(
SymlinkOperations
)
}
// FileID returns the (Ino, Gen) tuple for this node.
func
(
n
*
Inode
)
FileID
()
FileID
{
return
n
.
nodeID
...
...
nodefs/loopback.go
View file @
4f60fdad
...
...
@@ -37,7 +37,7 @@ func (n *loopbackNode) StatFs(ctx context.Context, out *fuse.StatfsOut) fuse.Sta
return
fuse
.
OK
}
func
(
n
*
loopbackRoot
)
GetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
func
(
n
*
loopbackRoot
)
GetAttr
(
ctx
context
.
Context
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
var
err
error
=
nil
st
:=
syscall
.
Stat_t
{}
err
=
syscall
.
Stat
(
n
.
root
,
&
st
)
...
...
@@ -253,7 +253,7 @@ func (n *loopbackNode) ReadDir(ctx context.Context) (DirStream, fuse.Status) {
return
NewLoopbackDirStream
(
n
.
path
())
}
func
(
n
*
loopbackNode
)
GetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
func
(
n
*
loopbackNode
)
F
GetAttr
(
ctx
context
.
Context
,
f
FileHandle
,
out
*
fuse
.
AttrOut
)
fuse
.
Status
{
if
f
!=
nil
{
return
f
.
GetAttr
(
ctx
,
out
)
}
...
...
@@ -270,7 +270,9 @@ func (n *loopbackNode) GetAttr(ctx context.Context, f FileHandle, out *fuse.Attr
return
fuse
.
OK
}
func
NewLoopback
(
root
string
)
Operations
{
// NewLoopback returns a root node for a loopback file system whose
// root is at the given root.
func
NewLoopback
(
root
string
)
DirOperations
{
n
:=
&
loopbackRoot
{
root
:
root
,
}
...
...
nodefs/simple_test.go
View file @
4f60fdad
...
...
@@ -34,7 +34,7 @@ type testCase struct {
origDir
string
mntDir
string
loopback
Operations
loopback
Dir
Operations
rawFS
fuse
.
RawFileSystem
server
*
fuse
.
Server
}
...
...
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