diff options
Diffstat (limited to 'native_client_sdk')
5 files changed, 131 insertions, 20 deletions
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc index fccc5c85..5ff8902 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc @@ -179,11 +179,30 @@ Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) { return EBADF; } -int KernelObject::AllocateFD(const ScopedKernelHandle& handle) { +Error KernelObject::AcquireHandleAndPath(int fd, ScopedKernelHandle* out_handle, + std::string* out_path){ + out_handle->reset(NULL); + + AUTO_LOCK(handle_lock_); + if (fd < 0 || fd >= static_cast<int>(handle_map_.size())) + return EBADF; + + *out_handle = handle_map_[fd].handle; + if (!out_handle) + return EBADF; + + *out_path = handle_map_[fd].path; + + return 0; +} + +int KernelObject::AllocateFD(const ScopedKernelHandle& handle, + const std::string& path) { AUTO_LOCK(handle_lock_); int id; - Descriptor_t descriptor(handle); + std::string abs_path = GetAbsParts(path).Join(); + Descriptor_t descriptor(handle, abs_path); // If we can recycle and FD, use that first if (free_fds_.size()) { @@ -196,10 +215,12 @@ int KernelObject::AllocateFD(const ScopedKernelHandle& handle) { id = handle_map_.size(); handle_map_.push_back(descriptor); } + return id; } -void KernelObject::FreeAndReassignFD(int fd, const ScopedKernelHandle& handle) { +void KernelObject::FreeAndReassignFD(int fd, const ScopedKernelHandle& handle, + const std::string& path) { if (NULL == handle) { FreeFD(fd); } else { @@ -209,7 +230,8 @@ void KernelObject::FreeAndReassignFD(int fd, const ScopedKernelHandle& handle) { if (fd >= (int)handle_map_.size()) handle_map_.resize(fd + 1); - handle_map_[fd] = Descriptor_t(handle); + // This path will be from an existing handle, and absolute. + handle_map_[fd] = Descriptor_t(handle, path); } } @@ -221,6 +243,7 @@ void KernelObject::FreeFD(int fd) { // Force lower numbered FD to be available first. std::push_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>()); + // } } // namespace nacl_io diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.h b/native_client_sdk/src/libraries/nacl_io/kernel_object.h index 70ffb2f..ca6be9d 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_object.h +++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.h @@ -31,10 +31,13 @@ class KernelObject { public: struct Descriptor_t { Descriptor_t() : flags(0) {} - explicit Descriptor_t(const ScopedKernelHandle& h) : handle(h), flags(0) {} + explicit Descriptor_t(const ScopedKernelHandle& h, + const std::string& open_path) + : handle(h), flags(0), path(open_path) {} ScopedKernelHandle handle; int flags; + std::string path; }; typedef std::vector<Descriptor_t> HandleMap_t; typedef std::map<std::string, ScopedFilesystem> FsMap_t; @@ -71,14 +74,18 @@ class KernelObject { // Convert from FD to KernelHandle, and acquire the handle. // Assumes |out_handle| is non-NULL. Error AcquireHandle(int fd, ScopedKernelHandle* out_handle); + Error AcquireHandleAndPath(int fd, ScopedKernelHandle *out_handle, + std::string* out_path); // Allocate a new fd and assign the handle to it, while // ref counting the handle and associated filesystem. // Assumes |handle| is non-NULL; - int AllocateFD(const ScopedKernelHandle& handle); + int AllocateFD(const ScopedKernelHandle& handle, + const std::string& path=std::string()); // Assumes |handle| is non-NULL; - void FreeAndReassignFD(int fd, const ScopedKernelHandle& handle); + void FreeAndReassignFD(int fd, const ScopedKernelHandle& handle, + const std::string& path); void FreeFD(int fd); // Returns or sets CWD 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 3ddca20..5451120 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc @@ -172,7 +172,7 @@ int KernelProxy::open_resource(const char* path) { return -1; } - return AllocateFD(handle); + return AllocateFD(handle, path); } int KernelProxy::open(const char* path, int open_flags) { @@ -192,7 +192,7 @@ int KernelProxy::open(const char* path, int open_flags) { return -1; } - return AllocateFD(handle); + return AllocateFD(handle, path); } int KernelProxy::pipe(int pipefds[2]) { @@ -233,13 +233,13 @@ int KernelProxy::close(int fd) { int KernelProxy::dup(int oldfd) { ScopedKernelHandle handle; - Error error = AcquireHandle(oldfd, &handle); + std::string path; + Error error = AcquireHandleAndPath(oldfd, &handle, &path); if (error) { errno = error; return -1; } - - return AllocateFD(handle); + return AllocateFD(handle, path); } int KernelProxy::dup2(int oldfd, int newfd) { @@ -248,13 +248,14 @@ int KernelProxy::dup2(int oldfd, int newfd) { return newfd; ScopedKernelHandle old_handle; - Error error = AcquireHandle(oldfd, &old_handle); + std::string old_path; + Error error = AcquireHandleAndPath(oldfd, &old_handle, &old_path); if (error) { errno = error; return -1; } - FreeAndReassignFD(newfd, old_handle); + FreeAndReassignFD(newfd, old_handle, old_path); return newfd; } @@ -509,8 +510,31 @@ int KernelProxy::getdents(int fd, void* buf, unsigned int count) { } int KernelProxy::fchdir(int fd) { - errno = ENOSYS; - return -1; + ScopedKernelHandle handle; + std::string path; + Error error = AcquireHandleAndPath(fd, &handle, &path); + if (error) { + errno = error; + return -1; + } + + if (!handle->node()->IsaDir()) { + errno = ENOTDIR; + return -1; + } + + if (path.empty()) { + errno = EBADF; + return -1; + } + + error = SetCWD(path); + if (error) { + // errno is return value from SetCWD + errno = error; + return -1; + } + return 0; } int KernelProxy::ftruncate(int fd, off_t length) { 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 cfa1ca4..4350aae 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 @@ -95,13 +95,13 @@ TEST_F(KernelObjectTest, Referencing) { // Allocating an FD should cause the KernelProxy to ref the handle and // the node and filesystem should be unchanged. - int fd1 = proxy.AllocateFD(handle_a); + int fd1 = proxy.AllocateFD(handle_a, "/example"); EXPECT_EQ(3, handle_a->RefCount()); EXPECT_EQ(2, fs->RefCount()); EXPECT_EQ(2, node->RefCount()); // If we "dup" the handle, we should bump the ref count on the handle - int fd2 = proxy.AllocateFD(handle_b); + int fd2 = proxy.AllocateFD(handle_b, ""); EXPECT_EQ(4, handle_a->RefCount()); EXPECT_EQ(2, fs->RefCount()); EXPECT_EQ(2, node->RefCount()); @@ -165,16 +165,17 @@ TEST_F(KernelObjectTest, FreeAndReassignFD) { EXPECT_EQ(2, node->RefCount()); EXPECT_EQ(1, raw_handle->RefCount()); - proxy.AllocateFD(handle); + proxy.AllocateFD(handle, "/example"); EXPECT_EQ(2, fs->RefCount()); EXPECT_EQ(2, node->RefCount()); EXPECT_EQ(2, raw_handle->RefCount()); - proxy.FreeAndReassignFD(5, handle); + proxy.FreeAndReassignFD(5, handle, "/example"); EXPECT_EQ(2, fs->RefCount()); EXPECT_EQ(2, node->RefCount()); EXPECT_EQ(3, raw_handle->RefCount()); + handle.reset(); EXPECT_EQ(2, raw_handle->RefCount()); 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 08e690e..183ba3b 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 @@ -282,6 +282,62 @@ TEST_F(KernelProxyTest, WorkingDirectory) { EXPECT_STREQ("/foo", text); } +TEST_F(KernelProxyTest, FDPathMapping) { + char text[1024]; + + int fd1, fd2, fd3, fd4, fd5; + + EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); + EXPECT_EQ(0, ki_mkdir("/foo/bar", S_IREAD | S_IWRITE)); + EXPECT_EQ(0, ki_mkdir("/example", S_IREAD | S_IWRITE)); + ki_chdir("/foo"); + + fd1 = ki_open("/example", O_RDONLY); + EXPECT_NE(-1, fd1); + EXPECT_EQ(ki_fchdir(fd1), 0); + EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); + EXPECT_STREQ("/example", text); + + EXPECT_EQ(0, ki_chdir("/foo")); + fd2 = ki_open("../example", O_RDONLY); + EXPECT_NE(-1, fd2); + EXPECT_EQ(0, ki_fchdir(fd2)); + EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); + EXPECT_STREQ("/example", text); + + EXPECT_EQ(0, ki_chdir("/foo")); + fd3 = ki_open("../test", O_CREAT | O_RDWR); + EXPECT_NE(-1, fd3); + EXPECT_EQ(-1, ki_fchdir(fd3)); + EXPECT_EQ(ENOTDIR, errno); + + EXPECT_EQ(0, ki_chdir("/foo")); + fd4 = ki_open("bar", O_RDONLY); + EXPECT_EQ(0, ki_fchdir(fd4)); + EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); + EXPECT_STREQ("/foo/bar", text); + EXPECT_EQ(0, ki_chdir("/example")); + EXPECT_EQ(0, ki_fchdir(fd4)); + EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); + EXPECT_STREQ("/foo/bar", text); + + EXPECT_EQ(0, ki_chdir("/example")); + fd5 = ki_dup(fd4); + ASSERT_GT(fd5, -1); + ASSERT_NE(fd4, fd5); + EXPECT_EQ(0, ki_fchdir(fd5)); + EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); + EXPECT_STREQ("/foo/bar", text); + + fd5 = 123; + + EXPECT_EQ(0, ki_chdir("/example")); + EXPECT_EQ(fd5, ki_dup2(fd4, fd5)); + EXPECT_EQ(0, ki_fchdir(fd5)); + EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); + EXPECT_STREQ("/foo/bar", text); +} + TEST_F(KernelProxyTest, MemMountIO) { char text[1024]; int fd1, fd2, fd3; |