1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "nacl_io/kernel_object.h"
17 #include "nacl_io/kernel_handle.h"
18 #include "nacl_io/mount.h"
19 #include "nacl_io/mount_node.h"
21 #include "sdk_util/auto_lock.h"
22 #include "sdk_util/ref_object.h"
23 #include "sdk_util/scoped_ref.h"
27 KernelObject::KernelObject() {
31 KernelObject::~KernelObject() {};
33 Error KernelObject::AttachMountAtPath(const ScopedMount& mnt,
34 const std::string& path) {
35 std::string abs_path = GetAbsParts(path).Join();
37 AUTO_LOCK(mount_lock_);
38 if (mounts_.find(abs_path) != mounts_.end())
41 mounts_[abs_path] = mnt;
45 Error KernelObject::DetachMountAtPath(const std::string& path) {
46 std::string abs_path = GetAbsParts(path).Join();
48 AUTO_LOCK(mount_lock_);
49 MountMap_t::iterator it = mounts_.find(abs_path);
50 if (mounts_.end() == it)
53 // It is only legal to unmount if there are no open references
54 if (it->second->RefCount() != 1)
61 // Uses longest prefix to find the mount for the give path, then
62 // acquires the mount and returns it with a relative path.
63 Error KernelObject::AcquireMountAndRelPath(const std::string& path,
64 ScopedMount* out_mount,
66 Path abs_parts = GetAbsParts(path);
68 out_mount->reset(NULL);
71 AUTO_LOCK(mount_lock_);
73 // Find longest prefix
74 size_t max = abs_parts.Size();
75 for (size_t len = 0; len < abs_parts.Size(); len++) {
76 MountMap_t::iterator it = mounts_.find(abs_parts.Range(0, max - len));
77 if (it != mounts_.end()) {
79 rel_parts->Append(abs_parts.Range(max - len, max));
81 *out_mount = it->second;
89 // Given a path, acquire the associated mount and node, creating the
90 // node if needed based on the provided flags.
91 Error KernelObject::AcquireMountAndNode(const std::string& path,
93 ScopedMount* out_mount,
94 ScopedMountNode* out_node) {
96 out_mount->reset(NULL);
97 out_node->reset(NULL);
98 Error error = AcquireMountAndRelPath(path, out_mount, &rel_parts);
102 error = (*out_mount)->Open(rel_parts, oflags, out_node);
109 Path KernelObject::GetAbsParts(const std::string& path) {
110 AUTO_LOCK(cwd_lock_);
112 Path abs_parts(cwd_);
113 if (path[0] == '/') {
117 abs_parts.Append(path);
123 std::string KernelObject::GetCWD() {
124 AUTO_LOCK(cwd_lock_);
125 std::string out = cwd_;
130 Error KernelObject::SetCWD(const std::string& path) {
131 std::string abs_path = GetAbsParts(path).Join();
134 ScopedMountNode node;
136 Error error = AcquireMountAndNode(abs_path, O_RDONLY, &mnt, &node);
140 if ((node->GetType() & S_IFDIR) == 0)
143 AUTO_LOCK(cwd_lock_);
148 Error KernelObject::GetFDFlags(int fd, int* out_flags) {
149 AUTO_LOCK(handle_lock_);
150 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
153 *out_flags = handle_map_[fd].flags;
157 Error KernelObject::SetFDFlags(int fd, int flags) {
158 AUTO_LOCK(handle_lock_);
159 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
162 // Only setting of FD_CLOEXEC is supported.
163 if (flags & ~FD_CLOEXEC)
166 handle_map_[fd].flags = flags;
170 Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) {
171 out_handle->reset(NULL);
173 AUTO_LOCK(handle_lock_);
174 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
177 *out_handle = handle_map_[fd].handle;
178 if (out_handle) return 0;
183 int KernelObject::AllocateFD(const ScopedKernelHandle& handle) {
184 AUTO_LOCK(handle_lock_);
187 Descriptor_t descriptor(handle);
189 // If we can recycle and FD, use that first
190 if (free_fds_.size()) {
191 id = free_fds_.front();
192 // Force lower numbered FD to be available first.
193 std::pop_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
194 free_fds_.pop_back();
195 handle_map_[id] = descriptor;
197 id = handle_map_.size();
198 handle_map_.push_back(descriptor);
203 void KernelObject::FreeAndReassignFD(int fd, const ScopedKernelHandle& handle) {
204 if (NULL == handle) {
207 AUTO_LOCK(handle_lock_);
209 // If the required FD is larger than the current set, grow the set
210 if (fd >= (int)handle_map_.size())
211 handle_map_.resize(fd + 1);
213 handle_map_[fd] = Descriptor_t(handle);
217 void KernelObject::FreeFD(int fd) {
218 AUTO_LOCK(handle_lock_);
220 handle_map_[fd].handle.reset(NULL);
221 free_fds_.push_back(fd);
223 // Force lower numbered FD to be available first.
224 std::push_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
227 } // namespace nacl_io