Home | History | Annotate | Download | only in nacl_io
      1 // Copyright (c) 2012 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/mount_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/kernel_handle.h"
     18 #include "nacl_io/kernel_wrap_real.h"
     19 #include "nacl_io/mount.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 MountNode::MountNode(Mount* mount) : mount_(mount) {
     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   // Mount 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 (mount_)
     37     mount_->OnNodeCreated(this);
     38   else
     39     stat_.st_ino = 1;
     40 }
     41 
     42 MountNode::~MountNode() {}
     43 
     44 Error MountNode::Init(int open_flags) {
     45   return 0;
     46 }
     47 
     48 void MountNode::Destroy() {
     49   if (mount_) {
     50     mount_->OnNodeDestroyed(this);
     51   }
     52 }
     53 
     54 EventEmitter* MountNode::GetEventEmitter() { return NULL; }
     55 
     56 uint32_t MountNode::GetEventStatus() {
     57   if (GetEventEmitter())
     58     return GetEventEmitter()->GetEventStatus();
     59 
     60   return POLLIN | POLLOUT;
     61 }
     62 
     63 bool MountNode::CanOpen(int open_flags) {
     64   switch (open_flags & 3) {
     65     case O_RDONLY:
     66       return (stat_.st_mode & S_IRALL) != 0;
     67     case O_WRONLY:
     68       return (stat_.st_mode & S_IWALL) != 0;
     69     case O_RDWR:
     70       return (stat_.st_mode & S_IRALL) != 0 && (stat_.st_mode & S_IWALL) != 0;
     71   }
     72 
     73   return false;
     74 }
     75 
     76 Error MountNode::FSync() { return 0; }
     77 
     78 Error MountNode::FTruncate(off_t length) { return EINVAL; }
     79 
     80 Error MountNode::GetDents(size_t offs,
     81                           struct dirent* pdir,
     82                           size_t count,
     83                           int* out_bytes) {
     84   *out_bytes = 0;
     85   return ENOTDIR;
     86 }
     87 
     88 Error MountNode::GetStat(struct stat* pstat) {
     89   AUTO_LOCK(node_lock_);
     90   memcpy(pstat, &stat_, sizeof(stat_));
     91   return 0;
     92 }
     93 
     94 Error MountNode::Ioctl(int request, ...) {
     95   va_list ap;
     96   va_start(ap, request);
     97   Error rtn = VIoctl(request, ap);
     98   va_end(ap);
     99   return rtn;
    100 }
    101 
    102 Error MountNode::VIoctl(int request, va_list args) { return EINVAL; }
    103 
    104 Error MountNode::Read(const HandleAttr& attr,
    105                       void* buf,
    106                       size_t count,
    107                       int* out_bytes) {
    108   *out_bytes = 0;
    109   return EINVAL;
    110 }
    111 
    112 Error MountNode::Write(const HandleAttr& attr,
    113                        const void* buf,
    114                        size_t count,
    115                        int* out_bytes) {
    116   *out_bytes = 0;
    117   return EINVAL;
    118 }
    119 
    120 Error MountNode::MMap(void* addr,
    121                       size_t length,
    122                       int prot,
    123                       int flags,
    124                       size_t offset,
    125                       void** out_addr) {
    126   *out_addr = NULL;
    127 
    128   // Never allow mmap'ing PROT_EXEC. The passthrough node supports this, but we
    129   // don't. Fortunately, glibc will fallback if this fails, so dlopen will
    130   // continue to work.
    131   if (prot & PROT_EXEC)
    132     return EPERM;
    133 
    134   // This default mmap support is just enough to make dlopen work.
    135   // This implementation just reads from the mount into the mmap'd memory area.
    136   void* new_addr = addr;
    137   int mmap_error = _real_mmap(
    138       &new_addr, length, prot | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
    139   if (new_addr == MAP_FAILED) {
    140     _real_munmap(new_addr, length);
    141     return mmap_error;
    142   }
    143 
    144   HandleAttr data;
    145   data.offs = offset;
    146   data.flags = 0;
    147   int bytes_read;
    148   Error read_error = Read(data, new_addr, length, &bytes_read);
    149   if (read_error) {
    150     _real_munmap(new_addr, length);
    151     return read_error;
    152   }
    153 
    154   *out_addr = new_addr;
    155   return 0;
    156 }
    157 
    158 Error MountNode::Tcflush(int queue_selector) {
    159   return EINVAL;
    160 }
    161 
    162 Error MountNode::Tcgetattr(struct termios* termios_p) {
    163   return EINVAL;
    164 }
    165 
    166 Error MountNode::Tcsetattr(int optional_actions,
    167                            const struct termios *termios_p) {
    168   return EINVAL;
    169 }
    170 
    171 int MountNode::GetLinks() { return stat_.st_nlink; }
    172 
    173 int MountNode::GetMode() { return stat_.st_mode & ~S_IFMT; }
    174 
    175 Error MountNode::GetSize(size_t* out_size) {
    176   *out_size = stat_.st_size;
    177   return 0;
    178 }
    179 
    180 int MountNode::GetType() { return stat_.st_mode & S_IFMT; }
    181 
    182 void MountNode::SetType(int type) {
    183   assert((type & ~S_IFMT) == 0);
    184   stat_.st_mode &= ~S_IFMT;
    185   stat_.st_mode |= type;
    186 }
    187 
    188 bool MountNode::IsaDir() { return (stat_.st_mode & S_IFDIR) != 0; }
    189 
    190 bool MountNode::IsaFile() { return (stat_.st_mode & S_IFREG) != 0; }
    191 
    192 bool MountNode::IsaSock() { return (stat_.st_mode & S_IFSOCK) != 0; }
    193 
    194 bool MountNode::IsaTTY() { return (stat_.st_mode & S_IFCHR) != 0; }
    195 
    196 Error MountNode::AddChild(const std::string& name,
    197                           const ScopedMountNode& node) {
    198   return ENOTDIR;
    199 }
    200 
    201 Error MountNode::RemoveChild(const std::string& name) { return ENOTDIR; }
    202 
    203 Error MountNode::FindChild(const std::string& name, ScopedMountNode* out_node) {
    204   out_node->reset(NULL);
    205   return ENOTDIR;
    206 }
    207 
    208 int MountNode::ChildCount() { return 0; }
    209 
    210 void MountNode::Link() { stat_.st_nlink++; }
    211 
    212 void MountNode::Unlink() { stat_.st_nlink--; }
    213 
    214 }  // namespace nacl_io
    215