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 17namespace nacl_io { 18 19// It is only legal to construct a handle while the kernel lock is held. 20KernelHandle::KernelHandle() : filesystem_(NULL), node_(NULL) { 21} 22 23KernelHandle::KernelHandle(const ScopedFilesystem& fs, const ScopedNode& node) 24 : filesystem_(fs), node_(node) { 25} 26 27KernelHandle::~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. 34SocketNode* KernelHandle::socket_node() { 35 if (node_.get() && node_->IsaSock()) 36 return reinterpret_cast<SocketNode*>(node_.get()); 37 return NULL; 38} 39 40Error 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 56Error 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 98Error 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 108Error 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 118Error 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 126Error 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 134Error 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 default: 155 LOG_ERROR("Unsupported fcntl: %#x", request); 156 break; 157 } 158 return ENOSYS; 159} 160 161Error KernelHandle::Accept(PP_Resource* new_sock, 162 struct sockaddr* addr, 163 socklen_t* len) { 164 SocketNode* sock = socket_node(); 165 if (!sock) 166 return ENOTSOCK; 167 168 AUTO_LOCK(handle_lock_); 169 return sock->Accept(handle_attr_, new_sock, addr, len); 170} 171 172Error KernelHandle::Connect(const struct sockaddr* addr, socklen_t len) { 173 SocketNode* sock = socket_node(); 174 if (!sock) 175 return ENOTSOCK; 176 177 AUTO_LOCK(handle_lock_); 178 return sock->Connect(handle_attr_, addr, len); 179} 180 181Error KernelHandle::Recv(void* buf, size_t len, int flags, int* out_len) { 182 SocketNode* sock = socket_node(); 183 if (!sock) 184 return ENOTSOCK; 185 if (OpenMode() == O_WRONLY) 186 return EACCES; 187 188 AUTO_LOCK(handle_lock_); 189 return sock->Recv(handle_attr_, buf, len, flags, out_len); 190} 191 192Error KernelHandle::RecvFrom(void* buf, 193 size_t len, 194 int flags, 195 struct sockaddr* src_addr, 196 socklen_t* addrlen, 197 int* out_len) { 198 SocketNode* sock = socket_node(); 199 if (!sock) 200 return ENOTSOCK; 201 if (OpenMode() == O_WRONLY) 202 return EACCES; 203 204 AUTO_LOCK(handle_lock_); 205 return sock->RecvFrom(handle_attr_, buf, len, flags, src_addr, addrlen, 206 out_len); 207} 208 209Error KernelHandle::Send(const void* buf, size_t len, int flags, int* out_len) { 210 SocketNode* sock = socket_node(); 211 if (!sock) 212 return ENOTSOCK; 213 if (OpenMode() == O_RDONLY) 214 return EACCES; 215 216 AUTO_LOCK(handle_lock_); 217 return sock->Send(handle_attr_, buf, len, flags, out_len); 218} 219 220Error KernelHandle::SendTo(const void* buf, 221 size_t len, 222 int flags, 223 const struct sockaddr* dest_addr, 224 socklen_t addrlen, 225 int* out_len) { 226 SocketNode* sock = socket_node(); 227 if (!sock) 228 return ENOTSOCK; 229 if (OpenMode() == O_RDONLY) 230 return EACCES; 231 232 AUTO_LOCK(handle_lock_); 233 return sock->SendTo(handle_attr_, buf, len, flags, dest_addr, addrlen, 234 out_len); 235} 236 237} // namespace nacl_io 238