ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / kernel_handle.cc
blob4f88bbf8c6de542164875651c7204cc97ac75a90
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 Error error = node_->GetSize(&node_size);
69 if (error)
70 return error;
72 switch (whence) {
73 case SEEK_SET:
74 base = 0;
75 break;
76 case SEEK_CUR:
77 base = handle_attr_.offs;
78 break;
79 case SEEK_END:
80 base = node_size;
81 break;
82 default:
83 return -1;
86 if (base + offset < 0)
87 return EINVAL;
89 off_t new_offset = base + offset;
91 // Seeking past the end of the file will zero out the space between the old
92 // end and the new end.
93 if (new_offset > node_size) {
94 error = node_->FTruncate(new_offset);
95 if (error)
96 return EINVAL;
99 *out_offset = handle_attr_.offs = new_offset;
100 return 0;
103 Error KernelHandle::Read(void* buf, size_t nbytes, int* cnt) {
104 AUTO_LOCK(handle_lock_);
105 if (OpenMode() == O_WRONLY)
106 return EACCES;
107 Error error = node_->Read(handle_attr_, buf, nbytes, cnt);
108 if (0 == error)
109 handle_attr_.offs += *cnt;
110 return error;
113 Error KernelHandle::Write(const void* buf, size_t nbytes, int* cnt) {
114 AUTO_LOCK(handle_lock_);
115 if (OpenMode() == O_RDONLY)
116 return EACCES;
117 Error error = node_->Write(handle_attr_, buf, nbytes, cnt);
118 if (0 == error)
119 handle_attr_.offs += *cnt;
120 return error;
123 Error KernelHandle::GetDents(struct dirent* pdir, size_t nbytes, int* cnt) {
124 AUTO_LOCK(handle_lock_);
125 Error error = node_->GetDents(handle_attr_.offs, pdir, nbytes, cnt);
126 if (0 == error)
127 handle_attr_.offs += *cnt;
128 return error;
131 Error KernelHandle::Fcntl(int request, int* result, ...) {
132 va_list ap;
133 va_start(ap, result);
134 Error rtn = VFcntl(request, result, ap);
135 va_end(ap);
136 return rtn;
139 Error KernelHandle::VFcntl(int request, int* result, va_list args) {
140 switch (request) {
141 case F_GETFL: {
142 *result = handle_attr_.flags;
143 return 0;
145 case F_SETFL: {
146 AUTO_LOCK(handle_lock_);
147 int flags = va_arg(args, int);
148 if (!(flags & O_APPEND) && (handle_attr_.flags & O_APPEND)) {
149 // Attempt to clear O_APPEND.
150 return EPERM;
152 // Only certain flags are mutable
153 const int mutable_flags = O_ASYNC | O_NONBLOCK;
154 flags &= mutable_flags;
155 handle_attr_.flags &= ~mutable_flags;
156 handle_attr_.flags |= flags;
157 return 0;
159 default:
160 LOG_ERROR("Unsupported fcntl: %#x", request);
161 break;
163 return ENOSYS;
166 Error KernelHandle::Accept(PP_Resource* new_sock,
167 struct sockaddr* addr,
168 socklen_t* len) {
169 SocketNode* sock = socket_node();
170 if (!sock)
171 return ENOTSOCK;
173 AUTO_LOCK(handle_lock_);
174 return sock->Accept(handle_attr_, new_sock, addr, len);
177 Error KernelHandle::Connect(const struct sockaddr* addr, socklen_t len) {
178 SocketNode* sock = socket_node();
179 if (!sock)
180 return ENOTSOCK;
182 AUTO_LOCK(handle_lock_);
183 return sock->Connect(handle_attr_, addr, len);
186 Error KernelHandle::Recv(void* buf, size_t len, int flags, int* out_len) {
187 SocketNode* sock = socket_node();
188 if (!sock)
189 return ENOTSOCK;
190 if (OpenMode() == O_WRONLY)
191 return EACCES;
193 AUTO_LOCK(handle_lock_);
194 return sock->Recv(handle_attr_, buf, len, flags, out_len);
197 Error KernelHandle::RecvFrom(void* buf,
198 size_t len,
199 int flags,
200 struct sockaddr* src_addr,
201 socklen_t* addrlen,
202 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(handle_lock_);
210 return sock->RecvFrom(handle_attr_, buf, len, flags, src_addr, addrlen,
211 out_len);
214 Error KernelHandle::Send(const void* buf, size_t len, int flags, int* out_len) {
215 SocketNode* sock = socket_node();
216 if (!sock)
217 return ENOTSOCK;
218 if (OpenMode() == O_RDONLY)
219 return EACCES;
221 AUTO_LOCK(handle_lock_);
222 return sock->Send(handle_attr_, buf, len, flags, out_len);
225 Error KernelHandle::SendTo(const void* buf,
226 size_t len,
227 int flags,
228 const struct sockaddr* dest_addr,
229 socklen_t addrlen,
230 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(handle_lock_);
238 return sock->SendTo(handle_attr_, buf, len, flags, dest_addr, addrlen,
239 out_len);
242 } // namespace nacl_io