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