Directory.cpp revision 5460a1f25d9ddecb5c70667267d66d51af177a99
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
12using namespace mcld;
13using namespace mcld::sys::fs;
14
15namespace { // anonymous
16
17bool status_known(FileStatus f)
18{
19  return f.type() != StatusError;
20}
21
22bool is_symlink(FileStatus f)
23{
24  return f.type() == SymlinkFile;
25}
26
27} // namespace of anonymous
28
29//==========================
30// Directory
31Directory::Directory()
32  : m_Path(),
33    m_FileStatus(),
34    m_SymLinkStatus(),
35    m_Handler(NULL),
36    m_Cache(),
37    m_CacheFull(false) {
38}
39
40Directory::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
55Directory::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
65Directory::~Directory()
66{
67  detail::close_dir(*this);
68}
69
70bool Directory::isGood() const
71{
72  return (0 != m_Handler);
73}
74
75Directory& Directory::operator=(const Directory& pCopy)
76{
77  assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus);
78  return *this;
79}
80
81void 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
98FileStatus 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
116FileStatus Directory::symlinkStatus() const
117{
118  if (!status_known(m_SymLinkStatus))
119     detail::symlink_status(m_Path,m_SymLinkStatus);
120  return  m_SymLinkStatus;
121}
122
123Directory::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
133Directory::iterator Directory::end()
134{
135  return iterator(0, m_Cache.end());
136}
137
138void 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
149DirIterator::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
156DirIterator::DirIterator(const DirIterator& pCopy)
157  : m_pParent(pCopy.m_pParent),
158    m_Iter(pCopy.m_Iter),
159    m_pEntry(pCopy.m_pEntry) {
160}
161
162DirIterator::~DirIterator()
163{
164}
165
166Path* DirIterator::path()
167{
168  if (m_pParent == 0) // end
169    return 0;
170  return m_pEntry->value();
171}
172
173const Path* DirIterator::path() const
174{
175  if (m_pParent == 0) // end
176    return 0;
177  return m_pEntry->value();
178}
179
180DirIterator& 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
188DirIterator& 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
211DirIterator 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
233bool 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
248bool DirIterator::operator!=(const DirIterator& y) const
249{
250  return !this->operator==(y);
251}
252
253