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