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