Directory.cpp revision 37b74a387bb3993387029859c2d9d051c41c724e
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 12namespace mcld { 13namespace sys { 14namespace fs { 15 16namespace { // anonymous 17 18bool status_known(FileStatus f) { 19 return f.type() != StatusError; 20} 21 22bool is_symlink(FileStatus f) { 23 return f.type() == SymlinkFile; 24} 25 26const Path dot_path("."); 27const Path dot_dot_path(".."); 28 29} // anonymous namespace 30 31//===----------------------------------------------------------------------===// 32// Directory 33//===----------------------------------------------------------------------===// 34Directory::Directory() 35 : m_Path(), 36 m_FileStatus(), 37 m_SymLinkStatus(), 38 m_Handler(0), 39 m_Cache(), 40 m_CacheFull(false) { 41} 42 43Directory::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 56Directory::Directory(const char* pPath, FileStatus st, FileStatus symlink_st) 57 : Directory(sys::fs::Path(pPath), st, symlink_st) { 58} 59 60Directory::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 70Directory::~Directory() { 71 detail::close_dir(*this); 72} 73 74bool Directory::isGood() const { 75 return (0 != m_Handler); 76} 77 78Directory& Directory::operator=(const Directory& pCopy) { 79 assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus); 80 return *this; 81} 82 83void 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 99FileStatus 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 112FileStatus Directory::symlinkStatus() const { 113 if (!status_known(m_SymLinkStatus)) 114 detail::symlink_status(m_Path, m_SymLinkStatus); 115 return m_SymLinkStatus; 116} 117 118Directory::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 127Directory::iterator Directory::end() { 128 return iterator(0, m_Cache.end()); 129} 130 131void 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 141DirIterator::DirIterator(Directory* pParent, 142 const DirIterator::DirCache::iterator& pIter) 143 : m_pParent(pParent), m_Iter(pIter) { 144 m_pEntry = m_Iter.getEntry(); 145} 146 147DirIterator::DirIterator(const DirIterator& pCopy) 148 : m_pParent(pCopy.m_pParent), 149 m_Iter(pCopy.m_Iter), 150 m_pEntry(pCopy.m_pEntry) { 151} 152 153DirIterator::~DirIterator() { 154} 155 156Path* DirIterator::path() { 157 if (m_pParent == NULL) 158 return NULL; 159 return &m_pEntry->value(); 160} 161 162const Path* DirIterator::path() const { 163 if (m_pParent == NULL) 164 return NULL; 165 return &m_pEntry->value(); 166} 167 168DirIterator& 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 175DirIterator& 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 197DirIterator 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 218bool 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 232bool DirIterator::operator!=(const DirIterator& y) const { 233 return !this->operator==(y); 234} 235 236} // namespace fs 237} // namespace sys 238} // namespace mcld 239