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