Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / nacl_io / dir_node.cc
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::AddChild(const std::string& name, const ScopedNode& node) {
73   AUTO_LOCK(node_lock_);
74
75   if (name.empty()) {
76     LOG_ERROR("Can't add child with no name.");
77     return ENOENT;
78   }
79
80   if (name.length() >= MEMBER_SIZE(dirent, d_name)) {
81     LOG_ERROR("Child name is too long: %" PRIuS " >= %" PRIuS,
82               name.length(),
83               MEMBER_SIZE(dirent, d_name));
84     return ENAMETOOLONG;
85   }
86
87   NodeMap_t::iterator it = map_.find(name);
88   if (it != map_.end()) {
89     LOG_TRACE("Can't add child \"%s\", it already exists.", name);
90     return EEXIST;
91   }
92
93   node->Link();
94   map_[name] = node;
95   ClearCache_Locked();
96   return 0;
97 }
98
99 Error DirNode::RemoveChild(const std::string& name) {
100   AUTO_LOCK(node_lock_);
101   NodeMap_t::iterator it = map_.find(name);
102   if (it != map_.end()) {
103     it->second->Unlink();
104     map_.erase(it);
105     ClearCache_Locked();
106     return 0;
107   }
108   return ENOENT;
109 }
110
111 Error DirNode::FindChild(const std::string& name, ScopedNode* out_node) {
112   out_node->reset(NULL);
113
114   AUTO_LOCK(node_lock_);
115   NodeMap_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
123 int DirNode::ChildCount() {
124   AUTO_LOCK(node_lock_);
125   return map_.size();
126 }
127
128 void DirNode::BuildCache_Locked() {
129   if (cache_built_)
130     return;
131
132   for (NodeMap_t::iterator it = map_.begin(), end = map_.end(); it != end;
133        ++it) {
134     const std::string& name = it->first;
135     ino_t ino = it->second->stat_.st_ino;
136     cache_.AddDirent(ino, name.c_str(), name.length());
137   }
138
139   cache_built_ = true;
140 }
141
142 void DirNode::ClearCache_Locked() {
143   cache_built_ = false;
144   cache_.Reset();
145 }
146
147 }  // namespace nacl_io