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 using namespace mcld;
     13 using namespace mcld::sys::fs;
     14 
     15 namespace { // anonymous
     16 
     17 bool status_known(FileStatus f)
     18 {
     19   return f.type() != StatusError;
     20 }
     21 
     22 bool is_symlink(FileStatus f)
     23 {
     24   return f.type() == SymlinkFile;
     25 }
     26 
     27 } // namespace of anonymous
     28 
     29 //===----------------------------------------------------------------------===//
     30 // Directory
     31 //===----------------------------------------------------------------------===//
     32 Directory::Directory()
     33   : m_Path(),
     34     m_FileStatus(),
     35     m_SymLinkStatus(),
     36     m_Handler(0),
     37     m_Cache(),
     38     m_CacheFull(false) {
     39 }
     40 
     41 Directory::Directory(const Path& pPath,
     42                      FileStatus st,
     43                      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.native() == ".")
     51     detail::get_pwd(m_Path.native());
     52   m_Path.m_append_separator_if_needed();
     53   mcld::sys::fs::detail::open_dir(*this);
     54 }
     55 
     56 Directory::Directory(const Directory& pCopy)
     57   : m_Path(pCopy.m_Path),
     58     m_FileStatus(pCopy.m_FileStatus),
     59     m_SymLinkStatus(pCopy.m_SymLinkStatus),
     60     m_Handler(0),
     61     m_Cache(),
     62     m_CacheFull(false) {
     63   mcld::sys::fs::detail::open_dir(*this);
     64 }
     65 
     66 Directory::~Directory()
     67 {
     68   detail::close_dir(*this);
     69 }
     70 
     71 bool Directory::isGood() const
     72 {
     73   return (0 != m_Handler);
     74 }
     75 
     76 Directory& Directory::operator=(const Directory& pCopy)
     77 {
     78   assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus);
     79   return *this;
     80 }
     81 
     82 void Directory::assign(const Path& pPath,
     83                        FileStatus st,
     84                        FileStatus symlink_st)
     85 {
     86   if (isGood())
     87     clear();
     88 
     89   m_Path = pPath;
     90   if (m_Path.native() == ".")
     91     detail::get_pwd(m_Path.native());
     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 {
    101   if (!status_known(m_FileStatus))
    102   {
    103     // optimization: if the symlink status is known, and it isn't a symlink,
    104     // then status and symlink_status are identical so just copy the
    105     // symlink status to the regular status.
    106     if (status_known(m_SymLinkStatus)
    107       && !is_symlink(m_SymLinkStatus))
    108     {
    109       m_FileStatus = m_SymLinkStatus;
    110     }
    111     else detail::status(m_Path,m_FileStatus);
    112   }
    113   return m_FileStatus;
    114 
    115 }
    116 
    117 FileStatus Directory::symlinkStatus() const
    118 {
    119   if (!status_known(m_SymLinkStatus))
    120      detail::symlink_status(m_Path,m_SymLinkStatus);
    121   return  m_SymLinkStatus;
    122 }
    123 
    124 Directory::iterator Directory::begin()
    125 {
    126   if (m_CacheFull && m_Cache.empty())
    127     return end();
    128   PathCache::iterator iter = m_Cache.begin();
    129   if (NULL == iter.getEntry())
    130     ++iter;
    131   return iterator(this, iter);
    132 }
    133 
    134 Directory::iterator Directory::end()
    135 {
    136   return iterator(0, m_Cache.end());
    137 }
    138 
    139 void Directory::clear()
    140 {
    141   m_Path.native().clear();
    142   m_FileStatus = FileStatus();
    143   m_SymLinkStatus = FileStatus();
    144   m_Cache.clear();
    145   detail::close_dir(*this);
    146 }
    147 
    148 //==========================
    149 // DirIterator
    150 DirIterator::DirIterator(Directory* pParent,
    151                          const DirIterator::DirCache::iterator& pIter)
    152   : m_pParent(pParent),
    153     m_Iter(pIter) {
    154   m_pEntry = m_Iter.getEntry();
    155 }
    156 
    157 DirIterator::DirIterator(const DirIterator& pCopy)
    158   : m_pParent(pCopy.m_pParent),
    159     m_Iter(pCopy.m_Iter),
    160     m_pEntry(pCopy.m_pEntry) {
    161 }
    162 
    163 DirIterator::~DirIterator()
    164 {
    165 }
    166 
    167 Path* DirIterator::path()
    168 {
    169   if (NULL == m_pParent)
    170     return NULL;
    171   return &m_pEntry->value();
    172 }
    173 
    174 const Path* DirIterator::path() const
    175 {
    176   if (NULL == m_pParent)
    177     return NULL;
    178   return &m_pEntry->value();
    179 }
    180 
    181 DirIterator& DirIterator::operator=(const DirIterator& pCopy)
    182 {
    183   m_pParent = pCopy.m_pParent;
    184   m_Iter = pCopy.m_Iter;
    185   m_pEntry = pCopy.m_pEntry;
    186   return (*this);
    187 }
    188 
    189 DirIterator& DirIterator::operator++()
    190 {
    191   if (0 == m_pParent)
    192     return *this;
    193 
    194   // move forward one step first.
    195   ++m_Iter;
    196 
    197   if (m_pParent->m_Cache.end() == m_Iter) {
    198     if (!m_pParent->m_CacheFull) {
    199       m_pEntry = detail::bring_one_into_cache(*this);
    200       if (0 == m_pEntry && m_pParent->m_CacheFull)
    201         m_pParent = 0;
    202       return *this;
    203     }
    204     m_pParent = 0;
    205     return *this;
    206   }
    207 
    208   m_pEntry = m_Iter.getEntry();
    209   return *this;
    210 }
    211 
    212 DirIterator DirIterator::operator++(int)
    213 {
    214   DirIterator tmp(*this);
    215 
    216   // move forward one step first.
    217   ++m_Iter;
    218 
    219   if (m_pParent->m_Cache.end() == m_Iter) {
    220     if (!m_pParent->m_CacheFull) {
    221       m_pEntry = detail::bring_one_into_cache(*this);
    222       if (0 == m_pEntry && m_pParent->m_CacheFull)
    223         m_pParent = 0;
    224       return tmp;
    225     }
    226     m_pParent = 0;
    227     return tmp;
    228   }
    229 
    230   m_pEntry = m_Iter.getEntry();
    231   return tmp;
    232 }
    233 
    234 bool DirIterator::operator==(const DirIterator& y) const
    235 {
    236   if (m_pParent != y.m_pParent)
    237     return false;
    238   if (0 == m_pParent)
    239     return true;
    240   const Path* x_path = path();
    241   const Path* y_path = y.path();
    242   if (0 == x_path && 0 == y_path)
    243     return true;
    244   if (0 == x_path || 0 == y_path)
    245     return false;
    246   return (*x_path == *y_path);
    247 }
    248 
    249 bool DirIterator::operator!=(const DirIterator& y) const
    250 {
    251   return !this->operator==(y);
    252 }
    253 
    254