239 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- 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
 |