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