207 lines
5.4 KiB
C++
207 lines
5.4 KiB
C++
//===- 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
|