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