Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / nacl_io / kernel_handle.cc
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.
20 KernelHandle::KernelHandle() : filesystem_(NULL), node_(NULL) {
21 }
22
23 KernelHandle::KernelHandle(const ScopedFilesystem& fs, const ScopedNode& node)
24     : filesystem_(fs), node_(node) {
25 }
26
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.
34 SocketNode* KernelHandle::socket_node() {
35   if (node_.get() && node_->IsaSock())
36     return reinterpret_cast<SocketNode*>(node_.get());
37   return NULL;
38 }
39
40 Error KernelHandle::Init(int open_flags) {
41   handle_attr_.flags = open_flags;
42
43   if ((open_flags & O_CREAT) == 0 && !node_->CanOpen(open_flags)) {
44     return EACCES;
45   }
46
47   // Directories can only be opened read-only.
48   if ((open_flags & 3) != O_RDONLY && node_->IsaDir()) {
49     return EISDIR;
50   }
51
52   if (open_flags & O_APPEND) {
53     Error error = node_->GetSize(&handle_attr_.offs);
54     if (error)
55       return error;
56   }
57
58   return 0;
59 }
60
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;
66
67   AUTO_LOCK(handle_lock_);
68   Error error = node_->GetSize(&node_size);
69   if (error)
70     return error;
71
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;
84   }
85
86   if (base + offset < 0)
87     return EINVAL;
88
89   off_t new_offset = base + offset;
90
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;
97   }
98
99   *out_offset = handle_attr_.offs = new_offset;
100   return 0;
101 }
102
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;
111 }
112
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;
121 }
122
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;
129 }
130
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;
137 }
138
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;
144     }
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;
151       }
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;
158     }
159     default:
160       LOG_ERROR("Unsupported fcntl: %#x", request);
161       break;
162   }
163   return ENOSYS;
164 }
165
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;
172
173   AUTO_LOCK(handle_lock_);
174   return sock->Accept(handle_attr_, new_sock, addr, len);
175 }
176
177 Error KernelHandle::Connect(const struct sockaddr* addr, socklen_t len) {
178   SocketNode* sock = socket_node();
179   if (!sock)
180     return ENOTSOCK;
181
182   AUTO_LOCK(handle_lock_);
183   return sock->Connect(handle_attr_, addr, len);
184 }
185
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;
192
193   AUTO_LOCK(handle_lock_);
194   return sock->Recv(handle_attr_, buf, len, flags, out_len);
195 }
196
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;
208
209   AUTO_LOCK(handle_lock_);
210   return sock->RecvFrom(handle_attr_, buf, len, flags, src_addr, addrlen,
211                         out_len);
212 }
213
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;
220
221   AUTO_LOCK(handle_lock_);
222   return sock->Send(handle_attr_, buf, len, flags, out_len);
223 }
224
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;
236
237   AUTO_LOCK(handle_lock_);
238   return sock->SendTo(handle_attr_, buf, len, flags, dest_addr, addrlen,
239                       out_len);
240 }
241
242 }  // namespace nacl_io