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"
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"
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.
38 filesystem_
->OnNodeCreated(this);
46 Error
Node::Init(int open_flags
) {
50 void Node::Destroy() {
52 filesystem_
->OnNodeDestroyed(this);
56 EventEmitter
* Node::GetEventEmitter() {
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) {
70 return (stat_
.st_mode
& S_IRALL
) != 0;
72 return (stat_
.st_mode
& S_IWALL
) != 0;
74 return (stat_
.st_mode
& S_IRALL
) != 0 && (stat_
.st_mode
& S_IWALL
) != 0;
84 Error
Node::FTruncate(off_t length
) {
88 Error
Node::GetDents(size_t offs
,
96 Error
Node::GetStat(struct stat
* pstat
) {
97 AUTO_LOCK(node_lock_
);
98 memcpy(pstat
, &stat_
, sizeof(stat_
));
102 Error
Node::Ioctl(int request
, ...) {
104 va_start(ap
, request
);
105 Error rtn
= VIoctl(request
, ap
);
110 Error
Node::VIoctl(int request
, va_list args
) {
114 Error
Node::Read(const HandleAttr
& attr
,
122 Error
Node::Write(const HandleAttr
& attr
,
130 Error
Node::MMap(void* addr
,
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
141 if (prot
& PROT_EXEC
)
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
);
158 Error read_error
= Read(data
, new_addr
, length
, &bytes_read
);
160 _real_munmap(new_addr
, length
);
164 *out_addr
= new_addr
;
168 Error
Node::Tcflush(int queue_selector
) {
172 Error
Node::Tcgetattr(struct termios
* termios_p
) {
176 Error
Node::Tcsetattr(int optional_actions
, const struct termios
* termios_p
) {
180 Error
Node::Futimens(const struct timespec times
[2]) {
184 Error
Node::Fchmod(mode_t mode
) {
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
;
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() {
237 Error
Node::AddChild(const std::string
& name
, const ScopedNode
& node
) {
241 Error
Node::RemoveChild(const std::string
& name
) {
245 Error
Node::FindChild(const std::string
& name
, ScopedNode
* out_node
) {
246 out_node
->reset(NULL
);
250 int Node::ChildCount() {
258 void Node::Unlink() {
262 void Node::UpdateTime(int update_bits
) {
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