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"
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"
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.
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());
40 Error
KernelHandle::Init(int open_flags
) {
41 handle_attr_
.flags
= open_flags
;
43 if ((open_flags
& O_CREAT
) == 0 && !node_
->CanOpen(open_flags
)) {
47 // Directories can only be opened read-only.
48 if ((open_flags
& 3) != O_RDONLY
&& node_
->IsaDir()) {
52 if (open_flags
& O_APPEND
) {
53 Error error
= node_
->GetSize(&handle_attr_
.offs
);
61 Error
KernelHandle::Seek(off_t offset
, int whence
, off_t
* out_offset
) {
62 // By default, don't move the offset.
67 AUTO_LOCK(handle_lock_
);
68 if (!node_
->IsSeekable())
71 Error error
= node_
->GetSize(&node_size
);
80 base
= handle_attr_
.offs
;
89 if (base
+ offset
< 0)
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
);
102 *out_offset
= handle_attr_
.offs
= new_offset
;
106 Error
KernelHandle::Read(void* buf
, size_t nbytes
, int* cnt
) {
107 sdk_util::AutoLock
read_lock(handle_lock_
);
108 if (OpenMode() == O_WRONLY
)
110 if (!node_
->IsSeekable()){
112 AUTO_LOCK(input_lock_
);
113 return node_
->Read(handle_attr_
, buf
, nbytes
, cnt
);
115 Error error
= node_
->Read(handle_attr_
, buf
, nbytes
, cnt
);
117 handle_attr_
.offs
+= *cnt
;
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
)
125 if (!node_
->IsSeekable()){
127 AUTO_LOCK(output_lock_
);
128 return node_
->Write(handle_attr_
, buf
, nbytes
, cnt
);
130 Error error
= node_
->Write(handle_attr_
, buf
, nbytes
, cnt
);
132 handle_attr_
.offs
+= *cnt
;
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
);
140 handle_attr_
.offs
+= *cnt
;
144 Error
KernelHandle::Fcntl(int request
, int* result
, ...) {
146 va_start(ap
, result
);
147 Error rtn
= VFcntl(request
, result
, ap
);
152 Error
KernelHandle::VFcntl(int request
, int* result
, va_list args
) {
155 // Should not block, but could if blocked on Connect or Accept. This is
157 AUTO_LOCK(handle_lock_
);
158 *result
= handle_attr_
.flags
;
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.
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
;
176 LOG_ERROR("Unsupported fcntl: %#x", request
);
182 Error
KernelHandle::Accept(PP_Resource
* new_sock
,
183 struct sockaddr
* addr
,
185 SocketNode
* sock
= socket_node();
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();
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();
206 if (OpenMode() == O_WRONLY
)
209 AUTO_LOCK(input_lock_
);
210 return sock
->Recv(handle_attr_
, buf
, len
, flags
, out_len
);
213 Error
KernelHandle::RecvFrom(void* buf
,
216 struct sockaddr
* src_addr
,
219 SocketNode
* sock
= socket_node();
222 if (OpenMode() == O_WRONLY
)
225 AUTO_LOCK(input_lock_
);
226 return sock
->RecvFrom(handle_attr_
, buf
, len
, flags
, src_addr
, addrlen
,
230 Error
KernelHandle::Send(const void* buf
, size_t len
, int flags
, int* out_len
) {
231 SocketNode
* sock
= socket_node();
234 if (OpenMode() == O_RDONLY
)
237 AUTO_LOCK(output_lock_
);
238 return sock
->Send(handle_attr_
, buf
, len
, flags
, out_len
);
241 Error
KernelHandle::SendTo(const void* buf
,
244 const struct sockaddr
* dest_addr
,
247 SocketNode
* sock
= socket_node();
250 if (OpenMode() == O_RDONLY
)
253 AUTO_LOCK(output_lock_
);
254 return sock
->SendTo(handle_attr_
, buf
, len
, flags
, dest_addr
, addrlen
,
258 } // namespace nacl_io