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