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 <errno.h>
      8 #include <fcntl.h>
      9 #include <poll.h>
     10 #include <string.h>
     11 #include <sys/stat.h>
     12 
     13 #include <algorithm>
     14 #include <string>
     15 
     16 #include "nacl_io/kernel_wrap_real.h"
     17 #include "nacl_io/mount.h"
     18 #include "nacl_io/osmman.h"
     19 #include "sdk_util/auto_lock.h"
     20 
     21 namespace nacl_io {
     22 
     23 static const int USR_ID = 1001;
     24 static const int GRP_ID = 1002;
     25 
     26 MountNode::MountNode(Mount* mount) : mount_(mount) {
     27   memset(&stat_, 0, sizeof(stat_));
     28   stat_.st_gid = GRP_ID;
     29   stat_.st_uid = USR_ID;
     30 
     31   // Mount should normally never be NULL, but may be null in tests.
     32   // If NULL, at least set the inode to a valid (nonzero) value.
     33   if (mount_)
     34     mount_->OnNodeCreated(this);
     35   else
     36     stat_.st_ino = 1;
     37 }
     38 
     39 MountNode::~MountNode() {}
     40 
     41 Error MountNode::Init(int perm) {
     42   stat_.st_mode |= perm;
     43   return 0;
     44 }
     45 
     46 void MountNode::Destroy() {
     47   if (mount_) {
     48     mount_->OnNodeDestroyed(this);
     49   }
     50 }
     51 
     52 // Declared in EventEmitter, default to regular files which always return
     53 // a ready of TRUE for read, write, or error.
     54 uint32_t MountNode::GetEventStatus() {
     55   uint32_t val = POLLIN | POLLOUT | POLLERR;
     56   return val;
     57 }
     58 
     59 
     60 Error MountNode::FSync() { return 0; }
     61 
     62 Error MountNode::FTruncate(off_t length) { return EINVAL; }
     63 
     64 Error MountNode::GetDents(size_t offs,
     65                           struct dirent* pdir,
     66                           size_t count,
     67                           int* out_bytes) {
     68   *out_bytes = 0;
     69   return ENOTDIR;
     70 }
     71 
     72 Error MountNode::GetStat(struct stat* pstat) {
     73   AUTO_LOCK(node_lock_);
     74   memcpy(pstat, &stat_, sizeof(stat_));
     75   return 0;
     76 }
     77 
     78 Error MountNode::Ioctl(int request, char* arg) { return EINVAL; }
     79 
     80 Error MountNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
     81   *out_bytes = 0;
     82   return EINVAL;
     83 }
     84 
     85 Error MountNode::Write(size_t offs,
     86                        const void* buf,
     87                        size_t count,
     88                        int* out_bytes) {
     89   *out_bytes = 0;
     90   return EINVAL;
     91 }
     92 
     93 Error MountNode::MMap(void* addr,
     94                       size_t length,
     95                       int prot,
     96                       int flags,
     97                       size_t offset,
     98                       void** out_addr) {
     99   *out_addr = NULL;
    100 
    101   // Never allow mmap'ing PROT_EXEC. The passthrough node supports this, but we
    102   // don't. Fortunately, glibc will fallback if this fails, so dlopen will
    103   // continue to work.
    104   if (prot & PROT_EXEC)
    105     return EPERM;
    106 
    107   // This default mmap support is just enough to make dlopen work.
    108   // This implementation just reads from the mount into the mmap'd memory area.
    109   void* new_addr = addr;
    110   int mmap_error = _real_mmap(
    111       &new_addr, length, prot | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
    112   if (new_addr == MAP_FAILED) {
    113     _real_munmap(new_addr, length);
    114     return mmap_error;
    115   }
    116 
    117   int bytes_read;
    118   Error read_error = Read(offset, new_addr, length, &bytes_read);
    119   if (read_error) {
    120     _real_munmap(new_addr, length);
    121     return read_error;
    122   }
    123 
    124   *out_addr = new_addr;
    125   return 0;
    126 }
    127 
    128 Error MountNode::Tcflush(int queue_selector) {
    129   return EINVAL;
    130 }
    131 
    132 Error MountNode::Tcgetattr(struct termios* termios_p) {
    133   return EINVAL;
    134 }
    135 
    136 Error MountNode::Tcsetattr(int optional_actions,
    137                            const struct termios *termios_p) {
    138   return EINVAL;
    139 }
    140 
    141 int MountNode::GetLinks() { return stat_.st_nlink; }
    142 
    143 int MountNode::GetMode() { return stat_.st_mode & ~S_IFMT; }
    144 
    145 Error MountNode::GetSize(size_t* out_size) {
    146   *out_size = stat_.st_size;
    147   return 0;
    148 }
    149 
    150 int MountNode::GetType() { return stat_.st_mode & S_IFMT; }
    151 
    152 bool MountNode::IsaDir() { return (stat_.st_mode & S_IFDIR) != 0; }
    153 
    154 bool MountNode::IsaFile() { return (stat_.st_mode & S_IFREG) != 0; }
    155 
    156 bool MountNode::IsaTTY() { return (stat_.st_mode & S_IFCHR) != 0; }
    157 
    158 Error MountNode::AddChild(const std::string& name,
    159                           const ScopedMountNode& node) {
    160   return ENOTDIR;
    161 }
    162 
    163 Error MountNode::RemoveChild(const std::string& name) { return ENOTDIR; }
    164 
    165 Error MountNode::FindChild(const std::string& name, ScopedMountNode* out_node) {
    166   out_node->reset(NULL);
    167   return ENOTDIR;
    168 }
    169 
    170 int MountNode::ChildCount() { return 0; }
    171 
    172 void MountNode::Link() { stat_.st_nlink++; }
    173 
    174 void MountNode::Unlink() { stat_.st_nlink--; }
    175 
    176 }  // namespace nacl_io
    177 
    178