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