http://stxxl.sourceforge.net
<dementiev@ira.uka.de>
<beckmann@cs.uni-frankfurt.de>
<singler@kit.edu>
http://www.boost.org/LICENSE_1_0.txt
#include <stxxl/bits/io/wfs_file_base.h>
#include <stxxl/bits/common/error_handling.h>
#if STXXL_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
STXXL_BEGIN_NAMESPACE
const char* wfs_file_base::io_type() const
{
return "wfs_base";
}
static HANDLE open_file_impl(const std::string& filename, int mode)
{
DWORD dwDesiredAccess = 0;
DWORD dwShareMode = 0;
DWORD dwCreationDisposition = 0;
DWORD dwFlagsAndAttributes = 0;
if (mode & file::RDONLY)
{
dwFlagsAndAttributes |= FILE_ATTRIBUTE_READONLY;
dwDesiredAccess |= GENERIC_READ;
}
if (mode & file::WRONLY)
{
dwDesiredAccess |= GENERIC_WRITE;
}
if (mode & file::RDWR)
{
dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE);
}
if (mode & file::CREAT)
{
}
if (mode & file::TRUNC)
{
dwCreationDisposition |= TRUNCATE_EXISTING;
}
else
{
dwCreationDisposition |= OPEN_ALWAYS;
}
if (mode & file::DIRECT)
{
#if !STXXL_DIRECT_IO_OFF
dwFlagsAndAttributes |= FILE_FLAG_NO_BUFFERING;
#else
if (mode & file::REQUIRE_DIRECT) {
STXXL_ERRMSG("Error: open()ing " << filename << " with DIRECT mode required, but the system does not support it.");
file_des = INVALID_HANDLE_VALUE;
return;
}
else {
STXXL_MSG("Warning: open()ing " << filename << " without DIRECT mode, as the system does not support it.");
}
#endif
}
if (mode & file::SYNC)
{
}
HANDLE file_des = ::CreateFile(filename.c_str(), dwDesiredAccess, dwShareMode, NULL,
dwCreationDisposition, dwFlagsAndAttributes, NULL);
if (file_des != INVALID_HANDLE_VALUE)
return file_des;
#if !STXXL_DIRECT_IO_OFF
if ((mode& file::DIRECT) && !(mode & file::REQUIRE_DIRECT))
{
STXXL_MSG("CreateFile() error on path=" << filename << " mode=" << mode << ", retrying without DIRECT mode.");
dwFlagsAndAttributes &= ~FILE_FLAG_NO_BUFFERING;
HANDLE file_des = ::CreateFile(filename.c_str(), dwDesiredAccess, dwShareMode, NULL,
dwCreationDisposition, dwFlagsAndAttributes, NULL);
if (file_des != INVALID_HANDLE_VALUE)
return file_des;
}
#endif
STXXL_THROW_WIN_LASTERROR(io_error, "CreateFile() path=" << filename << " mode=" << mode);
}
wfs_file_base::wfs_file_base(
const std::string& filename,
int mode) : file_des(INVALID_HANDLE_VALUE), mode_(mode), filename(filename), locked(false)
{
file_des = open_file_impl(filename, mode);
if (!(mode & NO_LOCK))
{
lock();
}
if (!(mode_ & RDONLY) && (mode & DIRECT))
{
char buf[32768], * part;
if (!GetFullPathName(filename.c_str(), sizeof(buf), buf, &part))
{
STXXL_ERRMSG("wfs_file_base::wfs_file_base(): GetFullPathName() error for file " << filename);
bytes_per_sector = 512;
}
else
{
part[0] = char();
DWORD bytes_per_sector_;
if (!GetDiskFreeSpace(buf, NULL, &bytes_per_sector_, NULL, NULL))
{
STXXL_ERRMSG("wfs_file_base::wfs_file_base(): GetDiskFreeSpace() error for path " << buf);
bytes_per_sector = 512;
}
else
bytes_per_sector = bytes_per_sector_;
}
}
}
wfs_file_base::~wfs_file_base()
{
close();
}
void wfs_file_base::close()
{
scoped_mutex_lock fd_lock(fd_mutex);
if (file_des == INVALID_HANDLE_VALUE)
return;
if (!CloseHandle(file_des))
STXXL_THROW_WIN_LASTERROR(io_error, "CloseHandle() of file fd=" << file_des);
file_des = INVALID_HANDLE_VALUE;
}
void wfs_file_base::lock()
{
scoped_mutex_lock fd_lock(fd_mutex);
if (locked)
return;
if (LockFile(file_des, 0, 0, 0xffffffff, 0xffffffff) == 0)
STXXL_THROW_WIN_LASTERROR(io_error, "LockFile() fd=" << file_des);
locked = true;
}
file::offset_type wfs_file_base::_size()
{
LARGE_INTEGER result;
if (!GetFileSizeEx(file_des, &result))
STXXL_THROW_WIN_LASTERROR(io_error, "GetFileSizeEx() fd=" << file_des);
return result.QuadPart;
}
file::offset_type wfs_file_base::size()
{
scoped_mutex_lock fd_lock(fd_mutex);
return _size();
}
void wfs_file_base::set_size(offset_type newsize)
{
scoped_mutex_lock fd_lock(fd_mutex);
offset_type cur_size = _size();
if (!(mode_ & RDONLY))
{
LARGE_INTEGER desired_pos;
desired_pos.QuadPart = newsize;
bool direct_with_bad_size = (mode_& file::DIRECT) && (newsize % bytes_per_sector);
if (direct_with_bad_size)
{
if (!CloseHandle(file_des))
STXXL_THROW_WIN_LASTERROR(io_error, "closing file (call of ::CloseHandle() from set_size) ");
file_des = INVALID_HANDLE_VALUE;
file_des = open_file_impl(filename, WRONLY);
}
if (!SetFilePointerEx(file_des, desired_pos, NULL, FILE_BEGIN))
STXXL_THROW_WIN_LASTERROR(io_error,
"SetFilePointerEx() in wfs_file_base::set_size(..) oldsize=" << cur_size <<
" newsize=" << newsize << " ");
if (!SetEndOfFile(file_des))
STXXL_THROW_WIN_LASTERROR(io_error, "SetEndOfFile() oldsize=" << cur_size <<
" newsize=" << newsize << " ");
if (direct_with_bad_size)
{
if (!CloseHandle(file_des))
STXXL_THROW_WIN_LASTERROR(io_error, "closing file (call of ::CloseHandle() from set_size) ");
file_des = INVALID_HANDLE_VALUE;
file_des = open_file_impl(filename, mode_ & ~TRUNC);
}
}
}
void wfs_file_base::close_remove()
{
close();
::DeleteFile(filename.c_str());
}
STXXL_END_NAMESPACE
#endif