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
a114c594
Commit
a114c594
authored
Mar 28, 2011
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor PathFileSystemConnector to use per directory children maps.
This makes the code somewhat cleaner.
parent
c6585f7f
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
96 additions
and
147 deletions
+96
-147
fuse/pathfilesystem.go
fuse/pathfilesystem.go
+96
-147
No files found.
fuse/pathfilesystem.go
View file @
a114c594
...
@@ -37,47 +37,40 @@ func newMount(fs PathFilesystem) *mountData {
...
@@ -37,47 +37,40 @@ func newMount(fs PathFilesystem) *mountData {
var
paranoia
=
false
var
paranoia
=
false
// TODO should rename to dentry?
// TODO should rename to dentry?
type
inodeData
struct
{
type
inode
struct
{
Parent
*
inodeData
Parent
*
inode
Children
map
[
string
]
*
inode
NodeId
uint64
NodeId
uint64
Name
string
Name
string
LookupCount
int
LookupCount
int
Type
uint32
Type
uint32
// Number of inodeData that have this as parent.
RefCount
int
mount
*
mountData
mount
*
mountData
}
}
func
(
me
*
inodeData
)
verify
(
c
*
PathFileSystemConnector
)
{
const
initDirSize
=
20
if
me
.
Parent
!=
nil
{
k
:=
inodeDataKey
(
me
.
Parent
.
NodeId
,
me
.
Name
)
func
(
me
*
inode
)
verify
()
{
n
:=
c
.
lookup
(
k
)
if
!
(
me
.
NodeId
==
FUSE_ROOT_ID
||
me
.
LookupCount
>
0
||
len
(
me
.
Children
)
>
0
)
{
if
n
!=
me
{
panic
(
fmt
.
Sprintf
(
"node should be dead: %v"
,
me
))
panic
(
fmt
.
Sprintf
(
"parent/child relation corrupted %v %v %v"
,
k
,
n
,
me
))
}
}
}
else
{
for
n
,
ch
:=
range
me
.
Children
{
// may both happen for deleted and root node.
if
ch
==
nil
{
panic
(
"Found nil child."
)
}
if
ch
.
Name
!=
n
{
panic
(
fmt
.
Sprintf
(
"parent/child name corrupted %v %v"
,
ch
.
Name
,
n
))
}
if
ch
.
Parent
!=
me
{
panic
(
fmt
.
Sprintf
(
"parent/child relation corrupted %v %v %v"
,
ch
.
Parent
,
me
,
ch
))
}
}
}
// Should implement some hash table method instead?
func
inodeDataKey
(
parentInode
uint64
,
name
string
)
string
{
return
string
(
parentInode
)
+
":"
+
name
}
func
(
me
*
inodeData
)
Key
()
string
{
var
p
uint64
=
0
if
me
.
Parent
!=
nil
{
p
=
me
.
Parent
.
NodeId
}
}
return
inodeDataKey
(
p
,
me
.
Name
)
}
}
func
(
me
*
inode
Data
)
GetPath
()
(
path
string
,
mount
*
mountData
)
{
func
(
me
*
inode
)
GetPath
()
(
path
string
,
mount
*
mountData
)
{
rev_components
:=
make
([]
string
,
0
,
10
)
rev_components
:=
make
([]
string
,
0
,
10
)
inode
:=
me
inode
:=
me
...
@@ -102,6 +95,27 @@ func (me *inodeData) GetPath() (path string, mount *mountData) {
...
@@ -102,6 +95,27 @@ func (me *inodeData) GetPath() (path string, mount *mountData) {
return
fullPath
,
mount
return
fullPath
,
mount
}
}
// Must be called with lock held.
func
(
me
*
inode
)
setParent
(
newParent
*
inode
)
{
if
me
.
Parent
==
newParent
{
return
}
if
me
.
Parent
!=
nil
{
me
.
Parent
.
Children
[
me
.
Name
]
=
nil
,
false
me
.
Parent
=
nil
}
if
newParent
!=
nil
{
me
.
Parent
=
newParent
ch
:=
me
.
Parent
.
Children
[
me
.
Name
]
if
ch
!=
nil
{
panic
(
fmt
.
Sprintf
(
"Already have an inode with same name: %v."
,
me
.
Name
))
}
me
.
Parent
.
Children
[
me
.
Name
]
=
me
}
}
type
TimeoutOptions
struct
{
type
TimeoutOptions
struct
{
EntryTimeout
float64
EntryTimeout
float64
AttrTimeout
float64
AttrTimeout
float64
...
@@ -126,18 +140,8 @@ type PathFileSystemConnector struct {
...
@@ -126,18 +140,8 @@ type PathFileSystemConnector struct {
// Protects the hashmap, its contents and the nextFreeInode counter.
// Protects the hashmap, its contents and the nextFreeInode counter.
lock
sync
.
RWMutex
lock
sync
.
RWMutex
// Invariants
// Invariants: see the verify() method.
// - For all values, (RefCount > 0 || LookupCount > 0).
inodeMap
map
[
uint64
]
*
inode
// - For all values, value = inodePathMap[value.Key()]
// - For all values, value = inodePathMapByInode[value.NodeId]
// fuse.c seems to have different lifetimes for the different
// hashtables, which could lead to the same directory entry
// existing twice with different generated inode numbers, if
// we have (FORGET, LOOKUP) on a directory entry with RefCount
// > 0.
inodePathMap
map
[
string
]
*
inodeData
inodePathMapByInode
map
[
uint64
]
*
inodeData
nextFreeInode
uint64
nextFreeInode
uint64
options
PathFileSystemConnectorOptions
options
PathFileSystemConnectorOptions
...
@@ -148,80 +152,48 @@ func (me *PathFileSystemConnector) verify() {
...
@@ -148,80 +152,48 @@ func (me *PathFileSystemConnector) verify() {
if
!
paranoia
{
if
!
paranoia
{
return
return
}
}
for
k
,
v
:=
range
me
.
inode
PathMapByInode
{
for
k
,
v
:=
range
me
.
inode
Map
{
if
v
.
NodeId
!=
k
{
if
v
.
NodeId
!=
k
{
panic
(
fmt
.
Sprintf
(
"
Nodeid mismatch"
,
k
,
v
.
NodeId
,
v
))
panic
(
fmt
.
Sprintf
(
"
nodeid mismatch %v %v"
,
v
,
k
))
}
}
v
.
verify
(
me
)
}
}
me
.
inodeMap
[
FUSE_ROOT_ID
]
.
verify
()
}
}
// Must be called with lock held.
func
(
me
*
PathFileSystemConnector
)
newInode
()
*
inode
{
func
(
me
*
PathFileSystemConnector
)
setParent
(
data
*
inodeData
,
newParent
*
inodeData
)
{
data
:=
new
(
inode
)
if
data
.
Parent
==
newParent
{
data
.
NodeId
=
me
.
nextFreeInode
return
me
.
nextFreeInode
++
}
if
newParent
==
nil
{
panic
(
"Unknown parent"
)
}
oldParent
:=
data
.
Parent
if
oldParent
!=
nil
{
me
.
unrefNode
(
oldParent
)
}
data
.
Parent
=
newParent
if
newParent
!=
nil
{
newParent
.
RefCount
++
}
}
// Must be called with lock held.
me
.
inodeMap
[
data
.
NodeId
]
=
data
func
(
me
*
PathFileSystemConnector
)
unrefNode
(
data
*
inodeData
)
{
data
.
RefCount
--
if
data
.
RefCount
<=
0
&&
data
.
LookupCount
<=
0
{
me
.
inodePathMapByInode
[
data
.
NodeId
]
=
nil
,
false
}
}
func
(
me
*
PathFileSystemConnector
)
lookup
(
key
string
)
*
inodeData
{
return
data
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
return
me
.
inodePathMap
[
key
]
}
}
func
(
me
*
PathFileSystemConnector
)
lookupUpdate
(
parent
*
inode
Data
,
name
string
)
*
inodeData
{
func
(
me
*
PathFileSystemConnector
)
lookupUpdate
(
parent
*
inode
,
name
string
,
isDir
bool
)
*
inode
{
defer
me
.
verify
()
defer
me
.
verify
()
key
:=
inodeDataKey
(
parent
.
NodeId
,
name
)
data
:=
me
.
lookup
(
key
)
if
data
!=
nil
{
return
data
}
me
.
lock
.
Lock
()
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
defer
me
.
lock
.
Unlock
()
data
,
ok
:=
me
.
inodePathMap
[
key
]
data
,
ok
:=
parent
.
Children
[
name
]
if
!
ok
{
if
!
ok
{
data
=
new
(
inodeData
)
data
=
me
.
newInode
()
me
.
setParent
(
data
,
parent
)
data
.
NodeId
=
me
.
nextFreeInode
data
.
Name
=
name
data
.
Name
=
name
me
.
nextFreeInode
++
data
.
setParent
(
parent
)
if
isDir
{
me
.
inodePathMapByInode
[
data
.
NodeId
]
=
data
data
.
Children
=
make
(
map
[
string
]
*
inode
,
initDirSize
)
me
.
inodePathMap
[
key
]
=
data
}
}
}
return
data
return
data
}
}
func
(
me
*
PathFileSystemConnector
)
getInodeData
(
nodeid
uint64
)
*
inode
Data
{
func
(
me
*
PathFileSystemConnector
)
getInodeData
(
nodeid
uint64
)
*
inode
{
me
.
lock
.
RLock
()
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
defer
me
.
lock
.
RUnlock
()
val
:=
me
.
inode
PathMapByInode
[
nodeid
]
val
:=
me
.
inode
Map
[
nodeid
]
if
val
==
nil
{
if
val
==
nil
{
panic
(
fmt
.
Sprintf
(
"inode %v unknown"
,
nodeid
))
panic
(
fmt
.
Sprintf
(
"inode %v unknown"
,
nodeid
))
}
}
...
@@ -233,7 +205,7 @@ func (me *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int)
...
@@ -233,7 +205,7 @@ func (me *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int)
me
.
lock
.
Lock
()
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
defer
me
.
lock
.
Unlock
()
data
,
ok
:=
me
.
inode
PathMapByInode
[
nodeId
]
data
,
ok
:=
me
.
inode
Map
[
nodeId
]
if
ok
{
if
ok
{
data
.
LookupCount
-=
forgetCount
data
.
LookupCount
-=
forgetCount
...
@@ -242,74 +214,53 @@ func (me *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int)
...
@@ -242,74 +214,53 @@ func (me *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int)
defer
data
.
mount
.
mutex
.
RUnlock
()
defer
data
.
mount
.
mutex
.
RUnlock
()
}
}
if
data
.
LookupCount
<=
0
&&
data
.
RefCount
<=
0
&&
(
data
.
mount
==
nil
||
data
.
mount
.
unmountPending
)
{
// TODO - this should probably not happen at all.
me
.
inodePathMapByInode
[
nodeId
]
=
nil
,
false
if
data
.
LookupCount
<=
0
&&
len
(
data
.
Children
)
==
0
&&
(
data
.
mount
==
nil
||
data
.
mount
.
unmountPending
)
{
me
.
inodePathMap
[
data
.
Key
()]
=
nil
,
false
data
.
setParent
(
nil
)
me
.
inodeMap
[
nodeId
]
=
nil
,
false
}
}
}
}
}
}
func
(
me
*
PathFileSystemConnector
)
renameUpdate
(
oldParent
*
inode
Data
,
oldName
string
,
newParent
*
inodeData
,
newName
string
)
{
func
(
me
*
PathFileSystemConnector
)
renameUpdate
(
oldParent
*
inode
,
oldName
string
,
newParent
*
inode
,
newName
string
)
{
defer
me
.
verify
()
defer
me
.
verify
()
me
.
lock
.
Lock
()
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
defer
me
.
lock
.
Unlock
()
oldKey
:=
inodeDataKey
(
oldParent
.
NodeId
,
oldName
)
node
:=
oldParent
.
Children
[
oldName
]
data
:=
me
.
inodePathMap
[
oldKey
]
if
node
==
nil
{
if
data
==
nil
{
panic
(
"Source of rename does not exist"
)
// This can happen if a rename raced with an unlink or
// another rename.
//
// TODO - does the VFS layer allow this?
//
// TODO - is this an error we should signal?
return
}
}
me
.
inodePathMap
[
oldKey
]
=
nil
,
false
node
.
setParent
(
nil
)
node
.
Name
=
newName
me
.
setParent
(
data
,
newParent
)
node
.
setParent
(
newParent
)
data
.
Name
=
newName
newKey
:=
data
.
Key
()
target
:=
me
.
inodePathMap
[
newKey
]
if
target
!=
nil
{
panic
(
"file moved into target place."
)
}
me
.
inodePathMap
[
newKey
]
=
data
}
}
func
(
me
*
PathFileSystemConnector
)
unlinkUpdate
(
parent
*
inode
Data
,
name
string
)
{
func
(
me
*
PathFileSystemConnector
)
unlinkUpdate
(
parent
*
inode
,
name
string
)
{
defer
me
.
verify
()
defer
me
.
verify
()
me
.
lock
.
Lock
()
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
defer
me
.
lock
.
Unlock
()
oldKey
:=
inodeDataKey
(
parent
.
NodeId
,
name
)
node
:=
parent
.
Children
[
name
]
data
:=
me
.
inodePathMap
[
oldKey
]
node
.
setParent
(
nil
)
if
data
!=
nil
{
me
.
inodePathMap
[
oldKey
]
=
nil
,
false
data
.
Parent
=
nil
me
.
unrefNode
(
data
)
}
}
}
// Walk the file system starting from the root.
// Walk the file system starting from the root.
func
(
me
*
PathFileSystemConnector
)
findInode
(
fullPath
string
)
*
inode
Data
{
func
(
me
*
PathFileSystemConnector
)
findInode
(
fullPath
string
)
*
inode
{
fullPath
=
strings
.
TrimLeft
(
filepath
.
Clean
(
fullPath
),
"/"
)
fullPath
=
strings
.
TrimLeft
(
filepath
.
Clean
(
fullPath
),
"/"
)
comps
:=
strings
.
Split
(
fullPath
,
"/"
,
-
1
)
comps
:=
strings
.
Split
(
fullPath
,
"/"
,
-
1
)
me
.
lock
.
RLock
()
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
defer
me
.
lock
.
RUnlock
()
node
:=
me
.
inode
PathMapByInode
[
FUSE_ROOT_ID
]
node
:=
me
.
inode
Map
[
FUSE_ROOT_ID
]
for
i
,
component
:=
range
comps
{
for
i
,
component
:=
range
comps
{
if
len
(
component
)
==
0
{
if
len
(
component
)
==
0
{
continue
continue
}
}
key
:=
inodeDataKey
(
node
.
NodeId
,
component
)
node
=
node
.
Children
[
component
]
node
=
me
.
inodePathMap
[
key
]
if
node
==
nil
{
if
node
==
nil
{
panic
(
fmt
.
Sprintf
(
"findInode: %v %v"
,
i
,
fullPath
))
panic
(
fmt
.
Sprintf
(
"findInode: %v %v"
,
i
,
fullPath
))
}
}
...
@@ -323,16 +274,13 @@ func (me *PathFileSystemConnector) findInode(fullPath string) *inodeData {
...
@@ -323,16 +274,13 @@ func (me *PathFileSystemConnector) findInode(fullPath string) *inodeData {
func
NewPathFileSystemConnector
(
fs
PathFilesystem
)
(
out
*
PathFileSystemConnector
)
{
func
NewPathFileSystemConnector
(
fs
PathFilesystem
)
(
out
*
PathFileSystemConnector
)
{
out
=
new
(
PathFileSystemConnector
)
out
=
new
(
PathFileSystemConnector
)
out
.
inodePathMap
=
make
(
map
[
string
]
*
inodeData
)
out
.
inodeMap
=
make
(
map
[
uint64
]
*
inode
)
out
.
inodePathMapByInode
=
make
(
map
[
uint64
]
*
inodeData
)
rootData
:=
new
(
inodeData
)
out
.
nextFreeInode
=
FUSE_ROOT_ID
rootData
:=
out
.
newInode
()
rootData
.
NodeId
=
FUSE_ROOT_ID
rootData
.
NodeId
=
FUSE_ROOT_ID
rootData
.
Type
=
ModeToType
(
S_IFDIR
)
rootData
.
Type
=
ModeToType
(
S_IFDIR
)
rootData
.
Children
=
make
(
map
[
string
]
*
inode
,
initDirSize
)
out
.
inodePathMap
[
rootData
.
Key
()]
=
rootData
out
.
inodePathMapByInode
[
FUSE_ROOT_ID
]
=
rootData
out
.
nextFreeInode
=
FUSE_ROOT_ID
+
1
out
.
options
.
NegativeTimeout
=
0.0
out
.
options
.
NegativeTimeout
=
0.0
out
.
options
.
AttrTimeout
=
1.0
out
.
options
.
AttrTimeout
=
1.0
...
@@ -341,6 +289,9 @@ func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector
...
@@ -341,6 +289,9 @@ func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector
if
code
:=
out
.
Mount
(
"/"
,
fs
);
code
!=
OK
{
if
code
:=
out
.
Mount
(
"/"
,
fs
);
code
!=
OK
{
panic
(
"root mount failed."
)
panic
(
"root mount failed."
)
}
}
out
.
verify
()
return
out
return
out
}
}
...
@@ -350,7 +301,7 @@ func (me *PathFileSystemConnector) SetOptions(opts PathFileSystemConnectorOption
...
@@ -350,7 +301,7 @@ func (me *PathFileSystemConnector) SetOptions(opts PathFileSystemConnectorOption
func
(
me
*
PathFileSystemConnector
)
Mount
(
mountPoint
string
,
fs
PathFilesystem
)
Status
{
func
(
me
*
PathFileSystemConnector
)
Mount
(
mountPoint
string
,
fs
PathFilesystem
)
Status
{
var
node
*
inode
Data
var
node
*
inode
if
mountPoint
!=
"/"
{
if
mountPoint
!=
"/"
{
dirParent
,
base
:=
filepath
.
Split
(
mountPoint
)
dirParent
,
base
:=
filepath
.
Split
(
mountPoint
)
...
@@ -363,7 +314,7 @@ func (me *PathFileSystemConnector) Mount(mountPoint string, fs PathFilesystem) S
...
@@ -363,7 +314,7 @@ func (me *PathFileSystemConnector) Mount(mountPoint string, fs PathFilesystem) S
node
=
me
.
findInode
(
mountPoint
)
node
=
me
.
findInode
(
mountPoint
)
// TODO - check that fs was not mounted elsewhere.
// TODO - check that fs was not mounted elsewhere.
if
node
.
RefCount
>
0
{
if
len
(
node
.
Children
)
>
0
{
return
EBUSY
return
EBUSY
}
}
if
node
.
Type
&
ModeToType
(
S_IFDIR
)
==
0
{
if
node
.
Type
&
ModeToType
(
S_IFDIR
)
==
0
{
...
@@ -413,7 +364,7 @@ func (me *PathFileSystemConnector) Unmount(path string) Status {
...
@@ -413,7 +364,7 @@ func (me *PathFileSystemConnector) Unmount(path string) Status {
log
.
Println
(
"Unmount: "
,
mount
)
log
.
Println
(
"Unmount: "
,
mount
)
}
}
if
node
.
RefCount
>
0
{
if
len
(
node
.
Children
)
>
0
{
mount
.
fs
.
Unmount
()
mount
.
fs
.
Unmount
()
mount
.
unmountPending
=
true
mount
.
unmountPending
=
true
}
else
{
}
else
{
...
@@ -427,7 +378,7 @@ func (me *PathFileSystemConnector) Unmount(path string) Status {
...
@@ -427,7 +378,7 @@ func (me *PathFileSystemConnector) Unmount(path string) Status {
return
OK
return
OK
}
}
func
(
me
*
PathFileSystemConnector
)
GetPath
(
nodeid
uint64
)
(
path
string
,
mount
*
mountData
,
node
*
inode
Data
)
{
func
(
me
*
PathFileSystemConnector
)
GetPath
(
nodeid
uint64
)
(
path
string
,
mount
*
mountData
,
node
*
inode
)
{
n
:=
me
.
getInodeData
(
nodeid
)
n
:=
me
.
getInodeData
(
nodeid
)
p
,
m
:=
n
.
GetPath
()
p
,
m
:=
n
.
GetPath
()
return
p
,
m
,
n
return
p
,
m
,
n
...
@@ -447,7 +398,7 @@ func (me *PathFileSystemConnector) Lookup(header *InHeader, name string) (out *E
...
@@ -447,7 +398,7 @@ func (me *PathFileSystemConnector) Lookup(header *InHeader, name string) (out *E
return
me
.
internalLookup
(
parent
,
name
,
1
)
return
me
.
internalLookup
(
parent
,
name
,
1
)
}
}
func
(
me
*
PathFileSystemConnector
)
internalLookup
(
parent
*
inode
Data
,
name
string
,
lookupCount
int
)
(
out
*
EntryOut
,
status
Status
)
{
func
(
me
*
PathFileSystemConnector
)
internalLookup
(
parent
*
inode
,
name
string
,
lookupCount
int
)
(
out
*
EntryOut
,
status
Status
)
{
// TODO - fuse.c has special case code for name == "." and
// TODO - fuse.c has special case code for name == "." and
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// Init.
// Init.
...
@@ -467,7 +418,7 @@ func (me *PathFileSystemConnector) internalLookup(parent *inodeData, name string
...
@@ -467,7 +418,7 @@ func (me *PathFileSystemConnector) internalLookup(parent *inodeData, name string
return
nil
,
err
return
nil
,
err
}
}
data
:=
me
.
lookupUpdate
(
parent
,
name
)
data
:=
me
.
lookupUpdate
(
parent
,
name
,
attr
.
Mode
&
S_IFDIR
!=
0
)
data
.
LookupCount
+=
lookupCount
data
.
LookupCount
+=
lookupCount
data
.
Type
=
ModeToType
(
attr
.
Mode
)
data
.
Type
=
ModeToType
(
attr
.
Mode
)
...
@@ -488,8 +439,6 @@ func (me *PathFileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
...
@@ -488,8 +439,6 @@ func (me *PathFileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
func
(
me
*
PathFileSystemConnector
)
GetAttr
(
header
*
InHeader
,
input
*
GetAttrIn
)
(
out
*
AttrOut
,
code
Status
)
{
func
(
me
*
PathFileSystemConnector
)
GetAttr
(
header
*
InHeader
,
input
*
GetAttrIn
)
(
out
*
AttrOut
,
code
Status
)
{
// TODO - do something intelligent with input.Fh.
// TODO - do something intelligent with input.Fh.
// TODO - should we update inodeData.Type?
fullPath
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
fullPath
,
mount
,
_
:=
me
.
GetPath
(
header
.
NodeId
)
if
mount
==
nil
{
if
mount
==
nil
{
return
nil
,
ENOENT
return
nil
,
ENOENT
...
...
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