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() : umask_(0) {
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(Path(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
,
102 int oflags
, mode_t mflags
,
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
)->OpenWithMode(rel_parts
, oflags
, mflags
, out_node
);
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_
;
131 Error
KernelObject::SetCWD(const std::string
& path
) {
132 std::string abs_path
= GetAbsParts(path
).Join();
137 Error error
= AcquireFsAndNode(abs_path
, O_RDONLY
, 0, &fs
, &node
);
141 if ((node
->GetType() & S_IFDIR
) == 0)
144 AUTO_LOCK(cwd_lock_
);
149 mode_t
KernelObject::GetUmask() {
153 mode_t
KernelObject::SetUmask(mode_t newmask
) {
154 AUTO_LOCK(umask_lock_
);
155 mode_t oldmask
= umask_
;
156 umask_
= newmask
& S_MODEBITS
;
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()))
165 *out_flags
= handle_map_
[fd
].flags
;
169 Error
KernelObject::SetFDFlags(int fd
, int flags
) {
170 AUTO_LOCK(handle_lock_
);
171 if (fd
< 0 || fd
>= static_cast<int>(handle_map_
.size()))
174 // Only setting of FD_CLOEXEC is supported.
175 if (flags
& ~FD_CLOEXEC
)
178 handle_map_
[fd
].flags
= flags
;
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()))
189 Descriptor_t
& desc
= handle_map_
[fd
];
193 *out_handle
= desc
.handle
;
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()))
206 Descriptor_t
& desc
= handle_map_
[fd
];
210 *out_handle
= desc
.handle
;
211 *out_path
= desc
.path
;
215 int KernelObject::AllocateFD(const ScopedKernelHandle
& handle
,
216 const std::string
& path
) {
217 AUTO_LOCK(handle_lock_
);
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();
229 handle_map_
[id
] = descriptor
;
231 id
= handle_map_
.size();
232 handle_map_
.push_back(descriptor
);
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());
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
);
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