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