Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jacobsa-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
jacobsa-fuse
Commits
069fff34
Commit
069fff34
authored
Jun 25, 2015
by
Aaron Jacobs
Browse files
Options
Browse Files
Download
Plain Diff
Added a rename op.
For GoogleCloudPlatform/gcsfuse#81.
parents
10b71ca5
b6588a6d
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
502 additions
and
13 deletions
+502
-13
fuseops/convert.go
fuseops/convert.go
+10
-0
fuseops/ops.go
fuseops/ops.go
+52
-0
fuseutil/file_system.go
fuseutil/file_system.go
+4
-0
fuseutil/not_implemented_file_system.go
fuseutil/not_implemented_file_system.go
+6
-0
samples/memfs/inode.go
samples/memfs/inode.go
+6
-2
samples/memfs/memfs.go
samples/memfs/memfs.go
+47
-11
samples/memfs/memfs_test.go
samples/memfs/memfs_test.go
+377
-0
No files found.
fuseops/convert.go
View file @
069fff34
...
...
@@ -117,6 +117,16 @@ func Convert(
io
=
to
co
=
&
to
.
commonOp
case
*
bazilfuse
.
RenameRequest
:
to
:=
&
RenameOp
{
OldParent
:
InodeID
(
typed
.
Header
.
Node
),
OldName
:
typed
.
OldName
,
NewParent
:
InodeID
(
typed
.
NewDir
),
NewName
:
typed
.
NewName
,
}
io
=
to
co
=
&
to
.
commonOp
case
*
bazilfuse
.
RemoveRequest
:
if
typed
.
Dir
{
to
:=
&
RmDirOp
{
...
...
fuseops/ops.go
View file @
069fff34
...
...
@@ -358,6 +358,58 @@ func (o *CreateSymlinkOp) toBazilfuseResponse() (bfResp interface{}) {
// Unlinking
////////////////////////////////////////////////////////////////////////
// Rename a file or directory, given the IDs of the original parent directory
// and the new one (which may be the same).
//
// In Linux, this is called by vfs_rename (https://goo.gl/eERItT), which is
// called by sys_renameat2 (https://goo.gl/fCC9qC).
//
// The kernel takes care of ensuring that the source and destination are not
// identical (in which case it does nothing), that the rename is not across
// file system boundaries, and that the destination doesn't already exist with
// the wrong type. Some subtleties that the file system must care about:
//
// * If the new name is an existing directory, the file system must ensure it
// is empty before replacing it, returning ENOTEMPTY otherwise. (This is
// per the posix spec: http://goo.gl/4XtT79)
//
// * The rename must be atomic from the point of view of an observer of the
// new name. That is, if the new name already exists, there must be no
// point at which it doesn't exist.
//
// * It is okay for the new name to be modified before the old name is
// removed; these need not be atomic. In fact, the Linux man page
// explicitly says this is likely (cf. https://goo.gl/Y1wVZc).
//
// * Linux bends over backwards (https://goo.gl/pLDn3r) to ensure that
// neither the old nor the new parent can be concurrently modified. But
// it's not clear whether OS X does this, and in any case it doesn't matter
// for file systems that may be modified remotely. Therefore a careful file
// system implementor should probably ensure if possible that the unlink
// step in the "link new name, unlink old name" process doesn't unlink a
// different inode than the one that was linked to the new name. Still,
// posix and the man pages are imprecise about the actual semantics of a
// rename if it's not atomic, so it is probably not disastrous to be loose
// about this.
//
type
RenameOp
struct
{
commonOp
// The old parent directory, and the name of the entry within it to be
// relocated.
OldParent
InodeID
OldName
string
// The new parent directory, and the name of the entry to be created or
// overwritten within it.
NewParent
InodeID
NewName
string
}
func
(
o
*
RenameOp
)
toBazilfuseResponse
()
(
bfResp
interface
{})
{
return
}
// Unlink a directory from its parent. Because directories cannot have a link
// count above one, this means the directory inode should be deleted as well
// once the kernel sends ForgetInodeOp.
...
...
fuseutil/file_system.go
View file @
069fff34
...
...
@@ -47,6 +47,7 @@ type FileSystem interface {
MkDir
(
*
fuseops
.
MkDirOp
)
error
CreateFile
(
*
fuseops
.
CreateFileOp
)
error
CreateSymlink
(
*
fuseops
.
CreateSymlinkOp
)
error
Rename
(
*
fuseops
.
RenameOp
)
error
RmDir
(
*
fuseops
.
RmDirOp
)
error
Unlink
(
*
fuseops
.
UnlinkOp
)
error
OpenDir
(
*
fuseops
.
OpenDirOp
)
error
...
...
@@ -148,6 +149,9 @@ func (s *fileSystemServer) handleOp(op fuseops.Op) {
case
*
fuseops
.
CreateSymlinkOp
:
err
=
s
.
fs
.
CreateSymlink
(
typed
)
case
*
fuseops
.
RenameOp
:
err
=
s
.
fs
.
Rename
(
typed
)
case
*
fuseops
.
RmDirOp
:
err
=
s
.
fs
.
RmDir
(
typed
)
...
...
fuseutil/not_implemented_file_system.go
View file @
069fff34
...
...
@@ -70,6 +70,12 @@ func (fs *NotImplementedFileSystem) CreateSymlink(
return
}
func
(
fs
*
NotImplementedFileSystem
)
Rename
(
op
*
fuseops
.
RenameOp
)
(
err
error
)
{
err
=
fuse
.
ENOSYS
return
}
func
(
fs
*
NotImplementedFileSystem
)
RmDir
(
op
*
fuseops
.
RmDirOp
)
(
err
error
)
{
err
=
fuse
.
ENOSYS
...
...
samples/memfs/inode.go
View file @
069fff34
...
...
@@ -202,10 +202,14 @@ func (in *inode) Len() (n int) {
// Find an entry for the given child name and return its inode ID.
//
// REQUIRES: in.isDir()
func
(
in
*
inode
)
LookUpChild
(
name
string
)
(
id
fuseops
.
InodeID
,
ok
bool
)
{
func
(
in
*
inode
)
LookUpChild
(
name
string
)
(
id
fuseops
.
InodeID
,
typ
fuseutil
.
DirentType
,
ok
bool
)
{
index
,
ok
:=
in
.
findChild
(
name
)
if
ok
{
id
=
in
.
entries
[
index
]
.
Inode
typ
=
in
.
entries
[
index
]
.
Type
}
return
...
...
@@ -274,7 +278,7 @@ func (in *inode) RemoveChild(name string) {
// Serve a ReadDir request.
//
// REQUIRES: in.isDir()
func
(
in
*
inode
)
ReadDir
(
offset
int
,
size
int
)
(
data
[]
byte
,
err
error
)
{
func
(
in
*
inode
)
ReadDir
(
offset
int
,
size
int
)
(
data
[]
byte
)
{
if
!
in
.
isDir
()
{
panic
(
"ReadDir called on non-directory."
)
}
...
...
samples/memfs/memfs.go
View file @
069fff34
...
...
@@ -192,7 +192,7 @@ func (fs *memFS) LookUpInode(
inode
:=
fs
.
getInodeOrDie
(
op
.
Parent
)
// Does the directory have an entry with the given name?
childID
,
ok
:=
inode
.
LookUpChild
(
op
.
Name
)
childID
,
_
,
ok
:=
inode
.
LookUpChild
(
op
.
Name
)
if
!
ok
{
err
=
fuse
.
ENOENT
return
...
...
@@ -262,7 +262,7 @@ func (fs *memFS) MkDir(
// Ensure that the name doesn't already exist, so we don't wind up with a
// duplicate.
_
,
exists
:=
parent
.
LookUpChild
(
op
.
Name
)
_
,
_
,
exists
:=
parent
.
LookUpChild
(
op
.
Name
)
if
exists
{
err
=
fuse
.
EEXIST
return
...
...
@@ -305,7 +305,7 @@ func (fs *memFS) CreateFile(
// Ensure that the name doesn't already exist, so we don't wind up with a
// duplicate.
_
,
exists
:=
parent
.
LookUpChild
(
op
.
Name
)
_
,
_
,
exists
:=
parent
.
LookUpChild
(
op
.
Name
)
if
exists
{
err
=
fuse
.
EEXIST
return
...
...
@@ -355,7 +355,7 @@ func (fs *memFS) CreateSymlink(
// Ensure that the name doesn't already exist, so we don't wind up with a
// duplicate.
_
,
exists
:=
parent
.
LookUpChild
(
op
.
Name
)
_
,
_
,
exists
:=
parent
.
LookUpChild
(
op
.
Name
)
if
exists
{
err
=
fuse
.
EEXIST
return
...
...
@@ -396,6 +396,46 @@ func (fs *memFS) CreateSymlink(
return
}
func
(
fs
*
memFS
)
Rename
(
op
*
fuseops
.
RenameOp
)
(
err
error
)
{
fs
.
mu
.
Lock
()
defer
fs
.
mu
.
Unlock
()
// Ask the old parent for the child's inode ID and type.
oldParent
:=
fs
.
getInodeOrDie
(
op
.
OldParent
)
childID
,
childType
,
ok
:=
oldParent
.
LookUpChild
(
op
.
OldName
)
if
!
ok
{
err
=
fuse
.
ENOENT
return
}
// If the new name exists already in the new parent, make sure it's not a
// non-empty directory, then delete it.
newParent
:=
fs
.
getInodeOrDie
(
op
.
NewParent
)
existingID
,
_
,
ok
:=
newParent
.
LookUpChild
(
op
.
NewName
)
if
ok
{
existing
:=
fs
.
getInodeOrDie
(
existingID
)
if
existing
.
isDir
()
&&
len
(
existing
.
ReadDir
(
0
,
1024
))
>
0
{
err
=
fuse
.
ENOTEMPTY
return
}
newParent
.
RemoveChild
(
op
.
NewName
)
}
// Link the new name.
newParent
.
AddChild
(
childID
,
op
.
NewName
,
childType
)
// Finally, remove the old name from the old parent.
oldParent
.
RemoveChild
(
op
.
OldName
)
return
}
func
(
fs
*
memFS
)
RmDir
(
op
*
fuseops
.
RmDirOp
)
(
err
error
)
{
fs
.
mu
.
Lock
()
...
...
@@ -405,7 +445,7 @@ func (fs *memFS) RmDir(
parent
:=
fs
.
getInodeOrDie
(
op
.
Parent
)
// Find the child within the parent.
childID
,
ok
:=
parent
.
LookUpChild
(
op
.
Name
)
childID
,
_
,
ok
:=
parent
.
LookUpChild
(
op
.
Name
)
if
!
ok
{
err
=
fuse
.
ENOENT
return
...
...
@@ -438,7 +478,7 @@ func (fs *memFS) Unlink(
parent
:=
fs
.
getInodeOrDie
(
op
.
Parent
)
// Find the child within the parent.
childID
,
ok
:=
parent
.
LookUpChild
(
op
.
Name
)
childID
,
_
,
ok
:=
parent
.
LookUpChild
(
op
.
Name
)
if
!
ok
{
err
=
fuse
.
ENOENT
return
...
...
@@ -482,11 +522,7 @@ func (fs *memFS) ReadDir(
inode
:=
fs
.
getInodeOrDie
(
op
.
Inode
)
// Serve the request.
op
.
Data
,
err
=
inode
.
ReadDir
(
int
(
op
.
Offset
),
op
.
Size
)
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"inode.ReadDir: %v"
,
err
)
return
}
op
.
Data
=
inode
.
ReadDir
(
int
(
op
.
Offset
),
op
.
Size
)
return
}
...
...
samples/memfs/memfs_test.go
View file @
069fff34
...
...
@@ -1271,3 +1271,380 @@ func (t *MemFSTest) MkdirInParallel() {
func
(
t
*
MemFSTest
)
SymlinkInParallel
()
{
fusetesting
.
RunSymlinkInParallelTest
(
t
.
Ctx
,
t
.
Dir
)
}
func
(
t
*
MemFSTest
)
RenameWithinDir_File
()
{
var
err
error
// Create a parent directory.
parentPath
:=
path
.
Join
(
t
.
Dir
,
"parent"
)
err
=
os
.
Mkdir
(
parentPath
,
0700
)
AssertEq
(
nil
,
err
)
// And a file within it.
oldPath
:=
path
.
Join
(
parentPath
,
"foo"
)
err
=
ioutil
.
WriteFile
(
oldPath
,
[]
byte
(
"taco"
),
0400
)
AssertEq
(
nil
,
err
)
// Rename it.
newPath
:=
path
.
Join
(
parentPath
,
"bar"
)
err
=
os
.
Rename
(
oldPath
,
newPath
)
AssertEq
(
nil
,
err
)
// The old name shouldn't work.
_
,
err
=
os
.
Stat
(
oldPath
)
ExpectTrue
(
os
.
IsNotExist
(
err
),
"err: %v"
,
err
)
_
,
err
=
ioutil
.
ReadFile
(
oldPath
)
ExpectTrue
(
os
.
IsNotExist
(
err
),
"err: %v"
,
err
)
// The new name should.
fi
,
err
:=
os
.
Stat
(
newPath
)
AssertEq
(
nil
,
err
)
ExpectEq
(
len
(
"taco"
),
fi
.
Size
())
ExpectEq
(
os
.
FileMode
(
0400
),
fi
.
Mode
())
contents
,
err
:=
ioutil
.
ReadFile
(
newPath
)
AssertEq
(
nil
,
err
)
ExpectEq
(
"taco"
,
string
(
contents
))
// There should only be the new entry in the directory.
entries
,
err
:=
fusetesting
.
ReadDirPicky
(
parentPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
path
.
Base
(
newPath
),
fi
.
Name
())
ExpectEq
(
os
.
FileMode
(
0400
),
fi
.
Mode
())
}
func
(
t
*
MemFSTest
)
RenameWithinDir_Directory
()
{
var
err
error
// Create a parent directory.
parentPath
:=
path
.
Join
(
t
.
Dir
,
"parent"
)
err
=
os
.
Mkdir
(
parentPath
,
0700
)
AssertEq
(
nil
,
err
)
// And a non-empty directory within it.
oldPath
:=
path
.
Join
(
parentPath
,
"foo"
)
err
=
os
.
MkdirAll
(
path
.
Join
(
oldPath
,
"child"
),
0700
)
AssertEq
(
nil
,
err
)
// Rename it.
newPath
:=
path
.
Join
(
parentPath
,
"bar"
)
err
=
os
.
Rename
(
oldPath
,
newPath
)
AssertEq
(
nil
,
err
)
// The old name shouldn't work.
_
,
err
=
os
.
Stat
(
oldPath
)
ExpectTrue
(
os
.
IsNotExist
(
err
),
"err: %v"
,
err
)
// The new name should.
fi
,
err
:=
os
.
Stat
(
newPath
)
AssertEq
(
nil
,
err
)
ExpectEq
(
os
.
FileMode
(
0700
)
|
os
.
ModeDir
,
fi
.
Mode
())
// There should only be the new entry in the parent.
entries
,
err
:=
fusetesting
.
ReadDirPicky
(
parentPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
path
.
Base
(
newPath
),
fi
.
Name
())
ExpectEq
(
os
.
FileMode
(
0700
)
|
os
.
ModeDir
,
fi
.
Mode
())
// And the child should still be present.
entries
,
err
=
fusetesting
.
ReadDirPicky
(
newPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
"child"
,
fi
.
Name
())
ExpectEq
(
os
.
FileMode
(
0700
)
|
os
.
ModeDir
,
fi
.
Mode
())
}
func
(
t
*
MemFSTest
)
RenameWithinDir_SameName
()
{
var
err
error
// Create a parent directory.
parentPath
:=
path
.
Join
(
t
.
Dir
,
"parent"
)
err
=
os
.
Mkdir
(
parentPath
,
0700
)
AssertEq
(
nil
,
err
)
// And a file within it.
filePath
:=
path
.
Join
(
parentPath
,
"foo"
)
err
=
ioutil
.
WriteFile
(
filePath
,
[]
byte
(
"taco"
),
0400
)
AssertEq
(
nil
,
err
)
// Attempt to rename it.
err
=
os
.
Rename
(
filePath
,
filePath
)
AssertEq
(
nil
,
err
)
// The file should still exist.
contents
,
err
:=
ioutil
.
ReadFile
(
filePath
)
AssertEq
(
nil
,
err
)
ExpectEq
(
"taco"
,
string
(
contents
))
// There should only be the one entry in the directory.
entries
,
err
:=
fusetesting
.
ReadDirPicky
(
parentPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
:=
entries
[
0
]
ExpectEq
(
path
.
Base
(
filePath
),
fi
.
Name
())
ExpectEq
(
os
.
FileMode
(
0400
),
fi
.
Mode
())
}
func
(
t
*
MemFSTest
)
RenameAcrossDirs_File
()
{
var
err
error
// Create two parent directories.
oldParentPath
:=
path
.
Join
(
t
.
Dir
,
"old"
)
newParentPath
:=
path
.
Join
(
t
.
Dir
,
"new"
)
err
=
os
.
Mkdir
(
oldParentPath
,
0700
)
AssertEq
(
nil
,
err
)
err
=
os
.
Mkdir
(
newParentPath
,
0700
)
AssertEq
(
nil
,
err
)
// And a file within the first.
oldPath
:=
path
.
Join
(
oldParentPath
,
"foo"
)
err
=
ioutil
.
WriteFile
(
oldPath
,
[]
byte
(
"taco"
),
0400
)
AssertEq
(
nil
,
err
)
// Rename it.
newPath
:=
path
.
Join
(
newParentPath
,
"bar"
)
err
=
os
.
Rename
(
oldPath
,
newPath
)
AssertEq
(
nil
,
err
)
// The old name shouldn't work.
_
,
err
=
os
.
Stat
(
oldPath
)
ExpectTrue
(
os
.
IsNotExist
(
err
),
"err: %v"
,
err
)
_
,
err
=
ioutil
.
ReadFile
(
oldPath
)
ExpectTrue
(
os
.
IsNotExist
(
err
),
"err: %v"
,
err
)
// The new name should.
fi
,
err
:=
os
.
Stat
(
newPath
)
AssertEq
(
nil
,
err
)
ExpectEq
(
len
(
"taco"
),
fi
.
Size
())
ExpectEq
(
os
.
FileMode
(
0400
),
fi
.
Mode
())
contents
,
err
:=
ioutil
.
ReadFile
(
newPath
)
AssertEq
(
nil
,
err
)
ExpectEq
(
"taco"
,
string
(
contents
))
// Check the old parent.
entries
,
err
:=
fusetesting
.
ReadDirPicky
(
oldParentPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
0
,
len
(
entries
))
// And the new one.
entries
,
err
=
fusetesting
.
ReadDirPicky
(
newParentPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
path
.
Base
(
newPath
),
fi
.
Name
())
ExpectEq
(
os
.
FileMode
(
0400
),
fi
.
Mode
())
}
func
(
t
*
MemFSTest
)
RenameAcrossDirs_Directory
()
{
var
err
error
// Create two parent directories.
oldParentPath
:=
path
.
Join
(
t
.
Dir
,
"old"
)
newParentPath
:=
path
.
Join
(
t
.
Dir
,
"new"
)
err
=
os
.
Mkdir
(
oldParentPath
,
0700
)
AssertEq
(
nil
,
err
)
err
=
os
.
Mkdir
(
newParentPath
,
0700
)
AssertEq
(
nil
,
err
)
// And a non-empty directory within the first.
oldPath
:=
path
.
Join
(
oldParentPath
,
"foo"
)
err
=
os
.
MkdirAll
(
path
.
Join
(
oldPath
,
"child"
),
0700
)
AssertEq
(
nil
,
err
)
// Rename it.
newPath
:=
path
.
Join
(
newParentPath
,
"bar"
)
err
=
os
.
Rename
(
oldPath
,
newPath
)
AssertEq
(
nil
,
err
)
// The old name shouldn't work.
_
,
err
=
os
.
Stat
(
oldPath
)
ExpectTrue
(
os
.
IsNotExist
(
err
),
"err: %v"
,
err
)
// The new name should.
fi
,
err
:=
os
.
Stat
(
newPath
)
AssertEq
(
nil
,
err
)
ExpectEq
(
os
.
FileMode
(
0700
)
|
os
.
ModeDir
,
fi
.
Mode
())
// And the child should still be present.
entries
,
err
:=
fusetesting
.
ReadDirPicky
(
newPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
"child"
,
fi
.
Name
())
ExpectEq
(
os
.
FileMode
(
0700
)
|
os
.
ModeDir
,
fi
.
Mode
())
// Check the old parent.
entries
,
err
=
fusetesting
.
ReadDirPicky
(
oldParentPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
0
,
len
(
entries
))
// And the new one.
entries
,
err
=
fusetesting
.
ReadDirPicky
(
newParentPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
path
.
Base
(
newPath
),
fi
.
Name
())
ExpectEq
(
os
.
FileMode
(
0700
)
|
os
.
ModeDir
,
fi
.
Mode
())
}
func
(
t
*
MemFSTest
)
RenameOutOfFileSystem
()
{
var
err
error
// Create a file.
oldPath
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
ioutil
.
WriteFile
(
oldPath
,
[]
byte
(
"taco"
),
0400
)
AssertEq
(
nil
,
err
)
// Attempt to move it out of the file system.
tempDir
,
err
:=
ioutil
.
TempDir
(
""
,
"memfs_test"
)
AssertEq
(
nil
,
err
)
defer
os
.
RemoveAll
(
tempDir
)
err
=
os
.
Rename
(
oldPath
,
path
.
Join
(
tempDir
,
"bar"
))
ExpectThat
(
err
,
Error
(
HasSubstr
(
"cross-device"
)))
}
func
(
t
*
MemFSTest
)
RenameIntoFileSystem
()
{
var
err
error
// Create a file outside of our file system.
f
,
err
:=
ioutil
.
TempFile
(
""
,
"memfs_test"
)
AssertEq
(
nil
,
err
)
defer
f
.
Close
()
oldPath
:=
f
.
Name
()
defer
os
.
Remove
(
oldPath
)
// Attempt to move it into the file system.
err
=
os
.
Rename
(
oldPath
,
path
.
Join
(
t
.
Dir
,
"bar"
))
ExpectThat
(
err
,
Error
(
HasSubstr
(
"cross-device"
)))
}
func
(
t
*
MemFSTest
)
RenameOverExistingFile
()
{
var
err
error
// Create two files.
oldPath
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
ioutil
.
WriteFile
(
oldPath
,
[]
byte
(
"taco"
),
0400
)
AssertEq
(
nil
,
err
)
newPath
:=
path
.
Join
(
t
.
Dir
,
"bar"
)
err
=
ioutil
.
WriteFile
(
newPath
,
[]
byte
(
"burrito"
),
0600
)
AssertEq
(
nil
,
err
)
// Rename one over the other.
err
=
os
.
Rename
(
oldPath
,
newPath
)
AssertEq
(
nil
,
err
)
// Check the file contents.
contents
,
err
:=
ioutil
.
ReadFile
(
newPath
)
AssertEq
(
nil
,
err
)
ExpectEq
(
"taco"
,
string
(
contents
))
// And the parent listing.
entries
,
err
:=
fusetesting
.
ReadDirPicky
(
t
.
Dir
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
:=
entries
[
0
]
ExpectEq
(
path
.
Base
(
newPath
),
fi
.
Name
())
ExpectEq
(
os
.
FileMode
(
0400
),
fi
.
Mode
())
ExpectEq
(
len
(
"taco"
),
fi
.
Size
())
}
func
(
t
*
MemFSTest
)
RenameOverExistingDirectory
()
{
var
err
error
// Create two directories, the first non-empty.
oldPath
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
os
.
MkdirAll
(
path
.
Join
(
oldPath
,
"child"
),
0700
)
AssertEq
(
nil
,
err
)
newPath
:=
path
.
Join
(
t
.
Dir
,
"bar"
)
err
=
os
.
Mkdir
(
newPath
,
0600
)
AssertEq
(
nil
,
err
)
// Renaming over the non-empty one shouldn't work.
err
=
os
.
Rename
(
newPath
,
oldPath
)
ExpectThat
(
err
,
Error
(
HasSubstr
(
"not empty"
)))
// But the other way around should.
err
=
os
.
Rename
(
oldPath
,
newPath
)
AssertEq
(
nil
,
err
)
// Check the parent listing.
entries
,
err
:=
fusetesting
.
ReadDirPicky
(
t
.
Dir
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
:=
entries
[
0
]
ExpectEq
(
path
.
Base
(
newPath
),
fi
.
Name
())
ExpectEq
(
os
.
FileMode
(
0700
)
|
os
.
ModeDir
,
fi
.
Mode
())
// And the directory itself.
entries
,
err
=
fusetesting
.
ReadDirPicky
(
newPath
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
"child"
,
fi
.
Name
())
}
func
(
t
*
MemFSTest
)
RenameOverExisting_WrongType
()
{
var
err
error
// Create a file and a directory.
filePath
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
ioutil
.
WriteFile
(
filePath
,
[]
byte
(
"taco"
),
0400
)
AssertEq
(
nil
,
err
)
dirPath
:=
path
.
Join
(
t
.
Dir
,
"bar"
)
err
=
os
.
Mkdir
(
dirPath
,
0700
)
AssertEq
(
nil
,
err
)
// Renaming one over the other shouldn't work.
err
=
os
.
Rename
(
filePath
,
dirPath
)
ExpectThat
(
err
,
Error
(
HasSubstr
(
"is a directory"
)))
err
=
os
.
Rename
(
dirPath
,
filePath
)
ExpectThat
(
err
,
Error
(
HasSubstr
(
"not a directory"
)))
}
func
(
t
*
MemFSTest
)
RenameNonExistentFile
()
{
var
err
error
err
=
os
.
Rename
(
path
.
Join
(
t
.
Dir
,
"foo"
),
path
.
Join
(
t
.
Dir
,
"bar"
))
ExpectThat
(
err
,
Error
(
HasSubstr
(
"no such file"
)))
}
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