15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file.
4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/dir_node.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "nacl_io/log.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/osdirent.h"
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "nacl_io/osinttypes.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/osstat.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "sdk_util/auto_lock.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "sdk_util/macros.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace nacl_io {
18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace {
2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// TODO(binji): For now, just use a dummy value for the parent ino.
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const ino_t kParentDirIno = -1;
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
2468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DirNode::DirNode(Filesystem* filesystem)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : Node(filesystem),
2768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      cache_(stat_.st_ino, kParentDirIno),
2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      cache_built_(false) {
298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  SetType(S_IFDIR);
308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Directories are raadable, writable and executable by default.
318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  stat_.st_mode |= S_IRALL | S_IWALL | S_IXALL;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DirNode::~DirNode() {
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (NodeMap_t::iterator it = map_.begin(); it != map_.end(); ++it) {
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    it->second->Unlink();
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error DirNode::Read(const HandleAttr& attr,
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    void* buf,
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    size_t count,
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    int* out_bytes) {
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *out_bytes = 0;
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LOG_TRACE("Can't read a directory.");
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return EISDIR;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)Error DirNode::FTruncate(off_t size) {
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LOG_TRACE("Can't truncate a directory.");
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return EISDIR;
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error DirNode::Write(const HandleAttr& attr,
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     const void* buf,
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     size_t count,
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     int* out_bytes) {
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *out_bytes = 0;
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LOG_TRACE("Can't write to a directory.");
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return EISDIR;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error DirNode::GetDents(size_t offs,
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        dirent* pdir,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        size_t size,
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        int* out_bytes) {
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  AUTO_LOCK(node_lock_);
6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  BuildCache_Locked();
6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return cache_.GetDents(offs, pdir, size, out_bytes);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciError DirNode::Fchmod(mode_t mode) {
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AUTO_LOCK(node_lock_);
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SetMode(mode);
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return 0;
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error DirNode::AddChild(const std::string& name, const ScopedNode& node) {
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  AUTO_LOCK(node_lock_);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (name.empty()) {
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Can't add child with no name.");
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return ENOENT;
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (name.length() >= MEMBER_SIZE(dirent, d_name)) {
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Child name is too long: %" PRIuS " >= %" PRIuS,
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              name.length(),
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              MEMBER_SIZE(dirent, d_name));
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return ENAMETOOLONG;
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NodeMap_t::iterator it = map_.find(name);
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (it != map_.end()) {
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_TRACE("Can't add child \"%s\", it already exists.", name);
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return EEXIST;
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  node->Link();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  map_[name] = node;
10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ClearCache_Locked();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error DirNode::RemoveChild(const std::string& name) {
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  AUTO_LOCK(node_lock_);
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NodeMap_t::iterator it = map_.find(name);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != map_.end()) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    it->second->Unlink();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    map_.erase(it);
11168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    ClearCache_Locked();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return ENOENT;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error DirNode::FindChild(const std::string& name, ScopedNode* out_node) {
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  out_node->reset(NULL);
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  AUTO_LOCK(node_lock_);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NodeMap_t::iterator it = map_.find(name);
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (it == map_.end())
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return ENOENT;
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *out_node = it->second;
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return 0;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int DirNode::ChildCount() {
1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  AUTO_LOCK(node_lock_);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return map_.size();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DirNode::BuildCache_Locked() {
13568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (cache_built_)
13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (NodeMap_t::iterator it = map_.begin(), end = map_.end(); it != end;
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
14068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& name = it->first;
14168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    ino_t ino = it->second->stat_.st_ino;
14268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    cache_.AddDirent(ino, name.c_str(), name.length());
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
14568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  cache_built_ = true;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DirNode::ClearCache_Locked() {
14968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  cache_built_ = false;
15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  cache_.Reset();
15168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace nacl_io
154