• 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
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