node.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 23namespace nacl_io { 24 25static const int USR_ID = 1001; 26static const int GRP_ID = 1002; 27 28Node::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 42Node::~Node() { 43} 44 45Error Node::Init(int open_flags) { 46 return 0; 47} 48 49void Node::Destroy() { 50 if (filesystem_) { 51 filesystem_->OnNodeDestroyed(this); 52 } 53} 54 55EventEmitter* Node::GetEventEmitter() { 56 return NULL; 57} 58 59uint32_t Node::GetEventStatus() { 60 if (GetEventEmitter()) 61 return GetEventEmitter()->GetEventStatus(); 62 63 return POLLIN | POLLOUT; 64} 65 66bool 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 79Error Node::FSync() { 80 return 0; 81} 82 83Error Node::FTruncate(off_t length) { 84 return EINVAL; 85} 86 87Error 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 95Error Node::GetStat(struct stat* pstat) { 96 AUTO_LOCK(node_lock_); 97 memcpy(pstat, &stat_, sizeof(stat_)); 98 return 0; 99} 100 101Error 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 109Error Node::VIoctl(int request, va_list args) { 110 return EINVAL; 111} 112 113Error 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 121Error 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 129Error 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 167Error Node::Tcflush(int queue_selector) { 168 return EINVAL; 169} 170 171Error Node::Tcgetattr(struct termios* termios_p) { 172 return EINVAL; 173} 174 175Error Node::Tcsetattr(int optional_actions, const struct termios* termios_p) { 176 return EINVAL; 177} 178 179Error Node::Futimens(const struct timespec times[2]) { 180 return 0; 181} 182 183Error Node::Fchmod(mode_t mode) { 184 return EINVAL; 185} 186 187int Node::GetLinks() { 188 return stat_.st_nlink; 189} 190 191int Node::GetMode() { 192 return stat_.st_mode & ~S_IFMT; 193} 194 195Error Node::GetSize(off_t* out_size) { 196 *out_size = stat_.st_size; 197 return 0; 198} 199 200int Node::GetType() { 201 return stat_.st_mode & S_IFMT; 202} 203 204void Node::SetType(int type) { 205 assert((type & ~S_IFMT) == 0); 206 stat_.st_mode &= ~S_IFMT; 207 stat_.st_mode |= type; 208} 209 210void Node::SetMode(int mode) { 211 assert((mode & S_IFMT) == 0); 212 stat_.st_mode &= S_IFMT; 213 stat_.st_mode |= mode; 214} 215 216bool Node::IsaDir() { 217 return GetType() == S_IFDIR; 218} 219 220bool Node::IsaFile() { 221 return GetType() == S_IFREG; 222} 223 224bool Node::IsaSock() { 225 return GetType() == S_IFSOCK; 226} 227 228Error Node::Isatty() { 229 return ENOTTY; 230} 231 232Error Node::AddChild(const std::string& name, const ScopedNode& node) { 233 return ENOTDIR; 234} 235 236Error Node::RemoveChild(const std::string& name) { 237 return ENOTDIR; 238} 239 240Error Node::FindChild(const std::string& name, ScopedNode* out_node) { 241 out_node->reset(NULL); 242 return ENOTDIR; 243} 244 245int Node::ChildCount() { 246 return 0; 247} 248 249void Node::Link() { 250 stat_.st_nlink++; 251} 252 253void Node::Unlink() { 254 stat_.st_nlink--; 255} 256 257} // namespace nacl_io 258