| //===- FileSystem.inc -----------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include "mcld/Support/FileHandle.h" |
| #include "mcld/Support/Directory.h" |
| |
| #include <llvm/Support/ErrorHandling.h> |
| |
| #include <string> |
| |
| #include <dirent.h> |
| #include <fcntl.h> |
| #include <limits.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/mman.h> |
| #include <unistd.h> |
| |
| namespace mcld { |
| namespace sys { |
| namespace fs { |
| namespace detail { |
| |
| std::string static_library_extension = ".a"; |
| std::string shared_library_extension = ".so"; |
| std::string executable_extension = ""; |
| std::string relocatable_extension = ".o"; |
| std::string assembly_extension = ".s"; |
| std::string bitcode_extension = ".bc"; |
| |
| //===----------------------------------------------------------------------===// |
| // Helper Functions |
| //===----------------------------------------------------------------------===// |
| /// read_dir - return true if we read one entry |
| // @return value -1: read error |
| // 0: read the end |
| // 1: success |
| static int read_dir(intptr_t& pDir, std::string& pOutFilename) { |
| errno = 0; |
| dirent* cur_dir = ::readdir(reinterpret_cast<DIR*>(pDir)); |
| if (0 == cur_dir && 0 != errno) |
| return -1; |
| |
| // idx does not stay at the end, but all elements had beed put into cache. |
| if (NULL == cur_dir) { |
| return 0; |
| } |
| |
| llvm::StringRef name(cur_dir->d_name, strlen(cur_dir->d_name)); |
| if ((name.size() == 1 && name[0] == '.') || |
| (name.size() == 2 && name[0] == '.' && name[1] == '.')) |
| return read_dir(pDir, pOutFilename); |
| |
| // find a new directory |
| pOutFilename.append(name.data(), name.size()); |
| return 1; |
| } |
| |
| void open_dir(Directory& pDir) { |
| pDir.m_Handler = reinterpret_cast<intptr_t>(opendir(pDir.path().c_str())); |
| if (0 == pDir.m_Handler) { |
| errno = 0; // opendir() will set errno if it failed to open directory. |
| // set cache is full, then Directory::begin() can return end(). |
| pDir.m_CacheFull = true; |
| return; |
| } |
| // read one entry for advance the end element of the cache. |
| std::string path(pDir.path().native()); |
| switch (read_dir(pDir.m_Handler, path)) { |
| case 1: { |
| // find a new directory |
| bool exist = false; |
| mcld::sys::fs::PathCache::entry_type* entry = |
| pDir.m_Cache.insert(path, exist); |
| if (!exist) |
| entry->setValue(sys::fs::Path(path)); |
| return; |
| } |
| case 0: |
| // FIXME: a warning function |
| pDir.m_CacheFull = true; |
| return; |
| default: |
| case -1: |
| llvm::report_fatal_error(std::string("Can't read directory: ") + |
| pDir.path().native()); |
| } |
| } |
| |
| void close_dir(Directory& pDir) { |
| if (pDir.m_Handler) |
| closedir(reinterpret_cast<DIR*>(pDir.m_Handler)); |
| pDir.m_Handler = 0; |
| } |
| |
| int open(const Path& pPath, int pOFlag) { |
| return ::open(pPath.native().c_str(), pOFlag); |
| } |
| |
| int open(const Path& pPath, int pOFlag, int pPerm) { |
| mode_t perm = 0; |
| if (pPerm & FileHandle::ReadOwner) |
| perm |= S_IRUSR; |
| if (pPerm & FileHandle::WriteOwner) |
| perm |= S_IWUSR; |
| if (pPerm & FileHandle::ExeOwner) |
| perm |= S_IXUSR; |
| if (pPerm & FileHandle::ReadGroup) |
| perm |= S_IRGRP; |
| if (pPerm & FileHandle::WriteGroup) |
| perm |= S_IWGRP; |
| if (pPerm & FileHandle::ExeGroup) |
| perm |= S_IXGRP; |
| if (pPerm & FileHandle::ReadOther) |
| perm |= S_IROTH; |
| if (pPerm & FileHandle::WriteOther) |
| perm |= S_IWOTH; |
| if (pPerm & FileHandle::ExeOther) |
| perm |= S_IXOTH; |
| |
| return ::open(pPath.native().c_str(), pOFlag, perm); |
| } |
| |
| ssize_t pread(int pFD, void* pBuf, size_t pCount, off_t pOffset) { |
| return ::pread(pFD, pBuf, pCount, pOffset); |
| } |
| |
| ssize_t pwrite(int pFD, const void* pBuf, size_t pCount, off_t pOffset) { |
| return ::pwrite(pFD, pBuf, pCount, pOffset); |
| } |
| |
| int ftruncate(int pFD, size_t pLength) { |
| return ::ftruncate(pFD, pLength); |
| } |
| |
| void get_pwd(Path& pPWD) { |
| char* pwd = (char*)malloc(PATH_MAX); |
| pPWD.assign(getcwd(pwd, PATH_MAX)); |
| free(pwd); |
| } |
| |
| } // namespace detail |
| } // namespace fs |
| } // namespace sys |
| |
| //===----------------------------------------------------------------------===// |
| // FileHandler |
| //===----------------------------------------------------------------------===// |
| bool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength) { |
| if (!isOpened()) { |
| setState(BadBit); |
| return false; |
| } |
| |
| if (0 == pLength) |
| return true; |
| |
| int prot, flag; |
| if (isReadable() && !isWritable()) { |
| // read-only |
| prot = PROT_READ; |
| flag = MAP_FILE | MAP_PRIVATE; |
| } else if (!isReadable() && isWritable()) { |
| // write-only |
| prot = PROT_WRITE; |
| flag = MAP_FILE | MAP_SHARED; |
| } else if (isReadWrite()) { |
| // read and write |
| prot = PROT_READ | PROT_WRITE; |
| flag = MAP_FILE | MAP_SHARED; |
| } else { |
| // can not read/write |
| setState(BadBit); |
| return false; |
| } |
| |
| pMemBuffer = ::mmap(NULL, pLength, prot, flag, m_Handler, pStartOffset); |
| |
| if (MAP_FAILED == pMemBuffer) { |
| setState(FailBit); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool FileHandle::munmap(void* pMemBuffer, size_t pLength) { |
| if (!isOpened()) { |
| setState(BadBit); |
| return false; |
| } |
| |
| if (-1 == ::munmap(pMemBuffer, pLength)) { |
| setState(FailBit); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| } // namespace mcld |