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