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