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