Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / nacl_io / node.cc
1 // Copyright 2013 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/node.h"
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <poll.h>
11 #include <string.h>
12 #include <sys/stat.h>
13
14 #include <algorithm>
15 #include <string>
16
17 #include "nacl_io/filesystem.h"
18 #include "nacl_io/kernel_handle.h"
19 #include "nacl_io/kernel_wrap_real.h"
20 #include "nacl_io/osmman.h"
21 #include "sdk_util/auto_lock.h"
22
23 namespace nacl_io {
24
25 static const int USR_ID = 1001;
26 static const int GRP_ID = 1002;
27
28 Node::Node(Filesystem* filesystem) : filesystem_(filesystem) {
29   memset(&stat_, 0, sizeof(stat_));
30   stat_.st_gid = GRP_ID;
31   stat_.st_uid = USR_ID;
32   stat_.st_mode = S_IRALL | S_IWALL;
33
34   // Filesystem should normally never be NULL, but may be null in tests.
35   // If NULL, at least set the inode to a valid (nonzero) value.
36   if (filesystem_)
37     filesystem_->OnNodeCreated(this);
38   else
39     stat_.st_ino = 1;
40 }
41
42 Node::~Node() {
43 }
44
45 Error Node::Init(int open_flags) {
46   return 0;
47 }
48
49 void Node::Destroy() {
50   if (filesystem_) {
51     filesystem_->OnNodeDestroyed(this);
52   }
53 }
54
55 EventEmitter* Node::GetEventEmitter() {
56   return NULL;
57 }
58
59 uint32_t Node::GetEventStatus() {
60   if (GetEventEmitter())
61     return GetEventEmitter()->GetEventStatus();
62
63   return POLLIN | POLLOUT;
64 }
65
66 bool Node::CanOpen(int open_flags) {
67   switch (open_flags & 3) {
68     case O_RDONLY:
69       return (stat_.st_mode & S_IRALL) != 0;
70     case O_WRONLY:
71       return (stat_.st_mode & S_IWALL) != 0;
72     case O_RDWR:
73       return (stat_.st_mode & S_IRALL) != 0 && (stat_.st_mode & S_IWALL) != 0;
74   }
75
76   return false;
77 }
78
79 Error Node::FSync() {
80   return 0;
81 }
82
83 Error Node::FTruncate(off_t length) {
84   return EINVAL;
85 }
86
87 Error Node::GetDents(size_t offs,
88                      struct dirent* pdir,
89                      size_t count,
90                      int* out_bytes) {
91   *out_bytes = 0;
92   return ENOTDIR;
93 }
94
95 Error Node::GetStat(struct stat* pstat) {
96   AUTO_LOCK(node_lock_);
97   memcpy(pstat, &stat_, sizeof(stat_));
98   return 0;
99 }
100
101 Error Node::Ioctl(int request, ...) {
102   va_list ap;
103   va_start(ap, request);
104   Error rtn = VIoctl(request, ap);
105   va_end(ap);
106   return rtn;
107 }
108
109 Error Node::VIoctl(int request, va_list args) {
110   return EINVAL;
111 }
112
113 Error Node::Read(const HandleAttr& attr,
114                  void* buf,
115                  size_t count,
116                  int* out_bytes) {
117   *out_bytes = 0;
118   return EINVAL;
119 }
120
121 Error Node::Write(const HandleAttr& attr,
122                   const void* buf,
123                   size_t count,
124                   int* out_bytes) {
125   *out_bytes = 0;
126   return EINVAL;
127 }
128
129 Error Node::MMap(void* addr,
130                  size_t length,
131                  int prot,
132                  int flags,
133                  size_t offset,
134                  void** out_addr) {
135   *out_addr = NULL;
136
137   // Never allow mmap'ing PROT_EXEC. The passthrough node supports this, but we
138   // don't. Fortunately, glibc will fallback if this fails, so dlopen will
139   // continue to work.
140   if (prot & PROT_EXEC)
141     return EPERM;
142
143   // This default mmap support is just enough to make dlopen work.  This
144   // implementation just reads from the filesystem into the mmap'd memory area.
145   void* new_addr = addr;
146   int mmap_error = _real_mmap(
147       &new_addr, length, prot | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
148   if (new_addr == MAP_FAILED) {
149     _real_munmap(new_addr, length);
150     return mmap_error;
151   }
152
153   HandleAttr data;
154   data.offs = offset;
155   data.flags = 0;
156   int bytes_read;
157   Error read_error = Read(data, new_addr, length, &bytes_read);
158   if (read_error) {
159     _real_munmap(new_addr, length);
160     return read_error;
161   }
162
163   *out_addr = new_addr;
164   return 0;
165 }
166
167 Error Node::Tcflush(int queue_selector) {
168   return EINVAL;
169 }
170
171 Error Node::Tcgetattr(struct termios* termios_p) {
172   return EINVAL;
173 }
174
175 Error Node::Tcsetattr(int optional_actions, const struct termios* termios_p) {
176   return EINVAL;
177 }
178
179 int Node::GetLinks() {
180   return stat_.st_nlink;
181 }
182
183 int Node::GetMode() {
184   return stat_.st_mode & ~S_IFMT;
185 }
186
187 Error Node::GetSize(off_t* out_size) {
188   *out_size = stat_.st_size;
189   return 0;
190 }
191
192 int Node::GetType() {
193   return stat_.st_mode & S_IFMT;
194 }
195
196 void Node::SetType(int type) {
197   assert((type & ~S_IFMT) == 0);
198   stat_.st_mode &= ~S_IFMT;
199   stat_.st_mode |= type;
200 }
201
202 bool Node::IsaDir() {
203   return GetType() == S_IFDIR;
204 }
205
206 bool Node::IsaFile() {
207   return GetType() == S_IFREG;
208 }
209
210 bool Node::IsaSock() {
211   return GetType() == S_IFSOCK;
212 }
213
214 Error Node::Isatty() {
215   return ENOTTY;
216 }
217
218 Error Node::AddChild(const std::string& name, const ScopedNode& node) {
219   return ENOTDIR;
220 }
221
222 Error Node::RemoveChild(const std::string& name) {
223   return ENOTDIR;
224 }
225
226 Error Node::FindChild(const std::string& name, ScopedNode* out_node) {
227   out_node->reset(NULL);
228   return ENOTDIR;
229 }
230
231 int Node::ChildCount() {
232   return 0;
233 }
234
235 void Node::Link() {
236   stat_.st_nlink++;
237 }
238
239 void Node::Unlink() {
240   stat_.st_nlink--;
241 }
242
243 }  // namespace nacl_io