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