Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / node.cc
blob6ca1a205e50fbb3d1be3bfda5e6b74850ba76302
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.
5 #include "nacl_io/node.h"
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>
14 #include <algorithm>
15 #include <string>
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 "nacl_io/ostime.h"
22 #include "sdk_util/auto_lock.h"
24 namespace nacl_io {
26 static const int USR_ID = 1001;
27 static const int GRP_ID = 1002;
29 Node::Node(Filesystem* filesystem) : filesystem_(filesystem) {
30 memset(&stat_, 0, sizeof(stat_));
31 stat_.st_gid = GRP_ID;
32 stat_.st_uid = USR_ID;
33 stat_.st_mode = S_IRALL | S_IWALL;
35 // Filesystem should normally never be NULL, but may be null in tests.
36 // If NULL, at least set the inode to a valid (nonzero) value.
37 if (filesystem_)
38 filesystem_->OnNodeCreated(this);
39 else
40 stat_.st_ino = 1;
43 Node::~Node() {
46 Error Node::Init(int open_flags) {
47 return 0;
50 void Node::Destroy() {
51 if (filesystem_) {
52 filesystem_->OnNodeDestroyed(this);
56 EventEmitter* Node::GetEventEmitter() {
57 return NULL;
60 uint32_t Node::GetEventStatus() {
61 if (GetEventEmitter())
62 return GetEventEmitter()->GetEventStatus();
64 return POLLIN | POLLOUT;
67 bool Node::CanOpen(int open_flags) {
68 switch (open_flags & 3) {
69 case O_RDONLY:
70 return (stat_.st_mode & S_IRALL) != 0;
71 case O_WRONLY:
72 return (stat_.st_mode & S_IWALL) != 0;
73 case O_RDWR:
74 return (stat_.st_mode & S_IRALL) != 0 && (stat_.st_mode & S_IWALL) != 0;
77 return false;
80 Error Node::FSync() {
81 return 0;
84 Error Node::FTruncate(off_t length) {
85 return EINVAL;
88 Error Node::GetDents(size_t offs,
89 struct dirent* pdir,
90 size_t count,
91 int* out_bytes) {
92 *out_bytes = 0;
93 return ENOTDIR;
96 Error Node::GetStat(struct stat* pstat) {
97 AUTO_LOCK(node_lock_);
98 memcpy(pstat, &stat_, sizeof(stat_));
99 return 0;
102 Error Node::Ioctl(int request, ...) {
103 va_list ap;
104 va_start(ap, request);
105 Error rtn = VIoctl(request, ap);
106 va_end(ap);
107 return rtn;
110 Error Node::VIoctl(int request, va_list args) {
111 return EINVAL;
114 Error Node::Read(const HandleAttr& attr,
115 void* buf,
116 size_t count,
117 int* out_bytes) {
118 *out_bytes = 0;
119 return EINVAL;
122 Error Node::Write(const HandleAttr& attr,
123 const void* buf,
124 size_t count,
125 int* out_bytes) {
126 *out_bytes = 0;
127 return EINVAL;
130 Error Node::MMap(void* addr,
131 size_t length,
132 int prot,
133 int flags,
134 size_t offset,
135 void** out_addr) {
136 *out_addr = NULL;
138 // Never allow mmap'ing PROT_EXEC. The passthrough node supports this, but we
139 // don't. Fortunately, glibc will fallback if this fails, so dlopen will
140 // continue to work.
141 if (prot & PROT_EXEC)
142 return EPERM;
144 // This default mmap support is just enough to make dlopen work. This
145 // implementation just reads from the filesystem into the mmap'd memory area.
146 void* new_addr = addr;
147 int mmap_error = _real_mmap(
148 &new_addr, length, prot | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
149 if (new_addr == MAP_FAILED) {
150 _real_munmap(new_addr, length);
151 return mmap_error;
154 HandleAttr data;
155 data.offs = offset;
156 data.flags = 0;
157 int bytes_read;
158 Error read_error = Read(data, new_addr, length, &bytes_read);
159 if (read_error) {
160 _real_munmap(new_addr, length);
161 return read_error;
164 *out_addr = new_addr;
165 return 0;
168 Error Node::Tcflush(int queue_selector) {
169 return EINVAL;
172 Error Node::Tcgetattr(struct termios* termios_p) {
173 return EINVAL;
176 Error Node::Tcsetattr(int optional_actions, const struct termios* termios_p) {
177 return EINVAL;
180 Error Node::Futimens(const struct timespec times[2]) {
181 return 0;
184 Error Node::Fchmod(mode_t mode) {
185 return EINVAL;
188 int Node::GetLinks() {
189 return stat_.st_nlink;
192 int Node::GetMode() {
193 return stat_.st_mode & S_MODEBITS;
196 Error Node::GetSize(off_t* out_size) {
197 *out_size = stat_.st_size;
198 return 0;
201 int Node::GetType() {
202 return stat_.st_mode & S_IFMT;
205 void Node::SetType(int type) {
206 assert((type & ~S_IFMT) == 0);
207 stat_.st_mode &= ~S_IFMT;
208 stat_.st_mode |= type;
211 void Node::SetMode(int mode) {
212 assert((mode & ~S_MODEBITS) == 0);
213 stat_.st_mode &= ~S_MODEBITS;
214 stat_.st_mode |= mode;
217 bool Node::IsaDir() {
218 return GetType() == S_IFDIR;
221 bool Node::IsaFile() {
222 return GetType() == S_IFREG;
225 bool Node::IsaSock() {
226 return GetType() == S_IFSOCK;
229 bool Node::IsSeekable() {
230 return !(IsaSock() || GetType() == S_IFIFO);
233 Error Node::Isatty() {
234 return ENOTTY;
237 Error Node::AddChild(const std::string& name, const ScopedNode& node) {
238 return ENOTDIR;
241 Error Node::RemoveChild(const std::string& name) {
242 return ENOTDIR;
245 Error Node::FindChild(const std::string& name, ScopedNode* out_node) {
246 out_node->reset(NULL);
247 return ENOTDIR;
250 int Node::ChildCount() {
251 return 0;
254 void Node::Link() {
255 stat_.st_nlink++;
258 void Node::Unlink() {
259 stat_.st_nlink--;
262 void Node::UpdateTime(int update_bits) {
263 struct timeval now;
264 gettimeofday(&now, NULL);
266 // TODO(binji): honor noatime mount option?
267 if (update_bits & UPDATE_ATIME) {
268 stat_.st_atime = now.tv_sec;
269 stat_.st_atimensec = now.tv_usec * 1000;
271 if (update_bits & UPDATE_MTIME) {
272 stat_.st_mtime = now.tv_sec;
273 stat_.st_mtimensec = now.tv_usec * 1000;
275 if (update_bits & UPDATE_CTIME) {
276 stat_.st_ctime = now.tv_sec;
277 stat_.st_ctimensec = now.tv_usec * 1000;
281 } // namespace nacl_io