Upstream version 7.36.149.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 Error Node::Init(int open_flags) { return 0; }
45
46 void Node::Destroy() {
47   if (filesystem_) {
48     filesystem_->OnNodeDestroyed(this);
49   }
50 }
51
52 EventEmitter* Node::GetEventEmitter() { return NULL; }
53
54 uint32_t Node::GetEventStatus() {
55   if (GetEventEmitter())
56     return GetEventEmitter()->GetEventStatus();
57
58   return POLLIN | POLLOUT;
59 }
60
61 bool Node::CanOpen(int open_flags) {
62   switch (open_flags & 3) {
63     case O_RDONLY:
64       return (stat_.st_mode & S_IRALL) != 0;
65     case O_WRONLY:
66       return (stat_.st_mode & S_IWALL) != 0;
67     case O_RDWR:
68       return (stat_.st_mode & S_IRALL) != 0 && (stat_.st_mode & S_IWALL) != 0;
69   }
70
71   return false;
72 }
73
74 Error Node::FSync() { return 0; }
75
76 Error Node::FTruncate(off_t length) { return EINVAL; }
77
78 Error Node::GetDents(size_t offs,
79                      struct dirent* pdir,
80                      size_t count,
81                      int* out_bytes) {
82   *out_bytes = 0;
83   return ENOTDIR;
84 }
85
86 Error Node::GetStat(struct stat* pstat) {
87   AUTO_LOCK(node_lock_);
88   memcpy(pstat, &stat_, sizeof(stat_));
89   return 0;
90 }
91
92 Error Node::Ioctl(int request, ...) {
93   va_list ap;
94   va_start(ap, request);
95   Error rtn = VIoctl(request, ap);
96   va_end(ap);
97   return rtn;
98 }
99
100 Error Node::VIoctl(int request, va_list args) { return EINVAL; }
101
102 Error Node::Read(const HandleAttr& attr,
103                  void* buf,
104                  size_t count,
105                  int* out_bytes) {
106   *out_bytes = 0;
107   return EINVAL;
108 }
109
110 Error Node::Write(const HandleAttr& attr,
111                   const void* buf,
112                   size_t count,
113                   int* out_bytes) {
114   *out_bytes = 0;
115   return EINVAL;
116 }
117
118 Error Node::MMap(void* addr,
119                  size_t length,
120                  int prot,
121                  int flags,
122                  size_t offset,
123                  void** out_addr) {
124   *out_addr = NULL;
125
126   // Never allow mmap'ing PROT_EXEC. The passthrough node supports this, but we
127   // don't. Fortunately, glibc will fallback if this fails, so dlopen will
128   // continue to work.
129   if (prot & PROT_EXEC)
130     return EPERM;
131
132   // This default mmap support is just enough to make dlopen work.  This
133   // implementation just reads from the filesystem into the mmap'd memory area.
134   void* new_addr = addr;
135   int mmap_error = _real_mmap(
136       &new_addr, length, prot | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
137   if (new_addr == MAP_FAILED) {
138     _real_munmap(new_addr, length);
139     return mmap_error;
140   }
141
142   HandleAttr data;
143   data.offs = offset;
144   data.flags = 0;
145   int bytes_read;
146   Error read_error = Read(data, new_addr, length, &bytes_read);
147   if (read_error) {
148     _real_munmap(new_addr, length);
149     return read_error;
150   }
151
152   *out_addr = new_addr;
153   return 0;
154 }
155
156 Error Node::Tcflush(int queue_selector) { return EINVAL; }
157
158 Error Node::Tcgetattr(struct termios* termios_p) { return EINVAL; }
159
160 Error Node::Tcsetattr(int optional_actions, const struct termios* termios_p) {
161   return EINVAL;
162 }
163
164 int Node::GetLinks() { return stat_.st_nlink; }
165
166 int Node::GetMode() { return stat_.st_mode & ~S_IFMT; }
167
168 Error Node::GetSize(off_t* out_size) {
169   *out_size = stat_.st_size;
170   return 0;
171 }
172
173 int Node::GetType() { return stat_.st_mode & S_IFMT; }
174
175 void Node::SetType(int type) {
176   assert((type & ~S_IFMT) == 0);
177   stat_.st_mode &= ~S_IFMT;
178   stat_.st_mode |= type;
179 }
180
181 bool Node::IsaDir() { return (stat_.st_mode & S_IFDIR) != 0; }
182
183 bool Node::IsaFile() { return (stat_.st_mode & S_IFREG) != 0; }
184
185 bool Node::IsaSock() { return (stat_.st_mode & S_IFSOCK) != 0; }
186
187 Error Node::Isatty() {
188   return ENOTTY;
189 }
190
191 Error Node::AddChild(const std::string& name, const ScopedNode& node) {
192   return ENOTDIR;
193 }
194
195 Error Node::RemoveChild(const std::string& name) { return ENOTDIR; }
196
197 Error Node::FindChild(const std::string& name, ScopedNode* out_node) {
198   out_node->reset(NULL);
199   return ENOTDIR;
200 }
201
202 int Node::ChildCount() { return 0; }
203
204 void Node::Link() { stat_.st_nlink++; }
205
206 void Node::Unlink() { stat_.st_nlink--; }
207
208 }  // namespace nacl_io