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 } // namespace of anonymous
28
29 //==========================
30 // Directory
Directory()31 Directory::Directory()
32 : m_Path(),
33 m_FileStatus(),
34 m_SymLinkStatus(),
35 m_Handler(NULL),
36 m_Cache(),
37 m_CacheFull(false) {
38 }
39
Directory(const Path & pPath,FileStatus st,FileStatus symlink_st)40 Directory::Directory(const Path& pPath,
41 FileStatus st,
42 FileStatus symlink_st)
43 : m_Path(pPath),
44 m_FileStatus(st),
45 m_SymLinkStatus(symlink_st),
46 m_Handler(NULL),
47 m_Cache(),
48 m_CacheFull(false) {
49 if (m_Path.native() == ".")
50 detail::get_pwd(m_Path.native());
51 m_Path.m_append_separator_if_needed();
52 mcld::sys::fs::detail::open_dir(*this);
53 }
54
Directory(const Directory & pCopy)55 Directory::Directory(const Directory& pCopy)
56 : m_Path(pCopy.m_Path),
57 m_FileStatus(pCopy.m_FileStatus),
58 m_SymLinkStatus(pCopy.m_SymLinkStatus),
59 m_Handler(NULL),
60 m_Cache(),
61 m_CacheFull(false) {
62 mcld::sys::fs::detail::open_dir(*this);
63 }
64
~Directory()65 Directory::~Directory()
66 {
67 detail::close_dir(*this);
68 }
69
isGood() const70 bool Directory::isGood() const
71 {
72 return (0 != m_Handler);
73 }
74
operator =(const Directory & pCopy)75 Directory& Directory::operator=(const Directory& pCopy)
76 {
77 assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus);
78 return *this;
79 }
80
assign(const Path & pPath,FileStatus st,FileStatus symlink_st)81 void Directory::assign(const Path& pPath,
82 FileStatus st,
83 FileStatus symlink_st)
84 {
85 if (isGood())
86 clear();
87
88 m_Path = pPath;
89 if (m_Path.native() == ".")
90 detail::get_pwd(m_Path.native());
91 m_Path.m_append_separator_if_needed();
92
93 m_FileStatus = st;
94 m_SymLinkStatus = symlink_st;
95 detail::open_dir(*this);
96 }
97
status() const98 FileStatus Directory::status() const
99 {
100 if (!status_known(m_FileStatus))
101 {
102 // optimization: if the symlink status is known, and it isn't a symlink,
103 // then status and symlink_status are identical so just copy the
104 // symlink status to the regular status.
105 if (status_known(m_SymLinkStatus)
106 && !is_symlink(m_SymLinkStatus))
107 {
108 m_FileStatus = m_SymLinkStatus;
109 }
110 else detail::status(m_Path,m_FileStatus);
111 }
112 return m_FileStatus;
113
114 }
115
symlinkStatus() const116 FileStatus Directory::symlinkStatus() const
117 {
118 if (!status_known(m_SymLinkStatus))
119 detail::symlink_status(m_Path,m_SymLinkStatus);
120 return m_SymLinkStatus;
121 }
122
begin()123 Directory::iterator Directory::begin()
124 {
125 if (m_CacheFull && m_Cache.empty())
126 return end();
127 PathCache::iterator iter = m_Cache.begin();
128 if (NULL == iter.getEntry())
129 ++iter;
130 return iterator(this, iter);
131 }
132
end()133 Directory::iterator Directory::end()
134 {
135 return iterator(0, m_Cache.end());
136 }
137
clear()138 void Directory::clear()
139 {
140 m_Path.native().clear();
141 m_FileStatus = FileStatus();
142 m_SymLinkStatus = FileStatus();
143 m_Cache.clear();
144 detail::close_dir(*this);
145 }
146
147 //==========================
148 // DirIterator
DirIterator(Directory * pParent,const DirIterator::DirCache::iterator & pIter)149 DirIterator::DirIterator(Directory* pParent,
150 const DirIterator::DirCache::iterator& pIter)
151 : m_pParent(pParent),
152 m_Iter(pIter) {
153 m_pEntry = m_Iter.getEntry();
154 }
155
DirIterator(const DirIterator & pCopy)156 DirIterator::DirIterator(const DirIterator& pCopy)
157 : m_pParent(pCopy.m_pParent),
158 m_Iter(pCopy.m_Iter),
159 m_pEntry(pCopy.m_pEntry) {
160 }
161
~DirIterator()162 DirIterator::~DirIterator()
163 {
164 }
165
path()166 Path* DirIterator::path()
167 {
168 if (m_pParent == 0) // end
169 return 0;
170 return m_pEntry->value();
171 }
172
path() const173 const Path* DirIterator::path() const
174 {
175 if (m_pParent == 0) // end
176 return 0;
177 return m_pEntry->value();
178 }
179
operator =(const DirIterator & pCopy)180 DirIterator& DirIterator::operator=(const DirIterator& pCopy)
181 {
182 m_pParent = pCopy.m_pParent;
183 m_Iter = pCopy.m_Iter;
184 m_pEntry = pCopy.m_pEntry;
185 return (*this);
186 }
187
operator ++()188 DirIterator& DirIterator::operator++()
189 {
190 if (0 == m_pParent)
191 return *this;
192
193 // move forward one step first.
194 ++m_Iter;
195
196 if (m_pParent->m_Cache.end() == m_Iter) {
197 if (!m_pParent->m_CacheFull) {
198 m_pEntry = detail::bring_one_into_cache(*this);
199 if (0 == m_pEntry && m_pParent->m_CacheFull)
200 m_pParent = 0;
201 return *this;
202 }
203 m_pParent = 0;
204 return *this;
205 }
206
207 m_pEntry = m_Iter.getEntry();
208 return *this;
209 }
210
operator ++(int)211 DirIterator DirIterator::operator++(int)
212 {
213 DirIterator tmp(*this);
214
215 // move forward one step first.
216 ++m_Iter;
217
218 if (m_pParent->m_Cache.end() == m_Iter) {
219 if (!m_pParent->m_CacheFull) {
220 m_pEntry = detail::bring_one_into_cache(*this);
221 if (0 == m_pEntry && m_pParent->m_CacheFull)
222 m_pParent = 0;
223 return tmp;
224 }
225 m_pParent = 0;
226 return tmp;
227 }
228
229 m_pEntry = m_Iter.getEntry();
230 return tmp;
231 }
232
operator ==(const DirIterator & y) const233 bool DirIterator::operator==(const DirIterator& y) const
234 {
235 if (m_pParent != y.m_pParent)
236 return false;
237 if (0 == m_pParent)
238 return true;
239 const Path* x_path = path();
240 const Path* y_path = y.path();
241 if (0 == x_path && 0 == y_path)
242 return true;
243 if (0 == x_path || 0 == y_path)
244 return false;
245 return (*x_path == *y_path);
246 }
247
operator !=(const DirIterator & y) const248 bool DirIterator::operator!=(const DirIterator& y) const
249 {
250 return !this->operator==(y);
251 }
252
253