• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/pepper_interface.h"
24 #include "sdk_util/auto_lock.h"
25 
26 #if defined(__native_client__)
27 #include <irt.h>
28 #elif defined(WIN32)
29 #include <stdlib.h>
30 #endif
31 
32 namespace nacl_io {
33 
34 namespace {
35 
36 class RealNode : public Node {
37  public:
38   RealNode(Filesystem* filesystem, int fd);
39 
40   virtual Error Read(const HandleAttr& attr,
41                      void* buf,
42                      size_t count,
43                      int* out_bytes);
44   virtual Error Write(const HandleAttr& attr,
45                       const void* buf,
46                       size_t count,
47                       int* out_bytes);
48   virtual Error GetStat(struct stat* stat);
49 
50  protected:
51   int fd_;
52 };
53 
54 class NullNode : public CharNode {
55  public:
NullNode(Filesystem * filesystem)56   explicit NullNode(Filesystem* filesystem) : CharNode(filesystem) {}
57 
58   virtual Error Read(const HandleAttr& attr,
59                      void* buf,
60                      size_t count,
61                      int* out_bytes);
62   virtual Error Write(const HandleAttr& attr,
63                       const void* buf,
64                       size_t count,
65                       int* out_bytes);
66 };
67 
68 class ConsoleNode : public CharNode {
69  public:
70   ConsoleNode(Filesystem* filesystem, PP_LogLevel level);
71 
72   virtual Error Write(const HandleAttr& attr,
73                       const void* buf,
74                       size_t count,
75                       int* out_bytes);
76 
77  private:
78   PP_LogLevel level_;
79 };
80 
81 class ZeroNode : public Node {
82  public:
83   explicit ZeroNode(Filesystem* filesystem);
84 
85   virtual Error Read(const HandleAttr& attr,
86                      void* buf,
87                      size_t count,
88                      int* out_bytes);
89   virtual Error Write(const HandleAttr& attr,
90                       const void* buf,
91                       size_t count,
92                       int* out_bytes);
93 };
94 
95 class UrandomNode : public Node {
96  public:
97   explicit UrandomNode(Filesystem* filesystem);
98 
99   virtual Error Read(const HandleAttr& attr,
100                      void* buf,
101                      size_t count,
102                      int* out_bytes);
103   virtual Error Write(const HandleAttr& attr,
104                       const void* buf,
105                       size_t count,
106                       int* out_bytes);
107 
108  private:
109 #if defined(__native_client__)
110   nacl_irt_random random_interface_;
111   bool interface_ok_;
112 #endif
113 };
114 
115 class FsNode : public Node {
116  public:
117   FsNode(Filesystem* filesystem, Filesystem* other_fs);
118 
119   virtual Error VIoctl(int request, va_list args);
120 
121  private:
122   // Don't addref the filesystem. We are relying on the fact that the
123   // KernelObject will keep the filsystem around as long as we need it, and
124   // this node will be destroyed when the filesystem is destroyed.
125   Filesystem* other_fs_;
126 };
127 
RealNode(Filesystem * filesystem,int fd)128 RealNode::RealNode(Filesystem* filesystem, int fd) : Node(filesystem), fd_(fd) {
129   SetType(S_IFCHR);
130 }
131 
Read(const HandleAttr & attr,void * buf,size_t count,int * out_bytes)132 Error RealNode::Read(const HandleAttr& attr,
133                      void* buf,
134                      size_t count,
135                      int* out_bytes) {
136   *out_bytes = 0;
137 
138   size_t readcnt;
139   int err = _real_read(fd_, buf, count, &readcnt);
140   if (err)
141     return err;
142 
143   *out_bytes = static_cast<int>(readcnt);
144   return 0;
145 }
146 
Write(const HandleAttr & attr,const void * buf,size_t count,int * out_bytes)147 Error RealNode::Write(const HandleAttr& attr,
148                       const void* buf,
149                       size_t count,
150                       int* out_bytes) {
151   *out_bytes = 0;
152 
153   size_t writecnt;
154   int err = _real_write(fd_, buf, count, &writecnt);
155   if (err)
156     return err;
157 
158   *out_bytes = static_cast<int>(writecnt);
159   return 0;
160 }
161 
GetStat(struct stat * stat)162 Error RealNode::GetStat(struct stat* stat) {
163   return _real_fstat(fd_, stat);
164 }
165 
Read(const HandleAttr & attr,void * buf,size_t count,int * out_bytes)166 Error NullNode::Read(const HandleAttr& attr,
167                      void* buf,
168                      size_t count,
169                      int* out_bytes) {
170   *out_bytes = 0;
171   return 0;
172 }
173 
Write(const HandleAttr & attr,const void * buf,size_t count,int * out_bytes)174 Error NullNode::Write(const HandleAttr& attr,
175                       const void* buf,
176                       size_t count,
177                       int* out_bytes) {
178   *out_bytes = count;
179   return 0;
180 }
181 
ConsoleNode(Filesystem * filesystem,PP_LogLevel level)182 ConsoleNode::ConsoleNode(Filesystem* filesystem, PP_LogLevel level)
183     : CharNode(filesystem), level_(level) {
184 }
185 
Write(const HandleAttr & attr,const void * buf,size_t count,int * out_bytes)186 Error ConsoleNode::Write(const HandleAttr& attr,
187                          const void* buf,
188                          size_t count,
189                          int* out_bytes) {
190   *out_bytes = 0;
191 
192   ConsoleInterface* con_intr = filesystem_->ppapi()->GetConsoleInterface();
193   VarInterface* var_intr = filesystem_->ppapi()->GetVarInterface();
194 
195   if (!(var_intr && con_intr))
196     return ENOSYS;
197 
198   const char* var_data = static_cast<const char*>(buf);
199   uint32_t len = static_cast<uint32_t>(count);
200   struct PP_Var val = var_intr->VarFromUtf8(var_data, len);
201   con_intr->Log(filesystem_->ppapi()->GetInstance(), level_, val);
202 
203   *out_bytes = count;
204   return 0;
205 }
206 
ZeroNode(Filesystem * filesystem)207 ZeroNode::ZeroNode(Filesystem* filesystem) : Node(filesystem) {
208   SetType(S_IFCHR);
209 }
210 
Read(const HandleAttr & attr,void * buf,size_t count,int * out_bytes)211 Error ZeroNode::Read(const HandleAttr& attr,
212                      void* buf,
213                      size_t count,
214                      int* out_bytes) {
215   memset(buf, 0, count);
216   *out_bytes = count;
217   return 0;
218 }
219 
Write(const HandleAttr & attr,const void * buf,size_t count,int * out_bytes)220 Error ZeroNode::Write(const HandleAttr& attr,
221                       const void* buf,
222                       size_t count,
223                       int* out_bytes) {
224   *out_bytes = count;
225   return 0;
226 }
227 
UrandomNode(Filesystem * filesystem)228 UrandomNode::UrandomNode(Filesystem* filesystem) : Node(filesystem) {
229   SetType(S_IFCHR);
230 #if defined(__native_client__)
231   size_t result = nacl_interface_query(
232       NACL_IRT_RANDOM_v0_1, &random_interface_, sizeof(random_interface_));
233   interface_ok_ = result != 0;
234 #endif
235 }
236 
Read(const HandleAttr & attr,void * buf,size_t count,int * out_bytes)237 Error UrandomNode::Read(const HandleAttr& attr,
238                         void* buf,
239                         size_t count,
240                         int* out_bytes) {
241   *out_bytes = 0;
242 
243 #if defined(__native_client__)
244   if (!interface_ok_)
245     return EBADF;
246 
247   size_t nread;
248   int error = (*random_interface_.get_random_bytes)(buf, count, &nread);
249   if (error)
250     return error;
251 #elif defined(WIN32)
252   char* out = static_cast<char*>(buf);
253   size_t bytes_left = count;
254   while (bytes_left) {
255     unsigned int random_int;
256     errno_t err = rand_s(&random_int);
257     if (err) {
258       *out_bytes = count - bytes_left;
259       return err;
260     }
261 
262     int bytes_to_copy = std::min(bytes_left, sizeof(random_int));
263     memcpy(out, &random_int, bytes_to_copy);
264     out += bytes_to_copy;
265     bytes_left -= bytes_to_copy;
266   }
267 #endif
268 
269   *out_bytes = count;
270   return 0;
271 }
272 
Write(const HandleAttr & attr,const void * buf,size_t count,int * out_bytes)273 Error UrandomNode::Write(const HandleAttr& attr,
274                          const void* buf,
275                          size_t count,
276                          int* out_bytes) {
277   *out_bytes = count;
278   return 0;
279 }
280 
FsNode(Filesystem * filesystem,Filesystem * other_fs)281 FsNode::FsNode(Filesystem* filesystem, Filesystem* other_fs)
282     : Node(filesystem), other_fs_(other_fs) {
283 }
284 
VIoctl(int request,va_list args)285 Error FsNode::VIoctl(int request, va_list args) {
286   return other_fs_->Filesystem_VIoctl(request, args);
287 }
288 
289 }  // namespace
290 
Access(const Path & path,int a_mode)291 Error DevFs::Access(const Path& path, int a_mode) {
292   ScopedNode node;
293   int error = root_->FindChild(path.Join(), &node);
294   if (error)
295     return error;
296 
297   // Don't allow execute access.
298   if (a_mode & X_OK)
299     return EACCES;
300 
301   return 0;
302 }
303 
Open(const Path & path,int open_flags,ScopedNode * out_node)304 Error DevFs::Open(const Path& path, int open_flags, ScopedNode* out_node) {
305   out_node->reset(NULL);
306   int error;
307   if (path.Part(1) == "fs") {
308     if (path.Size() == 3)
309       error = fs_dir_->FindChild(path.Part(2), out_node);
310     else
311       error = ENOENT;
312   } else {
313     error = root_->FindChild(path.Join(), out_node);
314   }
315 
316   // Only return EACCES when trying to create a node that does not exist.
317   if ((error == ENOENT) && (open_flags & O_CREAT))
318     return EACCES;
319 
320   return error;
321 }
322 
Unlink(const Path & path)323 Error DevFs::Unlink(const Path& path) {
324   return EPERM;
325 }
326 
Mkdir(const Path & path,int permissions)327 Error DevFs::Mkdir(const Path& path, int permissions) {
328   return EPERM;
329 }
330 
Rmdir(const Path & path)331 Error DevFs::Rmdir(const Path& path) {
332   return EPERM;
333 }
334 
Remove(const Path & path)335 Error DevFs::Remove(const Path& path) {
336   return EPERM;
337 }
338 
Rename(const Path & path,const Path & newpath)339 Error DevFs::Rename(const Path& path, const Path& newpath) {
340   return EPERM;
341 }
342 
CreateFsNode(Filesystem * other_fs)343 Error DevFs::CreateFsNode(Filesystem* other_fs) {
344   int dev = other_fs->dev();
345   char path[32];
346   snprintf(path, 32, "%d", dev);
347   ScopedNode new_node(new FsNode(this, other_fs));
348   return fs_dir_->AddChild(path, new_node);
349 }
350 
DestroyFsNode(Filesystem * other_fs)351 Error DevFs::DestroyFsNode(Filesystem* other_fs) {
352   int dev = other_fs->dev();
353   char path[32];
354   snprintf(path, 32, "%d", dev);
355   return fs_dir_->RemoveChild(path);
356 }
357 
DevFs()358 DevFs::DevFs() {
359 }
360 
361 #define INITIALIZE_DEV_NODE(path, klass)   \
362   new_node = ScopedNode(new klass(this));  \
363   error = root_->AddChild(path, new_node); \
364   if (error)                               \
365     return error;
366 
367 #define INITIALIZE_DEV_NODE_1(path, klass, arg) \
368   new_node = ScopedNode(new klass(this, arg));  \
369   error = root_->AddChild(path, new_node);      \
370   if (error)                                    \
371     return error;
372 
Init(const FsInitArgs & args)373 Error DevFs::Init(const FsInitArgs& args) {
374   Error error = Filesystem::Init(args);
375   if (error)
376     return error;
377 
378   root_.reset(new DirNode(this));
379 
380   ScopedNode new_node;
381   INITIALIZE_DEV_NODE("/null", NullNode);
382   INITIALIZE_DEV_NODE("/zero", ZeroNode);
383   INITIALIZE_DEV_NODE("/urandom", UrandomNode);
384   INITIALIZE_DEV_NODE_1("/console0", ConsoleNode, PP_LOGLEVEL_TIP);
385   INITIALIZE_DEV_NODE_1("/console1", ConsoleNode, PP_LOGLEVEL_LOG);
386   INITIALIZE_DEV_NODE_1("/console2", ConsoleNode, PP_LOGLEVEL_WARNING);
387   INITIALIZE_DEV_NODE_1("/console3", ConsoleNode, PP_LOGLEVEL_ERROR);
388   INITIALIZE_DEV_NODE("/tty", TtyNode);
389   INITIALIZE_DEV_NODE_1("/stdin", RealNode, 0);
390   INITIALIZE_DEV_NODE_1("/stdout", RealNode, 1);
391   INITIALIZE_DEV_NODE_1("/stderr", RealNode, 2);
392   INITIALIZE_DEV_NODE("/jspipe1", JSPipeNode);
393   new_node->Ioctl(NACL_IOC_PIPE_SETNAME, "jspipe1");
394   INITIALIZE_DEV_NODE("/jspipe2", JSPipeNode);
395   new_node->Ioctl(NACL_IOC_PIPE_SETNAME, "jspipe2");
396   INITIALIZE_DEV_NODE("/jspipe3", JSPipeNode);
397   new_node->Ioctl(NACL_IOC_PIPE_SETNAME, "jspipe3");
398 
399   // Add a directory for "fs" nodes; they represent all currently-mounted
400   // filesystems. We can ioctl these nodes to make changes or provide input to
401   // a mounted filesystem.
402   INITIALIZE_DEV_NODE("/fs", DirNode);
403   fs_dir_ = new_node;
404 
405   return 0;
406 }
407 
408 }  // namespace nacl_io
409