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/kernel_handle.h" 6 7 #include <errno.h> 8 #include <pthread.h> 9 10 #include "nacl_io/filesystem.h" 11 #include "nacl_io/node.h" 12 #include "nacl_io/osunistd.h" 13 #include "nacl_io/socket/socket_node.h" 14 15 #include "sdk_util/auto_lock.h" 16 17 namespace nacl_io { 18 19 // It is only legal to construct a handle while the kernel lock is held. 20 KernelHandle::KernelHandle() : filesystem_(NULL), node_(NULL) { 21 } 22 23 KernelHandle::KernelHandle(const ScopedFilesystem& fs, const ScopedNode& node) 24 : filesystem_(fs), node_(node) { 25 } 26 27 KernelHandle::~KernelHandle() { 28 // Force release order for cases where filesystem_ is not ref'd by mounting. 29 node_.reset(NULL); 30 filesystem_.reset(NULL); 31 } 32 33 // Returns the SocketNode* if this node is a socket. 34 SocketNode* KernelHandle::socket_node() { 35 if (node_.get() && node_->IsaSock()) 36 return reinterpret_cast<SocketNode*>(node_.get()); 37 return NULL; 38 } 39 40 Error KernelHandle::Init(int open_flags) { 41 handle_attr_.flags = open_flags; 42 43 if (!node_->CanOpen(open_flags)) { 44 return EACCES; 45 } 46 47 if (open_flags & O_APPEND) { 48 Error error = node_->GetSize(&handle_attr_.offs); 49 if (error) 50 return error; 51 } 52 53 return 0; 54 } 55 56 Error KernelHandle::Seek(off_t offset, int whence, off_t* out_offset) { 57 // By default, don't move the offset. 58 *out_offset = offset; 59 off_t base; 60 off_t node_size; 61 62 AUTO_LOCK(handle_lock_); 63 Error error = node_->GetSize(&node_size); 64 if (error) 65 return error; 66 67 switch (whence) { 68 case SEEK_SET: 69 base = 0; 70 break; 71 case SEEK_CUR: 72 base = handle_attr_.offs; 73 break; 74 case SEEK_END: 75 base = node_size; 76 break; 77 default: 78 return -1; 79 } 80 81 if (base + offset < 0) 82 return EINVAL; 83 84 off_t new_offset = base + offset; 85 86 // Seeking past the end of the file will zero out the space between the old 87 // end and the new end. 88 if (new_offset > node_size) { 89 error = node_->FTruncate(new_offset); 90 if (error) 91 return EINVAL; 92 } 93 94 *out_offset = handle_attr_.offs = new_offset; 95 return 0; 96 } 97 98 Error KernelHandle::Read(void* buf, size_t nbytes, int* cnt) { 99 AUTO_LOCK(handle_lock_); 100 if (OpenMode() == O_WRONLY) 101 return EACCES; 102 Error error = node_->Read(handle_attr_, buf, nbytes, cnt); 103 if (0 == error) 104 handle_attr_.offs += *cnt; 105 return error; 106 } 107 108 Error KernelHandle::Write(const void* buf, size_t nbytes, int* cnt) { 109 AUTO_LOCK(handle_lock_); 110 if (OpenMode() == O_RDONLY) 111 return EACCES; 112 Error error = node_->Write(handle_attr_, buf, nbytes, cnt); 113 if (0 == error) 114 handle_attr_.offs += *cnt; 115 return error; 116 } 117 118 Error KernelHandle::GetDents(struct dirent* pdir, size_t nbytes, int* cnt) { 119 AUTO_LOCK(handle_lock_); 120 Error error = node_->GetDents(handle_attr_.offs, pdir, nbytes, cnt); 121 if (0 == error) 122 handle_attr_.offs += *cnt; 123 return error; 124 } 125 126 Error KernelHandle::Fcntl(int request, int* result, ...) { 127 va_list ap; 128 va_start(ap, result); 129 Error rtn = VFcntl(request, result, ap); 130 va_end(ap); 131 return rtn; 132 } 133 134 Error KernelHandle::VFcntl(int request, int* result, va_list args) { 135 switch (request) { 136 case F_GETFL: { 137 *result = handle_attr_.flags; 138 return 0; 139 } 140 case F_SETFL: { 141 AUTO_LOCK(handle_lock_); 142 int flags = va_arg(args, int); 143 if (!(flags & O_APPEND) && (handle_attr_.flags & O_APPEND)) { 144 // Attempt to clear O_APPEND. 145 return EPERM; 146 } 147 // Only certain flags are mutable 148 const int mutable_flags = O_ASYNC | O_NONBLOCK; 149 flags &= mutable_flags; 150 handle_attr_.flags &= ~mutable_flags; 151 handle_attr_.flags |= flags; 152 return 0; 153 } 154 } 155 return ENOSYS; 156 } 157 158 Error KernelHandle::Accept(PP_Resource* new_sock, 159 struct sockaddr* addr, 160 socklen_t* len) { 161 SocketNode* sock = socket_node(); 162 if (!sock) 163 return ENOTSOCK; 164 165 AUTO_LOCK(handle_lock_); 166 return sock->Accept(handle_attr_, new_sock, addr, len); 167 } 168 169 Error KernelHandle::Connect(const struct sockaddr* addr, socklen_t len) { 170 SocketNode* sock = socket_node(); 171 if (!sock) 172 return ENOTSOCK; 173 174 AUTO_LOCK(handle_lock_); 175 return sock->Connect(handle_attr_, addr, len); 176 } 177 178 Error KernelHandle::Recv(void* buf, size_t len, int flags, int* out_len) { 179 SocketNode* sock = socket_node(); 180 if (!sock) 181 return ENOTSOCK; 182 if (OpenMode() == O_WRONLY) 183 return EACCES; 184 185 AUTO_LOCK(handle_lock_); 186 return sock->Recv(handle_attr_, buf, len, flags, out_len); 187 } 188 189 Error KernelHandle::RecvFrom(void* buf, 190 size_t len, 191 int flags, 192 struct sockaddr* src_addr, 193 socklen_t* addrlen, 194 int* out_len) { 195 SocketNode* sock = socket_node(); 196 if (!sock) 197 return ENOTSOCK; 198 if (OpenMode() == O_WRONLY) 199 return EACCES; 200 201 AUTO_LOCK(handle_lock_); 202 return sock->RecvFrom(handle_attr_, buf, len, flags, src_addr, addrlen, 203 out_len); 204 } 205 206 Error KernelHandle::Send(const void* buf, size_t len, int flags, int* out_len) { 207 SocketNode* sock = socket_node(); 208 if (!sock) 209 return ENOTSOCK; 210 if (OpenMode() == O_RDONLY) 211 return EACCES; 212 213 AUTO_LOCK(handle_lock_); 214 return sock->Send(handle_attr_, buf, len, flags, out_len); 215 } 216 217 Error KernelHandle::SendTo(const void* buf, 218 size_t len, 219 int flags, 220 const struct sockaddr* dest_addr, 221 socklen_t addrlen, 222 int* out_len) { 223 SocketNode* sock = socket_node(); 224 if (!sock) 225 return ENOTSOCK; 226 if (OpenMode() == O_RDONLY) 227 return EACCES; 228 229 AUTO_LOCK(handle_lock_); 230 return sock->SendTo(handle_attr_, buf, len, flags, dest_addr, addrlen, 231 out_len); 232 } 233 234 } // namespace nacl_io 235