1 // Copyright 2013 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/dir_node.h" 6 7 #include <errno.h> 8 #include <string.h> 9 10 #include "nacl_io/log.h" 11 #include "nacl_io/osdirent.h" 12 #include "nacl_io/osinttypes.h" 13 #include "nacl_io/osstat.h" 14 #include "sdk_util/auto_lock.h" 15 #include "sdk_util/macros.h" 16 17 namespace nacl_io { 18 19 namespace { 20 21 // TODO(binji): For now, just use a dummy value for the parent ino. 22 const ino_t kParentDirIno = -1; 23 } 24 25 DirNode::DirNode(Filesystem* filesystem) 26 : Node(filesystem), 27 cache_(stat_.st_ino, kParentDirIno), 28 cache_built_(false) { 29 SetType(S_IFDIR); 30 // Directories are raadable, writable and executable by default. 31 stat_.st_mode |= S_IRALL | S_IWALL | S_IXALL; 32 } 33 34 DirNode::~DirNode() { 35 for (NodeMap_t::iterator it = map_.begin(); it != map_.end(); ++it) { 36 it->second->Unlink(); 37 } 38 } 39 40 Error DirNode::Read(const HandleAttr& attr, 41 void* buf, 42 size_t count, 43 int* out_bytes) { 44 *out_bytes = 0; 45 LOG_TRACE("Can't read a directory."); 46 return EISDIR; 47 } 48 49 Error DirNode::FTruncate(off_t size) { 50 LOG_TRACE("Can't truncate a directory."); 51 return EISDIR; 52 } 53 54 Error DirNode::Write(const HandleAttr& attr, 55 const void* buf, 56 size_t count, 57 int* out_bytes) { 58 *out_bytes = 0; 59 LOG_TRACE("Can't write to a directory."); 60 return EISDIR; 61 } 62 63 Error DirNode::GetDents(size_t offs, 64 dirent* pdir, 65 size_t size, 66 int* out_bytes) { 67 AUTO_LOCK(node_lock_); 68 BuildCache_Locked(); 69 return cache_.GetDents(offs, pdir, size, out_bytes); 70 } 71 72 Error DirNode::Fchmod(mode_t mode) { 73 AUTO_LOCK(node_lock_); 74 SetMode(mode); 75 return 0; 76 } 77 78 Error DirNode::AddChild(const std::string& name, const ScopedNode& node) { 79 AUTO_LOCK(node_lock_); 80 81 if (name.empty()) { 82 LOG_ERROR("Can't add child with no name."); 83 return ENOENT; 84 } 85 86 if (name.length() >= MEMBER_SIZE(dirent, d_name)) { 87 LOG_ERROR("Child name is too long: %" PRIuS " >= %" PRIuS, 88 name.length(), 89 MEMBER_SIZE(dirent, d_name)); 90 return ENAMETOOLONG; 91 } 92 93 NodeMap_t::iterator it = map_.find(name); 94 if (it != map_.end()) { 95 LOG_TRACE("Can't add child \"%s\", it already exists.", name); 96 return EEXIST; 97 } 98 99 node->Link(); 100 map_[name] = node; 101 ClearCache_Locked(); 102 return 0; 103 } 104 105 Error DirNode::RemoveChild(const std::string& name) { 106 AUTO_LOCK(node_lock_); 107 NodeMap_t::iterator it = map_.find(name); 108 if (it != map_.end()) { 109 it->second->Unlink(); 110 map_.erase(it); 111 ClearCache_Locked(); 112 return 0; 113 } 114 return ENOENT; 115 } 116 117 Error DirNode::FindChild(const std::string& name, ScopedNode* out_node) { 118 out_node->reset(NULL); 119 120 AUTO_LOCK(node_lock_); 121 NodeMap_t::iterator it = map_.find(name); 122 if (it == map_.end()) 123 return ENOENT; 124 125 *out_node = it->second; 126 return 0; 127 } 128 129 int DirNode::ChildCount() { 130 AUTO_LOCK(node_lock_); 131 return map_.size(); 132 } 133 134 void DirNode::BuildCache_Locked() { 135 if (cache_built_) 136 return; 137 138 for (NodeMap_t::iterator it = map_.begin(), end = map_.end(); it != end; 139 ++it) { 140 const std::string& name = it->first; 141 ino_t ino = it->second->stat_.st_ino; 142 cache_.AddDirent(ino, name.c_str(), name.length()); 143 } 144 145 cache_built_ = true; 146 } 147 148 void DirNode::ClearCache_Locked() { 149 cache_built_ = false; 150 cache_.Reset(); 151 } 152 153 } // namespace nacl_io 154