http://stxxl.sourceforge.net
<dementiev@mpi-sb.mpg.de>
<sni4ok@yandex.ru>
<beckmann@cs.uni-frankfurt.de>
<singler@ira.uka.de>
<tb@panthema.net>
http://www.boost.org/LICENSE_1_0.txt
#include <stxxl/bits/common/error_handling.h>
#include <stxxl/bits/common/exceptions.h>
#include <stxxl/bits/config.h>
#include <stxxl/bits/io/file.h>
#include <stxxl/bits/io/ufs_file_base.h>
#include <stxxl/bits/verbose.h>
#include "ufs_platform.h"
STXXL_BEGIN_NAMESPACE
const char* ufs_file_base::io_type() const
{
return "ufs_base";
}
ufs_file_base::ufs_file_base(
const std::string& filename,
int mode) : file_des(-1), m_mode(mode), filename(filename)
{
int flags = 0;
if (mode & RDONLY)
{
flags |= O_RDONLY;
}
if (mode & WRONLY)
{
flags |= O_WRONLY;
}
if (mode & RDWR)
{
flags |= O_RDWR;
}
if (mode & CREAT)
{
flags |= O_CREAT;
}
if (mode & TRUNC)
{
flags |= O_TRUNC;
}
if ((mode & DIRECT) || (mode & REQUIRE_DIRECT))
{
#ifdef __APPLE__
#elif !STXXL_DIRECT_IO_OFF
flags |= O_DIRECT;
#else
if (mode & REQUIRE_DIRECT) {
STXXL_ERRMSG("Error: open()ing " << filename << " with DIRECT mode required, but the system does not support it.");
file_des = -1;
return;
}
else {
STXXL_MSG("Warning: open()ing " << filename << " without DIRECT mode, as the system does not support it.");
}
#endif
}
if (mode & SYNC)
{
flags |= O_RSYNC;
flags |= O_DSYNC;
flags |= O_SYNC;
}
#if STXXL_WINDOWS
flags |= O_BINARY;
#endif
#if STXXL_WINDOWS || defined(__MINGW32__)
const int perms = S_IREAD | S_IWRITE;
#else
const int perms = S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP;
#endif
if ((file_des = ::open(filename.c_str(), flags, perms)) >= 0)
{
_after_open();
return;
}
#if !STXXL_DIRECT_IO_OFF
if ((mode & DIRECT) && !(mode & REQUIRE_DIRECT) && errno == EINVAL)
{
STXXL_MSG("open() error on path=" << filename << " flags=" << flags << ", retrying without O_DIRECT.");
flags &= ~O_DIRECT;
m_mode &= ~DIRECT;
if ((file_des = ::open(filename.c_str(), flags, perms)) >= 0)
{
_after_open();
return;
}
}
#endif
STXXL_THROW_ERRNO(io_error, "open() rc=" << file_des << " path=" << filename << " flags=" << flags);
}
ufs_file_base::~ufs_file_base()
{
close();
}
void ufs_file_base::_after_open()
{
#if STXXL_WINDOWS || defined(__MINGW32__)
struct _stat64 st;
STXXL_THROW_ERRNO_NE_0(::_fstat64(file_des, &st), io_error,
"_fstat64() path=" << filename << " fd=" << file_des);
#else
struct stat st;
STXXL_THROW_ERRNO_NE_0(::fstat(file_des, &st), io_error,
"fstat() path=" << filename << " fd=" << file_des);
#endif
m_is_device = S_ISBLK(st.st_mode) ? true : false;
#ifdef __APPLE__
if (m_mode & REQUIRE_DIRECT) {
STXXL_THROW_ERRNO_NE_0(fcntl(file_des, F_NOCACHE, 1), io_error,
"fcntl() path=" << filename << " fd=" << file_des);
STXXL_THROW_ERRNO_NE_0(fcntl(file_des, F_RDAHEAD, 0), io_error,
"fcntl() path=" << filename << " fd=" << file_des);
}
else if (m_mode & DIRECT) {
if (fcntl(file_des, F_NOCACHE, 1) != 0) {
STXXL_MSG("fcntl(fd,F_NOCACHE,1) failed on path=" << filename <<
" fd=" << file_des << " : " << strerror(errno));
}
if (fcntl(file_des, F_RDAHEAD, 0) != 0) {
STXXL_MSG("fcntl(fd,F_RDAHEAD,0) failed on path=" << filename <<
" fd=" << file_des << " : " << strerror(errno));
}
}
#endif
if (!(m_mode & NO_LOCK))
lock();
}
void ufs_file_base::close()
{
scoped_mutex_lock fd_lock(fd_mutex);
if (file_des == -1)
return;
if (::close(file_des) < 0)
STXXL_THROW_ERRNO(io_error, "close() fd=" << file_des);
file_des = -1;
}
void ufs_file_base::lock()
{
#if STXXL_WINDOWS || defined(__MINGW32__)
#else
scoped_mutex_lock fd_lock(fd_mutex);
struct flock lock_struct;
lock_struct.l_type = (m_mode & RDONLY) ? F_RDLCK : F_RDLCK | F_WRLCK;
lock_struct.l_whence = SEEK_SET;
lock_struct.l_start = 0;
lock_struct.l_len = 0;
if ((::fcntl(file_des, F_SETLK, &lock_struct)) < 0)
STXXL_THROW_ERRNO(io_error, "fcntl(,F_SETLK,) path=" << filename << " fd=" << file_des);
#endif
}
file::offset_type ufs_file_base::_size()
{
off_t rc = ::lseek(file_des, 0, SEEK_END);
if (rc < 0)
STXXL_THROW_ERRNO(io_error, "lseek(fd,0,SEEK_END) path=" << filename << " fd=" << file_des);
return rc;
}
file::offset_type ufs_file_base::size()
{
scoped_mutex_lock fd_lock(fd_mutex);
return _size();
}
void ufs_file_base::set_size(offset_type newsize)
{
scoped_mutex_lock fd_lock(fd_mutex);
return _set_size(newsize);
}
void ufs_file_base::_set_size(offset_type newsize)
{
offset_type cur_size = _size();
if (!(m_mode & RDONLY) && !m_is_device)
{
#if STXXL_WINDOWS || defined(__MINGW32__)
HANDLE hfile = (HANDLE) ::_get_osfhandle(file_des);
STXXL_THROW_ERRNO_NE_0((hfile == INVALID_HANDLE_VALUE), io_error,
"_get_osfhandle() path=" << filename << " fd=" << file_des);
LARGE_INTEGER desired_pos;
desired_pos.QuadPart = newsize;
if (!SetFilePointerEx(hfile, desired_pos, NULL, FILE_BEGIN))
STXXL_THROW_WIN_LASTERROR(io_error,
"SetFilePointerEx in ufs_file_base::set_size(..) oldsize=" << cur_size <<
" newsize=" << newsize << " ");
if (!SetEndOfFile(hfile))
STXXL_THROW_WIN_LASTERROR(io_error,
"SetEndOfFile oldsize=" << cur_size <<
" newsize=" << newsize << " ");
#else
STXXL_THROW_ERRNO_NE_0(::ftruncate(file_des, newsize), io_error,
"ftruncate() path=" << filename << " fd=" << file_des);
#endif
}
#if !STXXL_WINDOWS
if (newsize > cur_size)
STXXL_THROW_ERRNO_LT_0(::lseek(file_des, newsize - 1, SEEK_SET), io_error,
"lseek() path=" << filename << " fd=" << file_des << " pos=" << newsize - 1);
#endif
}
void ufs_file_base::close_remove()
{
close();
if (m_is_device) {
STXXL_ERRMSG("remove() path=" << filename << " skipped as file is device node");
return;
}
if (::remove(filename.c_str()) != 0)
STXXL_ERRMSG("remove() error on path=" << filename << " error=" << strerror(errno));
}
void ufs_file_base::unlink()
{
if (m_is_device) {
STXXL_ERRMSG("unlink() path=" << filename << " skipped as file is device node");
return;
}
if (::unlink(filename.c_str()) != 0)
STXXL_THROW_ERRNO(io_error, "unlink() path=" << filename << " fd=" << file_des);
}
bool ufs_file_base::is_device() const
{
return m_is_device;
}
STXXL_END_NAMESPACE