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