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 int Node::GetLinks() {
    180   return stat_.st_nlink;
    181 }
    182 
    183 int Node::GetMode() {
    184   return stat_.st_mode & ~S_IFMT;
    185 }
    186 
    187 Error Node::GetSize(off_t* out_size) {
    188   *out_size = stat_.st_size;
    189   return 0;
    190 }
    191 
    192 int Node::GetType() {
    193   return stat_.st_mode & S_IFMT;
    194 }
    195 
    196 void Node::SetType(int type) {
    197   assert((type & ~S_IFMT) == 0);
    198   stat_.st_mode &= ~S_IFMT;
    199   stat_.st_mode |= type;
    200 }
    201 
    202 bool Node::IsaDir() {
    203   return GetType() == S_IFDIR;
    204 }
    205 
    206 bool Node::IsaFile() {
    207   return GetType() == S_IFREG;
    208 }
    209 
    210 bool Node::IsaSock() {
    211   return GetType() == S_IFSOCK;
    212 }
    213 
    214 Error Node::Isatty() {
    215   return ENOTTY;
    216 }
    217 
    218 Error Node::AddChild(const std::string& name, const ScopedNode& node) {
    219   return ENOTDIR;
    220 }
    221 
    222 Error Node::RemoveChild(const std::string& name) {
    223   return ENOTDIR;
    224 }
    225 
    226 Error Node::FindChild(const std::string& name, ScopedNode* out_node) {
    227   out_node->reset(NULL);
    228   return ENOTDIR;
    229 }
    230 
    231 int Node::ChildCount() {
    232   return 0;
    233 }
    234 
    235 void Node::Link() {
    236   stat_.st_nlink++;
    237 }
    238 
    239 void Node::Unlink() {
    240   stat_.st_nlink--;
    241 }
    242 
    243 }  // namespace nacl_io
    244