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/filesystem.h"
11 #include "nacl_io/node.h"
12 #include "nacl_io/osunistd.h"
13 #include "nacl_io/socket/socket_node.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.
KernelHandle()20 KernelHandle::KernelHandle() : filesystem_(NULL), node_(NULL) {
21 }
22
KernelHandle(const ScopedFilesystem & fs,const ScopedNode & node)23 KernelHandle::KernelHandle(const ScopedFilesystem& fs, const ScopedNode& node)
24 : filesystem_(fs), node_(node) {
25 }
26
~KernelHandle()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);
31 }
32
33 // Returns the SocketNode* if this node is a socket.
socket_node()34 SocketNode* KernelHandle::socket_node() {
35 if (node_.get() && node_->IsaSock())
36 return reinterpret_cast<SocketNode*>(node_.get());
37 return NULL;
38 }
39
Init(int open_flags)40 Error KernelHandle::Init(int open_flags) {
41 handle_attr_.flags = open_flags;
42
43 if (!node_->CanOpen(open_flags)) {
44 return EACCES;
45 }
46
47 if (open_flags & O_APPEND) {
48 Error error = node_->GetSize(&handle_attr_.offs);
49 if (error)
50 return error;
51 }
52
53 return 0;
54 }
55
Seek(off_t offset,int whence,off_t * out_offset)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;
61
62 AUTO_LOCK(handle_lock_);
63 Error error = node_->GetSize(&node_size);
64 if (error)
65 return error;
66
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;
79 }
80
81 if (base + offset < 0)
82 return EINVAL;
83
84 off_t new_offset = base + offset;
85
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;
92 }
93
94 *out_offset = handle_attr_.offs = new_offset;
95 return 0;
96 }
97
Read(void * buf,size_t nbytes,int * cnt)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;
106 }
107
Write(const void * buf,size_t nbytes,int * cnt)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;
116 }
117
GetDents(struct dirent * pdir,size_t nbytes,int * cnt)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;
124 }
125
Fcntl(int request,int * result,...)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;
132 }
133
VFcntl(int request,int * result,va_list args)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;
139 }
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;
146 }
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;
153 }
154 }
155 return ENOSYS;
156 }
157
Accept(PP_Resource * new_sock,struct sockaddr * addr,socklen_t * len)158 Error KernelHandle::Accept(PP_Resource* new_sock,
159 struct sockaddr* addr,
160 socklen_t* len) {
161 SocketNode* sock = socket_node();
162 if (!sock)
163 return ENOTSOCK;
164
165 AUTO_LOCK(handle_lock_);
166 return sock->Accept(handle_attr_, new_sock, addr, len);
167 }
168
Connect(const struct sockaddr * addr,socklen_t len)169 Error KernelHandle::Connect(const struct sockaddr* addr, socklen_t len) {
170 SocketNode* sock = socket_node();
171 if (!sock)
172 return ENOTSOCK;
173
174 AUTO_LOCK(handle_lock_);
175 return sock->Connect(handle_attr_, addr, len);
176 }
177
Recv(void * buf,size_t len,int flags,int * out_len)178 Error KernelHandle::Recv(void* buf, size_t len, int flags, int* out_len) {
179 SocketNode* sock = socket_node();
180 if (!sock)
181 return ENOTSOCK;
182 if (OpenMode() == O_WRONLY)
183 return EACCES;
184
185 AUTO_LOCK(handle_lock_);
186 return sock->Recv(handle_attr_, buf, len, flags, out_len);
187 }
188
RecvFrom(void * buf,size_t len,int flags,struct sockaddr * src_addr,socklen_t * addrlen,int * out_len)189 Error KernelHandle::RecvFrom(void* buf,
190 size_t len,
191 int flags,
192 struct sockaddr* src_addr,
193 socklen_t* addrlen,
194 int* out_len) {
195 SocketNode* sock = socket_node();
196 if (!sock)
197 return ENOTSOCK;
198 if (OpenMode() == O_WRONLY)
199 return EACCES;
200
201 AUTO_LOCK(handle_lock_);
202 return sock->RecvFrom(handle_attr_, buf, len, flags, src_addr, addrlen,
203 out_len);
204 }
205
Send(const void * buf,size_t len,int flags,int * out_len)206 Error KernelHandle::Send(const void* buf, size_t len, int flags, int* out_len) {
207 SocketNode* sock = socket_node();
208 if (!sock)
209 return ENOTSOCK;
210 if (OpenMode() == O_RDONLY)
211 return EACCES;
212
213 AUTO_LOCK(handle_lock_);
214 return sock->Send(handle_attr_, buf, len, flags, out_len);
215 }
216
SendTo(const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen,int * out_len)217 Error KernelHandle::SendTo(const void* buf,
218 size_t len,
219 int flags,
220 const struct sockaddr* dest_addr,
221 socklen_t addrlen,
222 int* out_len) {
223 SocketNode* sock = socket_node();
224 if (!sock)
225 return ENOTSOCK;
226 if (OpenMode() == O_RDONLY)
227 return EACCES;
228
229 AUTO_LOCK(handle_lock_);
230 return sock->SendTo(handle_attr_, buf, len, flags, dest_addr, addrlen,
231 out_len);
232 }
233
234 } // namespace nacl_io
235