summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorsbc@chromium.org <sbc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-08 18:45:09 +0000
committersbc@chromium.org <sbc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-08 18:45:09 +0000
commite9177515127e6f37247b3875248d0589d42209c9 (patch)
tree946bd7862017f8b08ba68ab0ac12521534f19770 /native_client_sdk
parenta5e38520049d0335802646ddb9840ea6b0e9c91d (diff)
downloadchromium_src-e9177515127e6f37247b3875248d0589d42209c9.zip
chromium_src-e9177515127e6f37247b3875248d0589d42209c9.tar.gz
chromium_src-e9177515127e6f37247b3875248d0589d42209c9.tar.bz2
[NaCl SDK] add rename(2) support to nacl_io.
Currently only supported by memfs. R=binji@chromium.org Review URL: https://codereview.chromium.org/64823004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@233947 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc35
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.cc10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc15
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_html5fs.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_http.cc8
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_http.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_mem.cc70
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_mem.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc5
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_stream.cc8
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_stream.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/path.h3
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc1
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc17
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_mock.h1
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_test.cc75
19 files changed, 240 insertions, 15 deletions
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
index 1f15a9b..1d26e0b 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -612,8 +612,39 @@ int KernelProxy::lstat(const char* path, struct stat* buf) {
}
int KernelProxy::rename(const char* path, const char* newpath) {
- errno = ENOSYS;
- return -1;
+ ScopedMount mnt;
+ Path rel;
+ Error error = AcquireMountAndRelPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ ScopedMount newmnt;
+ Path newrel;
+ error = AcquireMountAndRelPath(newpath, &newmnt, &newrel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ if (newmnt.get() != mnt.get()) {
+ // Renaming accross mountpoints is not allowed
+ errno = EXDEV;
+ return -1;
+ }
+
+ // They already point to the same path
+ if (rel == newrel)
+ return 0;
+
+ error = mnt->Rename(rel, newrel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ return 0;
}
int KernelProxy::remove(const char* path) {
diff --git a/native_client_sdk/src/libraries/nacl_io/mount.h b/native_client_sdk/src/libraries/nacl_io/mount.h
index 65a6e7a..b13fc08 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount.h
@@ -68,6 +68,7 @@ class Mount : public sdk_util::RefObject {
virtual Error Mkdir(const Path& path, int permissions) = 0;
virtual Error Rmdir(const Path& path) = 0;
virtual Error Remove(const Path& path) = 0;
+ virtual Error Rename(const Path& path, const Path& newpath) = 0;
// Assumes that |node| is non-NULL.
void OnNodeCreated(MountNode* node);
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
index fdc6379..14acb6d 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
@@ -288,13 +288,15 @@ Error MountDev::Open(const Path& path,
return root_->FindChild(path.Join(), out_node);
}
-Error MountDev::Unlink(const Path& path) { return EINVAL; }
+Error MountDev::Unlink(const Path& path) { return EPERM; }
-Error MountDev::Mkdir(const Path& path, int permissions) { return EINVAL; }
+Error MountDev::Mkdir(const Path& path, int permissions) { return EPERM; }
-Error MountDev::Rmdir(const Path& path) { return EINVAL; }
+Error MountDev::Rmdir(const Path& path) { return EPERM; }
-Error MountDev::Remove(const Path& path) { return EINVAL; }
+Error MountDev::Remove(const Path& path) { return EPERM; }
+
+Error MountDev::Rename(const Path& path, const Path& newpath) { return EPERM; }
MountDev::MountDev() {}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_dev.h b/native_client_sdk/src/libraries/nacl_io/mount_dev.h
index 5b253cd..640158b 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_dev.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.h
@@ -22,6 +22,7 @@ class MountDev : public Mount {
virtual Error Mkdir(const Path& path, int permissions);
virtual Error Rmdir(const Path& path);
virtual Error Remove(const Path& path);
+ virtual Error Rename(const Path& path, const Path& newpath);
protected:
MountDev();
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
index da8b4bb..3c9695f 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
@@ -103,6 +103,21 @@ Error MountHtml5Fs::Remove(const Path& path) {
return 0;
}
+Error MountHtml5Fs::Rename(const Path& path, const Path& newpath) {
+ Error error = BlockUntilFilesystemOpen();
+ if (error)
+ return error;
+
+ ScopedResource fileref_resource(
+ ppapi(),
+ ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
+ path.Join().c_str()));
+ if (!fileref_resource.pp_resource())
+ return ENOENT;
+
+ return EACCES;
+}
+
MountHtml5Fs::MountHtml5Fs()
: filesystem_resource_(0),
filesystem_open_has_result_(false),
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
index 8efa112..0408c79 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
@@ -24,6 +24,7 @@ class MountHtml5Fs : public Mount {
virtual Error Mkdir(const Path& path, int permissions);
virtual Error Rmdir(const Path& path);
virtual Error Remove(const Path& path);
+ virtual Error Rename(const Path& path, const Path& newpath);
PP_Resource filesystem_resource() { return filesystem_resource_; }
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_http.cc b/native_client_sdk/src/libraries/nacl_io/mount_http.cc
index 2d0eaa0..dcc1332 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_http.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_http.cc
@@ -138,6 +138,14 @@ Error MountHttp::Remove(const Path& path) {
return EACCES;
}
+Error MountHttp::Rename(const Path& path, const Path& newpath) {
+ NodeMap_t::iterator iter = node_cache_.find(path.Join());
+ if (iter == node_cache_.end())
+ return ENOENT;
+
+ return EACCES;
+}
+
PP_Resource MountHttp::MakeUrlRequestInfo(const std::string& url,
const char* method,
StringMap_t* additional_headers) {
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_http.h b/native_client_sdk/src/libraries/nacl_io/mount_http.h
index adec0e3..21d688e 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_http.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_http.h
@@ -29,6 +29,7 @@ class MountHttp : public Mount {
virtual Error Mkdir(const Path& path, int permissions);
virtual Error Rmdir(const Path& path);
virtual Error Remove(const Path& path);
+ virtual Error Rename(const Path& path, const Path& newpath);
PP_Resource MakeUrlRequestInfo(const std::string& url,
const char* method,
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_mem.cc b/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
index b7f2e77..dd4a402 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
@@ -184,6 +184,75 @@ Error MountMem::Remove(const Path& path) {
return RemoveInternal(path, REMOVE_ALL);
}
+Error MountMem::Rename(const Path& src_path, const Path& target_path) {
+ ScopedMountNode src_node;
+ ScopedMountNode src_parent;
+ ScopedMountNode target_node;
+ ScopedMountNode target_parent;
+ int error = FindNode(src_path, 0, &src_node);
+ if (error)
+ return error;
+
+ // The source must exist
+ error = FindNode(src_path.Parent(), S_IFDIR, &src_parent);
+ if (error)
+ return error;
+
+ // The parent of the target must exist
+ error = FindNode(target_path.Parent(), 0, &target_parent);
+ if (error)
+ return error;
+
+ std::string target_name = target_path.Basename();
+
+ // The target itself need not exist but if it does there are
+ // certain restrictions
+ error = FindNode(target_path, 0, &target_node);
+ bool replacing_target = error == 0;
+ if (replacing_target) {
+ if (target_node->IsaDir()) {
+ // If the target is a direcotry it must be empty
+ if (target_node->ChildCount()) {
+ return ENOTEMPTY;
+ }
+
+ if (src_node->IsaDir()) {
+ // Replacing an existing directory.
+ RemoveInternal(target_path, REMOVE_ALL);
+ } else {
+ // Renaming into an existing directory.
+ target_name = src_path.Basename();
+ target_parent = target_node;
+ }
+ } else {
+ if (src_node->IsaDir())
+ // Can't replace a file with a direcotory
+ return EISDIR;
+
+ // Replacing an existing file.
+ target_parent->RemoveChild(target_path.Basename());
+ }
+ }
+
+ // Perform that actual rename. Simply re-parent the original source node
+ // onto its new parent node.
+ error = src_parent->RemoveChild(src_path.Basename());
+ if (error)
+ return error;
+
+ error = target_parent->AddChild(target_name, src_node);
+ if (error) {
+ // Re-parent the old target_node if we failed to add the new one.
+ if (replacing_target)
+ target_parent->AddChild(target_path.Basename(), target_node);
+ // Re-parent the src_node
+ target_parent->AddChild(target_path.Basename(), src_node);
+ return error;
+ }
+
+ return 0;
+}
+
Error MountMem::RemoveInternal(const Path& path, int remove_type) {
bool dir_only = remove_type == REMOVE_DIR;
bool file_only = remove_type == REMOVE_FILE;
@@ -223,4 +292,3 @@ Error MountMem::RemoveInternal(const Path& path, int remove_type) {
}
} // namespace nacl_io
-
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_mem.h b/native_client_sdk/src/libraries/nacl_io/mount_mem.h
index 04ee665..4966975 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_mem.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_mem.h
@@ -34,6 +34,7 @@ class MountMem : public Mount {
virtual Error Mkdir(const Path& path, int perm);
virtual Error Rmdir(const Path& path);
virtual Error Remove(const Path& path);
+ virtual Error Rename(const Path& path, const Path& newpath);
private:
static const int REMOVE_DIR = 1;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
index f4c9951..33e6675 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
@@ -167,5 +167,10 @@ Error MountPassthrough::Remove(const Path& path) {
return ENOSYS;
}
+Error MountPassthrough::Rename(const Path& path, const Path& newpath) {
+ // Not implemented by NaCl.
+ return ENOSYS;
+}
+
} // namespace nacl_io
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
index de4f81c..7b9aa61 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
@@ -25,6 +25,7 @@ class MountPassthrough : public Mount {
virtual Error Mkdir(const Path& path, int perm);
virtual Error Rmdir(const Path& path);
virtual Error Remove(const Path& path);
+ virtual Error Rename(const Path& path, const Path& newpath);
private:
friend class TypedMountFactory<MountPassthrough>;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_stream.cc b/native_client_sdk/src/libraries/nacl_io/mount_stream.cc
index e38c8c9..e7b23ef 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_stream.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_stream.cc
@@ -86,13 +86,21 @@ MountStream::~MountStream() {
}
Error MountStream::Access(const Path& path, int a_mode) { return EACCES; }
+
Error MountStream::Open(const Path& path,
int o_flags,
ScopedMountNode* out_node) { return EACCES; }
Error MountStream::Unlink(const Path& path) { return EACCES; }
+
Error MountStream::Mkdir(const Path& path, int permissions) { return EACCES; }
+
Error MountStream::Rmdir(const Path& path) { return EACCES; }
+
Error MountStream::Remove(const Path& path) { return EACCES; }
+Error MountStream::Rename(const Path& path, const Path& newpath) {
+ return EACCES;
+}
+
} // namespace nacl_io
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_stream.h b/native_client_sdk/src/libraries/nacl_io/mount_stream.h
index 757e132..e03abe7 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_stream.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_stream.h
@@ -63,6 +63,7 @@ class MountStream : public Mount {
virtual Error Mkdir(const Path& path, int permissions);
virtual Error Rmdir(const Path& path);
virtual Error Remove(const Path& path);
+ virtual Error Rename(const Path& path, const Path& newpath);
static void* StreamThreadThunk(void*);
void StreamThread();
diff --git a/native_client_sdk/src/libraries/nacl_io/path.h b/native_client_sdk/src/libraries/nacl_io/path.h
index 9131d6a..4b39daf 100644
--- a/native_client_sdk/src/libraries/nacl_io/path.h
+++ b/native_client_sdk/src/libraries/nacl_io/path.h
@@ -25,7 +25,6 @@ class Path {
explicit Path(const std::string& path);
~Path();
-
// Return true of the first path item is '/'.
bool IsAbsolute() const;
@@ -60,6 +59,8 @@ class Path {
// Operator versions
Path& operator=(const Path& p);
Path& operator=(const std::string& str);
+ bool operator==(const Path& other) { return Split() == other.Split(); }
+ bool operator!=(const Path& other) { return !operator==(other); }
private:
// Internal representation of the path stored an array of string representing
diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc
index d86bd93..67e70f4 100644
--- a/native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc
@@ -40,6 +40,7 @@ class MountRefMock : public Mount {
Error Mkdir(const Path& path, int permissions) { return 0; }
Error Rmdir(const Path& path) { return 0; }
Error Remove(const Path& path) { return 0; }
+ Error Rename(const Path& path, const Path& newpath) { return 0; }
};
class KernelHandleRefMock : public KernelHandle {
diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
index 5c0a772..6d9af12 100644
--- a/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
@@ -127,6 +127,21 @@ TEST_F(KernelProxyTest, FileLeak) {
ASSERT_EQ(0, root->ChildCount());
}
+TEST_F(KernelProxyTest, Rename) {
+ // Create a dummy file
+ int file1 = ki_open("/test1.txt", O_RDWR | O_CREAT);
+ ASSERT_GT(file1, -1);
+ ASSERT_EQ(0, ki_close(file1));
+
+ // Test the renaming works
+ ASSERT_EQ(0, ki_rename("/test1.txt", "/test2.txt"));
+
+ // Test that renaming across mount points fails
+ ASSERT_EQ(0, ki_mount("", "/foo", "memfs", 0, ""));
+ ASSERT_EQ(-1, ki_rename("/test2.txt", "/foo/test2.txt"));
+ ASSERT_EQ(EXDEV, errno);
+}
+
TEST_F(KernelProxyTest, WorkingDirectory) {
char text[1024];
@@ -407,6 +422,7 @@ class MountMockMMap : public Mount {
virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
virtual Error Rmdir(const Path& path) { return ENOSYS; }
virtual Error Remove(const Path& path) { return ENOSYS; }
+ virtual Error Rename(const Path& path, const Path& newpath) { return ENOSYS; }
friend class TypedMountFactory<MountMockMMap>;
};
@@ -565,4 +581,3 @@ TEST_F(KernelProxyErrorTest, ReadError) {
// propagate through.
EXPECT_EQ(1234, errno);
}
-
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_mock.h b/native_client_sdk/src/tests/nacl_io_test/mount_mock.h
index 10d1cf2..b0e5700 100644
--- a/native_client_sdk/src/tests/nacl_io_test/mount_mock.h
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_mock.h
@@ -29,6 +29,7 @@ class MountMock : public nacl_io::Mount {
MOCK_METHOD2(Mkdir, Error(const Path&, int));
MOCK_METHOD1(Rmdir, Error(const Path&));
MOCK_METHOD1(Remove, Error(const Path&));
+ MOCK_METHOD2(Rename, Error(const Path&, const Path&));
};
#endif // LIBRARIES_NACL_IO_TEST_MOUNT_MOCK_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_test.cc
index 3f43ac9..ed6d674 100644
--- a/native_client_sdk/src/tests/nacl_io_test/mount_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_test.cc
@@ -188,8 +188,8 @@ TEST(MountTest, MemMountRemove) {
ScopedMountNode file;
ScopedMountNode result_node;
- EXPECT_EQ(0, mnt.Mkdir(Path("/dir"), O_RDWR));
- EXPECT_EQ(0, mnt.Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
+ ASSERT_EQ(0, mnt.Mkdir(Path("/dir"), O_RDWR));
+ ASSERT_EQ(0, mnt.Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
EXPECT_NE(NULL_NODE, file.get());
EXPECT_EQ(3, mnt.num_nodes());
file.reset();
@@ -199,11 +199,74 @@ TEST(MountTest, MemMountRemove) {
EXPECT_EQ(0, mnt.Remove(Path("/file")));
EXPECT_EQ(1, mnt.num_nodes());
- EXPECT_EQ(ENOENT,
+ ASSERT_EQ(ENOENT,
mnt.Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
- EXPECT_EQ(NULL_NODE, result_node.get());
- EXPECT_EQ(ENOENT, mnt.Open(Path("/file"), O_RDONLY, &result_node));
- EXPECT_EQ(NULL_NODE, result_node.get());
+ ASSERT_EQ(NULL_NODE, result_node.get());
+ ASSERT_EQ(ENOENT, mnt.Open(Path("/file"), O_RDONLY, &result_node));
+ ASSERT_EQ(NULL_NODE, result_node.get());
+}
+
+TEST(MountTest, MemMountRename) {
+ MountMemMock mnt;
+ ASSERT_EQ(0, mnt.Mkdir(Path("/dir1"), O_RDWR));
+ ASSERT_EQ(0, mnt.Mkdir(Path("/dir2"), O_RDWR));
+ ASSERT_EQ(3, mnt.num_nodes());
+
+ ScopedMountNode file;
+ ASSERT_EQ(0, mnt.Open(Path("/dir1/file"), O_RDWR | O_CREAT | O_EXCL, &file));
+ ASSERT_EQ(0, mnt.Access(Path("/dir1/file"), R_OK));
+ ASSERT_EQ(4, mnt.num_nodes());
+
+ // Move from one directory to another should ok
+ ASSERT_EQ(0, mnt.Rename(Path("/dir1/file"), Path("/dir2/new_file")));
+ ASSERT_NE(0, mnt.Access(Path("/dir1/file"), R_OK));
+ ASSERT_EQ(0, mnt.Access(Path("/dir2/new_file"), R_OK));
+ ASSERT_EQ(4, mnt.num_nodes());
+
+ // Move within the same directory
+ ASSERT_EQ(0, mnt.Rename(Path("/dir2/new_file"), Path("/dir2/new_file2")));
+ ASSERT_NE(0, mnt.Access(Path("/dir2/new_file"), R_OK));
+ ASSERT_EQ(0, mnt.Access(Path("/dir2/new_file2"), R_OK));
+ ASSERT_EQ(4, mnt.num_nodes());
+
+ // Move to another directory but without a filename
+ ASSERT_EQ(0, mnt.Rename(Path("/dir2/new_file2"), Path("/dir1")));
+ ASSERT_NE(0, mnt.Access(Path("/dir2/new_file2"), R_OK));
+ ASSERT_EQ(0, mnt.Access(Path("/dir1/new_file2"), R_OK));
+ ASSERT_EQ(4, mnt.num_nodes());
+}
+
+TEST(MountTest, MemMountRenameDir) {
+ MountMemMock mnt;
+
+ ASSERT_EQ(0, mnt.Mkdir(Path("/dir1"), O_RDWR));
+ ASSERT_EQ(0, mnt.Mkdir(Path("/dir2"), O_RDWR));
+ EXPECT_EQ(3, mnt.num_nodes());
+
+ // Renaming one directory to another should work
+ ASSERT_EQ(0, mnt.Rename(Path("/dir1"), Path("/dir2")));
+ ASSERT_NE(0, mnt.Access(Path("/dir1"), R_OK));
+ ASSERT_EQ(0, mnt.Access(Path("/dir2"), R_OK));
+ EXPECT_EQ(2, mnt.num_nodes());
+
+ // Reset to initial state
+ ASSERT_EQ(0, mnt.Mkdir(Path("/dir1"), O_RDWR));
+ EXPECT_EQ(3, mnt.num_nodes());
+
+ // Renaming a directory to a new name within another
+ ASSERT_EQ(0, mnt.Rename(Path("/dir1"), Path("/dir2/foo")));
+ ASSERT_EQ(0, mnt.Access(Path("/dir2"), R_OK));
+ ASSERT_EQ(0, mnt.Access(Path("/dir2/foo"), R_OK));
+ EXPECT_EQ(3, mnt.num_nodes());
+
+ // Reset to initial state
+ ASSERT_EQ(0, mnt.Rmdir(Path("/dir2/foo")));
+ ASSERT_EQ(0, mnt.Mkdir(Path("/dir1"), O_RDWR));
+ EXPECT_EQ(3, mnt.num_nodes());
+
+ // Renaming one directory to another should fail if the target is non-empty
+ ASSERT_EQ(0, mnt.Mkdir(Path("/dir2/dir3"), O_RDWR));
+ ASSERT_EQ(ENOTEMPTY, mnt.Rename(Path("/dir1"), Path("/dir2")));
}
TEST(MountTest, DevAccess) {