| Index: native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc
|
| ===================================================================
|
| --- native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc (revision 134714)
|
| +++ native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc (working copy)
|
| @@ -2,290 +2,290 @@
|
| * Use of this source code is governed by a BSD-style license that can be
|
| * found in the LICENSE file.
|
| */
|
| -
|
| -#include <assert.h>
|
| #include <dirent.h>
|
| #include <errno.h>
|
| #include <fcntl.h>
|
| #include <sys/stat.h>
|
| #include <string>
|
|
|
| -#include <vector>
|
| -
|
| +#include "mount.h"
|
| #include "mount_mem.h"
|
| +#include "mount_node.h"
|
| +#include "mount_node_dir.h"
|
| +#include "mount_node_mem.h"
|
| #include "path.h"
|
| -#include "util/simple_auto_lock.h"
|
|
|
| -static const size_t s_blksize = 1024;
|
| +#include "auto_lock.h"
|
| +#include "ref_object.h"
|
|
|
| -class MountNodeMem {
|
| - public:
|
| - MountNodeMem(int ino) {
|
| - ino_ = ino;
|
| - ref_count_ = 0;
|
| - data_ = NULL;
|
| - memset(&stat_, 0, sizeof(stat_));
|
| - Resize(s_blksize);
|
| - };
|
| +// TODO(noelallen) : Grab/Redefine these in the kernel object once available.
|
| +#define USR_ID 1002
|
| +#define GRP_ID 1003
|
|
|
| - size_t Size() const {
|
| - return stat_.st_size;
|
| - }
|
| +MountMem::MountMem()
|
| + : MountFactory(),
|
| + root_(NULL),
|
| + max_ino_(0) {
|
| +}
|
|
|
| - void Resize(size_t size) {
|
| - size_t cap = blocks_;
|
| - size_t req = (size + s_blksize - 1) / s_blksize;
|
| +bool MountMem::Init(int dev, StringMap_t& args) {
|
| + dev_ = dev;
|
| + root_ = AllocatePath(_S_IREAD | _S_IWRITE);
|
| + return (bool) (root_ != NULL);
|
| +}
|
|
|
| - if ((req > cap) || (req < (cap / 2))) {
|
| - char *newdata = (char *) malloc(req * s_blksize);
|
| - memcpy(newdata, data_, size);
|
| - free(data_);
|
| - stat_.st_size = size;
|
| - data_ = newdata;
|
| - blocks_ = req;
|
| - }
|
| - }
|
| +void MountMem::Destroy() {
|
| + if (root_)
|
| + root_->Release();
|
| + root_ = NULL;
|
| +}
|
|
|
| - int ino_;
|
| - int ref_count_;
|
| - struct stat stat_;
|
| - void *data_;
|
| - size_t blocks_;
|
| - pthread_mutex_t lock_;
|
| -};
|
| +MountNode* MountMem::AllocatePath(int mode) {
|
| + ino_t ino = AllocateINO();
|
|
|
| -MountMem::MountMem() {}
|
| -MountMem::~MountMem() {}
|
| -
|
| -int MountMem::AddDirEntry(MountMemNode* dir_node, MountMemNode* obj_node, const char *name) {
|
| - if (strlen(name > 255)) {
|
| - errno = EINVAL;
|
| - return -1;
|
| + MountNode *ptr = new MountNodeDir(this, ino, dev_);
|
| + if (!ptr->Init(mode, 1002, 1003)) {
|
| + ptr->Release();
|
| + FreeINO(ino);
|
| + return NULL;
|
| }
|
| + return ptr;
|
| +}
|
|
|
| - struct dirent* d = (struct dirent *) dir_node->data_;
|
| - size_t cnt = dir_node->Size() / sizeof(struct dirent);
|
| - size_t off;
|
| +MountNode* MountMem::AllocateData(int mode) {
|
| + ino_t ino = AllocateINO();
|
|
|
| - // Find a free location
|
| - for (off = 0; off < cnt; off++) {
|
| - if (d->d_name[0] == 0) break;
|
| - d++;
|
| + MountNode* ptr = new MountNodeMem(this, ino, dev_);
|
| + if (!ptr->Init(mode, USR_ID, GRP_ID)) {
|
| + ptr->Release();
|
| + FreeINO(ino);
|
| + return NULL;
|
| }
|
| + return ptr;
|
| +}
|
|
|
| - // Otherwise regrow and take the last spot.
|
| - if (off == cnt) {
|
| - dir_node->Resize(dir_node->Size() + sizeof(struct dirent));
|
| - d = &((struct dirent *) dir_node->data_)[off];
|
| - }
|
| -
|
| - strcpy(d->d_name, name);
|
| - d->d_ino = obj_node->ino_;
|
| - d->d_reclen = sizeof(dirent);
|
| - d->d_off = off * sizeof(dirent);
|
| -
|
| - // Add a ref_count_ and link count for the directory
|
| - obj_node->Acquire();
|
| - obj_node->stat_.st_nlink++;
|
| - return 0;
|
| +void MountMem::ReleaseNode(MountNode* node) {
|
| + node->Release();
|
| }
|
|
|
| +int MountMem::AllocateINO() {
|
| + const int INO_CNT = 8;
|
|
|
| -
|
| -
|
| -int MountMem::DelDirEntry_locked(int dir_ino, const char *name) {
|
| - MountMemNode* dir_node = inodes_.At(dir_ino);
|
| - struct dirent* d = (struct dirent *) dir_node->data_;
|
| - size_t cnt = dir_node->Size() / sizeof(struct dirent);
|
| - size_t off = 0;
|
| -
|
| - // Find a free location
|
| - for (off = 0; off < cnt; off++) {
|
| - if (!strcmp(d->d_name, name)) {
|
| - d->d_name[0] = 0;
|
| - obj_node->stat_.st_nlink--;
|
| - if (0 == --obj_node->ref_count_) FreeNode(obj_node->ino_);
|
| - dir_node->ref_count_--;
|
| - return 0;
|
| + // If we run out of INO numbers, then allocate 8 more
|
| + if (inos_.size() == 0) {
|
| + max_ino_ += INO_CNT;
|
| + // Add eight more to the stack in reverse order, offset by 1
|
| + // since '0' refers to no INO.
|
| + for (int a = 0; a < INO_CNT; a++) {
|
| + inos_.push_back((max_ino_ - a) + 1);
|
| }
|
| }
|
|
|
| - errno = ENOENT;
|
| - return -1;
|
| + // Return the INO at the top of the stack.
|
| + int val = inos_.back();
|
| + inos_.pop_back();
|
| + return val;
|
| }
|
|
|
| -MountNodeMem* MountMem::AcquireNode(int ino) {
|
| - SimpleAutoLock lock(&lock_);
|
| - MountNodeMem *node = inodes_.At(ino);
|
| - if (node) node->ref_count_++;
|
| - return node;
|
| +void MountMem::FreeINO(int ino) {
|
| + inos_.push_back(ino);
|
| }
|
|
|
| -void MountMem::ReleaseNode(MountMemNode* node) {
|
| - if (node) {
|
| - SimpleAutoLock lock(&lock_);
|
| - if (--node->ref_count_) inodes_.Free(node->ino_);
|
| +MountNode* MountMem::FindNode(const Path& path, int type) {
|
| + MountNode* node = root_;
|
| +
|
| + // If there is no root there, we have an error.
|
| + if (node == NULL) {
|
| + errno = ENOTDIR;
|
| + return NULL;
|
| }
|
| -}
|
|
|
| -void MountMem::Init(void) {
|
| - int root = inodes_.Alloc();
|
| + // We are expecting an "absolute" path from this mount point.
|
| + if (!path.IsAbsolute()) {
|
| + errno = EINVAL;
|
| + return NULL;
|
| + }
|
|
|
| - assert(root == 0);
|
| - AddDirEntry(root, root, "/");
|
| -}
|
| + // Starting at the root, traverse the path parts.
|
| + for (size_t index = 1; node && index < path.Size(); index++) {
|
| + // If not a directory, then we have an error so return.
|
| + if (!node->IsaDir()) {
|
| + errno = ENOTDIR;
|
| + return NULL;
|
| + }
|
|
|
| -int MountMem::Mkdir(const std::string& path, mode_t mode, struct stat *buf) {
|
| - SimpleAutoLock lock(&lock_);
|
| + // Find the child node
|
| + node = node->FindChild(path.Part(index));
|
| + }
|
|
|
| - int ino = AcquireNode(path);
|
| + // node should be root, a found child, or a failed 'FindChild'
|
| + // which already has the correct errno set.
|
| + if (NULL == node) return NULL;
|
|
|
| - // Make sure it doesn't already exist.
|
| - child = GetMemNode(path);
|
| - if (child) {
|
| - errno = EEXIST;
|
| - return -1;
|
| - }
|
| - // Get the parent node.
|
| - int parent_slot = GetParentSlot(path);
|
| - if (parent_slot == -1) {
|
| - errno = ENOENT;
|
| - return -1;
|
| - }
|
| - parent = slots_.At(parent_slot);
|
| - if (!parent->is_dir()) {
|
| + // If a directory is expected, but it's not a directory, then fail.
|
| + if ((type & _S_IFDIR) && !node->IsaDir()) {
|
| errno = ENOTDIR;
|
| - return -1;
|
| + return NULL;
|
| }
|
|
|
| - // Create a new node
|
| - int slot = slots_.Alloc();
|
| - child = slots_.At(slot);
|
| - child->set_slot(slot);
|
| - child->set_mount(this);
|
| - child->set_is_dir(true);
|
| - Path p(path);
|
| - child->set_name(p.Last());
|
| - child->set_parent(parent_slot);
|
| - parent->AddChild(slot);
|
| - if (!buf) {
|
| - return 0;
|
| + // If a file is expected, but it's not a file, then fail.
|
| + if ((type & _S_IFREG) && node->IsaDir()) {
|
| + errno = EISDIR;
|
| + return NULL;
|
| }
|
|
|
| - return Stat(slot, buf);
|
| + // We now have a valid object of the expected type, so return it.
|
| + return node;
|
| }
|
|
|
| -int MountMem::Rmdir(int node) {
|
| -}
|
| +MountNode* MountMem::Open(const Path& path, int mode) {
|
| + AutoLock lock(&lock_);
|
| + MountNode* node = FindNode(path);
|
|
|
| -int MountMem::Chmod(int ino, int mode) {
|
| - MountMemNode* node = AcquireNode(ino);
|
| -
|
| if (NULL == node) {
|
| - errno = BADF;
|
| - return -1;
|
| - }
|
| + // Now first find the parent directory to see if we can add it
|
| + MountNode* parent = FindNode(path.Parent(), _S_IFDIR);
|
| + if (NULL == parent) return NULL;
|
|
|
| - node->stat_.st_mode = mode;
|
| - ReleaseNode(node);
|
| - return 0;
|
| -}
|
| + // If the node does not exist and we can't create it, fail
|
| + if ((mode & O_CREAT) == 0) return NULL;
|
|
|
| -int MountMem::Stat(int ino, struct stat *buf) {
|
| - MountMemNode* node = AcquireNode(ino);
|
| + // Otherwise, create it with a single refernece
|
| + mode = OpenModeToPermission(mode);
|
| + node = AllocateData(mode);
|
| + if (NULL == node) return NULL;
|
|
|
| - if (NULL == node) {
|
| - errno = BADF;
|
| - return -1;
|
| + if (parent->AddChild(path.Filename(), node) == -1) {
|
| + // Or if it fails, release it
|
| + node->Release();
|
| + return NULL;
|
| + }
|
| + return node;
|
| }
|
|
|
| - memcpy(buf, node->stat_, sizeof(struct stat));
|
| + // If we were expected to create it exclusively, fail
|
| + if (mode & O_EXCL) {
|
| + errno = EEXIST;
|
| + return NULL;
|
| + }
|
| +
|
| + // Verify we got the requested permisions.
|
| + int req_mode = OpenModeToPermission(mode);
|
| + int obj_mode = node->GetMode() & OpenModeToPermission(O_RDWR);
|
| + if ((obj_mode & req_mode) != req_mode) {
|
| + errno = EACCES;
|
| + return NULL;
|
| + }
|
| +
|
| + // We opened it, so ref count it before passing it back.
|
| + node->Acquire();
|
| + return node;
|
| +}
|
| +
|
| +int MountMem::Close(MountNode* node) {
|
| + AutoLock lock(&lock_);
|
| + node->Close();
|
| ReleaseNode(node);
|
| return 0;
|
| }
|
|
|
| -int MountMem::Fsync(int ino) {
|
| - // Acquire the node in case he node
|
| - MountMemNode* node = AcquireNode(ino);
|
| - if (node) {
|
| - ReleaseNode(node);
|
| - return 0
|
| - }
|
| +int MountMem::Unlink(const Path& path) {
|
| + AutoLock lock(&lock_);
|
| + MountNode* parent = FindNode(path.Parent(), _S_IFDIR);
|
|
|
| - errno = BADF;
|
| - return -1;
|
| -}
|
| + if (NULL == parent) return -1;
|
|
|
| -int MountMem::Getdents(int ino, off_t offset, struct dirent *dirp, unsigned int count) {
|
| - MountMemNode* node = AcquireNode(ino);
|
| - if ((NULL == node) == 0) {
|
| - errno = EBADF;
|
| + MountNode* child = parent->FindChild(path.Filename());
|
| + if (NULL == child) {
|
| + errno = ENOENT;
|
| return -1;
|
| }
|
| + if (child->IsaDir()) {
|
| + errno = EISDIR;
|
| + return -1;
|
| + }
|
| + return parent->RemoveChild(path.Filename());
|
| +}
|
|
|
| - if ((node->stat_.st_mode & S_IFDIR) == 0) {
|
| - errno =ENOTDIR;
|
| +int MountMem::Mkdir(const Path& path, int mode) {
|
| + AutoLock lock(&lock_);
|
| +
|
| + // We expect a Mount "absolute" path
|
| + if (!path.IsAbsolute()) {
|
| + errno = ENOENT;
|
| return -1;
|
| }
|
|
|
| - if (offset + count > node->Size()) {
|
| - count = node->Size() - offset;
|
| + // The root of the mount is already created by the mount
|
| + if (path.Size() == 1) {
|
| + errno = EEXIST;
|
| + return -1;
|
| }
|
|
|
| - memcpy(dirp, &node->data_[offset], count);
|
| - return count;
|
| -}
|
| + MountNode* parent = FindNode(path.Parent(), _S_IFDIR);
|
| + MountNode* node;
|
|
|
| -ssize_t MountMem::Write(int ino, off_t offset, const void *buf, size_t count) {
|
| - MountMemNode* node = AcquireNode(ino);
|
| + // If we failed to find the parent, the error code is already set.
|
| + if (NULL == parent) return -1;
|
|
|
| - if (NULL == node || (node->stat_.st_mode & S_IWUSER) == 0) {
|
| - errno = EBADF;
|
| + node = parent->FindChild(path.Filename());
|
| + if (NULL != node) {
|
| + errno = EEXIST;
|
| return -1;
|
| }
|
|
|
| - if (offset + count > node->Size()) {
|
| - int err = node->Resize();
|
| - if (err) {
|
| - errno = err;
|
| - ReleaseNode(node);
|
| - return -1;
|
| - }
|
| + // Otherwise, create a new node and attempt to add it
|
| + mode = OpenModeToPermission(mode);
|
| +
|
| + // Allocate a node, with a RefCount of 1. If added to the parent
|
| + // it will get ref counted again. In either case, release the
|
| + // recount we have on exit.
|
| + node = AllocatePath(_S_IREAD | _S_IWRITE);
|
| + if (NULL == node) return -1;
|
| +
|
| + if (parent->AddChild(path.Filename(), node) == -1) {
|
| + node->Release();
|
| + return -1;
|
| }
|
|
|
| - mempcy(&node->data_[offset], buf, count);
|
| - ReleaseNode(node);
|
| - return count;
|
| + node->Release();
|
| + return 0;
|
| }
|
|
|
| -ssize_t MountMem::Read(int ino, off_t offset, const void *buf, size_t count) {
|
| - MountMemNode* node = AcquireNode(ino);
|
| +int MountMem::Rmdir(const Path& path) {
|
| + AutoLock lock(&lock_);
|
|
|
| - if (NULL == node || (node->stat_.st_mode & S_IRUSER) == 0) {
|
| - errno = EBADF;
|
| + // We expect a Mount "absolute" path
|
| + if (!path.IsAbsolute()) {
|
| + errno = ENOENT;
|
| return -1;
|
| }
|
|
|
| - if (offset + count > node->Size()) {
|
| - count = node->Size() - offset;
|
| + // The root of the mount is already created by the mount
|
| + if (path.Size() == 1) {
|
| + errno = EEXIST;
|
| + return -1;
|
| }
|
|
|
| - mempcy(buf, &node->data_[offset], count);
|
| - ReleaseNode(node);
|
| - return count;
|
| -}
|
| + MountNode* parent = FindNode(path.Parent(), _S_IFDIR);
|
| + MountNode* node;
|
|
|
| -int MountMem::Isatty(int ino) {
|
| - // Acquire the node in case he node array is in flux
|
| - MountMemNode* node = AcquireNode(ino);
|
| + // If we failed to find the parent, the error code is already set.
|
| + if (NULL == parent) return -1;
|
|
|
| - if (node) {
|
| - errno = ENOTTY;
|
| - ReleaseNode(node);
|
| + // Verify we find a child which is also a directory
|
| + node = parent->FindChild(path.Filename());
|
| + if (NULL == node) {
|
| + errno = ENOENT;
|
| + return -1;
|
| }
|
| - else {
|
| - errno = BADF;
|
| + if (!node->IsaDir()) {
|
| + errno = ENOTDIR;
|
| + return -1;
|
| }
|
| - return 0;
|
| + if (node->ChildCount() > 0) {
|
| + errno = ENOTEMPTY;
|
| + return -1;
|
| + }
|
| + return parent->RemoveChild(path.Filename());
|
| }
|
| -
|
|
|