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