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