Home | History | Annotate | Download | only in nacl_io
      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