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
a7a22fce
Commit
a7a22fce
authored
Feb 22, 2019
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nodefs: add Rename.
Inode.MvChild Fix opaqueID
parent
29229b42
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
124 additions
and
3 deletions
+124
-3
nodefs/api.go
nodefs/api.go
+1
-0
nodefs/bridge.go
nodefs/bridge.go
+17
-1
nodefs/inode.go
nodefs/inode.go
+54
-1
nodefs/loopback.go
nodefs/loopback.go
+14
-0
nodefs/simple_test.go
nodefs/simple_test.go
+38
-1
No files found.
nodefs/api.go
View file @
a7a22fce
...
...
@@ -91,6 +91,7 @@ type Node interface {
Mknod
(
ctx
context
.
Context
,
name
string
,
mode
uint32
,
dev
uint32
,
out
*
fuse
.
EntryOut
)
(
*
Inode
,
fuse
.
Status
)
Rmdir
(
ctx
context
.
Context
,
name
string
)
fuse
.
Status
Unlink
(
ctx
context
.
Context
,
name
string
)
fuse
.
Status
Rename
(
ctx
context
.
Context
,
name
string
,
newParent
Node
,
newName
string
)
fuse
.
Status
Open
(
ctx
context
.
Context
,
flags
uint32
)
(
fh
File
,
fuseFlags
uint32
,
code
fuse
.
Status
)
...
...
nodefs/bridge.go
View file @
a7a22fce
...
...
@@ -152,6 +152,10 @@ func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, out *f
b
.
registerInode
(
child
)
}
out
.
NodeId
=
child
.
nodeID
// NOSUBMIT - or should let FS expose Attr.Ino? This makes
// testing semantics hard though, because os.Lstat doesn't
// reflect the FUSE FS
out
.
Attr
.
Ino
=
child
.
nodeID
out
.
Generation
=
b
.
nodes
[
out
.
NodeId
]
.
generation
b
.
mu
.
Unlock
()
unlockNodes
(
parent
,
child
)
...
...
@@ -204,6 +208,7 @@ func (b *rawBridge) Create(input *fuse.CreateIn, name string, out *fuse.CreateOu
}
out
.
Fh
=
b
.
registerFile
(
f
)
out
.
NodeId
=
child
.
nodeID
out
.
Ino
=
child
.
nodeID
out
.
Generation
=
b
.
nodes
[
child
.
nodeID
]
.
generation
b
.
mu
.
Unlock
()
unlockNode2
(
parent
,
child
)
...
...
@@ -254,6 +259,8 @@ func (b *rawBridge) GetAttr(input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse
if
b
.
options
.
AttrTimeout
!=
nil
{
out
.
SetTimeout
(
*
b
.
options
.
AttrTimeout
)
}
out
.
Ino
=
input
.
NodeId
return
code
}
...
...
@@ -327,7 +334,16 @@ func (b *rawBridge) SetAttr(input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse
}
func
(
b
*
rawBridge
)
Rename
(
input
*
fuse
.
RenameIn
,
oldName
string
,
newName
string
)
(
code
fuse
.
Status
)
{
return
fuse
.
ENOSYS
p1
,
_
:=
b
.
inode
(
input
.
NodeId
,
0
)
p2
,
_
:=
b
.
inode
(
input
.
Newdir
,
0
)
if
code
:=
p1
.
node
.
Rename
(
context
.
TODO
(),
oldName
,
p2
.
node
,
newName
);
code
.
Ok
()
{
// NOSUBMIT - is it better to have the user code do
// this? Maybe the user code wants a transaction over
// more nodes?
p1
.
MvChild
(
oldName
,
p2
,
newName
)
}
return
code
}
func
(
b
*
rawBridge
)
Link
(
input
*
fuse
.
LinkIn
,
filename
string
,
out
*
fuse
.
EntryOut
)
(
code
fuse
.
Status
)
{
...
...
nodefs/inode.go
View file @
a7a22fce
...
...
@@ -5,6 +5,7 @@
package
nodefs
import
(
"fmt"
"log"
"sort"
"strings"
...
...
@@ -66,6 +67,16 @@ type Inode struct {
parents
map
[
parentData
]
struct
{}
}
// debugString is used for debugging. Racy.
func
(
n
*
Inode
)
debugString
()
string
{
var
ss
[]
string
for
nm
,
ch
:=
range
n
.
children
{
ss
=
append
(
ss
,
fmt
.
Sprintf
(
"%q=%d(%d)"
,
nm
,
ch
.
nodeID
,
ch
.
opaqueID
))
}
return
fmt
.
Sprintf
(
"%d: %s"
,
n
.
nodeID
,
strings
.
Join
(
ss
,
","
))
}
// newInode creates creates new inode pointing to node.
//
// node -> inode association is NOT set.
...
...
@@ -276,6 +287,7 @@ func (n *Inode) newInode(node Node, mode uint32, opaqueID uint64, persistent boo
ch
:=
&
Inode
{
mode
:
mode
^
07777
,
node
:
node
,
opaqueID
:
opaqueID
,
bridge
:
n
.
bridge
,
persistent
:
persistent
,
parents
:
make
(
map
[
parentData
]
struct
{}),
...
...
@@ -299,7 +311,7 @@ func (n *Inode) removeRef(nlookup uint64, dropPersistence bool) (forgotten bool,
n
.
mu
.
Lock
()
if
nlookup
>
0
&&
dropPersistence
{
p
anic
(
"only one allowed"
)
log
.
P
anic
(
"only one allowed"
)
}
else
if
nlookup
>
0
{
n
.
lookupCount
-=
nlookup
n
.
changeCounter
++
...
...
@@ -414,3 +426,44 @@ retry:
return
true
,
true
}
// TODO - RENAME_NOREPLACE, RENAME_EXCHANGE
func
(
n
*
Inode
)
MvChild
(
old
string
,
newParent
*
Inode
,
newName
string
)
{
retry
:
for
{
lockNode2
(
n
,
newParent
)
counter1
:=
n
.
changeCounter
counter2
:=
newParent
.
changeCounter
oldChild
:=
n
.
children
[
old
]
destChild
:=
newParent
.
children
[
newName
]
unlockNode2
(
n
,
newParent
)
lockNodes
(
n
,
newParent
,
oldChild
,
destChild
)
if
counter2
!=
newParent
.
changeCounter
||
counter1
!=
n
.
changeCounter
{
unlockNodes
(
n
,
newParent
,
oldChild
,
destChild
)
continue
retry
}
if
destChild
!=
nil
{
delete
(
newParent
.
children
,
newName
)
delete
(
destChild
.
parents
,
parentData
{
newName
,
newParent
})
destChild
.
changeCounter
++
newParent
.
changeCounter
++
}
if
oldChild
!=
nil
{
newParent
.
children
[
newName
]
=
oldChild
newParent
.
changeCounter
++
delete
(
n
.
children
,
old
)
delete
(
oldChild
.
parents
,
parentData
{
old
,
n
})
oldChild
.
parents
[
parentData
{
newName
,
newParent
}]
=
struct
{}{}
oldChild
.
changeCounter
++
}
unlockNodes
(
n
,
newParent
,
oldChild
,
destChild
)
return
}
}
nodefs/loopback.go
View file @
a7a22fce
...
...
@@ -115,6 +115,20 @@ func (n *loopbackNode) Unlink(ctx context.Context, name string) fuse.Status {
return
fuse
.
ToStatus
(
err
)
}
func
(
n
*
loopbackNode
)
Rename
(
ctx
context
.
Context
,
name
string
,
newParent
Node
,
newName
string
)
fuse
.
Status
{
p1
:=
filepath
.
Join
(
n
.
path
(),
name
)
var
newParentLoopback
*
loopbackNode
if
r
,
ok
:=
newParent
.
(
*
loopbackRoot
);
ok
{
newParentLoopback
=
&
r
.
loopbackNode
}
else
{
newParentLoopback
=
newParent
.
(
*
loopbackNode
)
}
p2
:=
filepath
.
Join
(
newParentLoopback
.
path
(),
newName
)
err
:=
os
.
Rename
(
p1
,
p2
)
return
fuse
.
ToStatus
(
err
)
}
func
(
n
*
loopbackNode
)
Create
(
ctx
context
.
Context
,
name
string
,
flags
uint32
,
mode
uint32
)
(
inode
*
Inode
,
fh
File
,
fuseFlags
uint32
,
code
fuse
.
Status
)
{
p
:=
filepath
.
Join
(
n
.
path
(),
name
)
...
...
nodefs/simple_test.go
View file @
a7a22fce
...
...
@@ -10,6 +10,7 @@ import (
"os"
"path/filepath"
"runtime"
"syscall"
"testing"
"time"
...
...
@@ -59,9 +60,12 @@ func newTestCase(t *testing.T) *testCase {
}
loopback
:=
NewLoopback
(
tc
.
origDir
)
_
=
time
.
Second
oneSec
:=
time
.
Second
tc
.
rawFS
=
NewNodeFS
(
loopback
,
&
Options
{
Debug
:
testutil
.
VerboseTest
(),
Debug
:
testutil
.
VerboseTest
(),
// NOSUBMIT - should run all tests without cache too
EntryTimeout
:
&
oneSec
,
AttrTimeout
:
&
oneSec
,
})
...
...
@@ -244,3 +248,36 @@ func TestMkdir(t *testing.T) {
t
.
Fatalf
(
"Remove: %v"
,
err
)
}
}
func
TestRename
(
t
*
testing
.
T
)
{
tc
:=
newTestCase
(
t
)
defer
tc
.
Clean
()
if
err
:=
os
.
Mkdir
(
tc
.
origDir
+
"/dir"
,
0755
);
err
!=
nil
{
t
.
Fatalf
(
"Mkdir: %v"
,
err
)
}
if
err
:=
ioutil
.
WriteFile
(
tc
.
origDir
+
"/file"
,
[]
byte
(
"hello"
),
0644
);
err
!=
nil
{
t
.
Fatalf
(
"WriteFile: %v"
,
err
)
}
st
:=
syscall
.
Stat_t
{}
if
err
:=
syscall
.
Lstat
(
tc
.
mntDir
+
"/file"
,
&
st
);
err
!=
nil
{
t
.
Fatalf
(
"Lstat before: %v"
,
err
)
}
beforeIno
:=
st
.
Ino
if
err
:=
os
.
Rename
(
tc
.
mntDir
+
"/file"
,
tc
.
mntDir
+
"/dir/renamed"
);
err
!=
nil
{
t
.
Errorf
(
"Rename: %v"
,
err
)
}
if
fi
,
err
:=
os
.
Lstat
(
tc
.
mntDir
+
"/file"
);
err
==
nil
{
t
.
Fatalf
(
"Lstat old: %v"
,
fi
)
}
if
err
:=
syscall
.
Lstat
(
tc
.
mntDir
+
"/dir/renamed"
,
&
st
);
err
!=
nil
{
t
.
Fatalf
(
"Lstat after: %v"
,
err
)
}
if
got
:=
st
.
Ino
;
got
!=
beforeIno
{
t
.
Errorf
(
"got ino %d, want %d"
,
got
,
beforeIno
)
}
}
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