| //===- Directory.cpp ------------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include "mcld/Support/Directory.h" |
| #include "mcld/Support/FileSystem.h" |
| |
| namespace mcld { |
| namespace sys { |
| namespace fs { |
| |
| namespace { // anonymous |
| |
| bool status_known(FileStatus f) { |
| return f.type() != StatusError; |
| } |
| |
| bool is_symlink(FileStatus f) { |
| return f.type() == SymlinkFile; |
| } |
| |
| const Path dot_path("."); |
| const Path dot_dot_path(".."); |
| |
| } // anonymous namespace |
| |
| //===----------------------------------------------------------------------===// |
| // Directory |
| //===----------------------------------------------------------------------===// |
| Directory::Directory() |
| : m_Path(), |
| m_FileStatus(), |
| m_SymLinkStatus(), |
| m_Handler(0), |
| m_Cache(), |
| m_CacheFull(false) { |
| } |
| |
| Directory::Directory(const Path& pPath, FileStatus st, FileStatus symlink_st) |
| : m_Path(pPath), |
| m_FileStatus(st), |
| m_SymLinkStatus(symlink_st), |
| m_Handler(0), |
| m_Cache(), |
| m_CacheFull(false) { |
| if (m_Path == dot_path) |
| detail::get_pwd(m_Path); |
| m_Path.m_append_separator_if_needed(); |
| detail::open_dir(*this); |
| } |
| |
| Directory::Directory(const char* pPath, FileStatus st, FileStatus symlink_st) |
| : Directory(sys::fs::Path(pPath), st, symlink_st) { |
| } |
| |
| Directory::Directory(const Directory& pCopy) |
| : m_Path(pCopy.m_Path), |
| m_FileStatus(pCopy.m_FileStatus), |
| m_SymLinkStatus(pCopy.m_SymLinkStatus), |
| m_Handler(0), |
| m_Cache(), |
| m_CacheFull(false) { |
| detail::open_dir(*this); |
| } |
| |
| Directory::~Directory() { |
| detail::close_dir(*this); |
| } |
| |
| bool Directory::isGood() const { |
| return (0 != m_Handler); |
| } |
| |
| Directory& Directory::operator=(const Directory& pCopy) { |
| assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus); |
| return *this; |
| } |
| |
| void Directory::assign(const Path& pPath, |
| FileStatus st, |
| FileStatus symlink_st) { |
| if (isGood()) |
| clear(); |
| |
| m_Path = pPath; |
| if (m_Path == dot_path) |
| detail::get_pwd(m_Path); |
| m_Path.m_append_separator_if_needed(); |
| |
| m_FileStatus = st; |
| m_SymLinkStatus = symlink_st; |
| detail::open_dir(*this); |
| } |
| |
| FileStatus Directory::status() const { |
| if (!status_known(m_FileStatus)) { |
| // optimization: if the symlink status is known, and it isn't a symlink, |
| // then status and symlink_status are identical so just copy the |
| // symlink status to the regular status. |
| if (status_known(m_SymLinkStatus) && !is_symlink(m_SymLinkStatus)) { |
| m_FileStatus = m_SymLinkStatus; |
| } else |
| detail::status(m_Path, m_FileStatus); |
| } |
| return m_FileStatus; |
| } |
| |
| FileStatus Directory::symlinkStatus() const { |
| if (!status_known(m_SymLinkStatus)) |
| detail::symlink_status(m_Path, m_SymLinkStatus); |
| return m_SymLinkStatus; |
| } |
| |
| Directory::iterator Directory::begin() { |
| if (m_CacheFull && m_Cache.empty()) |
| return end(); |
| PathCache::iterator iter = m_Cache.begin(); |
| if (iter.getEntry() == NULL) |
| ++iter; |
| return iterator(this, iter); |
| } |
| |
| Directory::iterator Directory::end() { |
| return iterator(0, m_Cache.end()); |
| } |
| |
| void Directory::clear() { |
| m_Path.native().clear(); |
| m_FileStatus = FileStatus(); |
| m_SymLinkStatus = FileStatus(); |
| m_Cache.clear(); |
| detail::close_dir(*this); |
| } |
| |
| //========================== |
| // DirIterator |
| DirIterator::DirIterator(Directory* pParent, |
| const DirIterator::DirCache::iterator& pIter) |
| : m_pParent(pParent), m_Iter(pIter) { |
| m_pEntry = m_Iter.getEntry(); |
| } |
| |
| DirIterator::DirIterator(const DirIterator& pCopy) |
| : m_pParent(pCopy.m_pParent), |
| m_Iter(pCopy.m_Iter), |
| m_pEntry(pCopy.m_pEntry) { |
| } |
| |
| DirIterator::~DirIterator() { |
| } |
| |
| Path* DirIterator::path() { |
| if (m_pParent == NULL) |
| return NULL; |
| return &m_pEntry->value(); |
| } |
| |
| const Path* DirIterator::path() const { |
| if (m_pParent == NULL) |
| return NULL; |
| return &m_pEntry->value(); |
| } |
| |
| DirIterator& DirIterator::operator=(const DirIterator& pCopy) { |
| m_pParent = pCopy.m_pParent; |
| m_Iter = pCopy.m_Iter; |
| m_pEntry = pCopy.m_pEntry; |
| return (*this); |
| } |
| |
| DirIterator& DirIterator::operator++() { |
| if (m_pParent == 0) |
| return *this; |
| |
| // move forward one step first. |
| ++m_Iter; |
| |
| if (m_pParent->m_Cache.end() == m_Iter) { |
| if (!m_pParent->m_CacheFull) { |
| m_pEntry = detail::bring_one_into_cache(*this); |
| if (m_pEntry == 0 && m_pParent->m_CacheFull) |
| m_pParent = 0; |
| return *this; |
| } |
| m_pParent = 0; |
| return *this; |
| } |
| |
| m_pEntry = m_Iter.getEntry(); |
| return *this; |
| } |
| |
| DirIterator DirIterator::operator++(int pIn) { |
| DirIterator tmp(*this); |
| |
| // move forward one step first. |
| ++m_Iter; |
| |
| if (m_pParent->m_Cache.end() == m_Iter) { |
| if (!m_pParent->m_CacheFull) { |
| m_pEntry = detail::bring_one_into_cache(*this); |
| if (m_pEntry == 0 && m_pParent->m_CacheFull) |
| m_pParent = 0; |
| return tmp; |
| } |
| m_pParent = 0; |
| return tmp; |
| } |
| |
| m_pEntry = m_Iter.getEntry(); |
| return tmp; |
| } |
| |
| bool DirIterator::operator==(const DirIterator& y) const { |
| if (m_pParent != y.m_pParent) |
| return false; |
| if (m_pParent == 0) |
| return true; |
| const Path* x_path = path(); |
| const Path* y_path = y.path(); |
| if (x_path == 0 && y_path == 0) |
| return true; |
| if (x_path == 0 || y_path == 0) |
| return false; |
| return (*x_path == *y_path); |
| } |
| |
| bool DirIterator::operator!=(const DirIterator& y) const { |
| return !this->operator==(y); |
| } |
| |
| } // namespace fs |
| } // namespace sys |
| } // namespace mcld |