Upstream version 5.34.104.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 <string.h>
15
16 #include "nacl_io/devfs/jspipe_node.h"
17 #include "nacl_io/devfs/tty_node.h"
18 #include "nacl_io/dir_node.h"
19 #include "nacl_io/kernel_wrap_real.h"
20 #include "nacl_io/node.h"
21 #include "nacl_io/osunistd.h"
22 #include "nacl_io/pepper_interface.h"
23 #include "sdk_util/auto_lock.h"
24
25 #if defined(__native_client__)
26 #include <irt.h>
27 #elif defined(WIN32)
28 #include <stdlib.h>
29 #endif
30
31 namespace nacl_io {
32
33 namespace {
34
35 class RealNode : public Node {
36  public:
37   RealNode(Filesystem* filesystem, int fd);
38
39   virtual Error Read(const HandleAttr& attr,
40                      void* buf,
41                      size_t count,
42                      int* out_bytes);
43   virtual Error Write(const HandleAttr& attr,
44                       const void* buf,
45                       size_t count,
46                       int* out_bytes);
47   virtual Error GetStat(struct stat* stat);
48
49  protected:
50   int fd_;
51 };
52
53 class NullNode : public CharNode {
54  public:
55   explicit NullNode(Filesystem* filesystem) : CharNode(filesystem) {}
56
57   virtual Error Read(const HandleAttr& attr,
58                      void* buf,
59                      size_t count,
60                      int* out_bytes);
61   virtual Error Write(const HandleAttr& attr,
62                       const void* buf,
63                       size_t count,
64                       int* out_bytes);
65 };
66
67 class ConsoleNode : public CharNode {
68  public:
69   ConsoleNode(Filesystem* filesystem, PP_LogLevel level);
70
71   virtual Error Write(const HandleAttr& attr,
72                       const void* buf,
73                       size_t count,
74                       int* out_bytes);
75
76  private:
77   PP_LogLevel level_;
78 };
79
80 class ZeroNode : public Node {
81  public:
82   explicit ZeroNode(Filesystem* filesystem);
83
84   virtual Error Read(const HandleAttr& attr,
85                      void* buf,
86                      size_t count,
87                      int* out_bytes);
88   virtual Error Write(const HandleAttr& attr,
89                       const void* buf,
90                       size_t count,
91                       int* out_bytes);
92 };
93
94 class UrandomNode : public Node {
95  public:
96   explicit UrandomNode(Filesystem* filesystem);
97
98   virtual Error Read(const HandleAttr& attr,
99                      void* buf,
100                      size_t count,
101                      int* out_bytes);
102   virtual Error Write(const HandleAttr& attr,
103                       const void* buf,
104                       size_t count,
105                       int* out_bytes);
106
107  private:
108 #if defined(__native_client__)
109   nacl_irt_random random_interface_;
110   bool interface_ok_;
111 #endif
112 };
113
114 RealNode::RealNode(Filesystem* filesystem, int fd) : Node(filesystem), fd_(fd) {
115   SetType(S_IFCHR);
116 }
117
118 Error RealNode::Read(const HandleAttr& attr,
119                      void* buf,
120                      size_t count,
121                      int* out_bytes) {
122   *out_bytes = 0;
123
124   size_t readcnt;
125   int err = _real_read(fd_, buf, count, &readcnt);
126   if (err)
127     return err;
128
129   *out_bytes = static_cast<int>(readcnt);
130   return 0;
131 }
132
133 Error RealNode::Write(const HandleAttr& attr,
134                       const void* buf,
135                       size_t count,
136                       int* out_bytes) {
137   *out_bytes = 0;
138
139   size_t writecnt;
140   int err = _real_write(fd_, buf, count, &writecnt);
141   if (err)
142     return err;
143
144   *out_bytes = static_cast<int>(writecnt);
145   return 0;
146 }
147
148 Error RealNode::GetStat(struct stat* stat) { return _real_fstat(fd_, stat); }
149
150 Error NullNode::Read(const HandleAttr& attr,
151                      void* buf,
152                      size_t count,
153                      int* out_bytes) {
154   *out_bytes = 0;
155   return 0;
156 }
157
158 Error NullNode::Write(const HandleAttr& attr,
159                       const void* buf,
160                       size_t count,
161                       int* out_bytes) {
162   *out_bytes = count;
163   return 0;
164 }
165
166 ConsoleNode::ConsoleNode(Filesystem* filesystem, PP_LogLevel level)
167     : CharNode(filesystem), level_(level) {}
168
169 Error ConsoleNode::Write(const HandleAttr& attr,
170                          const void* buf,
171                          size_t count,
172                          int* out_bytes) {
173   *out_bytes = 0;
174
175   ConsoleInterface* con_intr = filesystem_->ppapi()->GetConsoleInterface();
176   VarInterface* var_intr = filesystem_->ppapi()->GetVarInterface();
177
178   if (!(var_intr && con_intr))
179     return ENOSYS;
180
181   const char* var_data = static_cast<const char*>(buf);
182   uint32_t len = static_cast<uint32_t>(count);
183   struct PP_Var val = var_intr->VarFromUtf8(var_data, len);
184   con_intr->Log(filesystem_->ppapi()->GetInstance(), level_, val);
185
186   *out_bytes = count;
187   return 0;
188 }
189
190 ZeroNode::ZeroNode(Filesystem* filesystem) : Node(filesystem) {
191   SetType(S_IFCHR);
192 }
193
194 Error ZeroNode::Read(const HandleAttr& attr,
195                      void* buf,
196                      size_t count,
197                      int* out_bytes) {
198   memset(buf, 0, count);
199   *out_bytes = count;
200   return 0;
201 }
202
203 Error ZeroNode::Write(const HandleAttr& attr,
204                       const void* buf,
205                       size_t count,
206                       int* out_bytes) {
207   *out_bytes = count;
208   return 0;
209 }
210
211 UrandomNode::UrandomNode(Filesystem* filesystem) : Node(filesystem) {
212   SetType(S_IFCHR);
213 #if defined(__native_client__)
214   size_t result = nacl_interface_query(
215       NACL_IRT_RANDOM_v0_1, &random_interface_, sizeof(random_interface_));
216   interface_ok_ = result != 0;
217 #endif
218 }
219
220 Error UrandomNode::Read(const HandleAttr& attr,
221                         void* buf,
222                         size_t count,
223                         int* out_bytes) {
224   *out_bytes = 0;
225
226 #if defined(__native_client__)
227   if (!interface_ok_)
228     return EBADF;
229
230   size_t nread;
231   int error = (*random_interface_.get_random_bytes)(buf, count, &nread);
232   if (error)
233     return error;
234 #elif defined(WIN32)
235   char* out = static_cast<char*>(buf);
236   size_t bytes_left = count;
237   while (bytes_left) {
238     unsigned int random_int;
239     errno_t err = rand_s(&random_int);
240     if (err) {
241       *out_bytes = count - bytes_left;
242       return err;
243     }
244
245     int bytes_to_copy = std::min(bytes_left, sizeof(random_int));
246     memcpy(out, &random_int, bytes_to_copy);
247     out += bytes_to_copy;
248     bytes_left -= bytes_to_copy;
249   }
250 #endif
251
252   *out_bytes = count;
253   return 0;
254 }
255
256 Error UrandomNode::Write(const HandleAttr& attr,
257                          const void* buf,
258                          size_t count,
259                          int* out_bytes) {
260   *out_bytes = count;
261   return 0;
262 }
263
264 }  // namespace
265
266 Error DevFs::Access(const Path& path, int a_mode) {
267   ScopedNode node;
268   int error = root_->FindChild(path.Join(), &node);
269   if (error)
270     return error;
271
272   // Don't allow execute access.
273   if (a_mode & X_OK)
274     return EACCES;
275
276   return 0;
277 }
278
279 Error DevFs::Open(const Path& path, int open_flags, ScopedNode* out_node) {
280   out_node->reset(NULL);
281   int error = root_->FindChild(path.Join(), out_node);
282   // Only return EACCES when trying to create a node that does not exist.
283   if ((error == ENOENT) && (open_flags & O_CREAT))
284     return EACCES;
285
286   return error;
287 }
288
289 Error DevFs::Unlink(const Path& path) { return EPERM; }
290
291 Error DevFs::Mkdir(const Path& path, int permissions) { return EPERM; }
292
293 Error DevFs::Rmdir(const Path& path) { return EPERM; }
294
295 Error DevFs::Remove(const Path& path) { return EPERM; }
296
297 Error DevFs::Rename(const Path& path, const Path& newpath) { return EPERM; }
298
299 DevFs::DevFs() {}
300
301 #define INITIALIZE_DEV_NODE(path, klass)   \
302   new_node = ScopedNode(new klass(this));  \
303   error = root_->AddChild(path, new_node); \
304   if (error)                               \
305     return error;
306
307 #define INITIALIZE_DEV_NODE_1(path, klass, arg) \
308   new_node = ScopedNode(new klass(this, arg));  \
309   error = root_->AddChild(path, new_node);      \
310   if (error)                                    \
311     return error;
312
313 Error DevFs::Init(const FsInitArgs& args) {
314   Error error = Filesystem::Init(args);
315   if (error)
316     return error;
317
318   root_.reset(new DirNode(this));
319
320   ScopedNode new_node;
321   INITIALIZE_DEV_NODE("/null", NullNode);
322   INITIALIZE_DEV_NODE("/zero", ZeroNode);
323   INITIALIZE_DEV_NODE("/urandom", UrandomNode);
324   INITIALIZE_DEV_NODE_1("/console0", ConsoleNode, PP_LOGLEVEL_TIP);
325   INITIALIZE_DEV_NODE_1("/console1", ConsoleNode, PP_LOGLEVEL_LOG);
326   INITIALIZE_DEV_NODE_1("/console2", ConsoleNode, PP_LOGLEVEL_WARNING);
327   INITIALIZE_DEV_NODE_1("/console3", ConsoleNode, PP_LOGLEVEL_ERROR);
328   INITIALIZE_DEV_NODE("/tty", TtyNode);
329   INITIALIZE_DEV_NODE_1("/stdin", RealNode, 0);
330   INITIALIZE_DEV_NODE_1("/stdout", RealNode, 1);
331   INITIALIZE_DEV_NODE_1("/stderr", RealNode, 2);
332   INITIALIZE_DEV_NODE("/jspipe1", JSPipeNode);
333   new_node->Ioctl(TIOCNACLPIPENAME, "jspipe1");
334   INITIALIZE_DEV_NODE("/jspipe2", JSPipeNode);
335   new_node->Ioctl(TIOCNACLPIPENAME, "jspipe2");
336   INITIALIZE_DEV_NODE("/jspipe3", JSPipeNode);
337   new_node->Ioctl(TIOCNACLPIPENAME, "jspipe3");
338
339   return 0;
340 }
341
342 }  // namespace nacl_io