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 21namespace mcld{ 22namespace sys{ 23namespace fs{ 24 25//===----------------------------------------------------------------------===// 26// mcld::sys::fs::detail 27//===----------------------------------------------------------------------===// 28namespace detail{ 29 30// return the last charactor being handled. 31size_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 129bool not_found_error(int perrno) 130{ 131 return perrno == ENOENT || perrno == ENOTDIR; 132} 133 134void 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 162void 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) 199mcld::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