1 // Copyright 2013 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.
9 #include "nacl_io/devfs/dev_fs.h"
17 #include "nacl_io/devfs/jspipe_node.h"
18 #include "nacl_io/devfs/tty_node.h"
19 #include "nacl_io/dir_node.h"
20 #include "nacl_io/kernel_wrap_real.h"
21 #include "nacl_io/node.h"
22 #include "nacl_io/osunistd.h"
23 #include "nacl_io/passthroughfs/real_node.h"
24 #include "nacl_io/pepper_interface.h"
25 #include "sdk_util/auto_lock.h"
27 #if defined(__native_client__)
37 class NullNode : public CharNode {
39 explicit NullNode(Filesystem* filesystem) : CharNode(filesystem) {}
41 virtual Error Read(const HandleAttr& attr,
45 virtual Error Write(const HandleAttr& attr,
51 class ConsoleNode : public CharNode {
53 ConsoleNode(Filesystem* filesystem, PP_LogLevel level);
55 virtual Error Write(const HandleAttr& attr,
64 class ZeroNode : public Node {
66 explicit ZeroNode(Filesystem* filesystem);
68 virtual Error Read(const HandleAttr& attr,
72 virtual Error Write(const HandleAttr& attr,
78 class UrandomNode : public Node {
80 explicit UrandomNode(Filesystem* filesystem);
82 virtual Error Read(const HandleAttr& attr,
86 virtual Error Write(const HandleAttr& attr,
92 #if defined(__native_client__)
93 nacl_irt_random random_interface_;
98 class FsNode : public Node {
100 FsNode(Filesystem* filesystem, Filesystem* other_fs);
102 virtual Error VIoctl(int request, va_list args);
105 // Don't addref the filesystem. We are relying on the fact that the
106 // KernelObject will keep the filsystem around as long as we need it, and
107 // this node will be destroyed when the filesystem is destroyed.
108 Filesystem* other_fs_;
111 Error NullNode::Read(const HandleAttr& attr,
119 Error NullNode::Write(const HandleAttr& attr,
127 ConsoleNode::ConsoleNode(Filesystem* filesystem, PP_LogLevel level)
128 : CharNode(filesystem), level_(level) {
131 Error ConsoleNode::Write(const HandleAttr& attr,
137 ConsoleInterface* con_iface = filesystem_->ppapi()->GetConsoleInterface();
138 VarInterface* var_iface = filesystem_->ppapi()->GetVarInterface();
140 if (!(var_iface && con_iface)) {
141 LOG_ERROR("Got NULL interface(s): %s%s",
142 con_iface ? "" : "Console ",
143 var_iface ? "" : "Var");
147 const char* var_data = static_cast<const char*>(buf);
148 uint32_t len = static_cast<uint32_t>(count);
149 struct PP_Var val = var_iface->VarFromUtf8(var_data, len);
150 con_iface->Log(filesystem_->ppapi()->GetInstance(), level_, val);
151 var_iface->Release(val);
157 ZeroNode::ZeroNode(Filesystem* filesystem) : Node(filesystem) {
161 Error ZeroNode::Read(const HandleAttr& attr,
165 memset(buf, 0, count);
170 Error ZeroNode::Write(const HandleAttr& attr,
178 UrandomNode::UrandomNode(Filesystem* filesystem) : Node(filesystem) {
180 #if defined(__native_client__)
181 size_t result = nacl_interface_query(
182 NACL_IRT_RANDOM_v0_1, &random_interface_, sizeof(random_interface_));
183 interface_ok_ = result != 0;
187 Error UrandomNode::Read(const HandleAttr& attr,
193 #if defined(__native_client__)
194 if (!interface_ok_) {
195 LOG_ERROR("NACL_IRT_RANDOM_v0_1 interface not avaiable.");
200 int error = (*random_interface_.get_random_bytes)(buf, count, &nread);
204 char* out = static_cast<char*>(buf);
205 size_t bytes_left = count;
207 unsigned int random_int;
208 errno_t err = rand_s(&random_int);
210 *out_bytes = count - bytes_left;
214 int bytes_to_copy = std::min(bytes_left, sizeof(random_int));
215 memcpy(out, &random_int, bytes_to_copy);
216 out += bytes_to_copy;
217 bytes_left -= bytes_to_copy;
225 Error UrandomNode::Write(const HandleAttr& attr,
233 FsNode::FsNode(Filesystem* filesystem, Filesystem* other_fs)
234 : Node(filesystem), other_fs_(other_fs) {
237 Error FsNode::VIoctl(int request, va_list args) {
238 return other_fs_->Filesystem_VIoctl(request, args);
243 Error DevFs::OpenWithMode(const Path& path, int open_flags,
244 mode_t mode, ScopedNode* out_node) {
245 out_node->reset(NULL);
247 if (path.Part(1) == "fs") {
248 if (path.Size() == 3) {
249 error = fs_dir_->FindChild(path.Part(2), out_node);
251 LOG_TRACE("Bad devfs path: %s", path.Join().c_str());
255 error = root_->FindChild(path.Join(), out_node);
258 // Only return EACCES when trying to create a node that does not exist.
259 if ((error == ENOENT) && (open_flags & O_CREAT)) {
260 LOG_TRACE("Cannot create devfs node: %s", path.Join().c_str());
267 Error DevFs::Unlink(const Path& path) {
268 LOG_ERROR("unlink not supported.");
272 Error DevFs::Mkdir(const Path& path, int permissions) {
273 LOG_ERROR("mkdir not supported.");
277 Error DevFs::Rmdir(const Path& path) {
278 LOG_ERROR("rmdir not supported.");
282 Error DevFs::Remove(const Path& path) {
283 LOG_ERROR("remove not supported.");
287 Error DevFs::Rename(const Path& path, const Path& newpath) {
288 LOG_ERROR("rename not supported.");
292 Error DevFs::CreateFsNode(Filesystem* other_fs) {
293 int dev = other_fs->dev();
295 snprintf(path, 32, "%d", dev);
296 ScopedNode new_node(new FsNode(this, other_fs));
297 return fs_dir_->AddChild(path, new_node);
300 Error DevFs::DestroyFsNode(Filesystem* other_fs) {
301 int dev = other_fs->dev();
303 snprintf(path, 32, "%d", dev);
304 return fs_dir_->RemoveChild(path);
310 #define INITIALIZE_DEV_NODE(path, klass) \
311 new_node = ScopedNode(new klass(this)); \
312 error = root_->AddChild(path, new_node); \
316 #define INITIALIZE_DEV_NODE_1(path, klass, arg) \
317 new_node = ScopedNode(new klass(this, arg)); \
318 error = root_->AddChild(path, new_node); \
322 Error DevFs::Init(const FsInitArgs& args) {
323 Error error = Filesystem::Init(args);
327 root_.reset(new DirNode(this, S_IRALL | S_IXALL));
330 INITIALIZE_DEV_NODE("/null", NullNode);
331 INITIALIZE_DEV_NODE("/zero", ZeroNode);
332 INITIALIZE_DEV_NODE("/urandom", UrandomNode);
333 INITIALIZE_DEV_NODE_1("/console0", ConsoleNode, PP_LOGLEVEL_TIP);
334 INITIALIZE_DEV_NODE_1("/console1", ConsoleNode, PP_LOGLEVEL_LOG);
335 INITIALIZE_DEV_NODE_1("/console2", ConsoleNode, PP_LOGLEVEL_WARNING);
336 INITIALIZE_DEV_NODE_1("/console3", ConsoleNode, PP_LOGLEVEL_ERROR);
337 INITIALIZE_DEV_NODE("/tty", TtyNode);
338 INITIALIZE_DEV_NODE_1("/stdin", RealNode, 0);
339 INITIALIZE_DEV_NODE_1("/stdout", RealNode, 1);
340 INITIALIZE_DEV_NODE_1("/stderr", RealNode, 2);
341 INITIALIZE_DEV_NODE("/jspipe1", JSPipeNode);
342 new_node->Ioctl(NACL_IOC_PIPE_SETNAME, "jspipe1");
343 INITIALIZE_DEV_NODE("/jspipe2", JSPipeNode);
344 new_node->Ioctl(NACL_IOC_PIPE_SETNAME, "jspipe2");
345 INITIALIZE_DEV_NODE("/jspipe3", JSPipeNode);
346 new_node->Ioctl(NACL_IOC_PIPE_SETNAME, "jspipe3");
348 // Add a directory for "fs" nodes; they represent all currently-mounted
349 // filesystems. We can ioctl these nodes to make changes or provide input to
350 // a mounted filesystem.
351 INITIALIZE_DEV_NODE_1("/fs", DirNode, S_IRALL | S_IWALL | S_IXALL);
357 } // namespace nacl_io