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