Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / kernel_handle.cc
blobc3fb86f973b7d6349ff156c395a588de693fb64c
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.
5 #include "nacl_io/kernel_handle.h"
7 #include <errno.h>
8 #include <pthread.h>
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"
15 #include "sdk_util/auto_lock.h"
17 namespace nacl_io {
19 // It is only legal to construct a handle while the kernel lock is held.
20 KernelHandle::KernelHandle() : filesystem_(NULL), node_(NULL) {
23 KernelHandle::KernelHandle(const ScopedFilesystem& fs, const ScopedNode& node)
24 : filesystem_(fs), node_(node) {
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);
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;
40 Error KernelHandle::Init(int open_flags) {
41 handle_attr_.flags = open_flags;
43 if ((open_flags & O_CREAT) == 0 && !node_->CanOpen(open_flags)) {
44 return EACCES;
47 // Directories can only be opened read-only.
48 if ((open_flags & 3) != O_RDONLY && node_->IsaDir()) {
49 return EISDIR;
52 if (open_flags & O_APPEND) {
53 Error error = node_->GetSize(&handle_attr_.offs);
54 if (error)
55 return error;
58 return 0;
61 Error KernelHandle::Seek(off_t offset, int whence, off_t* out_offset) {
62 // By default, don't move the offset.
63 *out_offset = offset;
64 off_t base;
65 off_t node_size;
67 AUTO_LOCK(handle_lock_);
68 if (!node_->IsSeekable())
69 return ESPIPE;
71 Error error = node_->GetSize(&node_size);
72 if (error)
73 return error;
75 switch (whence) {
76 case SEEK_SET:
77 base = 0;
78 break;
79 case SEEK_CUR:
80 base = handle_attr_.offs;
81 break;
82 case SEEK_END:
83 base = node_size;
84 break;
85 default:
86 return -1;
89 if (base + offset < 0)
90 return EINVAL;
92 off_t new_offset = base + offset;
94 // Seeking past the end of the file will zero out the space between the old
95 // end and the new end.
96 if (new_offset > node_size) {
97 error = node_->FTruncate(new_offset);
98 if (error)
99 return EINVAL;
102 *out_offset = handle_attr_.offs = new_offset;
103 return 0;
106 Error KernelHandle::Read(void* buf, size_t nbytes, int* cnt) {
107 sdk_util::AutoLock read_lock(handle_lock_);
108 if (OpenMode() == O_WRONLY)
109 return EACCES;
110 if (!node_->IsSeekable()){
111 read_lock.Unlock();
112 AUTO_LOCK(input_lock_);
113 return node_->Read(handle_attr_, buf, nbytes, cnt);
115 Error error = node_->Read(handle_attr_, buf, nbytes, cnt);
116 if (0 == error)
117 handle_attr_.offs += *cnt;
118 return error;
121 Error KernelHandle::Write(const void* buf, size_t nbytes, int* cnt) {
122 sdk_util::AutoLock write_lock(handle_lock_);
123 if (OpenMode() == O_RDONLY)
124 return EACCES;
125 if (!node_->IsSeekable()){
126 write_lock.Unlock();
127 AUTO_LOCK(output_lock_);
128 return node_->Write(handle_attr_, buf, nbytes, cnt);
130 Error error = node_->Write(handle_attr_, buf, nbytes, cnt);
131 if (0 == error)
132 handle_attr_.offs += *cnt;
133 return error;
136 Error KernelHandle::GetDents(struct dirent* pdir, size_t nbytes, int* cnt) {
137 AUTO_LOCK(handle_lock_);
138 Error error = node_->GetDents(handle_attr_.offs, pdir, nbytes, cnt);
139 if (0 == error)
140 handle_attr_.offs += *cnt;
141 return error;
144 Error KernelHandle::Fcntl(int request, int* result, ...) {
145 va_list ap;
146 va_start(ap, result);
147 Error rtn = VFcntl(request, result, ap);
148 va_end(ap);
149 return rtn;
152 Error KernelHandle::VFcntl(int request, int* result, va_list args) {
153 switch (request) {
154 case F_GETFL: {
155 // Should not block, but could if blocked on Connect or Accept. This is
156 // acceptable.
157 AUTO_LOCK(handle_lock_);
158 *result = handle_attr_.flags;
159 return 0;
161 case F_SETFL: {
162 AUTO_LOCK(handle_lock_);
163 int flags = va_arg(args, int);
164 if (!(flags & O_APPEND) && (handle_attr_.flags & O_APPEND)) {
165 // Attempt to clear O_APPEND.
166 return EPERM;
168 // Only certain flags are mutable
169 const int mutable_flags = O_ASYNC | O_NONBLOCK;
170 flags &= mutable_flags;
171 handle_attr_.flags &= ~mutable_flags;
172 handle_attr_.flags |= flags;
173 return 0;
175 default:
176 LOG_ERROR("Unsupported fcntl: %#x", request);
177 break;
179 return ENOSYS;
182 Error KernelHandle::Accept(PP_Resource* new_sock,
183 struct sockaddr* addr,
184 socklen_t* len) {
185 SocketNode* sock = socket_node();
186 if (!sock)
187 return ENOTSOCK;
189 AUTO_LOCK(handle_lock_);
190 return sock->Accept(handle_attr_, new_sock, addr, len);
193 Error KernelHandle::Connect(const struct sockaddr* addr, socklen_t len) {
194 SocketNode* sock = socket_node();
195 if (!sock)
196 return ENOTSOCK;
198 AUTO_LOCK(handle_lock_);
199 return sock->Connect(handle_attr_, addr, len);
202 Error KernelHandle::Recv(void* buf, size_t len, int flags, int* out_len) {
203 SocketNode* sock = socket_node();
204 if (!sock)
205 return ENOTSOCK;
206 if (OpenMode() == O_WRONLY)
207 return EACCES;
209 AUTO_LOCK(input_lock_);
210 return sock->Recv(handle_attr_, buf, len, flags, out_len);
213 Error KernelHandle::RecvFrom(void* buf,
214 size_t len,
215 int flags,
216 struct sockaddr* src_addr,
217 socklen_t* addrlen,
218 int* out_len) {
219 SocketNode* sock = socket_node();
220 if (!sock)
221 return ENOTSOCK;
222 if (OpenMode() == O_WRONLY)
223 return EACCES;
225 AUTO_LOCK(input_lock_);
226 return sock->RecvFrom(handle_attr_, buf, len, flags, src_addr, addrlen,
227 out_len);
230 Error KernelHandle::Send(const void* buf, size_t len, int flags, int* out_len) {
231 SocketNode* sock = socket_node();
232 if (!sock)
233 return ENOTSOCK;
234 if (OpenMode() == O_RDONLY)
235 return EACCES;
237 AUTO_LOCK(output_lock_);
238 return sock->Send(handle_attr_, buf, len, flags, out_len);
241 Error KernelHandle::SendTo(const void* buf,
242 size_t len,
243 int flags,
244 const struct sockaddr* dest_addr,
245 socklen_t addrlen,
246 int* out_len) {
247 SocketNode* sock = socket_node();
248 if (!sock)
249 return ENOTSOCK;
250 if (OpenMode() == O_RDONLY)
251 return EACCES;
253 AUTO_LOCK(output_lock_);
254 return sock->SendTo(handle_attr_, buf, len, flags, dest_addr, addrlen,
255 out_len);
258 } // namespace nacl_io