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
cfe6a430
Commit
cfe6a430
authored
Apr 22, 2011
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Split pathfilesystem.go.
parent
1abfc5d4
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
494 additions
and
487 deletions
+494
-487
fuse/Makefile
fuse/Makefile
+2
-1
fuse/pathfilesystem.go
fuse/pathfilesystem.go
+0
-486
fuse/pathops.go
fuse/pathops.go
+492
-0
No files found.
fuse/Makefile
View file @
cfe6a430
...
...
@@ -20,7 +20,8 @@ GOFILES=misc.go\
xattr.go
\
devnull.go
\
pathdebug.go
\
opcode.go
opcode.go
\
pathops.go
\
include
$(GOROOT)/src/Make.pkg
fuse/pathfilesystem.go
View file @
cfe6a430
package
fuse
import
(
"bytes"
"fmt"
"log"
"path/filepath"
"strings"
"sync"
...
...
@@ -312,7 +310,6 @@ func (me *FileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) {
}
func
(
me
*
FileSystemConnector
)
considerDropInode
(
n
*
inode
)
{
// TODO - this should probably not happen at all.
if
n
.
LookupCount
<=
0
&&
len
(
n
.
Children
)
==
0
&&
(
n
.
mount
==
nil
||
n
.
mount
.
unmountPending
)
&&
n
.
OpenCount
<=
0
{
n
.
setParent
(
nil
)
...
...
@@ -388,486 +385,3 @@ func EmptyFileSystemConnector() (out *FileSystemConnector) {
out
.
verify
()
return
out
}
func
NewFileSystemConnector
(
fs
FileSystem
)
(
out
*
FileSystemConnector
)
{
out
=
EmptyFileSystemConnector
()
if
code
:=
out
.
Mount
(
"/"
,
fs
);
code
!=
OK
{
panic
(
"root mount failed."
)
}
out
.
verify
()
return
out
}
func
(
me
*
FileSystemConnector
)
SetOptions
(
opts
FileSystemConnectorOptions
)
{
me
.
options
=
opts
}
func
(
me
*
FileSystemConnector
)
Mount
(
mountPoint
string
,
fs
FileSystem
)
Status
{
var
node
*
inode
if
mountPoint
!=
"/"
{
dirParent
,
base
:=
filepath
.
Split
(
mountPoint
)
dirParentNode
:=
me
.
findInode
(
dirParent
)
// Make sure we know the mount point.
_
,
_
=
me
.
internalLookup
(
dirParentNode
,
base
,
0
)
}
node
=
me
.
findInode
(
mountPoint
)
if
!
node
.
IsDir
()
{
return
EINVAL
}
me
.
lock
.
Lock
()
hasChildren
:=
len
(
node
.
Children
)
>
0
// don't use defer, as we dont want to hold the lock during
// fs.Mount().
me
.
lock
.
Unlock
()
if
hasChildren
{
return
EBUSY
}
code
:=
fs
.
Mount
(
me
)
if
code
!=
OK
{
if
me
.
Debug
{
log
.
Println
(
"Mount error: "
,
mountPoint
,
code
)
}
return
code
}
if
me
.
Debug
{
log
.
Println
(
"Mount: "
,
fs
,
"on"
,
mountPoint
,
node
)
}
node
.
mount
=
newMount
(
fs
)
me
.
fileLock
.
Lock
()
defer
me
.
fileLock
.
Unlock
()
node
.
OpenCount
++
return
OK
}
func
(
me
*
FileSystemConnector
)
Unmount
(
path
string
)
Status
{
node
:=
me
.
findInode
(
path
)
if
node
==
nil
{
panic
(
path
)
}
mount
:=
node
.
mount
if
mount
==
nil
{
panic
(
path
)
}
// Need to lock to look at node.Children
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
me
.
fileLock
.
Lock
()
defer
me
.
fileLock
.
Unlock
()
// 1 = our own mount.
if
node
.
totalOpenCount
()
>
1
{
log
.
Println
(
"Umount - busy: "
,
mount
)
return
EBUSY
}
if
me
.
Debug
{
log
.
Println
(
"Unmount: "
,
mount
)
}
if
len
(
node
.
Children
)
>
0
{
mount
.
fs
.
Unmount
()
mount
.
unmountPending
=
true
}
else
{
node
.
mount
=
nil
}
node
.
OpenCount
--
return
OK
}
func
(
me
*
FileSystemConnector
)
GetPath
(
nodeid
uint64
)
(
path
string
,
mount
*
mountData
,
node
*
inode
)
{
n
:=
me
.
getInodeData
(
nodeid
)
p
,
m
:=
n
.
GetPath
()
return
p
,
m
,
n
}
func
(
me
*
FileSystemConnector
)
Init
(
h
*
InHeader
,
input
*
InitIn
)
(
*
InitOut
,
Status
)
{
// TODO ?
return
&
InitOut
{},
OK
}
func
(
me
*
FileSystemConnector
)
Destroy
(
h
*
InHeader
,
input
*
InitIn
)
{
// TODO - umount all.
}
func
(
me
*
FileSystemConnector
)
Lookup
(
header
*
InHeader
,
name
string
)
(
out
*
EntryOut
,
status
Status
)
{
parent
:=
me
.
getInodeData
(
header
.
NodeId
)
return
me
.
internalLookup
(
parent
,
name
,
1
)
}
func
(
me
*
FileSystemConnector
)
internalLookup
(
parent
*
inode
,
name
string
,
lookupCount
int
)
(
out
*
EntryOut
,
status
Status
)
{
out
,
status
,
_
=
me
.
internalLookupWithNode
(
parent
,
name
,
lookupCount
)
return
out
,
status
}
func
(
me
*
FileSystemConnector
)
internalLookupWithNode
(
parent
*
inode
,
name
string
,
lookupCount
int
)
(
out
*
EntryOut
,
status
Status
,
node
*
inode
)
{
// TODO - fuse.c has special case code for name == "." and
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// Init.
fullPath
,
mount
:=
parent
.
GetPath
()
if
mount
==
nil
{
return
NegativeEntry
(
me
.
options
.
NegativeTimeout
),
OK
,
nil
}
fullPath
=
filepath
.
Join
(
fullPath
,
name
)
attr
,
err
:=
mount
.
fs
.
GetAttr
(
fullPath
)
if
err
==
ENOENT
&&
me
.
options
.
NegativeTimeout
>
0.0
{
return
NegativeEntry
(
me
.
options
.
NegativeTimeout
),
OK
,
nil
}
if
err
!=
OK
{
return
nil
,
err
,
nil
}
data
:=
me
.
lookupUpdate
(
parent
,
name
,
attr
.
Mode
&
S_IFDIR
!=
0
)
data
.
LookupCount
+=
lookupCount
out
=
&
EntryOut
{
NodeId
:
data
.
NodeId
,
Generation
:
1
,
// where to get the generation?
}
SplitNs
(
me
.
options
.
EntryTimeout
,
&
out
.
EntryValid
,
&
out
.
EntryValidNsec
)
SplitNs
(
me
.
options
.
AttrTimeout
,
&
out
.
AttrValid
,
&
out
.
AttrValidNsec
)
out
.
Attr
=
*
attr
out
.
Attr
.
Ino
=
data
.
NodeId
return
out
,
OK
,
data
}
func
(
me
*
FileSystemConnector
)
Forget
(
h
*
InHeader
,
input
*
ForgetIn
)
{
me
.
forgetUpdate
(
h
.
NodeId
,
int
(
input
.
Nlookup
))
}
func
(
me
*
FileSystemConnector
)
GetAttr
(
header
*
InHeader
,
input
*
GetAttrIn
)
(
out
*
AttrOut
,
code
Status
)
{
// TODO - do something intelligent with input.Fh.
fullPath
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
attr
,
err
:=
mount
.
fs
.
GetAttr
(
fullPath
)
if
err
!=
OK
{
return
nil
,
err
}
out
=
&
AttrOut
{
Attr
:
*
attr
,
}
out
.
Attr
.
Ino
=
header
.
NodeId
SplitNs
(
me
.
options
.
AttrTimeout
,
&
out
.
AttrValid
,
&
out
.
AttrValidNsec
)
return
out
,
OK
}
func
(
me
*
FileSystemConnector
)
OpenDir
(
header
*
InHeader
,
input
*
OpenIn
)
(
flags
uint32
,
handle
uint64
,
status
Status
)
{
fullPath
,
mount
,
node
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
0
,
0
,
ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
stream
,
err
:=
mount
.
fs
.
OpenDir
(
fullPath
)
if
err
!=
OK
{
return
0
,
0
,
err
}
de
:=
&
Dir
{
stream
:
stream
,
}
h
:=
me
.
registerFile
(
node
,
de
)
return
0
,
h
,
OK
}
func
(
me
*
FileSystemConnector
)
ReadDir
(
header
*
InHeader
,
input
*
ReadIn
)
(
*
DirEntryList
,
Status
)
{
d
:=
me
.
getDir
(
input
.
Fh
)
de
,
code
:=
d
.
ReadDir
(
input
)
if
code
!=
OK
{
return
nil
,
code
}
return
de
,
OK
}
func
(
me
*
FileSystemConnector
)
Open
(
header
*
InHeader
,
input
*
OpenIn
)
(
flags
uint32
,
handle
uint64
,
status
Status
)
{
fullPath
,
mount
,
node
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
0
,
0
,
ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
f
,
err
:=
mount
.
fs
.
Open
(
fullPath
,
input
.
Flags
)
if
err
!=
OK
{
return
0
,
0
,
err
}
h
:=
me
.
registerFile
(
node
,
f
)
return
0
,
h
,
OK
}
func
(
me
*
FileSystemConnector
)
SetAttr
(
header
*
InHeader
,
input
*
SetAttrIn
)
(
out
*
AttrOut
,
code
Status
)
{
var
err
Status
=
OK
// TODO - support Fh. (FSetAttr/FGetAttr/FTruncate.)
fullPath
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
if
input
.
Valid
&
FATTR_MODE
!=
0
{
err
=
mount
.
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
=
mount
.
fs
.
Chown
(
fullPath
,
uint32
(
input
.
Uid
),
uint32
(
input
.
Gid
))
}
if
input
.
Valid
&
FATTR_SIZE
!=
0
{
mount
.
fs
.
Truncate
(
fullPath
,
input
.
Size
)
}
if
err
!=
OK
&&
(
input
.
Valid
&
FATTR_ATIME
!=
0
||
input
.
Valid
&
FATTR_MTIME
!=
0
)
{
err
=
mount
.
fs
.
Utimens
(
fullPath
,
uint64
(
input
.
Atime
*
1e9
)
+
uint64
(
input
.
Atimensec
),
uint64
(
input
.
Mtime
*
1e9
)
+
uint64
(
input
.
Mtimensec
))
}
if
err
!=
OK
&&
(
input
.
Valid
&
FATTR_ATIME_NOW
!=
0
||
input
.
Valid
&
FATTR_MTIME_NOW
!=
0
)
{
// TODO - should set time to now. Maybe just reuse
// Utimens() ? Go has no UTIME_NOW unfortunately.
}
if
err
!=
OK
{
return
nil
,
err
}
// TODO - where to get GetAttrIn.Flags / Fh ?
return
me
.
GetAttr
(
header
,
&
GetAttrIn
{})
}
func
(
me
*
FileSystemConnector
)
Readlink
(
header
*
InHeader
)
(
out
[]
byte
,
code
Status
)
{
fullPath
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
val
,
err
:=
mount
.
fs
.
Readlink
(
fullPath
)
return
bytes
.
NewBufferString
(
val
)
.
Bytes
(),
err
}
func
(
me
*
FileSystemConnector
)
Mknod
(
header
*
InHeader
,
input
*
MknodIn
,
name
string
)
(
out
*
EntryOut
,
code
Status
)
{
fullPath
,
mount
,
node
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
fullPath
=
filepath
.
Join
(
fullPath
,
name
)
err
:=
mount
.
fs
.
Mknod
(
fullPath
,
input
.
Mode
,
uint32
(
input
.
Rdev
))
if
err
!=
OK
{
return
nil
,
err
}
return
me
.
internalLookup
(
node
,
name
,
1
)
}
func
(
me
*
FileSystemConnector
)
Mkdir
(
header
*
InHeader
,
input
*
MkdirIn
,
name
string
)
(
out
*
EntryOut
,
code
Status
)
{
fullPath
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
code
=
mount
.
fs
.
Mkdir
(
filepath
.
Join
(
fullPath
,
name
),
input
.
Mode
)
if
code
==
OK
{
out
,
code
=
me
.
internalLookup
(
parent
,
name
,
1
)
}
return
out
,
code
}
func
(
me
*
FileSystemConnector
)
Unlink
(
header
*
InHeader
,
name
string
)
(
code
Status
)
{
fullPath
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
code
=
mount
.
fs
.
Unlink
(
filepath
.
Join
(
fullPath
,
name
))
if
code
==
OK
{
// Like fuse.c, we update our internal tables.
me
.
unlinkUpdate
(
parent
,
name
)
}
return
code
}
func
(
me
*
FileSystemConnector
)
Rmdir
(
header
*
InHeader
,
name
string
)
(
code
Status
)
{
fullPath
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
code
=
mount
.
fs
.
Rmdir
(
filepath
.
Join
(
fullPath
,
name
))
if
code
==
OK
{
me
.
unlinkUpdate
(
parent
,
name
)
}
return
code
}
func
(
me
*
FileSystemConnector
)
Symlink
(
header
*
InHeader
,
pointedTo
string
,
linkName
string
)
(
out
*
EntryOut
,
code
Status
)
{
fullPath
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
err
:=
mount
.
fs
.
Symlink
(
pointedTo
,
filepath
.
Join
(
fullPath
,
linkName
))
if
err
!=
OK
{
return
nil
,
err
}
out
,
code
=
me
.
internalLookup
(
parent
,
linkName
,
1
)
return
out
,
code
}
func
(
me
*
FileSystemConnector
)
Rename
(
header
*
InHeader
,
input
*
RenameIn
,
oldName
string
,
newName
string
)
(
code
Status
)
{
oldPath
,
oldMount
,
oldParent
:=
me
.
GetPath
(
header
.
NodeId
)
newPath
,
mount
,
newParent
:=
me
.
GetPath
(
input
.
Newdir
)
if
mount
==
nil
||
oldMount
==
nil
{
return
ENOENT
}
if
mount
!=
oldMount
{
return
EXDEV
}
oldPath
=
filepath
.
Join
(
oldPath
,
oldName
)
newPath
=
filepath
.
Join
(
newPath
,
newName
)
code
=
mount
.
fs
.
Rename
(
oldPath
,
newPath
)
if
code
==
OK
{
// It is conceivable that the kernel module will issue a
// forget for the old entry, and a lookup request for the new
// one, but the fuse.c updates its client-side tables on its
// own, so we do this as well.
//
// It should not hurt for us to do it here as well, although
// it remains unclear how we should update Count.
me
.
renameUpdate
(
oldParent
,
oldName
,
newParent
,
newName
)
}
return
code
}
func
(
me
*
FileSystemConnector
)
Link
(
header
*
InHeader
,
input
*
LinkIn
,
filename
string
)
(
out
*
EntryOut
,
code
Status
)
{
orig
,
mount
,
_
:=
me
.
GetPath
(
input
.
Oldnodeid
)
newName
,
newMount
,
newParent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
||
newMount
==
nil
{
return
nil
,
ENOENT
}
if
mount
!=
newMount
{
return
nil
,
EXDEV
}
newName
=
filepath
.
Join
(
newName
,
filename
)
err
:=
mount
.
fs
.
Link
(
orig
,
newName
)
if
err
!=
OK
{
return
nil
,
err
}
return
me
.
internalLookup
(
newParent
,
filename
,
1
)
}
func
(
me
*
FileSystemConnector
)
Access
(
header
*
InHeader
,
input
*
AccessIn
)
(
code
Status
)
{
p
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
return
mount
.
fs
.
Access
(
p
,
input
.
Mask
)
}
func
(
me
*
FileSystemConnector
)
Create
(
header
*
InHeader
,
input
*
CreateIn
,
name
string
)
(
flags
uint32
,
h
uint64
,
out
*
EntryOut
,
code
Status
)
{
directory
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
0
,
0
,
nil
,
ENOENT
}
fullPath
:=
filepath
.
Join
(
directory
,
name
)
f
,
err
:=
mount
.
fs
.
Create
(
fullPath
,
uint32
(
input
.
Flags
),
input
.
Mode
)
if
err
!=
OK
{
return
0
,
0
,
nil
,
err
}
out
,
code
,
inode
:=
me
.
internalLookupWithNode
(
parent
,
name
,
1
)
return
0
,
me
.
registerFile
(
inode
,
f
),
out
,
code
}
func
(
me
*
FileSystemConnector
)
Release
(
header
*
InHeader
,
input
*
ReleaseIn
)
{
node
:=
me
.
getInodeData
(
header
.
NodeId
)
f
:=
me
.
unregisterFile
(
node
,
input
.
Fh
)
.
(
File
)
f
.
Release
()
me
.
considerDropInode
(
node
)
}
func
(
me
*
FileSystemConnector
)
ReleaseDir
(
header
*
InHeader
,
input
*
ReleaseIn
)
{
node
:=
me
.
getInodeData
(
header
.
NodeId
)
d
:=
me
.
unregisterFile
(
node
,
input
.
Fh
)
.
(
RawDir
)
d
.
Release
()
me
.
considerDropInode
(
node
)
}
func
(
me
*
FileSystemConnector
)
FsyncDir
(
header
*
InHeader
,
input
*
FsyncIn
)
(
code
Status
)
{
// What the heck is FsyncDir supposed to do?
return
OK
}
func
(
me
*
FileSystemConnector
)
GetXAttr
(
header
*
InHeader
,
attribute
string
)
(
data
[]
byte
,
code
Status
)
{
path
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
data
,
code
=
mount
.
fs
.
GetXAttr
(
path
,
attribute
)
return
data
,
code
}
func
(
me
*
FileSystemConnector
)
RemoveXAttr
(
header
*
InHeader
,
attr
string
)
Status
{
path
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
return
mount
.
fs
.
RemoveXAttr
(
path
,
attr
)
}
func
(
me
*
FileSystemConnector
)
SetXAttr
(
header
*
InHeader
,
input
*
SetXAttrIn
,
attr
string
,
data
[]
byte
)
Status
{
path
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
return
mount
.
fs
.
SetXAttr
(
path
,
attr
,
data
,
int
(
input
.
Flags
))
}
func
(
me
*
FileSystemConnector
)
ListXAttr
(
header
*
InHeader
)
(
data
[]
byte
,
code
Status
)
{
path
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
attrs
,
code
:=
mount
.
fs
.
ListXAttr
(
path
)
if
code
!=
OK
{
return
nil
,
code
}
b
:=
bytes
.
NewBuffer
([]
byte
{})
for
_
,
v
:=
range
attrs
{
b
.
Write
([]
byte
(
v
))
b
.
WriteByte
(
0
)
}
return
b
.
Bytes
(),
code
}
func
(
me
*
FileSystemConnector
)
Write
(
input
*
WriteIn
,
data
[]
byte
)
(
written
uint32
,
code
Status
)
{
f
:=
me
.
getFile
(
input
.
Fh
)
.
(
File
)
return
f
.
Write
(
input
,
data
)
}
func
(
me
*
FileSystemConnector
)
Read
(
input
*
ReadIn
,
bp
*
BufferPool
)
([]
byte
,
Status
)
{
f
:=
me
.
getFile
(
input
.
Fh
)
return
f
.
Read
(
input
,
bp
)
}
fuse/pathops.go
0 → 100644
View file @
cfe6a430
// Translation of raw operation to path based operations.
package
fuse
import
(
"log"
"bytes"
"path/filepath"
)
func
NewFileSystemConnector
(
fs
FileSystem
)
(
out
*
FileSystemConnector
)
{
out
=
EmptyFileSystemConnector
()
if
code
:=
out
.
Mount
(
"/"
,
fs
);
code
!=
OK
{
panic
(
"root mount failed."
)
}
out
.
verify
()
return
out
}
func
(
me
*
FileSystemConnector
)
SetOptions
(
opts
FileSystemConnectorOptions
)
{
me
.
options
=
opts
}
func
(
me
*
FileSystemConnector
)
Mount
(
mountPoint
string
,
fs
FileSystem
)
Status
{
var
node
*
inode
if
mountPoint
!=
"/"
{
dirParent
,
base
:=
filepath
.
Split
(
mountPoint
)
dirParentNode
:=
me
.
findInode
(
dirParent
)
// Make sure we know the mount point.
_
,
_
=
me
.
internalLookup
(
dirParentNode
,
base
,
0
)
}
node
=
me
.
findInode
(
mountPoint
)
if
!
node
.
IsDir
()
{
return
EINVAL
}
me
.
lock
.
Lock
()
hasChildren
:=
len
(
node
.
Children
)
>
0
// don't use defer, as we dont want to hold the lock during
// fs.Mount().
me
.
lock
.
Unlock
()
if
hasChildren
{
return
EBUSY
}
code
:=
fs
.
Mount
(
me
)
if
code
!=
OK
{
if
me
.
Debug
{
log
.
Println
(
"Mount error: "
,
mountPoint
,
code
)
}
return
code
}
if
me
.
Debug
{
log
.
Println
(
"Mount: "
,
fs
,
"on"
,
mountPoint
,
node
)
}
node
.
mount
=
newMount
(
fs
)
me
.
fileLock
.
Lock
()
defer
me
.
fileLock
.
Unlock
()
node
.
OpenCount
++
return
OK
}
func
(
me
*
FileSystemConnector
)
Unmount
(
path
string
)
Status
{
node
:=
me
.
findInode
(
path
)
if
node
==
nil
{
panic
(
path
)
}
mount
:=
node
.
mount
if
mount
==
nil
{
panic
(
path
)
}
// Need to lock to look at node.Children
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
me
.
fileLock
.
Lock
()
// don't use defer: we don't want to call out to
// mount.fs.Unmount() with lock held.
ownMount
:=
1
isBusy
:=
node
.
totalOpenCount
()
>
ownMount
if
!
isBusy
{
node
.
OpenCount
--
}
me
.
fileLock
.
Unlock
()
if
isBusy
{
log
.
Println
(
"Umount - busy: "
,
mount
)
return
EBUSY
}
if
me
.
Debug
{
log
.
Println
(
"Unmount: "
,
mount
)
}
if
len
(
node
.
Children
)
>
0
{
mount
.
fs
.
Unmount
()
mount
.
unmountPending
=
true
}
else
{
node
.
mount
=
nil
}
return
OK
}
func
(
me
*
FileSystemConnector
)
GetPath
(
nodeid
uint64
)
(
path
string
,
mount
*
mountData
,
node
*
inode
)
{
n
:=
me
.
getInodeData
(
nodeid
)
p
,
m
:=
n
.
GetPath
()
return
p
,
m
,
n
}
func
(
me
*
FileSystemConnector
)
Init
(
h
*
InHeader
,
input
*
InitIn
)
(
*
InitOut
,
Status
)
{
// TODO ?
return
&
InitOut
{},
OK
}
func
(
me
*
FileSystemConnector
)
Destroy
(
h
*
InHeader
,
input
*
InitIn
)
{
// TODO - umount all.
}
func
(
me
*
FileSystemConnector
)
Lookup
(
header
*
InHeader
,
name
string
)
(
out
*
EntryOut
,
status
Status
)
{
parent
:=
me
.
getInodeData
(
header
.
NodeId
)
return
me
.
internalLookup
(
parent
,
name
,
1
)
}
func
(
me
*
FileSystemConnector
)
internalLookup
(
parent
*
inode
,
name
string
,
lookupCount
int
)
(
out
*
EntryOut
,
status
Status
)
{
out
,
status
,
_
=
me
.
internalLookupWithNode
(
parent
,
name
,
lookupCount
)
return
out
,
status
}
func
(
me
*
FileSystemConnector
)
internalLookupWithNode
(
parent
*
inode
,
name
string
,
lookupCount
int
)
(
out
*
EntryOut
,
status
Status
,
node
*
inode
)
{
// TODO - fuse.c has special case code for name == "." and
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// Init.
fullPath
,
mount
:=
parent
.
GetPath
()
if
mount
==
nil
{
return
NegativeEntry
(
me
.
options
.
NegativeTimeout
),
OK
,
nil
}
fullPath
=
filepath
.
Join
(
fullPath
,
name
)
attr
,
err
:=
mount
.
fs
.
GetAttr
(
fullPath
)
if
err
==
ENOENT
&&
me
.
options
.
NegativeTimeout
>
0.0
{
return
NegativeEntry
(
me
.
options
.
NegativeTimeout
),
OK
,
nil
}
if
err
!=
OK
{
return
nil
,
err
,
nil
}
data
:=
me
.
lookupUpdate
(
parent
,
name
,
attr
.
Mode
&
S_IFDIR
!=
0
)
data
.
LookupCount
+=
lookupCount
out
=
&
EntryOut
{
NodeId
:
data
.
NodeId
,
Generation
:
1
,
// where to get the generation?
}
SplitNs
(
me
.
options
.
EntryTimeout
,
&
out
.
EntryValid
,
&
out
.
EntryValidNsec
)
SplitNs
(
me
.
options
.
AttrTimeout
,
&
out
.
AttrValid
,
&
out
.
AttrValidNsec
)
out
.
Attr
=
*
attr
out
.
Attr
.
Ino
=
data
.
NodeId
return
out
,
OK
,
data
}
func
(
me
*
FileSystemConnector
)
Forget
(
h
*
InHeader
,
input
*
ForgetIn
)
{
me
.
forgetUpdate
(
h
.
NodeId
,
int
(
input
.
Nlookup
))
}
func
(
me
*
FileSystemConnector
)
GetAttr
(
header
*
InHeader
,
input
*
GetAttrIn
)
(
out
*
AttrOut
,
code
Status
)
{
// TODO - do something intelligent with input.Fh.
fullPath
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
attr
,
err
:=
mount
.
fs
.
GetAttr
(
fullPath
)
if
err
!=
OK
{
return
nil
,
err
}
out
=
&
AttrOut
{
Attr
:
*
attr
,
}
out
.
Attr
.
Ino
=
header
.
NodeId
SplitNs
(
me
.
options
.
AttrTimeout
,
&
out
.
AttrValid
,
&
out
.
AttrValidNsec
)
return
out
,
OK
}
func
(
me
*
FileSystemConnector
)
OpenDir
(
header
*
InHeader
,
input
*
OpenIn
)
(
flags
uint32
,
handle
uint64
,
status
Status
)
{
fullPath
,
mount
,
node
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
0
,
0
,
ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
stream
,
err
:=
mount
.
fs
.
OpenDir
(
fullPath
)
if
err
!=
OK
{
return
0
,
0
,
err
}
de
:=
&
Dir
{
stream
:
stream
,
}
h
:=
me
.
registerFile
(
node
,
de
)
return
0
,
h
,
OK
}
func
(
me
*
FileSystemConnector
)
ReadDir
(
header
*
InHeader
,
input
*
ReadIn
)
(
*
DirEntryList
,
Status
)
{
d
:=
me
.
getDir
(
input
.
Fh
)
de
,
code
:=
d
.
ReadDir
(
input
)
if
code
!=
OK
{
return
nil
,
code
}
return
de
,
OK
}
func
(
me
*
FileSystemConnector
)
Open
(
header
*
InHeader
,
input
*
OpenIn
)
(
flags
uint32
,
handle
uint64
,
status
Status
)
{
fullPath
,
mount
,
node
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
0
,
0
,
ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
f
,
err
:=
mount
.
fs
.
Open
(
fullPath
,
input
.
Flags
)
if
err
!=
OK
{
return
0
,
0
,
err
}
h
:=
me
.
registerFile
(
node
,
f
)
return
0
,
h
,
OK
}
func
(
me
*
FileSystemConnector
)
SetAttr
(
header
*
InHeader
,
input
*
SetAttrIn
)
(
out
*
AttrOut
,
code
Status
)
{
var
err
Status
=
OK
// TODO - support Fh. (FSetAttr/FGetAttr/FTruncate.)
fullPath
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
if
input
.
Valid
&
FATTR_MODE
!=
0
{
err
=
mount
.
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
=
mount
.
fs
.
Chown
(
fullPath
,
uint32
(
input
.
Uid
),
uint32
(
input
.
Gid
))
}
if
input
.
Valid
&
FATTR_SIZE
!=
0
{
mount
.
fs
.
Truncate
(
fullPath
,
input
.
Size
)
}
if
err
!=
OK
&&
(
input
.
Valid
&
FATTR_ATIME
!=
0
||
input
.
Valid
&
FATTR_MTIME
!=
0
)
{
err
=
mount
.
fs
.
Utimens
(
fullPath
,
uint64
(
input
.
Atime
*
1e9
)
+
uint64
(
input
.
Atimensec
),
uint64
(
input
.
Mtime
*
1e9
)
+
uint64
(
input
.
Mtimensec
))
}
if
err
!=
OK
&&
(
input
.
Valid
&
FATTR_ATIME_NOW
!=
0
||
input
.
Valid
&
FATTR_MTIME_NOW
!=
0
)
{
// TODO - should set time to now. Maybe just reuse
// Utimens() ? Go has no UTIME_NOW unfortunately.
}
if
err
!=
OK
{
return
nil
,
err
}
// TODO - where to get GetAttrIn.Flags / Fh ?
return
me
.
GetAttr
(
header
,
&
GetAttrIn
{})
}
func
(
me
*
FileSystemConnector
)
Readlink
(
header
*
InHeader
)
(
out
[]
byte
,
code
Status
)
{
fullPath
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
val
,
err
:=
mount
.
fs
.
Readlink
(
fullPath
)
return
bytes
.
NewBufferString
(
val
)
.
Bytes
(),
err
}
func
(
me
*
FileSystemConnector
)
Mknod
(
header
*
InHeader
,
input
*
MknodIn
,
name
string
)
(
out
*
EntryOut
,
code
Status
)
{
fullPath
,
mount
,
node
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
fullPath
=
filepath
.
Join
(
fullPath
,
name
)
err
:=
mount
.
fs
.
Mknod
(
fullPath
,
input
.
Mode
,
uint32
(
input
.
Rdev
))
if
err
!=
OK
{
return
nil
,
err
}
return
me
.
internalLookup
(
node
,
name
,
1
)
}
func
(
me
*
FileSystemConnector
)
Mkdir
(
header
*
InHeader
,
input
*
MkdirIn
,
name
string
)
(
out
*
EntryOut
,
code
Status
)
{
fullPath
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
code
=
mount
.
fs
.
Mkdir
(
filepath
.
Join
(
fullPath
,
name
),
input
.
Mode
)
if
code
==
OK
{
out
,
code
=
me
.
internalLookup
(
parent
,
name
,
1
)
}
return
out
,
code
}
func
(
me
*
FileSystemConnector
)
Unlink
(
header
*
InHeader
,
name
string
)
(
code
Status
)
{
fullPath
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
code
=
mount
.
fs
.
Unlink
(
filepath
.
Join
(
fullPath
,
name
))
if
code
==
OK
{
// Like fuse.c, we update our internal tables.
me
.
unlinkUpdate
(
parent
,
name
)
}
return
code
}
func
(
me
*
FileSystemConnector
)
Rmdir
(
header
*
InHeader
,
name
string
)
(
code
Status
)
{
fullPath
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
code
=
mount
.
fs
.
Rmdir
(
filepath
.
Join
(
fullPath
,
name
))
if
code
==
OK
{
me
.
unlinkUpdate
(
parent
,
name
)
}
return
code
}
func
(
me
*
FileSystemConnector
)
Symlink
(
header
*
InHeader
,
pointedTo
string
,
linkName
string
)
(
out
*
EntryOut
,
code
Status
)
{
fullPath
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
err
:=
mount
.
fs
.
Symlink
(
pointedTo
,
filepath
.
Join
(
fullPath
,
linkName
))
if
err
!=
OK
{
return
nil
,
err
}
out
,
code
=
me
.
internalLookup
(
parent
,
linkName
,
1
)
return
out
,
code
}
func
(
me
*
FileSystemConnector
)
Rename
(
header
*
InHeader
,
input
*
RenameIn
,
oldName
string
,
newName
string
)
(
code
Status
)
{
oldPath
,
oldMount
,
oldParent
:=
me
.
GetPath
(
header
.
NodeId
)
newPath
,
mount
,
newParent
:=
me
.
GetPath
(
input
.
Newdir
)
if
mount
==
nil
||
oldMount
==
nil
{
return
ENOENT
}
if
mount
!=
oldMount
{
return
EXDEV
}
oldPath
=
filepath
.
Join
(
oldPath
,
oldName
)
newPath
=
filepath
.
Join
(
newPath
,
newName
)
code
=
mount
.
fs
.
Rename
(
oldPath
,
newPath
)
if
code
==
OK
{
me
.
renameUpdate
(
oldParent
,
oldName
,
newParent
,
newName
)
}
return
code
}
func
(
me
*
FileSystemConnector
)
Link
(
header
*
InHeader
,
input
*
LinkIn
,
filename
string
)
(
out
*
EntryOut
,
code
Status
)
{
orig
,
mount
,
_
:=
me
.
GetPath
(
input
.
Oldnodeid
)
newName
,
newMount
,
newParent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
||
newMount
==
nil
{
return
nil
,
ENOENT
}
if
mount
!=
newMount
{
return
nil
,
EXDEV
}
newName
=
filepath
.
Join
(
newName
,
filename
)
err
:=
mount
.
fs
.
Link
(
orig
,
newName
)
if
err
!=
OK
{
return
nil
,
err
}
return
me
.
internalLookup
(
newParent
,
filename
,
1
)
}
func
(
me
*
FileSystemConnector
)
Access
(
header
*
InHeader
,
input
*
AccessIn
)
(
code
Status
)
{
p
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
return
mount
.
fs
.
Access
(
p
,
input
.
Mask
)
}
func
(
me
*
FileSystemConnector
)
Create
(
header
*
InHeader
,
input
*
CreateIn
,
name
string
)
(
flags
uint32
,
h
uint64
,
out
*
EntryOut
,
code
Status
)
{
directory
,
mount
,
parent
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
0
,
0
,
nil
,
ENOENT
}
fullPath
:=
filepath
.
Join
(
directory
,
name
)
f
,
err
:=
mount
.
fs
.
Create
(
fullPath
,
uint32
(
input
.
Flags
),
input
.
Mode
)
if
err
!=
OK
{
return
0
,
0
,
nil
,
err
}
out
,
code
,
inode
:=
me
.
internalLookupWithNode
(
parent
,
name
,
1
)
return
0
,
me
.
registerFile
(
inode
,
f
),
out
,
code
}
func
(
me
*
FileSystemConnector
)
Release
(
header
*
InHeader
,
input
*
ReleaseIn
)
{
node
:=
me
.
getInodeData
(
header
.
NodeId
)
f
:=
me
.
unregisterFile
(
node
,
input
.
Fh
)
.
(
File
)
f
.
Release
()
me
.
considerDropInode
(
node
)
}
func
(
me
*
FileSystemConnector
)
ReleaseDir
(
header
*
InHeader
,
input
*
ReleaseIn
)
{
node
:=
me
.
getInodeData
(
header
.
NodeId
)
d
:=
me
.
unregisterFile
(
node
,
input
.
Fh
)
.
(
RawDir
)
d
.
Release
()
me
.
considerDropInode
(
node
)
}
func
(
me
*
FileSystemConnector
)
FsyncDir
(
header
*
InHeader
,
input
*
FsyncIn
)
(
code
Status
)
{
// What the heck is FsyncDir supposed to do?
return
OK
}
func
(
me
*
FileSystemConnector
)
GetXAttr
(
header
*
InHeader
,
attribute
string
)
(
data
[]
byte
,
code
Status
)
{
path
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
data
,
code
=
mount
.
fs
.
GetXAttr
(
path
,
attribute
)
return
data
,
code
}
func
(
me
*
FileSystemConnector
)
RemoveXAttr
(
header
*
InHeader
,
attr
string
)
Status
{
path
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
return
mount
.
fs
.
RemoveXAttr
(
path
,
attr
)
}
func
(
me
*
FileSystemConnector
)
SetXAttr
(
header
*
InHeader
,
input
*
SetXAttrIn
,
attr
string
,
data
[]
byte
)
Status
{
path
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
ENOENT
}
return
mount
.
fs
.
SetXAttr
(
path
,
attr
,
data
,
int
(
input
.
Flags
))
}
func
(
me
*
FileSystemConnector
)
ListXAttr
(
header
*
InHeader
)
(
data
[]
byte
,
code
Status
)
{
path
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
return
nil
,
ENOENT
}
attrs
,
code
:=
mount
.
fs
.
ListXAttr
(
path
)
if
code
!=
OK
{
return
nil
,
code
}
b
:=
bytes
.
NewBuffer
([]
byte
{})
for
_
,
v
:=
range
attrs
{
b
.
Write
([]
byte
(
v
))
b
.
WriteByte
(
0
)
}
return
b
.
Bytes
(),
code
}
func
(
me
*
FileSystemConnector
)
Write
(
input
*
WriteIn
,
data
[]
byte
)
(
written
uint32
,
code
Status
)
{
f
:=
me
.
getFile
(
input
.
Fh
)
.
(
File
)
return
f
.
Write
(
input
,
data
)
}
func
(
me
*
FileSystemConnector
)
Read
(
input
*
ReadIn
,
bp
*
BufferPool
)
([]
byte
,
Status
)
{
f
:=
me
.
getFile
(
input
.
Fh
)
return
f
.
Read
(
input
,
bp
)
}
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