summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authormatthewturk@gmail.com <matthewturk@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-10 22:44:02 +0000
committermatthewturk@gmail.com <matthewturk@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-10 22:44:02 +0000
commitcdf90496ec748409bca6f3fd3e5f97abb482e846 (patch)
treeb044d186b1adb573c8b83755a8a3b8ded869fc5f /native_client_sdk
parent2219b756e9dcf1d5f37f029099cfb77f2ef9d1ef (diff)
downloadchromium_src-cdf90496ec748409bca6f3fd3e5f97abb482e846.zip
chromium_src-cdf90496ec748409bca6f3fd3e5f97abb482e846.tar.gz
chromium_src-cdf90496ec748409bca6f3fd3e5f97abb482e846.tar.bz2
[NaCl SDK] Map active fds to absolute paths.
This implements both fchdir and adds an absolute path to the Descriptor_t struct. Typically on Linux systems this information can be obtained by querying the /proc file system, but in absence of that, we can track it ourselves. For pipes and sockets, the path is the empty string. By enabling this behavior, fchdir can also be implemented. This also returns expected errno values from fchdir. This opens up the ability to do relative path operations like openat. While these currently can be executed in user code in a race condition prone way, they could be moved into the KernelProxy, where the absolute paths can be both accessed and resolved with AcquireHandleAndPath. R=binji@chromium.org, sbc@chromium.org BUG= Review URL: https://codereview.chromium.org/99203014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@244267 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.cc31
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.h13
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc42
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc9
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc56
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;