blob: d1d034d07f9f41c877b179dfcc28054f2533cbb9 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "nacl_io/mount_node.h"
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <algorithm>
#include <string>
#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/mount.h"
#include "nacl_io/osmman.h"
#include "sdk_util/auto_lock.h"
namespace nacl_io {
static const int USR_ID = 1001;
static const int GRP_ID = 1002;
MountNode::MountNode(Mount* mount) : mount_(mount) {
memset(&stat_, 0, sizeof(stat_));
stat_.st_gid = GRP_ID;
stat_.st_uid = USR_ID;
// Mount should normally never be NULL, but may be null in tests.
// If NULL, at least set the inode to a valid (nonzero) value.
if (mount_)
mount_->OnNodeCreated(this);
else
stat_.st_ino = 1;
}
MountNode::~MountNode() {}
Error MountNode::Init(int perm) {
stat_.st_mode |= perm;
return 0;
}
void MountNode::Destroy() {
if (mount_) {
mount_->OnNodeDestroyed(this);
}
}
Error MountNode::FSync() { return 0; }
Error MountNode::FTruncate(off_t length) { return EINVAL; }
Error MountNode::GetDents(size_t offs,
struct dirent* pdir,
size_t count,
int* out_bytes) {
*out_bytes = 0;
return ENOTDIR;
}
Error MountNode::GetStat(struct stat* pstat) {
AUTO_LOCK(node_lock_);
memcpy(pstat, &stat_, sizeof(stat_));
return 0;
}
Error MountNode::Ioctl(int request, char* arg) { return EINVAL; }
Error MountNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
*out_bytes = 0;
return EINVAL;
}
Error MountNode::Write(size_t offs,
const void* buf,
size_t count,
int* out_bytes) {
*out_bytes = 0;
return EINVAL;
}
Error MountNode::MMap(void* addr,
size_t length,
int prot,
int flags,
size_t offset,
void** out_addr) {
*out_addr = NULL;
// Never allow mmap'ing PROT_EXEC. The passthrough node supports this, but we
// don't. Fortunately, glibc will fallback if this fails, so dlopen will
// continue to work.
if (prot & PROT_EXEC)
return EPERM;
// This default mmap support is just enough to make dlopen work.
// This implementation just reads from the mount into the mmap'd memory area.
void* new_addr = addr;
int mmap_error = _real_mmap(
&new_addr, length, prot | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
if (new_addr == MAP_FAILED) {
_real_munmap(new_addr, length);
return mmap_error;
}
int bytes_read;
Error read_error = Read(offset, new_addr, length, &bytes_read);
if (read_error) {
_real_munmap(new_addr, length);
return read_error;
}
*out_addr = new_addr;
return 0;
}
int MountNode::GetLinks() { return stat_.st_nlink; }
int MountNode::GetMode() { return stat_.st_mode & ~S_IFMT; }
Error MountNode::GetSize(size_t* out_size) {
*out_size = stat_.st_size;
return 0;
}
int MountNode::GetType() { return stat_.st_mode & S_IFMT; }
bool MountNode::IsaDir() { return (stat_.st_mode & S_IFDIR) != 0; }
bool MountNode::IsaFile() { return (stat_.st_mode & S_IFREG) != 0; }
bool MountNode::IsaTTY() { return (stat_.st_mode & S_IFCHR) != 0; }
Error MountNode::AddChild(const std::string& name,
const ScopedMountNode& node) {
return ENOTDIR;
}
Error MountNode::RemoveChild(const std::string& name) { return ENOTDIR; }
Error MountNode::FindChild(const std::string& name, ScopedMountNode* out_node) {
out_node->reset(NULL);
return ENOTDIR;
}
int MountNode::ChildCount() { return 0; }
void MountNode::Link() { stat_.st_nlink++; }
void MountNode::Unlink() { stat_.st_nlink--; }
} // namespace nacl_io