C++程序  |  330行  |  6.31 KB

//===- FileHandle.cpp -----------------------------------------------------===//
//
//                     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/FileSystem.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>

using namespace mcld;

//===----------------------------------------------------------------------===//
// FileHandle
FileHandle::FileHandle()
  : m_Path(),
    m_Handler(-1),
    m_Size(0),
    m_State(GoodBit),
    m_OpenMode(NotOpen) {
}

FileHandle::~FileHandle()
{
  if (isOpened())
    close();
}

inline static int oflag(FileHandle::OpenMode pMode)
{
  int result = 0x0;
  if (FileHandle::Unknown == pMode)
    return result;

  if (FileHandle::ReadWrite == (pMode & FileHandle::ReadWrite))
    result |= O_RDWR;
  else if (pMode & FileHandle::ReadOnly)
    result |= O_RDONLY;
  else if (pMode & FileHandle::WriteOnly)
    result |= O_WRONLY;

  if (pMode & FileHandle::Append)
    result |= O_APPEND;

  if (pMode & FileHandle::Create)
    result |= O_CREAT;

  if (pMode & FileHandle::Truncate)
    result |= O_TRUNC;

  return result;
}

inline static bool get_size(int pHandler, unsigned int &pSize)
{
  struct ::stat file_stat;
  if (-1 == ::fstat(pHandler, &file_stat)) {
    pSize = 0;
    return false;
  }
  pSize = file_stat.st_size;
  return true;
}

bool FileHandle::open(const sys::fs::Path& pPath,
                      FileHandle::OpenMode pMode)
{
  if (isOpened() || Unknown == pMode) {
    setState(BadBit);
    return false;
  }

  m_OpenMode = pMode;
  m_Handler = ::open(pPath.native().c_str(), oflag(pMode));
  m_Path = pPath;
  if (-1 == m_Handler) {
    m_OpenMode = NotOpen;
    setState(FailBit);
    return false;
  }

  if (!get_size(m_Handler, m_Size)) {
    setState(FailBit);
    return false;
  }

  return true;
}

bool FileHandle::open(const sys::fs::Path& pPath,
                      FileHandle::OpenMode pMode,
                      FileHandle::Permission pPerm)
{
  if (isOpened() || Unknown == pMode) {
    setState(BadBit);
    return false;
  }

  m_OpenMode = pMode;
  m_Handler = sys::fs::detail::open(pPath, oflag(pMode), (int)pPerm);
  m_Path = pPath;
  if (-1 == m_Handler) {
    m_OpenMode = NotOpen;
    setState(FailBit);
    return false;
  }

  if (!get_size(m_Handler, m_Size)) {
    setState(FailBit);
    return false;
  }

  return true;
}

bool FileHandle::delegate(int pFD, FileHandle::OpenMode pMode)
{
  if (isOpened()) {
    setState(BadBit);
    return false;
  }

  m_Handler = pFD;
  m_OpenMode = pMode;
  m_State = GoodBit;

  if (!get_size(m_Handler, m_Size)) {
    setState(FailBit);
    return false;
  }

  return true;
}

bool FileHandle::close()
{
  if (!isOpened()) {
    setState(BadBit);
    return false;
  }

  if (-1 == ::close(m_Handler)) {
    setState(FailBit);
    return false;
  }

  m_Path.native().clear();
  m_Size = 0;
  m_OpenMode = NotOpen;
  cleanState();
  return true;
}

bool FileHandle::truncate(size_t pSize)
{
  if (!isOpened() || !isWritable()) {
    setState(BadBit);
    return false;
  }

  if (-1 == sys::fs::detail::ftruncate(m_Handler, pSize)) {
    setState(FailBit);
    return false;
  }

  m_Size = pSize;
  return true;
}

bool FileHandle::read(void* pMemBuffer, size_t pStartOffset, size_t pLength)
{
  if (!isOpened() || !isReadable()) {
    setState(BadBit);
    return false;
  }

  if (0 == pLength)
    return true;

  ssize_t read_bytes = sys::fs::detail::pread(m_Handler,
                                              pMemBuffer,
                                              pLength,
                                              pStartOffset);

  if (-1 == read_bytes) {
    setState(FailBit);
    return false;
  }

  return true;
}

bool FileHandle::write(const void* pMemBuffer, size_t pStartOffset, size_t pLength)
{
  if (!isOpened() || !isWritable()) {
    setState(BadBit);
    return false;
  }

  if (0 == pLength)
    return true;


  ssize_t write_bytes = sys::fs::detail::pwrite(m_Handler,
                                                pMemBuffer,
                                                pLength,
                                                pStartOffset);

  if (-1 == write_bytes) {
    setState(FailBit);
    return false;
  }

  return true;
}

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;
}

void FileHandle::setState(FileHandle::IOState pState)
{
  m_State |= pState;
}

void FileHandle::cleanState(FileHandle::IOState pState)
{
  m_State = pState;
}

bool FileHandle::isOpened() const
{
  if (-1 != m_Handler && m_OpenMode != NotOpen && isGood())
    return true;

  return false;
}

// Assume Unknown OpenMode is readable
bool FileHandle::isReadable() const
{
  return (m_OpenMode & ReadOnly);
}

// Assume Unknown OpenMode is writable
bool FileHandle::isWritable() const
{
  return (m_OpenMode & WriteOnly);
}

// Assume Unknown OpenMode is both readable and writable
bool FileHandle::isReadWrite() const
{
  return (FileHandle::ReadWrite == (m_OpenMode & FileHandle::ReadWrite));
}

bool FileHandle::isGood() const
{
  return !(m_State & (BadBit | FailBit));
}

bool FileHandle::isBad() const
{
  return (m_State & BadBit);
}

bool FileHandle::isFailed() const
{
  return (m_State & (BadBit | FailBit));
}