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