- add sources.
[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/mount.h"
11 #include "nacl_io/mount_node.h"
12 #include "nacl_io/mount_node_socket.h"
13 #include "nacl_io/osunistd.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()
21     : mount_(NULL), node_(NULL) {}
22
23 KernelHandle::KernelHandle(const ScopedMount& mnt, const ScopedMountNode& node)
24     : mount_(mnt), node_(node) {}
25
26 KernelHandle::~KernelHandle() {
27   // Force release order for cases where mount_ is not ref'd by mounting.
28   node_.reset(NULL);
29   mount_.reset(NULL);
30 }
31
32 // Returns the MountNodeSocket* if this node is a socket.
33 MountNodeSocket* KernelHandle::socket_node() {
34   if (node_.get() && node_->IsaSock())
35     return reinterpret_cast<MountNodeSocket*>(node_.get());
36   return NULL;
37 }
38
39 Error KernelHandle::Init(int open_flags) {
40   handle_attr_.flags = open_flags;
41
42   if (!node_->CanOpen(open_flags)) {
43     return EACCES;
44   }
45
46   if (open_flags & O_APPEND) {
47     Error error = node_->GetSize(&handle_attr_.offs);
48     if (error)
49       return error;
50   }
51
52   return 0;
53 }
54
55 Error KernelHandle::Seek(off_t offset, int whence, off_t* out_offset) {
56   // By default, don't move the offset.
57   *out_offset = offset;
58   size_t base;
59   size_t node_size;
60
61   AUTO_LOCK(handle_lock_);
62   Error error = node_->GetSize(&node_size);
63   if (error)
64     return error;
65
66   switch (whence) {
67     default:
68       return -1;
69     case SEEK_SET:
70       base = 0;
71       break;
72     case SEEK_CUR:
73       base = handle_attr_.offs;
74       break;
75     case SEEK_END:
76       base = node_size;
77       break;
78   }
79
80   if (base + offset < 0)
81     return EINVAL;
82
83   off_t new_offset = base + offset;
84
85   // Seeking past the end of the file will zero out the space between the old
86   // end and the new end.
87   if (new_offset > node_size) {
88     error = node_->FTruncate(new_offset);
89     if (error)
90       return EINVAL;
91   }
92
93   *out_offset = handle_attr_.offs = new_offset;
94   return 0;
95 }
96
97 Error KernelHandle::Read(void* buf, size_t nbytes, int* cnt) {
98   AUTO_LOCK(handle_lock_);
99   if (OpenMode() == O_WRONLY)
100     return EACCES;
101   Error error = node_->Read(handle_attr_, buf, nbytes, cnt);
102   if (0 == error)
103     handle_attr_.offs += *cnt;
104   return error;
105 }
106
107 Error KernelHandle::Write(const void* buf, size_t nbytes, int* cnt) {
108   AUTO_LOCK(handle_lock_);
109   if (OpenMode() == O_RDONLY)
110     return EACCES;
111   Error error = node_->Write(handle_attr_, buf, nbytes, cnt);
112   if (0 == error)
113     handle_attr_.offs += *cnt;
114   return error;
115 }
116
117 Error KernelHandle::GetDents(struct dirent* pdir, size_t nbytes, int* cnt) {
118   AUTO_LOCK(handle_lock_);
119   Error error = node_->GetDents(handle_attr_.offs, pdir, nbytes, cnt);
120   if (0 == error)
121     handle_attr_.offs += *cnt;
122   return error;
123 }
124
125 Error KernelHandle::Fcntl(int request, int* result, ...) {
126   va_list ap;
127   va_start(ap, result);
128   Error rtn = VFcntl(request, result, ap);
129   va_end(ap);
130   return rtn;
131 }
132
133 Error KernelHandle::VFcntl(int request, int* result, va_list args) {
134   switch (request) {
135     case F_GETFL: {
136       *result = handle_attr_.flags;
137       return 0;
138     }
139     case F_SETFL: {
140       AUTO_LOCK(handle_lock_);
141       int flags = va_arg(args, int);
142       if (!(flags & O_APPEND) && (handle_attr_.flags & O_APPEND)) {
143         // Attempt to clear O_APPEND.
144         return EPERM;
145       }
146       // Only certain flags are mutable
147       const int mutable_flags = O_ASYNC | O_NONBLOCK;
148       flags &= mutable_flags;
149       handle_attr_.flags &= ~mutable_flags;
150       handle_attr_.flags |= flags;
151       return 0;
152     }
153   }
154   return ENOSYS;
155 }
156
157 Error KernelHandle::Accept(PP_Resource* new_sock, struct sockaddr* addr,
158                            socklen_t* len) {
159   MountNodeSocket* sock = socket_node();
160   if (!sock)
161     return ENOTSOCK;
162
163   AUTO_LOCK(handle_lock_);
164   return sock->Accept(handle_attr_, new_sock, addr, len);
165 }
166
167 Error KernelHandle::Connect(const struct sockaddr* addr, socklen_t len) {
168   MountNodeSocket* sock = socket_node();
169   if (!sock)
170     return ENOTSOCK;
171
172   AUTO_LOCK(handle_lock_);
173   return sock->Connect(handle_attr_, addr, len);
174 }
175
176 Error KernelHandle::Recv(void* buf, size_t len, int flags, int* out_len) {
177   MountNodeSocket* sock = socket_node();
178   if (!sock)
179     return ENOTSOCK;
180
181   AUTO_LOCK(handle_lock_);
182   return sock->Recv(handle_attr_, buf, len, flags, out_len);
183 }
184
185 Error KernelHandle::RecvFrom(void* buf,
186                              size_t len,
187                              int flags,
188                              struct sockaddr* src_addr,
189                              socklen_t* addrlen,
190                              int* out_len) {
191   MountNodeSocket* sock = socket_node();
192   if (!sock)
193     return ENOTSOCK;
194
195   AUTO_LOCK(handle_lock_);
196   return sock->RecvFrom(handle_attr_, buf, len, flags, src_addr, addrlen,
197                         out_len);
198 }
199
200 Error KernelHandle::Send(const void* buf,
201                          size_t len,
202                          int flags,
203                          int* out_len) {
204   MountNodeSocket* sock = socket_node();
205   if (!sock)
206     return ENOTSOCK;
207
208   AUTO_LOCK(handle_lock_);
209   return sock->Send(handle_attr_, buf, len, flags, out_len);
210 }
211
212 Error KernelHandle::SendTo(const void* buf,
213                            size_t len,
214                            int flags,
215                            const struct sockaddr* dest_addr,
216                            socklen_t addrlen,
217                            int* out_len) {
218   MountNodeSocket* sock = socket_node();
219   if (!sock)
220     return ENOTSOCK;
221
222   AUTO_LOCK(handle_lock_);
223   return sock->SendTo(handle_attr_, buf, len, flags, dest_addr, addrlen,
224                       out_len);
225 }
226
227 }  // namespace nacl_io