Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / devfs / dev_fs.cc
blob3b04296841b76f170912288bb482ee4e01ad5807
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.
5 #if defined(WIN32)
6 #define _CRT_RAND_S
7 #endif
9 #include "nacl_io/devfs/dev_fs.h"
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <pthread.h>
14 #include <stdio.h>
15 #include <string.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__)
28 #include <irt.h>
29 #elif defined(WIN32)
30 #include <stdlib.h>
31 #endif
33 namespace nacl_io {
35 namespace {
37 class NullNode : public CharNode {
38 public:
39 explicit NullNode(Filesystem* filesystem) : CharNode(filesystem) {}
41 virtual Error Read(const HandleAttr& attr,
42 void* buf,
43 size_t count,
44 int* out_bytes);
45 virtual Error Write(const HandleAttr& attr,
46 const void* buf,
47 size_t count,
48 int* out_bytes);
51 class ConsoleNode : public CharNode {
52 public:
53 ConsoleNode(Filesystem* filesystem, PP_LogLevel level);
55 virtual Error Write(const HandleAttr& attr,
56 const void* buf,
57 size_t count,
58 int* out_bytes);
60 private:
61 PP_LogLevel level_;
64 class ZeroNode : public Node {
65 public:
66 explicit ZeroNode(Filesystem* filesystem);
68 virtual Error Read(const HandleAttr& attr,
69 void* buf,
70 size_t count,
71 int* out_bytes);
72 virtual Error Write(const HandleAttr& attr,
73 const void* buf,
74 size_t count,
75 int* out_bytes);
78 class UrandomNode : public Node {
79 public:
80 explicit UrandomNode(Filesystem* filesystem);
82 virtual Error Read(const HandleAttr& attr,
83 void* buf,
84 size_t count,
85 int* out_bytes);
86 virtual Error Write(const HandleAttr& attr,
87 const void* buf,
88 size_t count,
89 int* out_bytes);
91 private:
92 #if defined(__native_client__)
93 nacl_irt_random random_interface_;
94 bool interface_ok_;
95 #endif
98 class FsNode : public Node {
99 public:
100 FsNode(Filesystem* filesystem, Filesystem* other_fs);
102 virtual Error VIoctl(int request, va_list args);
104 private:
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,
112 void* buf,
113 size_t count,
114 int* out_bytes) {
115 *out_bytes = 0;
116 return 0;
119 Error NullNode::Write(const HandleAttr& attr,
120 const void* buf,
121 size_t count,
122 int* out_bytes) {
123 *out_bytes = count;
124 return 0;
127 ConsoleNode::ConsoleNode(Filesystem* filesystem, PP_LogLevel level)
128 : CharNode(filesystem), level_(level) {
131 Error ConsoleNode::Write(const HandleAttr& attr,
132 const void* buf,
133 size_t count,
134 int* out_bytes) {
135 *out_bytes = 0;
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");
144 return ENOSYS;
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);
153 *out_bytes = count;
154 return 0;
157 ZeroNode::ZeroNode(Filesystem* filesystem) : Node(filesystem) {
158 SetType(S_IFCHR);
161 Error ZeroNode::Read(const HandleAttr& attr,
162 void* buf,
163 size_t count,
164 int* out_bytes) {
165 memset(buf, 0, count);
166 *out_bytes = count;
167 return 0;
170 Error ZeroNode::Write(const HandleAttr& attr,
171 const void* buf,
172 size_t count,
173 int* out_bytes) {
174 *out_bytes = count;
175 return 0;
178 UrandomNode::UrandomNode(Filesystem* filesystem) : Node(filesystem) {
179 SetType(S_IFCHR);
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;
184 #endif
187 Error UrandomNode::Read(const HandleAttr& attr,
188 void* buf,
189 size_t count,
190 int* out_bytes) {
191 *out_bytes = 0;
193 #if defined(__native_client__)
194 if (!interface_ok_) {
195 LOG_ERROR("NACL_IRT_RANDOM_v0_1 interface not avaiable.");
196 return EBADF;
199 size_t nread;
200 int error = (*random_interface_.get_random_bytes)(buf, count, &nread);
201 if (error)
202 return error;
203 #elif defined(WIN32)
204 char* out = static_cast<char*>(buf);
205 size_t bytes_left = count;
206 while (bytes_left) {
207 unsigned int random_int;
208 errno_t err = rand_s(&random_int);
209 if (err) {
210 *out_bytes = count - bytes_left;
211 return err;
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;
219 #endif
221 *out_bytes = count;
222 return 0;
225 Error UrandomNode::Write(const HandleAttr& attr,
226 const void* buf,
227 size_t count,
228 int* out_bytes) {
229 *out_bytes = count;
230 return 0;
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);
241 } // namespace
243 Error DevFs::OpenWithMode(const Path& path, int open_flags,
244 mode_t mode, ScopedNode* out_node) {
245 out_node->reset(NULL);
246 int error;
247 if (path.Part(1) == "fs") {
248 if (path.Size() == 3) {
249 error = fs_dir_->FindChild(path.Part(2), out_node);
250 } else {
251 LOG_TRACE("Bad devfs path: %s", path.Join().c_str());
252 error = ENOENT;
254 } else {
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());
261 return EACCES;
264 return error;
267 Error DevFs::Unlink(const Path& path) {
268 LOG_ERROR("unlink not supported.");
269 return EPERM;
272 Error DevFs::Mkdir(const Path& path, int permissions) {
273 LOG_ERROR("mkdir not supported.");
274 return EPERM;
277 Error DevFs::Rmdir(const Path& path) {
278 LOG_ERROR("rmdir not supported.");
279 return EPERM;
282 Error DevFs::Remove(const Path& path) {
283 LOG_ERROR("remove not supported.");
284 return EPERM;
287 Error DevFs::Rename(const Path& path, const Path& newpath) {
288 LOG_ERROR("rename not supported.");
289 return EPERM;
292 Error DevFs::CreateFsNode(Filesystem* other_fs) {
293 int dev = other_fs->dev();
294 char path[32];
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();
302 char path[32];
303 snprintf(path, 32, "%d", dev);
304 return fs_dir_->RemoveChild(path);
307 DevFs::DevFs() {
310 #define INITIALIZE_DEV_NODE(path, klass) \
311 new_node = ScopedNode(new klass(this)); \
312 error = root_->AddChild(path, new_node); \
313 if (error) \
314 return error;
316 #define INITIALIZE_DEV_NODE_1(path, klass, arg) \
317 new_node = ScopedNode(new klass(this, arg)); \
318 error = root_->AddChild(path, new_node); \
319 if (error) \
320 return error;
322 Error DevFs::Init(const FsInitArgs& args) {
323 Error error = Filesystem::Init(args);
324 if (error)
325 return error;
327 root_.reset(new DirNode(this, S_IRALL | S_IXALL));
329 ScopedNode new_node;
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);
352 fs_dir_ = new_node;
354 return 0;
357 } // namespace nacl_io