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