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