Index: native_client_sdk/src/libraries/nacl_io/kernel_object.cc |
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 f593d21ce29e0808304098164541cb7ee9622e79..e4934cbf39663b1c1403dc9ffcb8408061a04099 100644 |
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc |
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc |
@@ -23,38 +23,66 @@ |
#include "sdk_util/scoped_ref.h" |
KernelObject::KernelObject() { |
- pthread_mutex_init(&kernel_lock_, NULL); |
- pthread_mutex_init(&process_lock_, NULL); |
+ pthread_mutex_init(&mount_lock_, NULL); |
+ pthread_mutex_init(&handle_lock_, NULL); |
+ pthread_mutex_init(&cwd_lock_,NULL); |
+ |
+ cwd_ = "/"; |
} |
KernelObject::~KernelObject() { |
- pthread_mutex_destroy(&process_lock_); |
- pthread_mutex_destroy(&kernel_lock_); |
+ pthread_mutex_destroy(&cwd_lock_); |
+ pthread_mutex_destroy(&handle_lock_); |
+ pthread_mutex_destroy(&mount_lock_); |
+} |
+ |
+Error KernelObject::AttachMountAtPath(const ScopedMount& mnt, |
+ const std::string& path) { |
+ std::string abs_path = GetAbsParts(path).Join(); |
+ |
+ AutoLock lock(&mount_lock_); |
+ if (mounts_.find(abs_path) != mounts_.end()) |
+ return EBUSY; |
+ |
+ mounts_[abs_path] = mnt; |
+ return 0; |
+} |
+ |
+Error KernelObject::DetachMountAtPath(const std::string& path) { |
+ std::string abs_path = GetAbsParts(path).Join(); |
+ |
+ AutoLock lock(&mount_lock_); |
+ MountMap_t::iterator it = mounts_.find(abs_path); |
+ if (mounts_.end() == it) |
+ return EINVAL; |
+ |
+ // It is only legal to unmount if there are no open references |
+ if (it->second->RefCount() != 1) |
+ return EBUSY; |
+ |
+ mounts_.erase(it); |
+ return 0; |
} |
// Uses longest prefix to find the mount for the give path, then |
// acquires the mount and returns it with a relative path. |
-Error KernelObject::AcquireMountAndPath(const std::string& relpath, |
- ScopedMount* out_mount, |
- Path* out_path) { |
- out_mount->reset(NULL); |
+Error KernelObject::AcquireMountAndRelPath(const std::string& path, |
+ ScopedMount* out_mount, |
+ Path* rel_parts) { |
+ Path abs_parts = GetAbsParts(path); |
- *out_path = Path(); |
- Path abs_path; |
- { |
- AutoLock lock(&process_lock_); |
- abs_path = GetAbsPathLocked(relpath); |
- } |
+ out_mount->reset(NULL); |
+ *rel_parts = Path(); |
- AutoLock lock(&kernel_lock_); |
+ AutoLock lock(&mount_lock_); |
// Find longest prefix |
- size_t max = abs_path.Size(); |
- for (size_t len = 0; len < abs_path.Size(); len++) { |
- MountMap_t::iterator it = mounts_.find(abs_path.Range(0, max - len)); |
+ size_t max = abs_parts.Size(); |
+ for (size_t len = 0; len < abs_parts.Size(); len++) { |
+ MountMap_t::iterator it = mounts_.find(abs_parts.Range(0, max - len)); |
if (it != mounts_.end()) { |
- out_path->Set("/"); |
- out_path->Append(abs_path.Range(max - len, max)); |
+ rel_parts->Set("/"); |
+ rel_parts->Append(abs_parts.Range(max - len, max)); |
*out_mount = it->second; |
return 0; |
@@ -64,10 +92,69 @@ Error KernelObject::AcquireMountAndPath(const std::string& relpath, |
return ENOTDIR; |
} |
+// Given a path, acquire the associated mount and node, creating the |
+// node if needed based on the provided flags. |
+Error KernelObject::AcquireMountAndNode(const std::string& path, |
+ int oflags, |
+ ScopedMount* out_mount, |
+ ScopedMountNode* out_node) { |
+ Path rel_parts; |
+ out_mount->reset(NULL); |
+ out_node->reset(NULL); |
+ Error error = AcquireMountAndRelPath(path, out_mount, &rel_parts); |
+ if (error) |
+ return error; |
+ |
+ error = (*out_mount)->Open(rel_parts, oflags, out_node); |
+ if (error) |
+ return error; |
+ |
+ return 0; |
+} |
+ |
+Path KernelObject::GetAbsParts(const std::string& path) { |
+ AutoLock lock(&cwd_lock_); |
+ |
+ Path abs_parts(cwd_); |
+ if (path[0] == '/') { |
+ abs_parts = path; |
+ } else { |
+ abs_parts = cwd_; |
+ abs_parts.Append(path); |
+ } |
+ |
+ return abs_parts; |
+} |
+ |
+std::string KernelObject::GetCWD() { |
+ AutoLock lock(&cwd_lock_); |
+ std::string out = cwd_; |
+ |
+ return out; |
+} |
+ |
+Error KernelObject::SetCWD(const std::string& path) { |
+ std::string abs_path = GetAbsParts(path).Join(); |
+ |
+ ScopedMount mnt; |
+ ScopedMountNode node; |
+ |
+ Error error = AcquireMountAndNode(abs_path, O_RDONLY, &mnt, &node); |
+ if (error) |
+ return error; |
+ |
+ if ((node->GetType() & S_IFDIR) == 0) |
+ return ENOTDIR; |
+ |
+ AutoLock lock(&cwd_lock_); |
+ cwd_ = abs_path; |
+ return 0; |
+} |
+ |
Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) { |
out_handle->reset(NULL); |
- AutoLock lock(&process_lock_); |
+ AutoLock lock(&handle_lock_); |
if (fd < 0 || fd >= static_cast<int>(handle_map_.size())) |
return EBADF; |
@@ -78,7 +165,7 @@ Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) { |
} |
int KernelObject::AllocateFD(const ScopedKernelHandle& handle) { |
- AutoLock lock(&process_lock_); |
+ AutoLock lock(&handle_lock_); |
int id; |
// If we can recycle and FD, use that first |
@@ -99,7 +186,7 @@ void KernelObject::FreeAndReassignFD(int fd, const ScopedKernelHandle& handle) { |
if (NULL == handle) { |
FreeFD(fd); |
} else { |
- AutoLock lock(&process_lock_); |
+ AutoLock lock(&handle_lock_); |
// If the required FD is larger than the current set, grow the set |
if (fd >= handle_map_.size()) |
@@ -110,7 +197,7 @@ void KernelObject::FreeAndReassignFD(int fd, const ScopedKernelHandle& handle) { |
} |
void KernelObject::FreeFD(int fd) { |
- AutoLock lock(&process_lock_); |
+ AutoLock lock(&handle_lock_); |
handle_map_[fd].reset(NULL); |
free_fds_.push_back(fd); |
@@ -118,18 +205,3 @@ 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>()); |
} |
- |
-Path KernelObject::GetAbsPathLocked(const std::string& path) { |
- // Generate absolute path |
- Path abs_path(cwd_); |
- |
- if (path[0] == '/') { |
- abs_path = path; |
- } else { |
- abs_path = cwd_; |
- abs_path.Append(path); |
- } |
- |
- return abs_path; |
-} |
- |