diff options
author | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-02 23:56:22 +0000 |
---|---|---|
committer | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-02 23:56:22 +0000 |
commit | cc5e89269c92e264c321a43291e0bd85cdb464fe (patch) | |
tree | 102d7e2913a3a6725ed95bf4c3a5c3acc2ee8c76 /native_client_sdk/src/libraries/nacl_mounts | |
parent | 0230169e78cea495e00e8346d52d0acaf5febd59 (diff) | |
download | chromium_src-cc5e89269c92e264c321a43291e0bd85cdb464fe.zip chromium_src-cc5e89269c92e264c321a43291e0bd85cdb464fe.tar.gz chromium_src-cc5e89269c92e264c321a43291e0bd85cdb464fe.tar.bz2 |
Add mount sources for a MountNode (inode)
Split abstact base mount.h and mount_mem.h
Add mount_mem test.
BUG=122229
R=binji@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9956156
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@135033 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk/src/libraries/nacl_mounts')
7 files changed, 264 insertions, 259 deletions
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc index cb797e2..d71a7b0 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc +++ b/native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc @@ -2,290 +2,291 @@ * 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 <unistd.h> -#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; - -class MountNodeMem { - public: - MountNodeMem(int ino) { - ino_ = ino; - ref_count_ = 0; - data_ = NULL; - memset(&stat_, 0, sizeof(stat_)); - Resize(s_blksize); - }; - - size_t Size() const { - return stat_.st_size; - } - void Resize(size_t size) { - size_t cap = blocks_; - size_t req = (size + s_blksize - 1) / s_blksize; - - 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; - } - } +#include "auto_lock.h" +#include "ref_object.h" - int ino_; - int ref_count_; - struct stat stat_; - void *data_; - size_t blocks_; - pthread_mutex_t lock_; -}; +// TODO(noelallen) : Grab/Redefine these in the kernel object once available. +#define USR_ID 1002 +#define GRP_ID 1003 -MountMem::MountMem() {} -MountMem::~MountMem() {} +MountMem::MountMem() + : MountFactory(), + root_(NULL), + max_ino_(0) { +} -int MountMem::AddDirEntry(MountMemNode* dir_node, MountMemNode* obj_node, const char *name) { - if (strlen(name > 255)) { - errno = EINVAL; - return -1; - } +bool MountMem::Init(int dev, StringMap_t& args) { + dev_ = dev; + root_ = AllocatePath(_S_IREAD | _S_IWRITE); + return (bool) (root_ != NULL); +} - struct dirent* d = (struct dirent *) dir_node->data_; - size_t cnt = dir_node->Size() / sizeof(struct dirent); - size_t off; +void MountMem::Destroy() { + if (root_) + root_->Release(); + root_ = NULL; +} - // Find a free location - for (off = 0; off < cnt; off++) { - if (d->d_name[0] == 0) break; - d++; - } +MountNode* MountMem::AllocatePath(int mode) { + ino_t ino = AllocateINO(); - // 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]; + MountNode *ptr = new MountNodeDir(this, ino, dev_); + if (!ptr->Init(mode, 1002, 1003)) { + ptr->Release(); + FreeINO(ino); + return NULL; } - - 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; + return ptr; } +MountNode* MountMem::AllocateData(int mode) { + ino_t ino = AllocateINO(); + MountNode* ptr = new MountNodeMem(this, ino, dev_); + if (!ptr->Init(mode, getuid(), getgid())) { + ptr->Release(); + FreeINO(ino); + return NULL; + } + return ptr; +} +void MountMem::ReleaseNode(MountNode* node) { + node->Release(); +} -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; +int MountMem::AllocateINO() { + const int INO_CNT = 8; - // 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); } } - 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); -} - -int MountMem::Rmdir(int node) { + // We now have a valid object of the expected type, so return it. + return node; } -int MountMem::Chmod(int ino, int mode) { - MountMemNode* node = AcquireNode(ino); +MountNode* MountMem::Open(const Path& path, int mode) { + AutoLock lock(&lock_); + MountNode* node = FindNode(path); 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; + + // If the node does not exist and we can't create it, fail + if ((mode & O_CREAT) == 0) return NULL; + + // Otherwise, create it with a single refernece + mode = OpenModeToPermission(mode); + node = AllocateData(mode); + if (NULL == node) return NULL; + + if (parent->AddChild(path.Filename(), node) == -1) { + // Or if it fails, release it + node->Release(); + return NULL; + } + return node; } - node->stat_.st_mode = mode; - ReleaseNode(node); - return 0; -} - -int MountMem::Stat(int ino, struct stat *buf) { - MountMemNode* node = AcquireNode(ino); + // If we were expected to create it exclusively, fail + if (mode & O_EXCL) { + errno = EEXIST; + return NULL; + } - if (NULL == node) { - errno = BADF; - return -1; + // 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; } - memcpy(buf, node->stat_, sizeof(struct stat)); + // 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()); +} + +int MountMem::Mkdir(const Path& path, int mode) { + AutoLock lock(&lock_); - if ((node->stat_.st_mode & S_IFDIR) == 0) { - errno =ENOTDIR; + // 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; + } + if (!node->IsaDir()) { + errno = ENOTDIR; + return -1; } - else { - errno = BADF; + if (node->ChildCount() > 0) { + errno = ENOTEMPTY; + return -1; } - return 0; + return parent->RemoveChild(path.Filename()); } - diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_mem.h b/native_client_sdk/src/libraries/nacl_mounts/mount_mem.h index dd7ffdd..4340f11 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/mount_mem.h +++ b/native_client_sdk/src/libraries/nacl_mounts/mount_mem.h @@ -9,56 +9,45 @@ #include <map> #include <string> -#include "mount.h" -#include "util/macros.h" -#include "util/SlotAllocator.h" +#include "nacl_mounts/mount.h" -struct dirent; -struct stat; -class MountMemNode; - -// Mount serves as the base mounting class that will be used by -// the mount manager (class MountManager). The mount manager -// relies heavily on the GetNode method as a way of directing -// system calls that take a path as an argument. The methods -// of this class are pure virtual. BaseMount class contains -// stub implementations for these methods. Feel free to use -// BaseMount if your mount does not implement all of these -// operations. -class MountMem : public Mount { +class MountMem : public MountFactory<MountMem, Mount> { protected: MountMem(); - virtual ~MountMem(); - // Init must be called by the factory before - void Init(); + virtual bool Init(int dev, StringMap_t& args); + virtual void Destroy(); - int MountMem::AddDirEntry(MountNode* node, MountNode* node, const char *name); + // The protected functions are only used internally and will not + // acquire or release the mount's lock themselves. The caller is + // returned to use correct locking as needed. + virtual MountNode *AllocateData(int mode); + virtual MountNode *AllocatePath(int mode); + virtual void ReleaseNode(MountNode *node); - public: - // System calls that can be overridden by a mount implementation - virtual int Creat(const std::string& path, int mode, struct stat *st); - virtual int Mkdir(const std::string& path, int mode, struct stat *st); - virtual int Unlink(const std::string& path); + // Allocate or free an INODE number. + int AllocateINO(); + void FreeINO(int ino); - virtual int Rmdir(int node); - virtual int Chmod(int node, int mode); - virtual int Stat(int node, struct stat *buf); - virtual int Fsync(int node); + // Find a Node specified node optionally failing if type does not match. + virtual MountNode* FindNode(const Path& path, int type = 0); + + public: + typedef std::vector<ino_t> INOList_t; - virtual int Getdents(int node, off_t offset, struct dirent *dirp, - unsigned int count); + virtual MountNode *Open(const Path& path, int mode); + virtual int Close(MountNode* node); + virtual int Unlink(const Path& path); + virtual int Mkdir(const Path& path, int perm); + virtual int Rmdir(const Path& path); - virtual ssize_t Read(int node, off_t offset, - void *buf, size_t count); - virtual ssize_t Write(int node, off_t offset, - const void *buf, size_t count); - virtual int Isatty(int node); +private: + MountNode* root_; + INOList_t inos_; + size_t max_ino_; - private: - pthread_mutex_t lock_; - SlotAllocator<MountMemNode> inodes_; + template <class M, class P> friend class MountFactory; DISALLOW_COPY_AND_ASSIGN(MountMem); }; diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_node.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_node.cc index 1aeacd1..1012604 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/mount_node.cc +++ b/native_client_sdk/src/libraries/nacl_mounts/mount_node.cc @@ -13,8 +13,8 @@ #include "mount.h" #include "mount_node.h" -MountNode::MountNode(Mount* mount, int ino, int dev) : - mount_(mount) { +MountNode::MountNode(Mount* mount, int ino, int dev) + : mount_(mount) { memset(&stat_, 0, sizeof(stat_)); stat_.st_ino = ino; stat_.st_dev = dev; @@ -23,16 +23,16 @@ MountNode::MountNode(Mount* mount, int ino, int dev) : MountNode::~MountNode() { } -bool MountNode::Init(int mode, short gid, short uid) { +bool MountNode::Init(int mode, short uid, short gid) { stat_.st_mode = mode; stat_.st_gid = gid; stat_.st_uid = uid; return true; } -void MountNode::Destroy() { +int MountNode::Close() { FSync(); - mount_->FreeNode(this); + return 0; } int MountNode::FSync() { @@ -113,6 +113,11 @@ MountNode* MountNode::FindChild(const std::string& name) { return NULL; } +int MountNode::ChildCount() { + errno = ENOTDIR; + return -1; +} + void MountNode::Link() { Acquire(); stat_.st_nlink++; diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_node.h b/native_client_sdk/src/libraries/nacl_mounts/mount_node.h index dbe6c57..be28427 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/mount_node.h +++ b/native_client_sdk/src/libraries/nacl_mounts/mount_node.h @@ -23,7 +23,7 @@ class MountNode : public RefObject { protected: MountNode(Mount* mount, int ino, int dev); virtual bool Init(int mode, short uid, short gid); - virtual void Destroy(); + virtual int Close(); public: // Normal OS operations on a node (file), can be called by the kernel @@ -55,6 +55,7 @@ protected: // Find a child and return it without updating the refcount virtual MountNode* FindChild(const std::string& name); + virtual int ChildCount(); // Update the link count virtual void Link(); @@ -64,7 +65,8 @@ protected: struct stat stat_; Mount* mount_; - friend class Mount; + friend class MountHFS; + friend class MountMem; friend class MountNodeDir; }; diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.cc index 2e43977..6c1109c 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.cc +++ b/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.cc @@ -3,15 +3,17 @@ * found in the LICENSE file. */ +#include <dirent.h> #include <errno.h> #include <sys/stat.h> +#include "macros.h" #include "auto_lock.h" #include "mount_node_dir.h" -MountNodeDir::MountNodeDir(Mount* mount, int ino, int dev) : - MountNode(mount, ino, dev), - cache_(NULL) { +MountNodeDir::MountNodeDir(Mount* mount, int ino, int dev) + : MountNode(mount, ino, dev), + cache_(NULL) { } MountNodeDir::~MountNodeDir() { @@ -73,7 +75,6 @@ int MountNodeDir:: AddChild(const std::string& name, MountNode* node) { errno = ENOENT; return -1; } - if (name.length() >= MEMBER_SIZE(struct dirent, d_name)) { errno = ENAMETOOLONG; return -1; @@ -114,6 +115,11 @@ MountNode* MountNodeDir::FindChild(const std::string& name) { return NULL; } +int MountNodeDir::ChildCount() { + AutoLock lock(&lock_); + return map_.size(); +} + void MountNodeDir::ClearCache() { free(cache_); cache_ = NULL; diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.h b/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.h index 36840b0..a2c2e0e 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.h +++ b/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.h @@ -12,7 +12,7 @@ #include <string> #include <vector> -#include "mount_node.h" +#include "nacl_mounts/mount_node.h" class MountNodeDir : public MountNode { @@ -32,7 +32,8 @@ class MountNodeDir : public MountNode { // Adds a finds or adds a directory entry as an INO, updating the refcount virtual int AddChild(const std::string& name, MountNode *node); virtual int RemoveChild(const std::string& name); - virtual MountNode* FindChild(const std::string& name); + virtual MountNode* FindChild(const std::string& name); + virtual int ChildCount(); protected: @@ -42,7 +43,8 @@ protected: private: struct dirent* cache_; MountNodeMap_t map_; - friend class Mount; + + friend class MountMem; }; #endif // LIBRARIES_NACL_MOUNTS_MOUNT_NODE_DIR_H_ diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_node_mem.h b/native_client_sdk/src/libraries/nacl_mounts/mount_node_mem.h index 63a2908..031293a 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/mount_node_mem.h +++ b/native_client_sdk/src/libraries/nacl_mounts/mount_node_mem.h @@ -6,7 +6,7 @@ #ifndef LIBRARIES_NACL_MOUNTS_MOUNT_NODE_MEM_H_ #define LIBRARIES_NACL_MOUNTS_MOUNT_NODE_MEM_H_ -#include "mount_node.h" +#include "nacl_mounts/mount_node.h" class MountNodeMem : public MountNode { public: @@ -25,7 +25,7 @@ public: private: char* data_; size_t capacity_; - friend class Mount; + friend class MountMem; }; #endif // LIBRARIES_NACL_MOUNTS_MOUNT_NODE_MEM_H_ |