First
This commit is contained in:
+168
@@ -0,0 +1,168 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Lewis Baker
|
||||
// Licenced under MIT license. See LICENSE.txt for details.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cppcoro/file.hpp>
|
||||
#include <cppcoro/io_service.hpp>
|
||||
|
||||
#include <system_error>
|
||||
#include <cassert>
|
||||
|
||||
#if CPPCORO_OS_WINNT
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# include <Windows.h>
|
||||
#endif
|
||||
|
||||
cppcoro::file::~file()
|
||||
{}
|
||||
|
||||
std::uint64_t cppcoro::file::size() const
|
||||
{
|
||||
#if CPPCORO_OS_WINNT
|
||||
LARGE_INTEGER size;
|
||||
BOOL ok = ::GetFileSizeEx(m_fileHandle.handle(), &size);
|
||||
if (!ok)
|
||||
{
|
||||
DWORD errorCode = ::GetLastError();
|
||||
throw std::system_error
|
||||
{
|
||||
static_cast<int>(errorCode),
|
||||
std::system_category(),
|
||||
"error getting file size: GetFileSizeEx"
|
||||
};
|
||||
}
|
||||
|
||||
return size.QuadPart;
|
||||
#endif
|
||||
}
|
||||
|
||||
cppcoro::file::file(detail::win32::safe_handle&& fileHandle) noexcept
|
||||
: m_fileHandle(std::move(fileHandle))
|
||||
{
|
||||
}
|
||||
|
||||
cppcoro::detail::win32::safe_handle cppcoro::file::open(
|
||||
detail::win32::dword_t fileAccess,
|
||||
io_service& ioService,
|
||||
const cppcoro::filesystem::path& path,
|
||||
file_open_mode openMode,
|
||||
file_share_mode shareMode,
|
||||
file_buffering_mode bufferingMode)
|
||||
{
|
||||
DWORD flags = FILE_FLAG_OVERLAPPED;
|
||||
if ((bufferingMode & file_buffering_mode::random_access) == file_buffering_mode::random_access)
|
||||
{
|
||||
flags |= FILE_FLAG_RANDOM_ACCESS;
|
||||
}
|
||||
if ((bufferingMode & file_buffering_mode::sequential) == file_buffering_mode::sequential)
|
||||
{
|
||||
flags |= FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
}
|
||||
if ((bufferingMode & file_buffering_mode::write_through) == file_buffering_mode::write_through)
|
||||
{
|
||||
flags |= FILE_FLAG_WRITE_THROUGH;
|
||||
}
|
||||
if ((bufferingMode & file_buffering_mode::temporary) == file_buffering_mode::temporary)
|
||||
{
|
||||
flags |= FILE_ATTRIBUTE_TEMPORARY;
|
||||
}
|
||||
if ((bufferingMode & file_buffering_mode::unbuffered) == file_buffering_mode::unbuffered)
|
||||
{
|
||||
flags |= FILE_FLAG_NO_BUFFERING;
|
||||
}
|
||||
|
||||
DWORD shareFlags = 0;
|
||||
if ((shareMode & file_share_mode::read) == file_share_mode::read)
|
||||
{
|
||||
shareFlags |= FILE_SHARE_READ;
|
||||
}
|
||||
if ((shareMode & file_share_mode::write) == file_share_mode::write)
|
||||
{
|
||||
shareFlags |= FILE_SHARE_WRITE;
|
||||
}
|
||||
if ((shareMode & file_share_mode::delete_) == file_share_mode::delete_)
|
||||
{
|
||||
shareFlags |= FILE_SHARE_DELETE;
|
||||
}
|
||||
|
||||
DWORD creationDisposition = 0;
|
||||
switch (openMode)
|
||||
{
|
||||
case file_open_mode::create_or_open:
|
||||
creationDisposition = OPEN_ALWAYS;
|
||||
break;
|
||||
case file_open_mode::create_always:
|
||||
creationDisposition = CREATE_ALWAYS;
|
||||
break;
|
||||
case file_open_mode::create_new:
|
||||
creationDisposition = CREATE_NEW;
|
||||
break;
|
||||
case file_open_mode::open_existing:
|
||||
creationDisposition = OPEN_EXISTING;
|
||||
break;
|
||||
case file_open_mode::truncate_existing:
|
||||
creationDisposition = TRUNCATE_EXISTING;
|
||||
break;
|
||||
}
|
||||
|
||||
// Open the file
|
||||
detail::win32::safe_handle fileHandle(
|
||||
::CreateFileW(
|
||||
path.wstring().c_str(),
|
||||
fileAccess,
|
||||
shareFlags,
|
||||
nullptr,
|
||||
creationDisposition,
|
||||
flags,
|
||||
nullptr));
|
||||
if (fileHandle.handle() == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
const DWORD errorCode = ::GetLastError();
|
||||
throw std::system_error
|
||||
{
|
||||
static_cast<int>(errorCode),
|
||||
std::system_category(),
|
||||
"error opening file: CreateFileW"
|
||||
};
|
||||
}
|
||||
|
||||
// Associate with the I/O service's completion port.
|
||||
const HANDLE result = ::CreateIoCompletionPort(
|
||||
fileHandle.handle(),
|
||||
ioService.native_iocp_handle(),
|
||||
0,
|
||||
0);
|
||||
if (result == nullptr)
|
||||
{
|
||||
const DWORD errorCode = ::GetLastError();
|
||||
throw std::system_error
|
||||
{
|
||||
static_cast<int>(errorCode),
|
||||
std::system_category(),
|
||||
"error opening file: CreateIoCompletionPort"
|
||||
};
|
||||
}
|
||||
|
||||
// Configure I/O operations to avoid dispatching a completion event
|
||||
// to the I/O service if the operation completes synchronously.
|
||||
// This avoids unnecessary suspension/resuption of the awaiting coroutine.
|
||||
const BOOL ok = ::SetFileCompletionNotificationModes(
|
||||
fileHandle.handle(),
|
||||
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS |
|
||||
FILE_SKIP_SET_EVENT_ON_HANDLE);
|
||||
if (!ok)
|
||||
{
|
||||
const DWORD errorCode = ::GetLastError();
|
||||
throw std::system_error
|
||||
{
|
||||
static_cast<int>(errorCode),
|
||||
std::system_category(),
|
||||
"error opening file: SetFileCompletionNotificationModes"
|
||||
};
|
||||
}
|
||||
|
||||
return std::move(fileHandle);
|
||||
}
|
||||
Reference in New Issue
Block a user