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