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/FileSystem.h" 10#include "mcld/Support/Path.h" 11 12#include <llvm/Support/ErrorHandling.h> 13 14#include <cerrno> 15#include <stack> 16#include <stdio.h> 17#include <string> 18#include <sys/stat.h> 19#include <sys/types.h> 20#include <unistd.h> 21 22namespace mcld { 23namespace sys { 24namespace fs { 25 26//===----------------------------------------------------------------------===// 27// mcld::sys::fs::detail 28//===----------------------------------------------------------------------===// 29namespace detail { 30 31// return the last charactor being handled. 32size_t canonicalize(std::string& pathname) { 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 } else { 122 handler = pathname.find_first_of(separator, handler); 123 } 124 } 125 return handler; 126} 127 128bool not_found_error(int perrno) { 129 return perrno == ENOENT || perrno == ENOTDIR; 130} 131 132void status(const Path& p, FileStatus& pFileStatus) { 133 struct stat path_stat; 134 if (stat(p.c_str(), &path_stat) != 0) { 135 if (not_found_error(errno)) { 136 pFileStatus.setType(FileNotFound); 137 } else 138 pFileStatus.setType(StatusError); 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 if (S_ISSOCK(path_stat.st_mode)) 150 pFileStatus.setType(SocketFile); 151 else 152 pFileStatus.setType(TypeUnknown); 153} 154 155void symlink_status(const Path& p, FileStatus& pFileStatus) { 156 struct stat path_stat; 157 if (lstat(p.c_str(), &path_stat) != 0) { 158 if (errno == ENOENT || errno == ENOTDIR) // these are not errors 159 { 160 pFileStatus.setType(FileNotFound); 161 } else 162 pFileStatus.setType(StatusError); 163 } 164 if (S_ISREG(path_stat.st_mode)) 165 pFileStatus.setType(RegularFile); 166 if (S_ISDIR(path_stat.st_mode)) 167 pFileStatus.setType(DirectoryFile); 168 if (S_ISLNK(path_stat.st_mode)) 169 pFileStatus.setType(SymlinkFile); 170 if (S_ISBLK(path_stat.st_mode)) 171 pFileStatus.setType(BlockFile); 172 if (S_ISCHR(path_stat.st_mode)) 173 pFileStatus.setType(CharacterFile); 174 if (S_ISFIFO(path_stat.st_mode)) 175 pFileStatus.setType(FifoFile); 176 if (S_ISSOCK(path_stat.st_mode)) 177 pFileStatus.setType(SocketFile); 178 else 179 pFileStatus.setType(TypeUnknown); 180} 181 182/// directory_iterator_increment - increment function implementation 183// 184// iterator will call this function in two situations: 185// 1. All elements have been put into cache, and iterator stays at the end 186// of cache. (a real end) 187// 2. Some but not all elements had been put into cache, and we stoped. 188// An iterator now is staying at the end of cache. (a temporal end) 189mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter) { 190 mcld::sys::fs::PathCache::entry_type* entry = 0; 191 std::string path(pIter.m_pParent->m_Path.native()); 192 switch (read_dir(pIter.m_pParent->m_Handler, path)) { 193 case 1: { 194 // read one 195 bool exist = false; 196 entry = pIter.m_pParent->m_Cache.insert(path, exist); 197 if (!exist) 198 entry->setValue(sys::fs::Path(path)); 199 break; 200 } 201 case 0: // meet real end 202 pIter.m_pParent->m_CacheFull = true; 203 break; 204 default: 205 case -1: 206 llvm::report_fatal_error(std::string("Can't read directory: ") + 207 pIter.m_pParent->path().native()); 208 break; 209 } 210 return entry; 211} 212 213} // namespace detail 214} // namespace fs 215} // namespace sys 216} // namespace mcld 217