Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / kernel_object.cc
blob9c14eeeb4b8dddc44fb893867796e31dbc53bcd9
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"
7 #include <assert.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <pthread.h>
12 #include <algorithm>
13 #include <map>
14 #include <string>
15 #include <vector>
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"
26 namespace nacl_io {
28 KernelObject::KernelObject() : umask_(0) {
29 cwd_ = "/";
32 KernelObject::~KernelObject() {};
34 Error KernelObject::AttachFsAtPath(const ScopedFilesystem& fs,
35 const std::string& path) {
36 std::string abs_path = GetAbsParts(path).Join();
38 AUTO_LOCK(fs_lock_);
39 if (filesystems_.find(abs_path) != filesystems_.end()) {
40 LOG_ERROR("Can't mount at %s, it is already mounted.", path.c_str());
41 return EBUSY;
44 filesystems_[abs_path] = fs;
45 return 0;
48 Error KernelObject::DetachFsAtPath(const std::string& path,
49 ScopedFilesystem* out_fs) {
50 std::string abs_path = GetAbsParts(path).Join();
52 AUTO_LOCK(fs_lock_);
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());
56 return EINVAL;
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());
62 return EBUSY;
65 *out_fs = it->second;
67 filesystems_.erase(it);
68 return 0;
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,
75 Path* rel_parts) {
76 Path abs_parts = GetAbsParts(path);
78 out_fs->reset(NULL);
79 *rel_parts = Path();
81 AUTO_LOCK(fs_lock_);
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()) {
88 rel_parts->Set("/");
89 rel_parts->Append(Path(abs_parts.Range(max - len, max)));
91 *out_fs = it->second;
92 return 0;
96 return ENOTDIR;
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,
102 int oflags, mode_t mflags,
103 ScopedFilesystem* out_fs,
104 ScopedNode* out_node) {
105 Path rel_parts;
106 out_fs->reset(NULL);
107 out_node->reset(NULL);
108 Error error = AcquireFsAndRelPath(path, out_fs, &rel_parts);
109 if (error)
110 return error;
112 error = (*out_fs)->OpenWithMode(rel_parts, oflags, mflags, out_node);
113 if (error)
114 return error;
116 return 0;
119 Path KernelObject::GetAbsParts(const std::string& path) {
120 AUTO_LOCK(cwd_lock_);
121 Path abs_parts(cwd_);
122 return abs_parts.Append(Path(path));
125 std::string KernelObject::GetCWD() {
126 AUTO_LOCK(cwd_lock_);
127 std::string out = cwd_;
128 return out;
131 Error KernelObject::SetCWD(const std::string& path) {
132 std::string abs_path = GetAbsParts(path).Join();
134 ScopedFilesystem fs;
135 ScopedNode node;
137 Error error = AcquireFsAndNode(abs_path, O_RDONLY, 0, &fs, &node);
138 if (error)
139 return error;
141 if ((node->GetType() & S_IFDIR) == 0)
142 return ENOTDIR;
144 AUTO_LOCK(cwd_lock_);
145 cwd_ = abs_path;
146 return 0;
149 mode_t KernelObject::GetUmask() {
150 return umask_;
153 mode_t KernelObject::SetUmask(mode_t newmask) {
154 AUTO_LOCK(umask_lock_);
155 mode_t oldmask = umask_;
156 umask_ = newmask & S_MODEBITS;
157 return oldmask;
160 Error KernelObject::GetFDFlags(int fd, int* out_flags) {
161 AUTO_LOCK(handle_lock_);
162 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
163 return EBADF;
165 *out_flags = handle_map_[fd].flags;
166 return 0;
169 Error KernelObject::SetFDFlags(int fd, int flags) {
170 AUTO_LOCK(handle_lock_);
171 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
172 return EBADF;
174 // Only setting of FD_CLOEXEC is supported.
175 if (flags & ~FD_CLOEXEC)
176 return EINVAL;
178 handle_map_[fd].flags = flags;
179 return 0;
182 Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) {
183 out_handle->reset(NULL);
185 AUTO_LOCK(handle_lock_);
186 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
187 return EBADF;
189 Descriptor_t& desc = handle_map_[fd];
190 if (!desc.handle)
191 return EBADF;
193 *out_handle = desc.handle;
194 return 0;
197 Error KernelObject::AcquireHandleAndPath(int fd,
198 ScopedKernelHandle* out_handle,
199 std::string* out_path) {
200 out_handle->reset(NULL);
202 AUTO_LOCK(handle_lock_);
203 if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
204 return EBADF;
206 Descriptor_t& desc = handle_map_[fd];
207 if (!desc.handle)
208 return EBADF;
210 *out_handle = desc.handle;
211 *out_path = desc.path;
212 return 0;
215 int KernelObject::AllocateFD(const ScopedKernelHandle& handle,
216 const std::string& path) {
217 AUTO_LOCK(handle_lock_);
218 int id;
220 std::string abs_path = GetAbsParts(path).Join();
221 Descriptor_t descriptor(handle, abs_path);
223 // If we can recycle an FD, use that first
224 if (free_fds_.size()) {
225 // Force lower numbered FD to be available first.
226 // std::set is ordered, so begin() returns the lowest value.
227 id = *free_fds_.begin();
228 free_fds_.erase(id);
229 handle_map_[id] = descriptor;
230 } else {
231 id = handle_map_.size();
232 handle_map_.push_back(descriptor);
235 return id;
238 void KernelObject::FreeAndReassignFD(int fd,
239 const ScopedKernelHandle& handle,
240 const std::string& path) {
241 AUTO_LOCK(handle_lock_);
243 // If the required FD is larger than the current set, grow the set.
244 int sz = static_cast<int>(handle_map_.size());
245 if (fd >= sz) {
246 // Expand the handle map to include all the extra descriptors
247 // up to and including fd.
248 handle_map_.resize(fd + 1);
249 // Add all the new descriptors, except fd, to the free list.
250 for (; sz < fd; ++sz) {
251 free_fds_.insert(sz);
255 assert(handle != NULL);
257 free_fds_.erase(fd);
259 // This path will be from an existing handle, and absolute.
260 handle_map_[fd] = Descriptor_t(handle, path);
263 void KernelObject::FreeFD(int fd) {
264 AUTO_LOCK(handle_lock_);
266 handle_map_[fd].handle.reset(NULL);
267 free_fds_.insert(fd);
270 } // namespace nacl_io