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
7373951b
Commit
7373951b
authored
Mar 09, 2019
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nodefs: rename2 exchange support in loopback
parent
5a5aec24
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
97 additions
and
8 deletions
+97
-8
nodefs/inode.go
nodefs/inode.go
+8
-0
nodefs/loopback.go
nodefs/loopback.go
+33
-4
nodefs/simple_test.go
nodefs/simple_test.go
+56
-4
No files found.
nodefs/inode.go
View file @
7373951b
...
...
@@ -85,6 +85,14 @@ type Inode struct {
parents
map
[
parentData
]
struct
{}
}
func
(
n
*
Inode
)
FileID
()
FileID
{
return
n
.
nodeID
}
func
(
n
*
Inode
)
IsRoot
()
bool
{
return
n
.
nodeID
.
Ino
==
fuse
.
FUSE_ROOT_ID
}
// debugString is used for debugging. Racy.
func
(
n
*
Inode
)
debugString
()
string
{
var
ss
[]
string
...
...
nodefs/loopback.go
View file @
7373951b
...
...
@@ -13,6 +13,7 @@ import (
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/internal"
"golang.org/x/sys/unix"
)
type
loopbackRoot
struct
{
...
...
@@ -150,14 +151,42 @@ func toLoopbackNode(op Operations) *loopbackNode {
return
op
.
(
*
loopbackNode
)
}
func
(
n
*
loopbackNode
)
Rename
(
ctx
context
.
Context
,
name
string
,
newParent
Operations
,
newName
string
,
flags
uint32
)
fuse
.
Status
{
func
(
n
*
loopbackNode
)
renameExchange
(
name
string
,
newparent
*
loopbackNode
,
newName
string
)
fuse
.
Status
{
fd1
,
err
:=
syscall
.
Open
(
n
.
path
(),
syscall
.
O_DIRECTORY
,
0
)
if
err
!=
nil
{
return
fuse
.
ToStatus
(
err
)
}
defer
syscall
.
Close
(
fd1
)
fd2
,
err
:=
syscall
.
Open
(
newparent
.
path
(),
syscall
.
O_DIRECTORY
,
0
)
defer
syscall
.
Close
(
fd2
)
if
err
!=
nil
{
return
fuse
.
ToStatus
(
err
)
}
var
st
syscall
.
Stat_t
if
err
:=
syscall
.
Fstat
(
fd1
,
&
st
);
err
!=
nil
{
return
fuse
.
ToStatus
(
err
)
}
if
!
InodeOf
(
n
)
.
IsRoot
()
&&
InodeOf
(
n
)
.
FileID
()
.
Ino
!=
idFromStat
(
&
st
)
.
Ino
{
return
fuse
.
EBUSY
}
if
err
:=
syscall
.
Fstat
(
fd2
,
&
st
);
err
!=
nil
{
return
fuse
.
ToStatus
(
err
)
}
if
!
InodeOf
(
newparent
)
.
IsRoot
()
&&
InodeOf
(
newparent
)
.
FileID
()
.
Ino
!=
idFromStat
(
&
st
)
.
Ino
{
return
fuse
.
EBUSY
}
if
flags
!=
0
{
return
fuse
.
ENOSYS
return
fuse
.
ToStatus
(
unix
.
Renameat2
(
fd1
,
name
,
fd2
,
newName
,
unix
.
RENAME_EXCHANGE
))
}
func
(
n
*
loopbackNode
)
Rename
(
ctx
context
.
Context
,
name
string
,
newParent
Operations
,
newName
string
,
flags
uint32
)
fuse
.
Status
{
newParentLoopback
:=
toLoopbackNode
(
newParent
)
if
flags
&
unix
.
RENAME_EXCHANGE
!=
0
{
return
n
.
renameExchange
(
name
,
newParentLoopback
,
newName
)
}
p1
:=
filepath
.
Join
(
n
.
path
(),
name
)
newParentLoopback
:=
toLoopbackNode
(
newParent
)
p2
:=
filepath
.
Join
(
newParentLoopback
.
path
(),
newName
)
err
:=
os
.
Rename
(
p1
,
p2
)
...
...
nodefs/simple_test.go
View file @
7373951b
...
...
@@ -22,6 +22,7 @@ import (
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/internal/testutil"
"github.com/kylelemons/godebug/pretty"
)
var
_
=
log
.
Println
...
...
@@ -320,11 +321,62 @@ func TestRenameNoOverwrite(t *testing.T) {
}
else
if
err
!=
syscall
.
EEXIST
{
t
.
Errorf
(
"got %v (%T) want EEXIST"
,
err
,
err
)
}
}
func
TestRenameExchange
(
t
*
testing
.
T
)
{
tc
:=
newTestCase
(
t
)
defer
tc
.
Clean
()
if
err
:=
os
.
Mkdir
(
tc
.
origDir
+
"/dir"
,
0755
);
err
!=
nil
{
t
.
Fatalf
(
"Mkdir: %v"
,
err
)
}
tc
.
writeOrig
(
"file"
,
"hello"
,
0644
)
tc
.
writeOrig
(
"dir/file"
,
"x"
,
0644
)
if
err
:=
unix
.
Renameat2
(
f1
,
"file"
,
f2
,
"file"
,
unix
.
RENAME_EXCHANGE
);
err
==
nil
{
t
.
Errorf
(
"rename EXCHANGE succeeded"
)
}
else
if
err
!=
syscall
.
EINVAL
{
t
.
Errorf
(
"got %v (%T) want %v (%T)"
,
err
,
err
,
syscall
.
EINVAL
,
syscall
.
EINVAL
)
f1
,
err
:=
syscall
.
Open
(
tc
.
mntDir
+
"/"
,
syscall
.
O_DIRECTORY
,
0
)
if
err
!=
nil
{
t
.
Fatalf
(
"open 1: %v"
,
err
)
}
defer
syscall
.
Close
(
f1
)
f2
,
err
:=
syscall
.
Open
(
tc
.
mntDir
+
"/dir"
,
syscall
.
O_DIRECTORY
,
0
)
if
err
!=
nil
{
t
.
Fatalf
(
"open 2: %v"
,
err
)
}
defer
syscall
.
Close
(
f2
)
var
before1
,
before2
unix
.
Stat_t
if
err
:=
unix
.
Fstatat
(
f1
,
"file"
,
&
before1
,
0
);
err
!=
nil
{
t
.
Fatalf
(
"Fstatat: %v"
,
err
)
}
if
err
:=
unix
.
Fstatat
(
f2
,
"file"
,
&
before2
,
0
);
err
!=
nil
{
t
.
Fatalf
(
"Fstatat: %v"
,
err
)
}
if
err
:=
unix
.
Renameat2
(
f1
,
"file"
,
f2
,
"file"
,
unix
.
RENAME_EXCHANGE
);
err
!=
nil
{
t
.
Errorf
(
"rename EXCHANGE: %v"
,
err
)
}
var
after1
,
after2
unix
.
Stat_t
if
err
:=
unix
.
Fstatat
(
f1
,
"file"
,
&
after1
,
0
);
err
!=
nil
{
t
.
Fatalf
(
"Fstatat: %v"
,
err
)
}
if
err
:=
unix
.
Fstatat
(
f2
,
"file"
,
&
after2
,
0
);
err
!=
nil
{
t
.
Fatalf
(
"Fstatat: %v"
,
err
)
}
clearCtime
:=
func
(
s
*
unix
.
Stat_t
)
{
s
.
Ctim
.
Sec
=
0
s
.
Ctim
.
Nsec
=
0
}
clearCtime
(
&
after1
)
clearCtime
(
&
after2
)
clearCtime
(
&
before2
)
clearCtime
(
&
before1
)
if
diff
:=
pretty
.
Compare
(
after1
,
before2
);
diff
!=
""
{
t
.
Errorf
(
"after1, before2: %s"
,
diff
)
}
if
!
reflect
.
DeepEqual
(
after2
,
before1
)
{
t
.
Errorf
(
"after2, before1: %#v, %#v"
,
after2
,
before1
)
}
}
...
...
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