//===- 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