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