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
Node(Filesystem * filesystem)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
~Node()42 Node::~Node() {
43 }
44
Init(int open_flags)45 Error Node::Init(int open_flags) {
46 return 0;
47 }
48
Destroy()49 void Node::Destroy() {
50 if (filesystem_) {
51 filesystem_->OnNodeDestroyed(this);
52 }
53 }
54
GetEventEmitter()55 EventEmitter* Node::GetEventEmitter() {
56 return NULL;
57 }
58
GetEventStatus()59 uint32_t Node::GetEventStatus() {
60 if (GetEventEmitter())
61 return GetEventEmitter()->GetEventStatus();
62
63 return POLLIN | POLLOUT;
64 }
65
CanOpen(int open_flags)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
FSync()79 Error Node::FSync() {
80 return 0;
81 }
82
FTruncate(off_t length)83 Error Node::FTruncate(off_t length) {
84 return EINVAL;
85 }
86
GetDents(size_t offs,struct dirent * pdir,size_t count,int * out_bytes)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
GetStat(struct stat * pstat)95 Error Node::GetStat(struct stat* pstat) {
96 AUTO_LOCK(node_lock_);
97 memcpy(pstat, &stat_, sizeof(stat_));
98 return 0;
99 }
100
Ioctl(int request,...)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
VIoctl(int request,va_list args)109 Error Node::VIoctl(int request, va_list args) {
110 return EINVAL;
111 }
112
Read(const HandleAttr & attr,void * buf,size_t count,int * out_bytes)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
Write(const HandleAttr & attr,const void * buf,size_t count,int * out_bytes)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
MMap(void * addr,size_t length,int prot,int flags,size_t offset,void ** out_addr)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
Tcflush(int queue_selector)167 Error Node::Tcflush(int queue_selector) {
168 return EINVAL;
169 }
170
Tcgetattr(struct termios * termios_p)171 Error Node::Tcgetattr(struct termios* termios_p) {
172 return EINVAL;
173 }
174
Tcsetattr(int optional_actions,const struct termios * termios_p)175 Error Node::Tcsetattr(int optional_actions, const struct termios* termios_p) {
176 return EINVAL;
177 }
178
GetLinks()179 int Node::GetLinks() {
180 return stat_.st_nlink;
181 }
182
GetMode()183 int Node::GetMode() {
184 return stat_.st_mode & ~S_IFMT;
185 }
186
GetSize(off_t * out_size)187 Error Node::GetSize(off_t* out_size) {
188 *out_size = stat_.st_size;
189 return 0;
190 }
191
GetType()192 int Node::GetType() {
193 return stat_.st_mode & S_IFMT;
194 }
195
SetType(int type)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
IsaDir()202 bool Node::IsaDir() {
203 return GetType() == S_IFDIR;
204 }
205
IsaFile()206 bool Node::IsaFile() {
207 return GetType() == S_IFREG;
208 }
209
IsaSock()210 bool Node::IsaSock() {
211 return GetType() == S_IFSOCK;
212 }
213
Isatty()214 Error Node::Isatty() {
215 return ENOTTY;
216 }
217
AddChild(const std::string & name,const ScopedNode & node)218 Error Node::AddChild(const std::string& name, const ScopedNode& node) {
219 return ENOTDIR;
220 }
221
RemoveChild(const std::string & name)222 Error Node::RemoveChild(const std::string& name) {
223 return ENOTDIR;
224 }
225
FindChild(const std::string & name,ScopedNode * out_node)226 Error Node::FindChild(const std::string& name, ScopedNode* out_node) {
227 out_node->reset(NULL);
228 return ENOTDIR;
229 }
230
ChildCount()231 int Node::ChildCount() {
232 return 0;
233 }
234
Link()235 void Node::Link() {
236 stat_.st_nlink++;
237 }
238
Unlink()239 void Node::Unlink() {
240 stat_.st_nlink--;
241 }
242
243 } // namespace nacl_io
244