Home | History | Annotate | Download | only in Unix
      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 
     24 namespace mcld {
     25 namespace sys {
     26 namespace fs {
     27 namespace detail {
     28 
     29 std::string static_library_extension = ".a";
     30 std::string shared_library_extension = ".so";
     31 std::string executable_extension = "";
     32 std::string relocatable_extension = ".o";
     33 std::string assembly_extension = ".s";
     34 std::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
     43 static 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 
     64 void 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 
     95 void close_dir(Directory& pDir) {
     96   if (pDir.m_Handler)
     97     closedir(reinterpret_cast<DIR*>(pDir.m_Handler));
     98   pDir.m_Handler = 0;
     99 }
    100 
    101 int open(const Path& pPath, int pOFlag) {
    102   return ::open(pPath.native().c_str(), pOFlag);
    103 }
    104 
    105 int 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 
    129 ssize_t pread(int pFD, void* pBuf, size_t pCount, off_t pOffset) {
    130   return ::pread(pFD, pBuf, pCount, pOffset);
    131 }
    132 
    133 ssize_t pwrite(int pFD, const void* pBuf, size_t pCount, off_t pOffset) {
    134   return ::pwrite(pFD, pBuf, pCount, pOffset);
    135 }
    136 
    137 int ftruncate(int pFD, size_t pLength) {
    138   return ::ftruncate(pFD, pLength);
    139 }
    140 
    141 void 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 //===----------------------------------------------------------------------===//
    154 bool 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 
    192 bool 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