Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / kernel_handle.cc
blob5c5bcc10b2f30e2ca66ba561ea0f936a81a13132
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 (!node_->CanOpen(open_flags)) {
44 return EACCES;
47 if (open_flags & O_APPEND) {
48 Error error = node_->GetSize(&handle_attr_.offs);
49 if (error)
50 return error;
53 return 0;
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;
62 AUTO_LOCK(handle_lock_);
63 Error error = node_->GetSize(&node_size);
64 if (error)
65 return error;
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;
81 if (base + offset < 0)
82 return EINVAL;
84 off_t new_offset = base + offset;
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;
94 *out_offset = handle_attr_.offs = new_offset;
95 return 0;
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;
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;
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;
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;
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;
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;
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;
154 default:
155 LOG_ERROR("Unsupported fcntl: %#x", request);
156 break;
158 return ENOSYS;
161 Error 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;
168 AUTO_LOCK(handle_lock_);
169 return sock->Accept(handle_attr_, new_sock, addr, len);
172 Error KernelHandle::Connect(const struct sockaddr* addr, socklen_t len) {
173 SocketNode* sock = socket_node();
174 if (!sock)
175 return ENOTSOCK;
177 AUTO_LOCK(handle_lock_);
178 return sock->Connect(handle_attr_, addr, len);
181 Error 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;
188 AUTO_LOCK(handle_lock_);
189 return sock->Recv(handle_attr_, buf, len, flags, out_len);
192 Error 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;
204 AUTO_LOCK(handle_lock_);
205 return sock->RecvFrom(handle_attr_, buf, len, flags, src_addr, addrlen,
206 out_len);
209 Error 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;
216 AUTO_LOCK(handle_lock_);
217 return sock->Send(handle_attr_, buf, len, flags, out_len);
220 Error 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;
232 AUTO_LOCK(handle_lock_);
233 return sock->SendTo(handle_attr_, buf, len, flags, dest_addr, addrlen,
234 out_len);
237 } // namespace nacl_io