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 //===----------------------------------------------------------------------===// 32 Directory::Directory() 33 : m_Path(), 34 m_FileStatus(), 35 m_SymLinkStatus(), 36 m_Handler(0), 37 m_Cache(), 38 m_CacheFull(false) { 39 } 40 41 Directory::Directory(const Path& pPath, 42 FileStatus st, 43 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.native() == ".") 51 detail::get_pwd(m_Path.native()); 52 m_Path.m_append_separator_if_needed(); 53 mcld::sys::fs::detail::open_dir(*this); 54 } 55 56 Directory::Directory(const Directory& pCopy) 57 : m_Path(pCopy.m_Path), 58 m_FileStatus(pCopy.m_FileStatus), 59 m_SymLinkStatus(pCopy.m_SymLinkStatus), 60 m_Handler(0), 61 m_Cache(), 62 m_CacheFull(false) { 63 mcld::sys::fs::detail::open_dir(*this); 64 } 65 66 Directory::~Directory() 67 { 68 detail::close_dir(*this); 69 } 70 71 bool Directory::isGood() const 72 { 73 return (0 != m_Handler); 74 } 75 76 Directory& Directory::operator=(const Directory& pCopy) 77 { 78 assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus); 79 return *this; 80 } 81 82 void Directory::assign(const Path& pPath, 83 FileStatus st, 84 FileStatus symlink_st) 85 { 86 if (isGood()) 87 clear(); 88 89 m_Path = pPath; 90 if (m_Path.native() == ".") 91 detail::get_pwd(m_Path.native()); 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 99 FileStatus Directory::status() const 100 { 101 if (!status_known(m_FileStatus)) 102 { 103 // optimization: if the symlink status is known, and it isn't a symlink, 104 // then status and symlink_status are identical so just copy the 105 // symlink status to the regular status. 106 if (status_known(m_SymLinkStatus) 107 && !is_symlink(m_SymLinkStatus)) 108 { 109 m_FileStatus = m_SymLinkStatus; 110 } 111 else detail::status(m_Path,m_FileStatus); 112 } 113 return m_FileStatus; 114 115 } 116 117 FileStatus Directory::symlinkStatus() const 118 { 119 if (!status_known(m_SymLinkStatus)) 120 detail::symlink_status(m_Path,m_SymLinkStatus); 121 return m_SymLinkStatus; 122 } 123 124 Directory::iterator Directory::begin() 125 { 126 if (m_CacheFull && m_Cache.empty()) 127 return end(); 128 PathCache::iterator iter = m_Cache.begin(); 129 if (NULL == iter.getEntry()) 130 ++iter; 131 return iterator(this, iter); 132 } 133 134 Directory::iterator Directory::end() 135 { 136 return iterator(0, m_Cache.end()); 137 } 138 139 void Directory::clear() 140 { 141 m_Path.native().clear(); 142 m_FileStatus = FileStatus(); 143 m_SymLinkStatus = FileStatus(); 144 m_Cache.clear(); 145 detail::close_dir(*this); 146 } 147 148 //========================== 149 // DirIterator 150 DirIterator::DirIterator(Directory* pParent, 151 const DirIterator::DirCache::iterator& pIter) 152 : m_pParent(pParent), 153 m_Iter(pIter) { 154 m_pEntry = m_Iter.getEntry(); 155 } 156 157 DirIterator::DirIterator(const DirIterator& pCopy) 158 : m_pParent(pCopy.m_pParent), 159 m_Iter(pCopy.m_Iter), 160 m_pEntry(pCopy.m_pEntry) { 161 } 162 163 DirIterator::~DirIterator() 164 { 165 } 166 167 Path* DirIterator::path() 168 { 169 if (NULL == m_pParent) 170 return NULL; 171 return &m_pEntry->value(); 172 } 173 174 const Path* DirIterator::path() const 175 { 176 if (NULL == m_pParent) 177 return NULL; 178 return &m_pEntry->value(); 179 } 180 181 DirIterator& DirIterator::operator=(const DirIterator& pCopy) 182 { 183 m_pParent = pCopy.m_pParent; 184 m_Iter = pCopy.m_Iter; 185 m_pEntry = pCopy.m_pEntry; 186 return (*this); 187 } 188 189 DirIterator& DirIterator::operator++() 190 { 191 if (0 == m_pParent) 192 return *this; 193 194 // move forward one step first. 195 ++m_Iter; 196 197 if (m_pParent->m_Cache.end() == m_Iter) { 198 if (!m_pParent->m_CacheFull) { 199 m_pEntry = detail::bring_one_into_cache(*this); 200 if (0 == m_pEntry && m_pParent->m_CacheFull) 201 m_pParent = 0; 202 return *this; 203 } 204 m_pParent = 0; 205 return *this; 206 } 207 208 m_pEntry = m_Iter.getEntry(); 209 return *this; 210 } 211 212 DirIterator DirIterator::operator++(int) 213 { 214 DirIterator tmp(*this); 215 216 // move forward one step first. 217 ++m_Iter; 218 219 if (m_pParent->m_Cache.end() == m_Iter) { 220 if (!m_pParent->m_CacheFull) { 221 m_pEntry = detail::bring_one_into_cache(*this); 222 if (0 == m_pEntry && m_pParent->m_CacheFull) 223 m_pParent = 0; 224 return tmp; 225 } 226 m_pParent = 0; 227 return tmp; 228 } 229 230 m_pEntry = m_Iter.getEntry(); 231 return tmp; 232 } 233 234 bool DirIterator::operator==(const DirIterator& y) const 235 { 236 if (m_pParent != y.m_pParent) 237 return false; 238 if (0 == m_pParent) 239 return true; 240 const Path* x_path = path(); 241 const Path* y_path = y.path(); 242 if (0 == x_path && 0 == y_path) 243 return true; 244 if (0 == x_path || 0 == y_path) 245 return false; 246 return (*x_path == *y_path); 247 } 248 249 bool DirIterator::operator!=(const DirIterator& y) const 250 { 251 return !this->operator==(y); 252 } 253 254