Home | History | Annotate | Download | only in Unix
      1 //===- PathV3.inc ---------------------------------------------------------===//
      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/Path.h>
     10 #include <mcld/Support/FileSystem.h>
     11 #include <llvm/Support/ErrorHandling.h>
     12 
     13 #include <cerrno>
     14 #include <stdio.h>
     15 #include <sys/stat.h>
     16 #include <sys/types.h>
     17 #include <string>
     18 #include <stack>
     19 #include <unistd.h>
     20 
     21 namespace mcld{
     22 namespace sys{
     23 namespace fs{
     24 
     25 //===----------------------------------------------------------------------===//
     26 // mcld::sys::fs::detail
     27 //===----------------------------------------------------------------------===//
     28 namespace detail{
     29 
     30 // return the last charactor being handled.
     31 size_t canonicalize(std::string& pathname)
     32 {
     33   // Variable Index //
     34   // SepTable - stack of result separators
     35   // LR(1) Algorithm //
     36   // traverse pPathName
     37   //   if we meet '//', '///', '////', ...
     38   //     -> ignore it
     39   //     -> push current into stack
     40   //     -> jump to the next not '/'
     41   //   if we meet '/./'
     42   //     -> ignore
     43   //     -> jump to the next not '/'
     44   //   if we meet '/../'
     45   //     -> pop previous position of '/' P
     46   //     -> erase P+1 to now
     47   //   if we meet other else
     48   //     -> go go go
     49   //   if we meet '/.../', '/..../', ... -> illegal
     50   if (pathname.empty())
     51     return 0;
     52 
     53   size_t handler = 0;
     54   std::stack<size_t> slash_stack;
     55   slash_stack.push(-1);
     56   while (handler < pathname.size()) {
     57     if (separator == pathname[handler]) { // handler = 1st '/'
     58       size_t next = handler + 1;
     59       if (next >= pathname.size())
     60         return handler;
     61       switch(pathname[next]) { // next = handler + 1;
     62         case separator: { // '//'
     63           while (next < pathname.size() && separator == pathname[next])
     64             ++next;
     65           // next is the last not '/'
     66           pathname.erase(handler, next - handler - 1);
     67           // handler is the first '/'
     68           slash_stack.push(handler);
     69           break;
     70         }
     71         case '.': { // '/.'
     72           ++next; // next = handler + 2
     73           if (next >= pathname.size()) // '/.'
     74             return handler;
     75           switch (pathname[next]) {
     76             case separator: { // '/./'
     77               pathname.erase(handler, 2);
     78               break;
     79             }
     80             case '.': { // '/..'
     81               ++next; // next = handler + 3;
     82               if (next >= pathname.size()) // '/..?'
     83                 return handler;
     84               switch(pathname[next]) {
     85                 case separator: { // '/../'
     86                   handler = slash_stack.top();
     87                   slash_stack.pop();
     88                   pathname.erase(handler+1, next-handler);
     89                   if (static_cast<size_t>(-1) == handler) {
     90                     slash_stack.push(-1);
     91                     handler = pathname.find_first_of(separator, handler);
     92                   }
     93                   break;
     94                 }
     95                 case '.': { // '/...', illegal
     96                   return handler;
     97                   break;
     98                 }
     99                 default : { // '/..a'
    100                   slash_stack.push(handler);
    101                   handler = pathname.find_first_of(separator, handler+3);
    102                   break;
    103                 }
    104               }
    105               break;
    106             }
    107             default : { // '/.a'
    108               slash_stack.push(handler);
    109               handler = pathname.find_first_of(separator, handler+2);
    110               break;
    111             }
    112           }
    113           break;
    114         }
    115         default : { // '/a
    116           slash_stack.push(handler);
    117           handler = pathname.find_first_of(separator, handler+1);
    118           break;
    119         }
    120       }
    121     }
    122     else {
    123       handler = pathname.find_first_of(separator, handler);
    124     }
    125   }
    126   return handler;
    127 }
    128 
    129 bool not_found_error(int perrno)
    130 {
    131   return perrno == ENOENT || perrno == ENOTDIR;
    132 }
    133 
    134 void status(const Path& p, FileStatus& pFileStatus)
    135 {
    136   struct stat path_stat;
    137   if(stat(p.c_str(), &path_stat)!= 0)
    138   {
    139     if(not_found_error(errno))
    140     {
    141       pFileStatus.setType(FileNotFound);
    142     }
    143     else
    144       pFileStatus.setType(StatusError);
    145   }
    146   else if(S_ISDIR(path_stat.st_mode))
    147     pFileStatus.setType(DirectoryFile);
    148   else if(S_ISREG(path_stat.st_mode))
    149     pFileStatus.setType(RegularFile);
    150   else if(S_ISBLK(path_stat.st_mode))
    151     pFileStatus.setType(BlockFile);
    152   else if(S_ISCHR(path_stat.st_mode))
    153     pFileStatus.setType(CharacterFile);
    154   else if(S_ISFIFO(path_stat.st_mode))
    155     pFileStatus.setType(FifoFile);
    156   else if(S_ISSOCK(path_stat.st_mode))
    157     pFileStatus.setType(SocketFile);
    158   else
    159     pFileStatus.setType(TypeUnknown);
    160 }
    161 
    162 void symlink_status(const Path& p, FileStatus& pFileStatus)
    163 {
    164   struct stat path_stat;
    165   if(lstat(p.c_str(), &path_stat)!= 0)
    166   {
    167     if(errno == ENOENT || errno == ENOTDIR) // these are not errors
    168     {
    169       pFileStatus.setType(FileNotFound);
    170     }
    171     else
    172       pFileStatus.setType(StatusError);
    173   }
    174   if(S_ISREG(path_stat.st_mode))
    175     pFileStatus.setType(RegularFile);
    176   if(S_ISDIR(path_stat.st_mode))
    177     pFileStatus.setType(DirectoryFile);
    178   if(S_ISLNK(path_stat.st_mode))
    179     pFileStatus.setType(SymlinkFile);
    180   if(S_ISBLK(path_stat.st_mode))
    181     pFileStatus.setType(BlockFile);
    182   if(S_ISCHR(path_stat.st_mode))
    183     pFileStatus.setType(CharacterFile);
    184   if(S_ISFIFO(path_stat.st_mode))
    185     pFileStatus.setType(FifoFile);
    186   if(S_ISSOCK(path_stat.st_mode))
    187     pFileStatus.setType(SocketFile);
    188   else
    189     pFileStatus.setType(TypeUnknown);
    190 }
    191 
    192 /// directory_iterator_increment - increment function implementation
    193 //
    194 //  iterator will call this function in two situations:
    195 //  1. All elements have been put into cache, and iterator stays at the end
    196 //     of cache. (a real end)
    197 //  2. Some but not all elements had been put into cache, and we stoped.
    198 //     An iterator now is staying at the end of cache. (a temporal end)
    199 mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter)
    200 {
    201   mcld::sys::fs::PathCache::entry_type* entry = 0;
    202   std::string path(pIter.m_pParent->m_Path.native());
    203   switch (read_dir(pIter.m_pParent->m_Handler, path)) {
    204   case 1: {
    205     // read one
    206     bool exist = false;
    207     entry = pIter.m_pParent->m_Cache.insert(path, exist);
    208     if (!exist)
    209       entry->setValue(path);
    210     break;
    211   }
    212   case 0:// meet real end
    213     pIter.m_pParent->m_CacheFull = true;
    214     break;
    215   default:
    216   case -1:
    217     llvm::report_fatal_error(std::string("Can't read directory: ")+
    218                              pIter.m_pParent->path().native());
    219     break;
    220   }
    221   return entry;
    222 }
    223 
    224 } // namespace of detail
    225 } // namespace of fs
    226 } // namespace of sys
    227 } // namespace of mcld
    228 
    229