Home | History | Annotate | Download | only in nacl_io
      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 #include "nacl_io/node.h"
      6 
      7 #include <assert.h>
      8 #include <errno.h>
      9 #include <fcntl.h>
     10 #include <poll.h>
     11 #include <string.h>
     12 #include <sys/stat.h>
     13 
     14 #include <algorithm>
     15 #include <string>
     16 
     17 #include "nacl_io/filesystem.h"
     18 #include "nacl_io/kernel_handle.h"
     19 #include "nacl_io/kernel_wrap_real.h"
     20 #include "nacl_io/osmman.h"
     21 #include "sdk_util/auto_lock.h"
     22 
     23 namespace nacl_io {
     24 
     25 static const int USR_ID = 1001;
     26 static const int GRP_ID = 1002;
     27 
     28 Node::Node(Filesystem* filesystem) : filesystem_(filesystem) {
     29   memset(&stat_, 0, sizeof(stat_));
     30   stat_.st_gid = GRP_ID;
     31   stat_.st_uid = USR_ID;
     32   stat_.st_mode = S_IRALL | S_IWALL;
     33 
     34   // Filesystem should normally never be NULL, but may be null in tests.
     35   // If NULL, at least set the inode to a valid (nonzero) value.
     36   if (filesystem_)
     37     filesystem_->OnNodeCreated(this);
     38   else
     39     stat_.st_ino = 1;
     40 }
     41 
     42 Node::~Node() {
     43 }
     44 
     45 Error Node::Init(int open_flags) {
     46   return 0;
     47 }
     48 
     49 void Node::Destroy() {
     50   if (filesystem_) {
     51     filesystem_->OnNodeDestroyed(this);
     52   }
     53 }
     54 
     55 EventEmitter* Node::GetEventEmitter() {
     56   return NULL;
     57 }
     58 
     59 uint32_t Node::GetEventStatus() {
     60   if (GetEventEmitter())
     61     return GetEventEmitter()->GetEventStatus();
     62 
     63   return POLLIN | POLLOUT;
     64 }
     65 
     66 bool Node::CanOpen(int open_flags) {
     67   switch (open_flags & 3) {
     68     case O_RDONLY:
     69       return (stat_.st_mode & S_IRALL) != 0;
     70     case O_WRONLY:
     71       return (stat_.st_mode & S_IWALL) != 0;
     72     case O_RDWR:
     73       return (stat_.st_mode & S_IRALL) != 0 && (stat_.st_mode & S_IWALL) != 0;
     74   }
     75 
     76   return false;
     77 }
     78 
     79 Error Node::FSync() {
     80   return 0;
     81 }
     82 
     83 Error Node::FTruncate(off_t length) {
     84   return EINVAL;
     85 }
     86 
     87 Error Node::GetDents(size_t offs,
     88                      struct dirent* pdir,
     89                      size_t count,
     90                      int* out_bytes) {
     91   *out_bytes = 0;
     92   return ENOTDIR;
     93 }
     94 
     95 Error Node::GetStat(struct stat* pstat) {
     96   AUTO_LOCK(node_lock_);
     97   memcpy(pstat, &stat_, sizeof(stat_));
     98   return 0;
     99 }
    100 
    101 Error Node::Ioctl(int request, ...) {
    102   va_list ap;
    103   va_start(ap, request);
    104   Error rtn = VIoctl(request, ap);
    105   va_end(ap);
    106   return rtn;
    107 }
    108 
    109 Error Node::VIoctl(int request, va_list args) {
    110   return EINVAL;
    111 }
    112 
    113 Error Node::Read(const HandleAttr& attr,
    114                  void* buf,
    115                  size_t count,
    116                  int* out_bytes) {
    117   *out_bytes = 0;
    118   return EINVAL;
    119 }
    120 
    121 Error Node::Write(const HandleAttr& attr,
    122                   const void* buf,
    123                   size_t count,
    124                   int* out_bytes) {
    125   *out_bytes = 0;
    126   return EINVAL;
    127 }
    128 
    129 Error Node::MMap(void* addr,
    130                  size_t length,
    131                  int prot,
    132                  int flags,
    133                  size_t offset,
    134                  void** out_addr) {
    135   *out_addr = NULL;
    136 
    137   // Never allow mmap'ing PROT_EXEC. The passthrough node supports this, but we
    138   // don't. Fortunately, glibc will fallback if this fails, so dlopen will
    139   // continue to work.
    140   if (prot & PROT_EXEC)
    141     return EPERM;
    142 
    143   // This default mmap support is just enough to make dlopen work.  This
    144   // implementation just reads from the filesystem into the mmap'd memory area.
    145   void* new_addr = addr;
    146   int mmap_error = _real_mmap(
    147       &new_addr, length, prot | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
    148   if (new_addr == MAP_FAILED) {
    149     _real_munmap(new_addr, length);
    150     return mmap_error;
    151   }
    152 
    153   HandleAttr data;
    154   data.offs = offset;
    155   data.flags = 0;
    156   int bytes_read;
    157   Error read_error = Read(data, new_addr, length, &bytes_read);
    158   if (read_error) {
    159     _real_munmap(new_addr, length);
    160     return read_error;
    161   }
    162 
    163   *out_addr = new_addr;
    164   return 0;
    165 }
    166 
    167 Error Node::Tcflush(int queue_selector) {
    168   return EINVAL;
    169 }
    170 
    171 Error Node::Tcgetattr(struct termios* termios_p) {
    172   return EINVAL;
    173 }
    174 
    175 Error Node::Tcsetattr(int optional_actions, const struct termios* termios_p) {
    176   return EINVAL;
    177 }
    178 
    179 Error Node::Futimens(const struct timespec times[2]) {
    180   return 0;
    181 }
    182 
    183 Error Node::Fchmod(mode_t mode) {
    184   return EINVAL;
    185 }
    186 
    187 int Node::GetLinks() {
    188   return stat_.st_nlink;
    189 }
    190 
    191 int Node::GetMode() {
    192   return stat_.st_mode & ~S_IFMT;
    193 }
    194 
    195 Error Node::GetSize(off_t* out_size) {
    196   *out_size = stat_.st_size;
    197   return 0;
    198 }
    199 
    200 int Node::GetType() {
    201   return stat_.st_mode & S_IFMT;
    202 }
    203 
    204 void Node::SetType(int type) {
    205   assert((type & ~S_IFMT) == 0);
    206   stat_.st_mode &= ~S_IFMT;
    207   stat_.st_mode |= type;
    208 }
    209 
    210 void Node::SetMode(int mode) {
    211   assert((mode & S_IFMT) == 0);
    212   stat_.st_mode &= S_IFMT;
    213   stat_.st_mode |= mode;
    214 }
    215 
    216 bool Node::IsaDir() {
    217   return GetType() == S_IFDIR;
    218 }
    219 
    220 bool Node::IsaFile() {
    221   return GetType() == S_IFREG;
    222 }
    223 
    224 bool Node::IsaSock() {
    225   return GetType() == S_IFSOCK;
    226 }
    227 
    228 Error Node::Isatty() {
    229   return ENOTTY;
    230 }
    231 
    232 Error Node::AddChild(const std::string& name, const ScopedNode& node) {
    233   return ENOTDIR;
    234 }
    235 
    236 Error Node::RemoveChild(const std::string& name) {
    237   return ENOTDIR;
    238 }
    239 
    240 Error Node::FindChild(const std::string& name, ScopedNode* out_node) {
    241   out_node->reset(NULL);
    242   return ENOTDIR;
    243 }
    244 
    245 int Node::ChildCount() {
    246   return 0;
    247 }
    248 
    249 void Node::Link() {
    250   stat_.st_nlink++;
    251 }
    252 
    253 void Node::Unlink() {
    254   stat_.st_nlink--;
    255 }
    256 
    257 }  // namespace nacl_io
    258