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 14namespace mcld{ 15namespace sys{ 16namespace fs{ 17 18//===----------------------------------------------------------------------===// 19// mcld::sys::fs::detail 20//===----------------------------------------------------------------------===// 21namespace detail{ 22 23// return the last charactor being handled. 24size_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 122bool not_found_error(int perrno) 123{ 124 return perrno == ENOENT || perrno == ENOTDIR; 125} 126 127void 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 153void 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) 165mcld::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