1 //===- Directory.cpp ------------------------------------------------------===//
2 //
3 // The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include <mcld/Support/Directory.h>
10 #include <mcld/Support/FileSystem.h>
11
12 using namespace mcld;
13 using namespace mcld::sys::fs;
14
15 namespace { // anonymous
16
status_known(FileStatus f)17 bool status_known(FileStatus f)
18 {
19 return f.type() != StatusError;
20 }
21
is_symlink(FileStatus f)22 bool is_symlink(FileStatus f)
23 {
24 return f.type() == SymlinkFile;
25 }
26
27 const Path dot_path(".");
28 const Path dot_dot_path("..");
29
30 } // namespace of anonymous
31
32 //===----------------------------------------------------------------------===//
33 // Directory
34 //===----------------------------------------------------------------------===//
Directory()35 Directory::Directory()
36 : m_Path(),
37 m_FileStatus(),
38 m_SymLinkStatus(),
39 m_Handler(0),
40 m_Cache(),
41 m_CacheFull(false) {
42 }
43
Directory(const Path & pPath,FileStatus st,FileStatus symlink_st)44 Directory::Directory(const Path& pPath,
45 FileStatus st,
46 FileStatus symlink_st)
47 : m_Path(pPath),
48 m_FileStatus(st),
49 m_SymLinkStatus(symlink_st),
50 m_Handler(0),
51 m_Cache(),
52 m_CacheFull(false) {
53 if (m_Path == dot_path)
54 detail::get_pwd(m_Path);
55 m_Path.m_append_separator_if_needed();
56 detail::open_dir(*this);
57 }
58
Directory(const Directory & pCopy)59 Directory::Directory(const Directory& pCopy)
60 : m_Path(pCopy.m_Path),
61 m_FileStatus(pCopy.m_FileStatus),
62 m_SymLinkStatus(pCopy.m_SymLinkStatus),
63 m_Handler(0),
64 m_Cache(),
65 m_CacheFull(false) {
66 detail::open_dir(*this);
67 }
68
~Directory()69 Directory::~Directory()
70 {
71 detail::close_dir(*this);
72 }
73
isGood() const74 bool Directory::isGood() const
75 {
76 return (0 != m_Handler);
77 }
78
operator =(const Directory & pCopy)79 Directory& Directory::operator=(const Directory& pCopy)
80 {
81 assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus);
82 return *this;
83 }
84
assign(const Path & pPath,FileStatus st,FileStatus symlink_st)85 void Directory::assign(const Path& pPath,
86 FileStatus st,
87 FileStatus symlink_st)
88 {
89 if (isGood())
90 clear();
91
92 m_Path = pPath;
93 if (m_Path == dot_path)
94 detail::get_pwd(m_Path);
95 m_Path.m_append_separator_if_needed();
96
97 m_FileStatus = st;
98 m_SymLinkStatus = symlink_st;
99 detail::open_dir(*this);
100 }
101
status() const102 FileStatus Directory::status() const
103 {
104 if (!status_known(m_FileStatus))
105 {
106 // optimization: if the symlink status is known, and it isn't a symlink,
107 // then status and symlink_status are identical so just copy the
108 // symlink status to the regular status.
109 if (status_known(m_SymLinkStatus)
110 && !is_symlink(m_SymLinkStatus))
111 {
112 m_FileStatus = m_SymLinkStatus;
113 }
114 else detail::status(m_Path,m_FileStatus);
115 }
116 return m_FileStatus;
117
118 }
119
symlinkStatus() const120 FileStatus Directory::symlinkStatus() const
121 {
122 if (!status_known(m_SymLinkStatus))
123 detail::symlink_status(m_Path,m_SymLinkStatus);
124 return m_SymLinkStatus;
125 }
126
begin()127 Directory::iterator Directory::begin()
128 {
129 if (m_CacheFull && m_Cache.empty())
130 return end();
131 PathCache::iterator iter = m_Cache.begin();
132 if (NULL == iter.getEntry())
133 ++iter;
134 return iterator(this, iter);
135 }
136
end()137 Directory::iterator Directory::end()
138 {
139 return iterator(0, m_Cache.end());
140 }
141
clear()142 void Directory::clear()
143 {
144 m_Path.native().clear();
145 m_FileStatus = FileStatus();
146 m_SymLinkStatus = FileStatus();
147 m_Cache.clear();
148 detail::close_dir(*this);
149 }
150
151 //==========================
152 // DirIterator
DirIterator(Directory * pParent,const DirIterator::DirCache::iterator & pIter)153 DirIterator::DirIterator(Directory* pParent,
154 const DirIterator::DirCache::iterator& pIter)
155 : m_pParent(pParent),
156 m_Iter(pIter) {
157 m_pEntry = m_Iter.getEntry();
158 }
159
DirIterator(const DirIterator & pCopy)160 DirIterator::DirIterator(const DirIterator& pCopy)
161 : m_pParent(pCopy.m_pParent),
162 m_Iter(pCopy.m_Iter),
163 m_pEntry(pCopy.m_pEntry) {
164 }
165
~DirIterator()166 DirIterator::~DirIterator()
167 {
168 }
169
path()170 Path* DirIterator::path()
171 {
172 if (NULL == m_pParent)
173 return NULL;
174 return &m_pEntry->value();
175 }
176
path() const177 const Path* DirIterator::path() const
178 {
179 if (NULL == m_pParent)
180 return NULL;
181 return &m_pEntry->value();
182 }
183
operator =(const DirIterator & pCopy)184 DirIterator& DirIterator::operator=(const DirIterator& pCopy)
185 {
186 m_pParent = pCopy.m_pParent;
187 m_Iter = pCopy.m_Iter;
188 m_pEntry = pCopy.m_pEntry;
189 return (*this);
190 }
191
operator ++()192 DirIterator& DirIterator::operator++()
193 {
194 if (0 == m_pParent)
195 return *this;
196
197 // move forward one step first.
198 ++m_Iter;
199
200 if (m_pParent->m_Cache.end() == m_Iter) {
201 if (!m_pParent->m_CacheFull) {
202 m_pEntry = detail::bring_one_into_cache(*this);
203 if (0 == m_pEntry && m_pParent->m_CacheFull)
204 m_pParent = 0;
205 return *this;
206 }
207 m_pParent = 0;
208 return *this;
209 }
210
211 m_pEntry = m_Iter.getEntry();
212 return *this;
213 }
214
operator ++(int)215 DirIterator DirIterator::operator++(int)
216 {
217 DirIterator tmp(*this);
218
219 // move forward one step first.
220 ++m_Iter;
221
222 if (m_pParent->m_Cache.end() == m_Iter) {
223 if (!m_pParent->m_CacheFull) {
224 m_pEntry = detail::bring_one_into_cache(*this);
225 if (0 == m_pEntry && m_pParent->m_CacheFull)
226 m_pParent = 0;
227 return tmp;
228 }
229 m_pParent = 0;
230 return tmp;
231 }
232
233 m_pEntry = m_Iter.getEntry();
234 return tmp;
235 }
236
operator ==(const DirIterator & y) const237 bool DirIterator::operator==(const DirIterator& y) const
238 {
239 if (m_pParent != y.m_pParent)
240 return false;
241 if (0 == m_pParent)
242 return true;
243 const Path* x_path = path();
244 const Path* y_path = y.path();
245 if (0 == x_path && 0 == y_path)
246 return true;
247 if (0 == x_path || 0 == y_path)
248 return false;
249 return (*x_path == *y_path);
250 }
251
operator !=(const DirIterator & y) const252 bool DirIterator::operator!=(const DirIterator& y) const
253 {
254 return !this->operator==(y);
255 }
256
257