/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: FileStream.NT.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "FS.hpp" #include "FileStream.NT.hpp" #if !defined(_AURUNTIME_GENERICFILESTREAM) namespace Aurora::IO::FS { static const AuUInt64 kFileCopyBlock = 0xFFFF; // 64KiB, 1k iterations to max out 64MB/s disk, 2k iteration to make out 128MB/s disk, is this number still way too low? cpu go brr WinFileStream::~WinFileStream() { Close(); } void WinFileStream::Init(HANDLE handle, const AuString &path) { handle_ = handle; path_ = path; } AuUInt64 WinFileStream::GetOffset() { LARGE_INTEGER distance {}; LARGE_INTEGER pos {}; if (handle_ == INVALID_HANDLE_VALUE) { SysPushErrorUninitialized(); return 0; } if (SetFilePointerEx(handle_, distance, &pos, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { LogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO(); return 0; } return pos.QuadPart; } bool WinFileStream::SetOffset(AuUInt64 offset) { LARGE_INTEGER distance {}; LARGE_INTEGER pos {}; if (handle_ == INVALID_HANDLE_VALUE) { SysPushErrorUninitialized(); return false; } distance.QuadPart = offset; if (SetFilePointerEx(handle_, distance, &pos, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { LogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO(); return false; } return true; } AuUInt64 WinFileStream::GetLength() { LARGE_INTEGER length; if (handle_ == INVALID_HANDLE_VALUE) { SysPushErrorUninitialized(); return 0; } if (!GetFileSizeEx(handle_, &length)) { SysPushErrorIO(); return 0; } return length.QuadPart; } bool WinFileStream::Read(const Memory::MemoryViewStreamWrite ¶meters) { if (handle_ == INVALID_HANDLE_VALUE) { SysPushErrorUninitialized(); return {}; } auto length = parameters.length; AuUInt64 offset {0}; while (length) { DWORD read; int blockSize = std::min(kFileCopyBlock, length); if (!::ReadFile(handle_, &reinterpret_cast(parameters.ptr)[offset], blockSize, &read, NULL)) { LogWarn("ReadFile IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO(); return false; } if (read == 0) { break; } offset += read; length -= read; } if (!offset) { return false; } parameters.outVariable = offset; return true; } bool WinFileStream::Write(const Memory::MemoryViewStreamRead & parameters) { if (handle_ == INVALID_HANDLE_VALUE) { SysPushErrorUninitialized(); return 0; } auto length = parameters.length; AuUInt offset {0}; while (length) { DWORD written; int blockSize = std::min(kFileCopyBlock, length); if (!::WriteFile(handle_, &reinterpret_cast(parameters.ptr)[offset], blockSize, &written, NULL)) { LogWarn("WriteFileEx IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO(); return false; } if (written != blockSize) { SysPushErrorIO(); parameters.outVariable = offset; return true; } offset += written; length -= written; } if (!offset) { return false; } parameters.outVariable = offset; return true; } void WinFileStream::Close() { AuWin32CloseHandle(handle_); } void WinFileStream::Flush() { FlushFileBuffers(handle_); } static IFileStream *OpenNew(const AuString &path, bool read) { auto pathex = NormalizePathRet(path); auto win32Path = Locale::ConvertFromUTF8(pathex); HANDLE fileHandle; if (read) { fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else { CreateDirectories(pathex, true); fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } if (fileHandle == INVALID_HANDLE_VALUE) { LogWarn("Missing file: {}", path); SysPushErrorIO("Missing file: {}", path); return nullptr; } auto stream = _new WinFileStream(); if (!stream) { CloseHandle(fileHandle); return nullptr; } stream->Init(fileHandle, pathex); return stream; } AUKN_SYM IFileStream *OpenReadNew(const AuString &path) { return OpenNew(path, true); } AUKN_SYM void OpenReadRelease(IFileStream * that) { SafeDelete(that); } AUKN_SYM IFileStream *OpenWriteNew(const AuString &path) { return OpenNew(path, false); } AUKN_SYM void OpenWriteRelease(IFileStream * that) { SafeDelete(that); } } #endif