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
27const Path dot_path(".");
28const Path dot_dot_path("..");
29
30} // namespace of anonymous
31
32//===----------------------------------------------------------------------===//
33// Directory
34//===----------------------------------------------------------------------===//
35Directory::Directory()
36  : m_Path(),
37    m_FileStatus(),
38    m_SymLinkStatus(),
39    m_Handler(0),
40    m_Cache(),
41    m_CacheFull(false) {
42}
43
44Directory::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
59Directory::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
69Directory::~Directory()
70{
71  detail::close_dir(*this);
72}
73
74bool Directory::isGood() const
75{
76  return (0 != m_Handler);
77}
78
79Directory& Directory::operator=(const Directory& pCopy)
80{
81  assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus);
82  return *this;
83}
84
85void 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
102FileStatus 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
120FileStatus Directory::symlinkStatus() const
121{
122  if (!status_known(m_SymLinkStatus))
123     detail::symlink_status(m_Path,m_SymLinkStatus);
124  return  m_SymLinkStatus;
125}
126
127Directory::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
137Directory::iterator Directory::end()
138{
139  return iterator(0, m_Cache.end());
140}
141
142void 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
153DirIterator::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
160DirIterator::DirIterator(const DirIterator& pCopy)
161  : m_pParent(pCopy.m_pParent),
162    m_Iter(pCopy.m_Iter),
163    m_pEntry(pCopy.m_pEntry) {
164}
165
166DirIterator::~DirIterator()
167{
168}
169
170Path* DirIterator::path()
171{
172  if (NULL == m_pParent)
173    return NULL;
174  return &m_pEntry->value();
175}
176
177const Path* DirIterator::path() const
178{
179  if (NULL == m_pParent)
180    return NULL;
181  return &m_pEntry->value();
182}
183
184DirIterator& 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
192DirIterator& 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
215DirIterator 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
237bool 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
252bool DirIterator::operator!=(const DirIterator& y) const
253{
254  return !this->operator==(y);
255}
256
257