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
0f4e53e7
Commit
0f4e53e7
authored
Jan 25, 2011
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote branch 'origin/master' into gcopt
parents
0b0f4ddb
9e57c957
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
316 additions
and
92 deletions
+316
-92
.gitignore
.gitignore
+1
-0
README
README
+16
-4
example/main.go
example/main.go
+3
-3
examplelib/Makefile
examplelib/Makefile
+2
-1
examplelib/dummyfuse.go
examplelib/dummyfuse.go
+3
-6
examplelib/misc.go
examplelib/misc.go
+20
-0
examplelib/passthrough.go
examplelib/passthrough.go
+3
-3
examplelib/passthrough_test.go
examplelib/passthrough_test.go
+47
-21
examplelib/stackfs_test.go
examplelib/stackfs_test.go
+1
-1
fuse/direntry.go
fuse/direntry.go
+1
-1
fuse/misc.go
fuse/misc.go
+4
-0
fuse/mount.go
fuse/mount.go
+3
-3
fuse/pathfilesystem.go
fuse/pathfilesystem.go
+207
-45
fuse/types.go
fuse/types.go
+5
-4
No files found.
.gitignore
View file @
0f4e53e7
*~
*.6
8.out
.nfs*
_*
README
View file @
0f4e53e7
...
...
@@ -10,9 +10,6 @@ directory as a loopback:
./example/main -debug -threaded=false mountpoint /some/other/directory &
(cd mountpoint ; ls)
on my machine, compiles over loopback (threaded, without debug) are
about 2x slower compared to normal compiles.
Tested on:
- x86 32bits (Fedora 14).
...
...
@@ -21,7 +18,22 @@ Tested on:
LICENSE
Like Go, this library is distributed under the new BSD. See accompanying LICENSE file.
Like Go, this library is distributed under the new BSD license. See
accompanying LICENSE file.
BENCHMARKS
The speed of go-fuse is close to libfuse's speed (measurements on my
lenovo T60 laptop):
* 'find' in tree with 14k files. fs access: 0.06s, go-fuse: 3.5s, bbfs: 3.9
* 'ls -lR' in same tree: fs access: 0.5s, go-fuse: 9.5s, bbfs: 8.8s
* copying a 100 mb file: fs access: 200mb/s, go-fuse: 182mb/s, bbfs: 190mb/s
bbfs is a loopback filesystem written in C, see
http://www.cs.nmsu.edu/~pfeiffer/fuse-tutorial.tgz
CREDITS
...
...
example/main.go
View file @
0f4e53e7
...
...
@@ -23,9 +23,9 @@ func main() {
}
orig
:=
flag
.
Arg
(
0
)
pt
:=
examplelib
.
NewPassThroughFuse
(
orig
)
fs
:=
fuse
.
NewPathFileSystemConnector
(
pt
)
state
:=
fuse
.
NewMountState
(
fs
)
fs
:=
examplelib
.
NewPassThroughFuse
(
orig
)
conn
:=
fuse
.
NewPathFileSystemConnector
(
fs
)
state
:=
fuse
.
NewMountState
(
conn
)
state
.
Debug
=
*
debug
mountPoint
:=
flag
.
Arg
(
1
)
...
...
examplelib/Makefile
View file @
0f4e53e7
...
...
@@ -7,7 +7,8 @@ DEPS=../fuse
GOFILES
=
dummyfuse.go
\
passthrough.go
\
stackfs.go
stackfs.go
\
misc.go
include
$(GOROOT)/src/Make.pkg
examplelib/dummyfuse.go
View file @
0f4e53e7
...
...
@@ -194,11 +194,11 @@ func (self *DummyPathFuse) OpenDir(name string) (dir fuse.RawFuseDir, code fuse.
return
nil
,
fuse
.
ENOSYS
}
func
(
self
*
DummyPathFuse
)
Init
()
(
*
fuse
.
InitOut
,
fuse
.
Status
)
{
return
nil
,
fuse
.
ENOSYS
func
(
self
*
DummyPathFuse
)
Mount
(
conn
*
fuse
.
PathFileSystemConnector
)
(
fuse
.
Status
)
{
return
fuse
.
OK
}
func
(
self
*
DummyPathFuse
)
Destroy
()
{
func
(
self
*
DummyPathFuse
)
Unmount
()
{
}
func
(
self
*
DummyPathFuse
)
Access
(
name
string
,
mode
uint32
)
(
code
fuse
.
Status
)
{
...
...
@@ -213,6 +213,3 @@ func (self *DummyPathFuse) Utimens(name string, AtimeNs uint64, CtimeNs uint64)
return
fuse
.
ENOSYS
}
func
(
self
*
DummyPathFuse
)
SetOptions
(
*
fuse
.
PathFileSystemConnectorOptions
)
{
}
examplelib/misc.go
0 → 100644
View file @
0f4e53e7
package
examplelib
import
"os"
////////////////
func
IsDir
(
name
string
)
bool
{
fi
,
_
:=
os
.
Lstat
(
name
)
return
fi
!=
nil
&&
fi
.
IsDirectory
()
}
func
IsFile
(
name
string
)
bool
{
fi
,
_
:=
os
.
Lstat
(
name
)
return
fi
!=
nil
&&
fi
.
IsRegular
()
}
func
FileExists
(
name
string
)
bool
{
_
,
err
:=
os
.
Lstat
(
name
)
return
err
==
nil
}
examplelib/passthrough.go
View file @
0f4e53e7
...
...
@@ -25,11 +25,11 @@ func NewPassThroughFuse(root string) (out *PassThroughFuse) {
return
out
}
func
(
self
*
PassThroughFuse
)
Init
()
(
*
fuse
.
InitOut
,
fuse
.
Status
)
{
return
new
(
fuse
.
InitOut
),
fuse
.
OK
func
(
self
*
PassThroughFuse
)
Mount
(
conn
*
fuse
.
PathFileSystemConnector
)
(
fuse
.
Status
)
{
return
fuse
.
OK
}
func
(
self
*
PassThroughFuse
)
Destroy
()
{
func
(
self
*
PassThroughFuse
)
Unmount
()
{
}
...
...
examplelib/passthrough_test.go
View file @
0f4e53e7
...
...
@@ -16,23 +16,6 @@ import (
var
_
=
strings
.
Join
var
_
=
log
.
Println
////////////////
func
IsDir
(
name
string
)
bool
{
fi
,
_
:=
os
.
Lstat
(
name
)
return
fi
!=
nil
&&
fi
.
IsDirectory
()
}
func
IsFile
(
name
string
)
bool
{
fi
,
_
:=
os
.
Lstat
(
name
)
return
fi
!=
nil
&&
fi
.
IsRegular
()
}
func
FileExists
(
name
string
)
bool
{
_
,
err
:=
os
.
Lstat
(
name
)
return
err
==
nil
}
////////////////
// state for our testcase, mostly constants
...
...
@@ -50,6 +33,7 @@ type testCase struct {
origSubfile
string
tester
*
testing
.
T
state
*
fuse
.
MountState
connector
*
fuse
.
PathFileSystemConnector
}
// Create and mount filesystem.
...
...
@@ -68,10 +52,11 @@ func (self *testCase) Setup(t *testing.T) {
self
.
origFile
=
path
.
Join
(
self
.
origDir
,
name
)
self
.
origSubdir
=
path
.
Join
(
self
.
origDir
,
subdir
)
self
.
origSubfile
=
path
.
Join
(
self
.
origSubdir
,
"subfile"
)
fs
:=
fuse
.
NewPathFileSystemConnector
(
NewPassThroughFuse
(
self
.
origDir
))
self
.
state
=
fuse
.
NewMountState
(
fs
)
pfs
:=
NewPassThroughFuse
(
self
.
origDir
)
self
.
connector
=
fuse
.
NewPathFileSystemConnector
(
pfs
)
self
.
connector
.
Debug
=
true
self
.
state
=
fuse
.
NewMountState
(
self
.
connector
)
self
.
state
.
Mount
(
self
.
mountPoint
)
//self.state.Debug = false
...
...
@@ -610,3 +595,44 @@ func TestMount(t *testing.T) {
ts
.
testLargeDirRead
()
ts
.
Cleanup
()
}
func
TestRecursiveMount
(
t
*
testing
.
T
)
{
ts
:=
new
(
testCase
)
ts
.
Setup
(
t
)
f
,
err
:=
os
.
Open
(
path
.
Join
(
ts
.
mountPoint
,
"hello.txt"
),
os
.
O_WRONLY
|
os
.
O_CREATE
,
0777
)
if
err
!=
nil
{
t
.
Errorf
(
"open write err %v"
,
err
)
}
f
.
WriteString
(
"bla"
)
f
.
Close
()
pfs2
:=
NewPassThroughFuse
(
ts
.
origDir
)
code
:=
ts
.
connector
.
Mount
(
"/hello.txt"
,
pfs2
)
if
code
!=
fuse
.
EINVAL
{
t
.
Error
(
"expect EINVAL"
,
code
)
}
submnt
:=
path
.
Join
(
ts
.
mountPoint
,
"mnt"
)
err
=
os
.
Mkdir
(
submnt
,
0777
)
if
err
!=
nil
{
t
.
Errorf
(
"mkdir"
)
}
code
=
ts
.
connector
.
Mount
(
"/mnt"
,
pfs2
)
if
code
!=
fuse
.
OK
{
t
.
Errorf
(
"mkdir"
)
}
_
,
err
=
os
.
Lstat
(
submnt
)
if
err
!=
nil
{
t
.
Error
(
"lstat submount"
,
err
)
}
_
,
err
=
os
.
Lstat
(
path
.
Join
(
submnt
,
"hello.txt"
))
if
err
!=
nil
{
t
.
Error
(
"lstat submount/file"
,
err
)
}
ts
.
Cleanup
()
}
examplelib/stackfs_test.go
View file @
0f4e53e7
...
...
@@ -43,7 +43,7 @@ func (self *stackFsTestCase) Setup(t *testing.T) {
fs1
:=
fuse
.
NewPathFileSystemConnector
(
NewPassThroughFuse
(
self
.
origDir1
))
fs2
:=
fuse
.
NewPathFileSystemConnector
(
NewPassThroughFuse
(
self
.
origDir2
))
self
.
fs
=
NewSubmountFileSystem
()
attr
:=
fuse
.
Attr
{
...
...
fuse/direntry.go
View file @
0f4e53e7
...
...
@@ -31,7 +31,7 @@ func (de *DirEntryList) Add(name []byte, inode uint64, mode uint32) bool {
dirent
.
Off
=
de
.
offset
dirent
.
Ino
=
inode
dirent
.
NameLen
=
uint32
(
len
(
name
))
dirent
.
Typ
=
(
mode
&
0170000
)
>>
12
dirent
.
Typ
=
ModeToType
(
mode
)
err
:=
binary
.
Write
(
&
de
.
buf
,
binary
.
LittleEndian
,
dirent
)
if
err
!=
nil
{
...
...
fuse/misc.go
View file @
0f4e53e7
...
...
@@ -291,3 +291,7 @@ func NegativeEntry(time float64) *EntryOut {
SplitNs
(
time
,
&
out
.
EntryValid
,
&
out
.
EntryValidNsec
)
return
out
}
func
ModeToType
(
mode
uint32
)
uint32
{
return
(
mode
&
0170000
)
>>
12
}
fuse/mount.go
View file @
0f4e53e7
...
...
@@ -96,10 +96,10 @@ func getFuseConn(local *os.File) (f *os.File, err os.Error) {
var
data
[
4
]
byte
control
:=
make
([]
byte
,
4
*
256
)
// n, oobn, recvflags - todo: error checking.
_
,
oobn
,
_
,
// n, oobn, recvflags
, from, errno
- todo: error checking.
_
,
oobn
,
_
,
_
,
errno
:=
syscall
.
Recvmsg
(
local
.
Fd
(),
data
[
:
],
control
[
:
],
nil
,
0
)
local
.
Fd
(),
data
[
:
],
control
[
:
],
0
)
if
errno
!=
0
{
return
}
...
...
fuse/pathfilesystem.go
View file @
0f4e53e7
...
...
@@ -4,6 +4,7 @@ import (
"bytes"
"sync"
"fmt"
"log"
"path"
"strings"
)
...
...
@@ -15,8 +16,15 @@ type inodeData struct {
Name
string
LookupCount
int
Type
uint32
// Number of inodeData that have this as parent.
RefCount
int
// If non-nil the file system mounted here.
Mounted
PathFilesystem
// If yes, we are looking to unmount the mounted fs.
unmountPending
bool
}
// Should implement some hash table method instead?
...
...
@@ -33,18 +41,22 @@ func (self *inodeData) Key() string {
return
inodeDataKey
(
p
,
self
.
Name
)
}
func
(
self
*
inodeData
)
GetPath
()
string
{
func
(
self
*
inodeData
)
GetPath
()
(
path
string
,
fs
PathFilesystem
)
{
// TODO - softcode this.
var
components
[
100
]
string
j
:=
len
(
components
)
for
p
:=
self
;
p
!=
nil
&&
p
.
NodeId
!=
FUSE_ROOT_ID
;
p
=
p
.
Parent
{
inode
:=
self
for
;
inode
!=
nil
&&
inode
.
Mounted
==
nil
;
inode
=
inode
.
Parent
{
j
--
components
[
j
]
=
p
.
Name
components
[
j
]
=
inode
.
Name
}
fullPath
:=
strings
.
Join
(
components
[
j
:
],
"/"
)
return
fullPath
if
!
inode
.
unmountPending
{
fs
=
inode
.
Mounted
}
return
fullPath
,
fs
}
type
TimeoutOptions
struct
{
...
...
@@ -66,8 +78,6 @@ type PathFileSystemConnectorOptions struct {
}
type
PathFileSystemConnector
struct
{
fileSystem
PathFilesystem
// Protects the hashmap, its contents and the nextFreeInode counter.
lock
sync
.
RWMutex
...
...
@@ -84,8 +94,9 @@ type PathFileSystemConnector struct {
inodePathMap
map
[
string
]
*
inodeData
inodePathMapByInode
map
[
uint64
]
*
inodeData
nextFreeInode
uint64
options
PathFileSystemConnectorOptions
Debug
bool
}
// Must be called with lock held.
...
...
@@ -156,7 +167,7 @@ func (self *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int
data
,
ok
:=
self
.
inodePathMapByInode
[
nodeId
]
if
ok
{
data
.
LookupCount
-=
forgetCount
if
data
.
LookupCount
<=
0
&&
data
.
RefCount
<=
0
{
if
data
.
LookupCount
<=
0
&&
data
.
RefCount
<=
0
&&
(
data
.
Mounted
==
nil
||
data
.
unmountPending
)
{
self
.
inodePathMap
[
data
.
Key
()]
=
nil
,
false
}
}
...
...
@@ -219,6 +230,29 @@ func (self *PathFileSystemConnector) unlinkUpdate(nodeid uint64, name string) {
}
}
// Walk the file system starting from the root.
func
(
self
*
PathFileSystemConnector
)
findInode
(
fullPath
string
)
*
inodeData
{
fullPath
=
strings
.
TrimLeft
(
path
.
Clean
(
fullPath
),
"/"
)
comps
:=
strings
.
Split
(
fullPath
,
"/"
,
-
1
)
self
.
lock
.
RLock
()
defer
self
.
lock
.
RUnlock
()
node
:=
self
.
inodePathMapByInode
[
FUSE_ROOT_ID
]
for
i
,
component
:=
range
(
comps
)
{
if
len
(
component
)
==
0
{
continue
}
key
:=
inodeDataKey
(
node
.
NodeId
,
component
)
node
=
self
.
inodePathMap
[
key
]
if
node
==
nil
{
panic
(
fmt
.
Sprintf
(
"findInode: %v %v"
,
i
,
fullPath
))
}
}
return
node
}
////////////////////////////////////////////////////////////////
// Below routines should not access inodePathMap(ByInode) directly,
// and there need no locking.
...
...
@@ -227,11 +261,11 @@ func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector
out
=
new
(
PathFileSystemConnector
)
out
.
inodePathMap
=
make
(
map
[
string
]
*
inodeData
)
out
.
inodePathMapByInode
=
make
(
map
[
uint64
]
*
inodeData
)
out
.
fileSystem
=
fs
rootData
:=
new
(
inodeData
)
rootData
.
NodeId
=
FUSE_ROOT_ID
rootData
.
Type
=
ModeToType
(
S_IFDIR
)
out
.
inodePathMap
[
rootData
.
Key
()]
=
rootData
out
.
inodePathMapByInode
[
FUSE_ROOT_ID
]
=
rootData
out
.
nextFreeInode
=
FUSE_ROOT_ID
+
1
...
...
@@ -240,21 +274,79 @@ func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector
out
.
options
.
AttrTimeout
=
1.0
out
.
options
.
EntryTimeout
=
1.0
fs
.
SetOptions
(
&
out
.
options
)
if
code
:=
out
.
Mount
(
"/"
,
fs
);
code
!=
OK
{
panic
(
"root mount failed."
)
}
return
out
}
func
(
self
*
PathFileSystemConnector
)
GetPath
(
nodeid
uint64
)
string
{
func
(
self
*
PathFileSystemConnector
)
SetOptions
(
opts
PathFileSystemConnectorOptions
)
{
self
.
options
=
opts
}
func
(
self
*
PathFileSystemConnector
)
Mount
(
path
string
,
fs
PathFilesystem
)
Status
{
node
:=
self
.
findInode
(
path
)
// TODO - check that fs was not mounted elsewhere.
if
node
.
RefCount
>
0
{
return
EBUSY
}
if
node
.
Type
&
ModeToType
(
S_IFDIR
)
==
0
{
return
EINVAL
}
code
:=
fs
.
Mount
(
self
)
if
code
!=
OK
{
if
self
.
Debug
{
log
.
Println
(
"Mount error: "
,
path
,
code
)
}
return
code
}
if
self
.
Debug
{
log
.
Println
(
"Mount: "
,
fs
,
"on"
,
path
,
node
)
}
// TODO - this is technically a race-condition.
node
.
Mounted
=
fs
node
.
unmountPending
=
false
return
OK
}
func
(
self
*
PathFileSystemConnector
)
Unmount
(
path
string
)
Status
{
node
:=
self
.
findInode
(
path
)
if
node
==
nil
||
node
.
Mounted
==
nil
{
panic
(
path
)
}
// TODO - check if we have open files.
if
self
.
Debug
{
log
.
Println
(
"Unmount: "
,
node
)
}
// node manipulations are racy?
if
node
.
RefCount
>
0
{
node
.
Mounted
.
Unmount
()
node
.
unmountPending
=
true
}
else
{
node
.
Mounted
=
nil
}
return
OK
}
func
(
self
*
PathFileSystemConnector
)
GetPath
(
nodeid
uint64
)
(
path
string
,
fs
PathFilesystem
)
{
return
self
.
getInodeData
(
nodeid
)
.
GetPath
()
}
func
(
self
*
PathFileSystemConnector
)
Init
(
h
*
InHeader
,
input
*
InitIn
)
(
*
InitOut
,
Status
)
{
return
self
.
fileSystem
.
Init
()
// TODO ?
return
new
(
InitOut
),
OK
}
func
(
self
*
PathFileSystemConnector
)
Destroy
(
h
*
InHeader
,
input
*
InitIn
)
{
self
.
fileSystem
.
Destroy
()
// TODO - umount all.
}
func
(
self
*
PathFileSystemConnector
)
Lookup
(
header
*
InHeader
,
name
string
)
(
out
*
EntryOut
,
status
Status
)
{
...
...
@@ -263,8 +355,14 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
// TODO - fuse.c has special case code for name == "." and
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// Init.
fullPath
:=
path
.
Join
(
parent
.
GetPath
(),
name
)
attr
,
err
:=
self
.
fileSystem
.
GetAttr
(
fullPath
)
fullPath
,
fs
:=
parent
.
GetPath
()
if
fs
==
nil
{
return
NegativeEntry
(
self
.
options
.
NegativeTimeout
),
OK
}
fullPath
=
path
.
Join
(
fullPath
,
name
)
attr
,
err
:=
fs
.
GetAttr
(
fullPath
)
if
err
==
ENOENT
&&
self
.
options
.
NegativeTimeout
>
0.0
{
return
NegativeEntry
(
self
.
options
.
NegativeTimeout
),
OK
}
...
...
@@ -274,7 +372,8 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
}
data
:=
self
.
lookupUpdate
(
header
.
NodeId
,
name
)
data
.
Type
=
ModeToType
(
attr
.
Mode
)
out
=
new
(
EntryOut
)
out
.
NodeId
=
data
.
NodeId
out
.
Generation
=
1
// where to get the generation?
...
...
@@ -282,7 +381,6 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
SplitNs
(
self
.
options
.
EntryTimeout
,
&
out
.
EntryValid
,
&
out
.
EntryValidNsec
)
SplitNs
(
self
.
options
.
AttrTimeout
,
&
out
.
AttrValid
,
&
out
.
AttrValidNsec
)
out
.
Attr
=
*
attr
return
out
,
OK
}
...
...
@@ -291,7 +389,12 @@ func (self *PathFileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
}
func
(
self
*
PathFileSystemConnector
)
GetAttr
(
header
*
InHeader
,
input
*
GetAttrIn
)
(
out
*
AttrOut
,
code
Status
)
{
attr
,
err
:=
self
.
fileSystem
.
GetAttr
(
self
.
GetPath
(
header
.
NodeId
))
// TODO - should we update inodeData.Type?
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
nil
,
ENOENT
}
attr
,
err
:=
fs
.
GetAttr
(
fullPath
)
if
err
!=
OK
{
return
nil
,
err
}
...
...
@@ -305,8 +408,12 @@ func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn)
}
func
(
self
*
PathFileSystemConnector
)
OpenDir
(
header
*
InHeader
,
input
*
OpenIn
)
(
flags
uint32
,
fuseFile
RawFuseDir
,
status
Status
)
{
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
0
,
nil
,
ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
f
,
err
:=
self
.
fileSystem
.
OpenDir
(
self
.
GetPath
(
header
.
NodeId
)
)
f
,
err
:=
fs
.
OpenDir
(
fullPath
)
if
err
!=
OK
{
return
0
,
nil
,
err
}
...
...
@@ -315,8 +422,12 @@ func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (f
}
func
(
self
*
PathFileSystemConnector
)
Open
(
header
*
InHeader
,
input
*
OpenIn
)
(
flags
uint32
,
fuseFile
RawFuseFile
,
status
Status
)
{
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
0
,
nil
,
ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
f
,
err
:=
self
.
fileSystem
.
Open
(
self
.
GetPath
(
header
.
NodeId
)
,
input
.
Flags
)
f
,
err
:=
fs
.
Open
(
fullPath
,
input
.
Flags
)
if
err
!=
OK
{
return
0
,
nil
,
err
}
...
...
@@ -327,19 +438,23 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn)
var
err
Status
=
OK
// TODO - support Fh. (FSetAttr/FGetAttr/FTruncate.)
fullPath
:=
self
.
GetPath
(
header
.
NodeId
)
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
nil
,
ENOENT
}
if
input
.
Valid
&
FATTR_MODE
!=
0
{
err
=
self
.
fileSystem
.
Chmod
(
fullPath
,
input
.
Mode
)
err
=
fs
.
Chmod
(
fullPath
,
input
.
Mode
)
}
if
err
!=
OK
&&
(
input
.
Valid
&
FATTR_UID
!=
0
||
input
.
Valid
&
FATTR_GID
!=
0
)
{
// TODO - can we get just FATTR_GID but not FATTR_UID ?
err
=
self
.
fileSystem
.
Chown
(
fullPath
,
uint32
(
input
.
Uid
),
uint32
(
input
.
Gid
))
err
=
fs
.
Chown
(
fullPath
,
uint32
(
input
.
Uid
),
uint32
(
input
.
Gid
))
}
if
input
.
Valid
&
FATTR_SIZE
!=
0
{
self
.
fileSystem
.
Truncate
(
fullPath
,
input
.
Size
)
fs
.
Truncate
(
fullPath
,
input
.
Size
)
}
if
err
!=
OK
&&
(
input
.
Valid
&
FATTR_ATIME
!=
0
||
input
.
Valid
&
FATTR_MTIME
!=
0
)
{
err
=
self
.
fileSystem
.
Utimens
(
fullPath
,
err
=
fs
.
Utimens
(
fullPath
,
uint64
(
input
.
Atime
*
1e9
)
+
uint64
(
input
.
Atimensec
),
uint64
(
input
.
Mtime
*
1e9
)
+
uint64
(
input
.
Mtimensec
))
}
...
...
@@ -356,14 +471,21 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn)
}
func
(
self
*
PathFileSystemConnector
)
Readlink
(
header
*
InHeader
)
(
out
[]
byte
,
code
Status
)
{
fullPath
:=
self
.
GetPath
(
header
.
NodeId
)
val
,
err
:=
self
.
fileSystem
.
Readlink
(
fullPath
)
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
nil
,
ENOENT
}
val
,
err
:=
fs
.
Readlink
(
fullPath
)
return
bytes
.
NewBufferString
(
val
)
.
Bytes
(),
err
}
func
(
self
*
PathFileSystemConnector
)
Mknod
(
header
*
InHeader
,
input
*
MknodIn
,
name
string
)
(
out
*
EntryOut
,
code
Status
)
{
fullPath
:=
path
.
Join
(
self
.
GetPath
(
header
.
NodeId
),
name
)
err
:=
self
.
fileSystem
.
Mknod
(
fullPath
,
input
.
Mode
,
uint32
(
input
.
Rdev
))
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
nil
,
ENOENT
}
fullPath
=
path
.
Join
(
fullPath
,
name
)
err
:=
fs
.
Mknod
(
fullPath
,
input
.
Mode
,
uint32
(
input
.
Rdev
))
if
err
!=
OK
{
return
nil
,
err
}
...
...
@@ -371,7 +493,11 @@ func (self *PathFileSystemConnector) Mknod(header *InHeader, input *MknodIn, nam
}
func
(
self
*
PathFileSystemConnector
)
Mkdir
(
header
*
InHeader
,
input
*
MkdirIn
,
name
string
)
(
out
*
EntryOut
,
code
Status
)
{
err
:=
self
.
fileSystem
.
Mkdir
(
path
.
Join
(
self
.
GetPath
(
header
.
NodeId
),
name
),
input
.
Mode
)
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
nil
,
ENOENT
}
err
:=
fs
.
Mkdir
(
path
.
Join
(
fullPath
,
name
),
input
.
Mode
)
if
err
!=
OK
{
return
nil
,
err
}
...
...
@@ -380,7 +506,11 @@ func (self *PathFileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, nam
}
func
(
self
*
PathFileSystemConnector
)
Unlink
(
header
*
InHeader
,
name
string
)
(
code
Status
)
{
code
=
self
.
fileSystem
.
Unlink
(
path
.
Join
(
self
.
GetPath
(
header
.
NodeId
),
name
))
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
ENOENT
}
code
=
fs
.
Unlink
(
path
.
Join
(
fullPath
,
name
))
// Like fuse.c, we update our internal tables.
self
.
unlinkUpdate
(
header
.
NodeId
,
name
)
...
...
@@ -389,13 +519,21 @@ func (self *PathFileSystemConnector) Unlink(header *InHeader, name string) (code
}
func
(
self
*
PathFileSystemConnector
)
Rmdir
(
header
*
InHeader
,
name
string
)
(
code
Status
)
{
code
=
self
.
fileSystem
.
Rmdir
(
path
.
Join
(
self
.
GetPath
(
header
.
NodeId
),
name
))
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
ENOENT
}
code
=
fs
.
Rmdir
(
path
.
Join
(
fullPath
,
name
))
self
.
unlinkUpdate
(
header
.
NodeId
,
name
)
return
code
}
func
(
self
*
PathFileSystemConnector
)
Symlink
(
header
*
InHeader
,
pointedTo
string
,
linkName
string
)
(
out
*
EntryOut
,
code
Status
)
{
err
:=
self
.
fileSystem
.
Symlink
(
pointedTo
,
path
.
Join
(
self
.
GetPath
(
header
.
NodeId
),
linkName
))
fullPath
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
nil
,
ENOENT
}
err
:=
fs
.
Symlink
(
pointedTo
,
path
.
Join
(
fullPath
,
linkName
))
if
err
!=
OK
{
return
nil
,
err
}
...
...
@@ -405,10 +543,18 @@ func (self *PathFileSystemConnector) Symlink(header *InHeader, pointedTo string,
}
func
(
self
*
PathFileSystemConnector
)
Rename
(
header
*
InHeader
,
input
*
RenameIn
,
oldName
string
,
newName
string
)
(
code
Status
)
{
oldPath
:=
path
.
Join
(
self
.
GetPath
(
header
.
NodeId
),
oldName
)
newPath
:=
path
.
Join
(
self
.
GetPath
(
input
.
Newdir
),
newName
)
code
=
self
.
fileSystem
.
Rename
(
oldPath
,
newPath
)
oldPath
,
oldFs
:=
self
.
GetPath
(
header
.
NodeId
)
newPath
,
fs
:=
self
.
GetPath
(
input
.
Newdir
)
if
fs
==
nil
||
oldFs
==
nil
{
return
ENOENT
}
if
fs
!=
oldFs
{
return
EXDEV
}
oldPath
=
path
.
Join
(
oldPath
,
oldName
)
newPath
=
path
.
Join
(
newPath
,
newName
)
code
=
fs
.
Rename
(
oldPath
,
newPath
)
if
code
!=
OK
{
return
}
...
...
@@ -425,9 +571,18 @@ func (self *PathFileSystemConnector) Rename(header *InHeader, input *RenameIn, o
}
func
(
self
*
PathFileSystemConnector
)
Link
(
header
*
InHeader
,
input
*
LinkIn
,
filename
string
)
(
out
*
EntryOut
,
code
Status
)
{
orig
:=
self
.
GetPath
(
input
.
Oldnodeid
)
newName
:=
path
.
Join
(
self
.
GetPath
(
header
.
NodeId
),
filename
)
err
:=
self
.
fileSystem
.
Link
(
orig
,
newName
)
orig
,
fs
:=
self
.
GetPath
(
input
.
Oldnodeid
)
newName
,
newFs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
||
newFs
==
nil
{
return
nil
,
ENOENT
}
if
newFs
!=
fs
{
return
nil
,
EXDEV
}
newName
=
path
.
Join
(
newName
,
filename
)
err
:=
fs
.
Link
(
orig
,
newName
)
if
err
!=
OK
{
return
nil
,
err
...
...
@@ -437,14 +592,21 @@ func (self *PathFileSystemConnector) Link(header *InHeader, input *LinkIn, filen
}
func
(
self
*
PathFileSystemConnector
)
Access
(
header
*
InHeader
,
input
*
AccessIn
)
(
code
Status
)
{
return
self
.
fileSystem
.
Access
(
self
.
GetPath
(
header
.
NodeId
),
input
.
Mask
)
p
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
ENOENT
}
return
fs
.
Access
(
p
,
input
.
Mask
)
}
func
(
self
*
PathFileSystemConnector
)
Create
(
header
*
InHeader
,
input
*
CreateIn
,
name
string
)
(
flags
uint32
,
fuseFile
RawFuseFile
,
out
*
EntryOut
,
code
Status
)
{
directory
:=
self
.
GetPath
(
header
.
NodeId
)
directory
,
fs
:=
self
.
GetPath
(
header
.
NodeId
)
if
fs
==
nil
{
return
0
,
nil
,
nil
,
ENOENT
}
fullPath
:=
path
.
Join
(
directory
,
name
)
f
,
err
:=
self
.
fileSystem
.
Create
(
fullPath
,
uint32
(
input
.
Flags
),
input
.
Mode
)
f
,
err
:=
fs
.
Create
(
fullPath
,
uint32
(
input
.
Flags
),
input
.
Mode
)
if
err
!=
OK
{
return
0
,
nil
,
nil
,
err
}
...
...
fuse/types.go
View file @
0f4e53e7
...
...
@@ -92,6 +92,9 @@ const (
ENOTDIR
=
Status
(
syscall
.
ENOTDIR
)
EACCES
=
Status
(
syscall
.
EACCES
)
EPERM
=
Status
(
syscall
.
EPERM
)
EBUSY
=
Status
(
syscall
.
EBUSY
)
EINVAL
=
Status
(
syscall
.
EINVAL
)
EXDEV
=
Status
(
syscall
.
EXDEV
)
)
type
Opcode
int
...
...
@@ -568,14 +571,12 @@ type PathFilesystem interface {
OpenDir
(
name
string
)
(
dir
RawFuseDir
,
code
Status
)
// TODO - what is a good interface?
Init
()
(
*
InitOut
,
Status
)
Destroy
()
Mount
(
connector
*
PathFileSystemConnector
)
Status
Unmount
()
Access
(
name
string
,
mode
uint32
)
(
code
Status
)
Create
(
name
string
,
flags
uint32
,
mode
uint32
)
(
file
RawFuseFile
,
code
Status
)
Utimens
(
name
string
,
AtimeNs
uint64
,
CtimeNs
uint64
)
(
code
Status
)
// unimplemented: poll, ioctl, bmap.
SetOptions
(
*
PathFileSystemConnectorOptions
)
}
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