Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / nacl_io / devfs / dev_fs.cc
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.
4
5 #if defined(WIN32)
6 #define _CRT_RAND_S
7 #endif
8
9 #include "nacl_io/devfs/dev_fs.h"
10
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <pthread.h>
14 #include <stdio.h>
15 #include <string.h>
16
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"
26
27 #if defined(__native_client__)
28 #include <irt.h>
29 #elif defined(WIN32)
30 #include <stdlib.h>
31 #endif
32
33 namespace nacl_io {
34
35 namespace {
36
37 class NullNode : public CharNode {
38  public:
39   explicit NullNode(Filesystem* filesystem) : CharNode(filesystem) {}
40
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);
49 };
50
51 class ConsoleNode : public CharNode {
52  public:
53   ConsoleNode(Filesystem* filesystem, PP_LogLevel level);
54
55   virtual Error Write(const HandleAttr& attr,
56                       const void* buf,
57                       size_t count,
58                       int* out_bytes);
59
60  private:
61   PP_LogLevel level_;
62 };
63
64 class ZeroNode : public Node {
65  public:
66   explicit ZeroNode(Filesystem* filesystem);
67
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);
76 };
77
78 class UrandomNode : public Node {
79  public:
80   explicit UrandomNode(Filesystem* filesystem);
81
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);
90
91  private:
92 #if defined(__native_client__)
93   nacl_irt_random random_interface_;
94   bool interface_ok_;
95 #endif
96 };
97
98 class FsNode : public Node {
99  public:
100   FsNode(Filesystem* filesystem, Filesystem* other_fs);
101
102   virtual Error VIoctl(int request, va_list args);
103
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_;
109 };
110
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;
117 }
118
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;
125 }
126
127 ConsoleNode::ConsoleNode(Filesystem* filesystem, PP_LogLevel level)
128     : CharNode(filesystem), level_(level) {
129 }
130
131 Error ConsoleNode::Write(const HandleAttr& attr,
132                          const void* buf,
133                          size_t count,
134                          int* out_bytes) {
135   *out_bytes = 0;
136
137   ConsoleInterface* con_iface = filesystem_->ppapi()->GetConsoleInterface();
138   VarInterface* var_iface = filesystem_->ppapi()->GetVarInterface();
139
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;
145   }
146
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);
152
153   *out_bytes = count;
154   return 0;
155 }
156
157 ZeroNode::ZeroNode(Filesystem* filesystem) : Node(filesystem) {
158   SetType(S_IFCHR);
159 }
160
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;
168 }
169
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;
176 }
177
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
185 }
186
187 Error UrandomNode::Read(const HandleAttr& attr,
188                         void* buf,
189                         size_t count,
190                         int* out_bytes) {
191   *out_bytes = 0;
192
193 #if defined(__native_client__)
194   if (!interface_ok_) {
195     LOG_ERROR("NACL_IRT_RANDOM_v0_1 interface not avaiable.");
196     return EBADF;
197   }
198
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;
212     }
213
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;
218   }
219 #endif
220
221   *out_bytes = count;
222   return 0;
223 }
224
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;
231 }
232
233 FsNode::FsNode(Filesystem* filesystem, Filesystem* other_fs)
234     : Node(filesystem), other_fs_(other_fs) {
235 }
236
237 Error FsNode::VIoctl(int request, va_list args) {
238   return other_fs_->Filesystem_VIoctl(request, args);
239 }
240
241 }  // namespace
242
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;
253     }
254   } else {
255     error = root_->FindChild(path.Join(), out_node);
256   }
257
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;
262   }
263
264   return error;
265 }
266
267 Error DevFs::Unlink(const Path& path) {
268   LOG_ERROR("unlink not supported.");
269   return EPERM;
270 }
271
272 Error DevFs::Mkdir(const Path& path, int permissions) {
273   LOG_ERROR("mkdir not supported.");
274   return EPERM;
275 }
276
277 Error DevFs::Rmdir(const Path& path) {
278   LOG_ERROR("rmdir not supported.");
279   return EPERM;
280 }
281
282 Error DevFs::Remove(const Path& path) {
283   LOG_ERROR("remove not supported.");
284   return EPERM;
285 }
286
287 Error DevFs::Rename(const Path& path, const Path& newpath) {
288   LOG_ERROR("rename not supported.");
289   return EPERM;
290 }
291
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);
298 }
299
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);
305 }
306
307 DevFs::DevFs() {
308 }
309
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;
315
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;
321
322 Error DevFs::Init(const FsInitArgs& args) {
323   Error error = Filesystem::Init(args);
324   if (error)
325     return error;
326
327   root_.reset(new DirNode(this, S_IRALL | S_IXALL));
328
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");
347
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;
353
354   return 0;
355 }
356
357 }  // namespace nacl_io