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
|