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