Upstream version 8.37.180.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 (!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
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
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
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
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
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
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
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
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
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
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
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
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