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/filesystem.h"
18 #include "nacl_io/kernel_handle.h"
19 #include "nacl_io/log.h"
20 #include "nacl_io/node.h"
22 #include "sdk_util/auto_lock.h"
23 #include "sdk_util/ref_object.h"
24 #include "sdk_util/scoped_ref.h"
28 KernelObject::KernelObject() {
32 KernelObject::~KernelObject() {};
34 Error KernelObject::AttachFsAtPath(const ScopedFilesystem& fs,
35 const std::string& path) {
36 std::string abs_path = GetAbsParts(path).Join();
39 if (filesystems_.find(abs_path) != filesystems_.end()) {
40 LOG_ERROR("Can't mount at %s, it is already mounted.", path.c_str());
44 filesystems_[abs_path] = fs;
48 Error KernelObject::DetachFsAtPath(const std::string& path,
49 ScopedFilesystem* out_fs) {
50 std::string abs_path = GetAbsParts(path).Join();
53 FsMap_t::iterator it = filesystems_.find(abs_path);
54 if (filesystems_.end() == it) {
55 LOG_TRACE("Can't unmount at %s, nothing is mounted.", path.c_str());
59 // It is only legal to unmount if there are no open references
60 if (it->second->RefCount() != 1) {
61 LOG_TRACE("Can't unmount at %s, refcount is != 1.", path.c_str());
67 filesystems_.erase(it);
71 // Uses longest prefix to find the filesystem for the give path, then
72 // acquires the filesystem and returns it with a relative path.
73 Error KernelObject::AcquireFsAndRelPath(const std::string& path,
74 ScopedFilesystem* out_fs,
76 Path abs_parts = GetAbsParts(path);
83 // Find longest prefix
84 size_t max = abs_parts.Size();
85 for (size_t len = 0; len < abs_parts.Size(); len++) {
86 FsMap_t::iterator it = filesystems_.find(abs_parts.Range(0, max - len));
87 if (it != filesystems_.end()) {
89 rel_parts->Append(abs_parts.Range(max - len, max));
99 // Given a path, acquire the associated filesystem and node, creating the
100 // node if needed based on the provided flags.
101 Error KernelObject::AcquireFsAndNode(const std::string& path,
103 ScopedFilesystem* out_fs,
104 ScopedNode* out_node) {
107 out_node->reset(NULL);
108 Error error = AcquireFsAndRelPath(path, out_fs, &rel_parts);
112 error = (*out_fs)->Open(rel_parts, oflags, out_node);
119 Path KernelObject::GetAbsParts(const std::string& path) {
120 AUTO_LOCK(cwd_lock_);
122 Path abs_parts(cwd_);
123 if (path[0] == '/') {
127 abs_parts.Append(path);
133 std::string KernelObject::GetCWD() {
134 AUTO_LOCK(cwd_lock_);
135 std::string out = cwd_;
140 Error KernelObject::SetCWD(const std::string& path) {
141 std::string abs_path = GetAbsParts(path).Join();
146 Error error = AcquireFsAndNode(abs_path, O_RDONLY, &fs, &node);
150 if ((node->GetType() & S_IFDIR) == 0)
153 AUTO_LOCK(cwd_lock_);
158 Error KernelObject::GetFDFlags(int fd, int* out_flags) {
159 AUTO_LOCK(handle_lock_);
160 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
163 *out_flags = handle_map_[fd].flags;
167 Error KernelObject::SetFDFlags(int fd, int flags) {
168 AUTO_LOCK(handle_lock_);
169 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
172 // Only setting of FD_CLOEXEC is supported.
173 if (flags & ~FD_CLOEXEC)
176 handle_map_[fd].flags = flags;
180 Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) {
181 out_handle->reset(NULL);
183 AUTO_LOCK(handle_lock_);
184 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
187 Descriptor_t& desc = handle_map_[fd];
191 *out_handle = desc.handle;
195 Error KernelObject::AcquireHandleAndPath(int fd,
196 ScopedKernelHandle* out_handle,
197 std::string* out_path) {
198 out_handle->reset(NULL);
200 AUTO_LOCK(handle_lock_);
201 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
204 Descriptor_t& desc = handle_map_[fd];
208 *out_handle = desc.handle;
209 *out_path = desc.path;
213 int KernelObject::AllocateFD(const ScopedKernelHandle& handle,
214 const std::string& path) {
215 AUTO_LOCK(handle_lock_);
218 std::string abs_path = GetAbsParts(path).Join();
219 Descriptor_t descriptor(handle, abs_path);
221 // If we can recycle and FD, use that first
222 if (free_fds_.size()) {
223 id = free_fds_.front();
224 // Force lower numbered FD to be available first.
225 std::pop_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
226 free_fds_.pop_back();
227 handle_map_[id] = descriptor;
229 id = handle_map_.size();
230 handle_map_.push_back(descriptor);
236 void KernelObject::FreeAndReassignFD(int fd,
237 const ScopedKernelHandle& handle,
238 const std::string& path) {
239 if (NULL == handle) {
242 AUTO_LOCK(handle_lock_);
244 // If the required FD is larger than the current set, grow the set
245 if (fd >= (int)handle_map_.size())
246 handle_map_.resize(fd + 1);
248 // This path will be from an existing handle, and absolute.
249 handle_map_[fd] = Descriptor_t(handle, path);
253 void KernelObject::FreeFD(int fd) {
254 AUTO_LOCK(handle_lock_);
256 handle_map_[fd].handle.reset(NULL);
257 free_fds_.push_back(fd);
259 // Force lower numbered FD to be available first.
260 std::push_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
263 } // namespace nacl_io