This source file includes following definitions.
- Init
- FindNode
- Access
- Open
- Mkdir
- Unlink
- Rmdir
- Remove
- Rename
- RemoveInternal
#include "nacl_io/memfs/mem_fs.h"
#include <errno.h>
#include <fcntl.h>
#include <string>
#include "nacl_io/dir_node.h"
#include "nacl_io/filesystem.h"
#include "nacl_io/memfs/mem_fs_node.h"
#include "nacl_io/node.h"
#include "nacl_io/osstat.h"
#include "nacl_io/osunistd.h"
#include "nacl_io/path.h"
#include "sdk_util/auto_lock.h"
#include "sdk_util/ref_object.h"
namespace nacl_io {
MemFs::MemFs() : root_(NULL) {}
Error MemFs::Init(const FsInitArgs& args) {
Error error = Filesystem::Init(args);
if (error)
return error;
root_.reset(new DirNode(this));
error = root_->Init(0);
if (error) {
root_.reset(NULL);
return error;
}
return 0;
}
Error MemFs::FindNode(const Path& path, int type, ScopedNode* out_node) {
out_node->reset(NULL);
ScopedNode node = root_;
if (node == NULL)
return ENOTDIR;
if (!path.IsAbsolute())
return EINVAL;
for (size_t index = 1; node && index < path.Size(); index++) {
if (!node->IsaDir())
return ENOTDIR;
Error error = node->FindChild(path.Part(index), &node);
if (error)
return error;
}
if ((type & S_IFDIR) && !node->IsaDir())
return ENOTDIR;
if ((type & S_IFREG) && node->IsaDir())
return EISDIR;
*out_node = node;
return 0;
}
Error MemFs::Access(const Path& path, int a_mode) {
ScopedNode node;
Error error = FindNode(path, 0, &node);
if (error)
return error;
int obj_mode = node->GetMode();
if (((a_mode & R_OK) && !(obj_mode & S_IREAD)) ||
((a_mode & W_OK) && !(obj_mode & S_IWRITE)) ||
((a_mode & X_OK) && !(obj_mode & S_IEXEC))) {
return EACCES;
}
return 0;
}
Error MemFs::Open(const Path& path, int open_flags, ScopedNode* out_node) {
out_node->reset(NULL);
ScopedNode node;
Error error = FindNode(path, 0, &node);
if (error) {
if ((open_flags & O_CREAT) == 0)
return ENOENT;
ScopedNode parent;
error = FindNode(path.Parent(), S_IFDIR, &parent);
if (error)
return error;
node.reset(new MemFsNode(this));
error = node->Init(open_flags);
if (error)
return error;
error = parent->AddChild(path.Basename(), node);
if (error)
return error;
} else {
if (node->IsaDir() && (open_flags & 3) != O_RDONLY)
return EISDIR;
if (open_flags & O_EXCL)
return EEXIST;
if (open_flags & O_TRUNC)
static_cast<MemFsNode*>(node.get())->Resize(0);
}
*out_node = node;
return 0;
}
Error MemFs::Mkdir(const Path& path, int mode) {
if (!path.IsAbsolute())
return ENOENT;
if (path.Size() == 1)
return EEXIST;
ScopedNode parent;
int error = FindNode(path.Parent(), S_IFDIR, &parent);
if (error)
return error;
ScopedNode node;
error = parent->FindChild(path.Basename(), &node);
if (!error)
return EEXIST;
if (error != ENOENT)
return error;
node.reset(new DirNode(this));
error = node->Init(0);
if (error)
return error;
return parent->AddChild(path.Basename(), node);
}
Error MemFs::Unlink(const Path& path) {
return RemoveInternal(path, REMOVE_FILE);
}
Error MemFs::Rmdir(const Path& path) {
return RemoveInternal(path, REMOVE_DIR);
}
Error MemFs::Remove(const Path& path) {
return RemoveInternal(path, REMOVE_ALL);
}
Error MemFs::Rename(const Path& src_path, const Path& target_path) {
ScopedNode src_node;
ScopedNode src_parent;
ScopedNode target_node;
ScopedNode target_parent;
int error = FindNode(src_path, 0, &src_node);
if (error)
return error;
error = FindNode(src_path.Parent(), S_IFDIR, &src_parent);
if (error)
return error;
error = FindNode(target_path.Parent(), 0, &target_parent);
if (error)
return error;
std::string target_name = target_path.Basename();
error = FindNode(target_path, 0, &target_node);
bool replacing_target = error == 0;
if (replacing_target) {
if (target_node->IsaDir()) {
if (target_node->ChildCount()) {
return ENOTEMPTY;
}
if (src_node->IsaDir()) {
RemoveInternal(target_path, REMOVE_ALL);
} else {
target_name = src_path.Basename();
target_parent = target_node;
}
} else {
if (src_node->IsaDir())
return EISDIR;
target_parent->RemoveChild(target_path.Basename());
}
}
error = src_parent->RemoveChild(src_path.Basename());
if (error)
return error;
error = target_parent->AddChild(target_name, src_node);
if (error) {
if (replacing_target)
target_parent->AddChild(target_path.Basename(), target_node);
target_parent->AddChild(target_path.Basename(), src_node);
return error;
}
return 0;
}
Error MemFs::RemoveInternal(const Path& path, int remove_type) {
bool dir_only = remove_type == REMOVE_DIR;
bool file_only = remove_type == REMOVE_FILE;
bool remove_dir = (remove_type & REMOVE_DIR) != 0;
if (dir_only) {
if (!path.IsAbsolute())
return ENOENT;
if (path.Size() == 1)
return EEXIST;
}
ScopedNode parent;
int error = FindNode(path.Parent(), S_IFDIR, &parent);
if (error)
return error;
ScopedNode child;
error = parent->FindChild(path.Basename(), &child);
if (error)
return error;
if (dir_only && !child->IsaDir())
return ENOTDIR;
if (file_only && child->IsaDir())
return EISDIR;
if (remove_dir && child->ChildCount() > 0)
return ENOTEMPTY;
return parent->RemoveChild(path.Basename());
}
}