• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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