1//===- FileSystem.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 <string> 10#include <sys/types.h> 11#include <sys/stat.h> 12#include <sys/mman.h> 13#include <dirent.h> 14#include <unistd.h> 15#include <fcntl.h> 16#include <mcld/Support/FileHandle.h> 17#include <mcld/Support/Directory.h> 18#include <llvm/Support/ErrorHandling.h> 19 20namespace mcld{ 21namespace sys{ 22namespace fs{ 23namespace detail{ 24 25std::string static_library_extension = ".a"; 26std::string shared_library_extension = ".so"; 27std::string executable_extension = ""; 28std::string relocatable_extension = ".o"; 29std::string assembly_extension = ".s"; 30std::string bitcode_extension = ".bc"; 31 32//===----------------------------------------------------------------------===// 33// Helper Functions 34//===----------------------------------------------------------------------===// 35/// read_dir - return true if we read one entry 36// @return value -1: read error 37// 0: read the end 38// 1: success 39static int read_dir(intptr_t& pDir, std::string& pOutFilename) 40{ 41 errno = 0; 42 dirent *cur_dir = ::readdir(reinterpret_cast<DIR*>(pDir)); 43 if (0 == cur_dir && 0 != errno) 44 return -1; 45 46 // idx does not stay at the end, but all elements had beed put into cache. 47 if (NULL == cur_dir) { 48 return 0; 49 } 50 51 llvm::StringRef name(cur_dir->d_name, strlen(cur_dir->d_name)); 52 if ((name.size() == 1 && name[0] == '.') || 53 (name.size() == 2 && name[0] == '.' && name[1] == '.')) 54 return read_dir(pDir, pOutFilename); 55 56 // find a new directory 57 pOutFilename.append(name.data(), name.size()); 58 return 1; 59} 60 61void open_dir(Directory& pDir) 62{ 63 pDir.m_Handler = reinterpret_cast<intptr_t>(opendir(pDir.path().c_str())); 64 if (0 == pDir.m_Handler) { 65 errno = 0; // opendir() will set errno if it failed to open directory. 66 // set cache is full, then Directory::begin() can return end(). 67 pDir.m_CacheFull = true; 68 return; 69 } 70 // read one entry for advance the end element of the cache. 71 std::string path(pDir.path().native()); 72 switch (read_dir(pDir.m_Handler, path)) { 73 case 1: { 74 // find a new directory 75 bool exist = false; 76 mcld::sys::fs::PathCache::entry_type* entry = pDir.m_Cache.insert(path, exist); 77 if (!exist) 78 entry->setValue(path); 79 return; 80 } 81 case 0: 82 // FIXME: a warning function 83 pDir.m_CacheFull = true; 84 return; 85 default: 86 case -1: 87 llvm::report_fatal_error(std::string("Can't read directory: ")+ 88 pDir.path().native()); 89 } 90} 91 92void close_dir(Directory& pDir) 93{ 94 if (pDir.m_Handler) 95 closedir(reinterpret_cast<DIR *>(pDir.m_Handler)); 96 pDir.m_Handler = 0; 97} 98 99int open(const Path& pPath, int pOFlag) 100{ 101 return ::open(pPath.native().c_str(), pOFlag); 102} 103 104int open(const Path& pPath, int pOFlag, int pPerm) 105{ 106 mode_t perm = 0; 107 if (pPerm & FileHandle::ReadOwner) 108 perm |= S_IRUSR; 109 if (pPerm & FileHandle::WriteOwner) 110 perm |= S_IWUSR; 111 if (pPerm & FileHandle::ExeOwner) 112 perm |= S_IXUSR; 113 if (pPerm & FileHandle::ReadGroup) 114 perm |= S_IRGRP; 115 if (pPerm & FileHandle::WriteGroup) 116 perm |= S_IWGRP; 117 if (pPerm & FileHandle::ExeGroup) 118 perm |= S_IXGRP; 119 if (pPerm & FileHandle::ReadOther) 120 perm |= S_IROTH; 121 if (pPerm & FileHandle::WriteOther) 122 perm |= S_IWOTH; 123 if (pPerm & FileHandle::ExeOther) 124 perm |= S_IXOTH; 125 126 return ::open(pPath.native().c_str(), pOFlag, perm); 127} 128 129ssize_t pread(int pFD, void* pBuf, size_t pCount, off_t pOffset) 130{ 131 return ::pread(pFD, pBuf, pCount, pOffset); 132} 133 134ssize_t pwrite(int pFD, const void* pBuf, size_t pCount, off_t pOffset) 135{ 136 return ::pwrite(pFD, pBuf, pCount, pOffset); 137} 138 139int ftruncate(int pFD, size_t pLength) 140{ 141 return ::ftruncate(pFD, pLength); 142} 143 144void get_pwd(Path& pPWD) 145{ 146 char* pwd = (char*)malloc(PATH_MAX); 147 pPWD.assign(getcwd(pwd, PATH_MAX)); 148 free(pwd); 149} 150 151} // namespace of detail 152} // namespace of fs 153} // namespace of sys 154 155//===----------------------------------------------------------------------===// 156// FileHandler 157//===----------------------------------------------------------------------===// 158bool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength) 159{ 160 if (!isOpened()) { 161 setState(BadBit); 162 return false; 163 } 164 165 if (0 == pLength) 166 return true; 167 168 int prot, flag; 169 if (isReadable() && !isWritable()) { 170 // read-only 171 prot = PROT_READ; 172 flag = MAP_FILE | MAP_PRIVATE; 173 } 174 else if (!isReadable() && isWritable()) { 175 // write-only 176 prot = PROT_WRITE; 177 flag = MAP_FILE | MAP_SHARED; 178 } 179 else if (isReadWrite()) { 180 // read and write 181 prot = PROT_READ | PROT_WRITE; 182 flag = MAP_FILE | MAP_SHARED; 183 } 184 else { 185 // can not read/write 186 setState(BadBit); 187 return false; 188 } 189 190 pMemBuffer = ::mmap(NULL, pLength, prot, flag, m_Handler, pStartOffset); 191 192 if (MAP_FAILED == pMemBuffer) { 193 setState(FailBit); 194 return false; 195 } 196 197 return true; 198} 199 200bool FileHandle::munmap(void* pMemBuffer, size_t pLength) 201{ 202 if (!isOpened()) { 203 setState(BadBit); 204 return false; 205 } 206 207 if (-1 == ::munmap(pMemBuffer, pLength)) { 208 setState(FailBit); 209 return false; 210 } 211 212 return true; 213} 214 215} // namespace of mcld 216 217