1// Copyright (c) 2012 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. 4 5#include "nacl_io/mount_node_dir.h" 6 7#include <errno.h> 8#include <string.h> 9 10#include "nacl_io/osdirent.h" 11#include "nacl_io/osstat.h" 12#include "sdk_util/auto_lock.h" 13#include "sdk_util/macros.h" 14 15namespace nacl_io { 16 17MountNodeDir::MountNodeDir(Mount* mount) : MountNode(mount), cache_(NULL) { 18 stat_.st_mode |= S_IFDIR; 19} 20 21MountNodeDir::~MountNodeDir() { 22 for (MountNodeMap_t::iterator it = map_.begin(); it != map_.end(); ++it) { 23 it->second->Unlink(); 24 } 25 free(cache_); 26} 27 28Error MountNodeDir::Read(size_t offs, void* buf, size_t count, int* out_bytes) { 29 *out_bytes = 0; 30 return EISDIR; 31} 32 33Error MountNodeDir::FTruncate(off_t size) { return EISDIR; } 34 35Error MountNodeDir::Write(size_t offs, 36 const void* buf, 37 size_t count, 38 int* out_bytes) { 39 *out_bytes = 0; 40 return EISDIR; 41} 42 43Error MountNodeDir::GetDents(size_t offs, 44 struct dirent* pdir, 45 size_t size, 46 int* out_bytes) { 47 *out_bytes = 0; 48 49 AUTO_LOCK(node_lock_); 50 51 // If the buffer pointer is invalid, fail 52 if (NULL == pdir) 53 return EINVAL; 54 55 // If the buffer is too small, fail 56 if (size < sizeof(struct dirent)) 57 return EINVAL; 58 59 // Force size to a multiple of dirent 60 size -= size % sizeof(struct dirent); 61 size_t max = map_.size() * sizeof(struct dirent); 62 if (cache_ == NULL) 63 BuildCache(); 64 65 if (offs >= max) { 66 // OK, trying to read past the end. 67 return 0; 68 } 69 70 if (offs + size >= max) 71 size = max - offs; 72 73 memcpy(pdir, ((char*)cache_) + offs, size); 74 *out_bytes = size; 75 return 0; 76} 77 78Error MountNodeDir::AddChild(const std::string& name, 79 const ScopedMountNode& node) { 80 AUTO_LOCK(node_lock_); 81 82 if (name.empty()) 83 return ENOENT; 84 85 if (name.length() >= MEMBER_SIZE(struct dirent, d_name)) 86 return ENAMETOOLONG; 87 88 MountNodeMap_t::iterator it = map_.find(name); 89 if (it != map_.end()) 90 return EEXIST; 91 92 node->Link(); 93 map_[name] = node; 94 ClearCache(); 95 return 0; 96} 97 98Error MountNodeDir::RemoveChild(const std::string& name) { 99 AUTO_LOCK(node_lock_); 100 MountNodeMap_t::iterator it = map_.find(name); 101 if (it != map_.end()) { 102 it->second->Unlink(); 103 map_.erase(it); 104 ClearCache(); 105 return 0; 106 } 107 return ENOENT; 108} 109 110Error MountNodeDir::FindChild(const std::string& name, 111 ScopedMountNode* out_node) { 112 out_node->reset(NULL); 113 114 AUTO_LOCK(node_lock_); 115 MountNodeMap_t::iterator it = map_.find(name); 116 if (it == map_.end()) 117 return ENOENT; 118 119 *out_node = it->second; 120 return 0; 121} 122 123int MountNodeDir::ChildCount() { 124 AUTO_LOCK(node_lock_); 125 return map_.size(); 126} 127 128void MountNodeDir::ClearCache() { 129 free(cache_); 130 cache_ = NULL; 131} 132 133void MountNodeDir::BuildCache() { 134 if (map_.size()) { 135 cache_ = (struct dirent*)malloc(sizeof(struct dirent) * map_.size()); 136 MountNodeMap_t::iterator it = map_.begin(); 137 for (size_t index = 0; it != map_.end(); it++, index++) { 138 size_t len = it->first.length(); 139 cache_[index].d_ino = it->second->stat_.st_ino; 140 cache_[index].d_off = sizeof(struct dirent); 141 cache_[index].d_reclen = sizeof(struct dirent); 142 cache_[index].d_name[len] = 0; 143 strncpy(cache_[index].d_name, &it->first[0], len); 144 } 145 } 146} 147 148} // namespace nacl_io 149 150