mirror of
https://github.com/thunderbrewhq/bc.git
synced 2025-12-13 02:22:28 +00:00
feat(file): implement filesystem utilities
This commit is contained in:
parent
5e6af0ea70
commit
bd65df59e9
26 changed files with 4163 additions and 5 deletions
811
bc/system/file/win/Stacked.cpp
Normal file
811
bc/system/file/win/Stacked.cpp
Normal file
|
|
@ -0,0 +1,811 @@
|
|||
#include "bc/file/Defines.hpp"
|
||||
#include "bc/file/File.hpp"
|
||||
#include "bc/file/Path.hpp"
|
||||
#include "bc/file/system/Stacked.hpp"
|
||||
#include "bc/file/system/win/WinFile.hpp"
|
||||
#include "bc/Debug.hpp"
|
||||
#include "bc/Memory.hpp"
|
||||
#include "bc/String.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
/********************************
|
||||
* Begin Win32 Stacked functions *
|
||||
*********************************/
|
||||
|
||||
namespace Blizzard {
|
||||
namespace System_File {
|
||||
namespace Stacked {
|
||||
|
||||
bool SetWorkingDirectory(FileParms* parms) {
|
||||
BLIZZARD_ASSERT(parms->filename);
|
||||
return ::SetCurrentDirectory(parms->filename) != 0;
|
||||
}
|
||||
|
||||
bool Close(FileParms* parms) {
|
||||
auto file = parms->stream;
|
||||
BLIZZARD_ASSERT(file != nullptr);
|
||||
|
||||
::CloseHandle(file->filehandle);
|
||||
Memory::Free(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetWorkingDirectory(FileParms* parms) {
|
||||
if (!parms->directory || !parms->directorySize) {
|
||||
// System_File::FileError(8)
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto size = static_cast<DWORD>(parms->directorySize);
|
||||
auto directory = static_cast<LPSTR>(parms->directory);
|
||||
|
||||
::GetCurrentDirectory(size, directory);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessDirFast(FileParms* parms) {
|
||||
// Get parameters
|
||||
auto unkflag = parms->flag;
|
||||
auto directory = parms->filename;
|
||||
auto callback = parms->callback;
|
||||
auto param = parms->param;
|
||||
|
||||
// Set up walk parameters
|
||||
File::ProcessDirParms processDirParms;
|
||||
processDirParms.root = directory;
|
||||
processDirParms.param = param;
|
||||
|
||||
constexpr uint32_t formatSize = BC_FILE_MAX_PATH * 2;
|
||||
char formatted[formatSize] = "";
|
||||
|
||||
// Tack on a backslash as well as an asterisk.
|
||||
String::Format(formatted, formatSize, "%s\\*", processDirParms.root);
|
||||
|
||||
// Convert potentially large path to universal format
|
||||
BC_FILE_PATH(path);
|
||||
if (!File::Path::MakeNativePath(formatted, path, formatSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
WIN32_FIND_DATA findData;
|
||||
|
||||
auto hFindFile = ::FindFirstFile(formatted, &findData);
|
||||
|
||||
if (hFindFile == INVALID_HANDLE_VALUE) {
|
||||
BC_FILE_SET_ERROR_MSG(BC_FILE_ERROR_INVALID_ARGUMENT, "Win32 ProcessDirFast - %s", directory);
|
||||
return false;
|
||||
}
|
||||
|
||||
BC_FILE_PATH(currentPath);
|
||||
processDirParms.item = currentPath;
|
||||
|
||||
while (true) {
|
||||
// Ignore .. and .
|
||||
if (findData.cFileName[0] != '.' || findData.cFileName[1] && (findData.cFileName[1] != '.' || findData.cFileName[2])) {
|
||||
String::Copy(currentPath, findData.cFileName, BC_FILE_MAX_PATH);
|
||||
processDirParms.itemIsDirectory = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
|
||||
if (!callback(processDirParms)) {
|
||||
::FindClose(hFindFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!::FindNextFile(hFindFile, &findData)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::FindClose(hFindFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Exists(FileParms* parms) {
|
||||
auto filepath = parms->filename;
|
||||
if (!filepath) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
File::Path::QuickNative filepathNative(filepath);
|
||||
|
||||
auto dwFileAttributes = ::GetFileAttributes(static_cast<LPCSTR>(filepathNative.Str()));
|
||||
|
||||
if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||||
parms->info->attributes = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t fileAttributes = WinFile::AttributesToBC(dwFileAttributes);
|
||||
parms->info->attributes = fileAttributes;
|
||||
|
||||
return fileAttributes & BC_FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
|
||||
bool Flush(FileParms* parms) {
|
||||
auto file = parms->stream;
|
||||
|
||||
if (file == nullptr || file->filehandle == INVALID_HANDLE_VALUE ) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto status = ::FlushFileBuffers(file->filehandle);
|
||||
return status != 0;
|
||||
}
|
||||
|
||||
bool GetFileInfo(FileParms* parms) {
|
||||
auto file = parms->stream;
|
||||
auto filepath = parms->filename;
|
||||
auto info = parms->info;
|
||||
|
||||
if (filepath == nullptr && file == nullptr) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
// StreamRecord* file may be used to supply storage of file info. (StreamRecord*->info)
|
||||
if (file) {
|
||||
BLIZZARD_ASSERT(file->filehandle != INVALID_HANDLE_VALUE);
|
||||
if (info == nullptr) {
|
||||
// telling this function to save file info into StreamRecord
|
||||
info = &file->info;
|
||||
}
|
||||
}
|
||||
|
||||
if (filepath) {
|
||||
// Fetch info based on filepath.
|
||||
static File::FileInfo s_noinfo = {};
|
||||
if (info == nullptr) {
|
||||
info = &s_noinfo;
|
||||
}
|
||||
|
||||
File::Path::QuickNative filepathNative(filepath);
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA fileAttributeData = {};
|
||||
|
||||
// Read attributes
|
||||
if (!::GetFileAttributesEx(filepathNative.Str(), GetFileExInfoStandard, &fileAttributeData)) {
|
||||
BC_FILE_SET_ERROR_MSG(BC_FILE_ERROR_INVALID_HANDLE, "Win32 GetFileInfo - GetFileAttributesExA failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return WinFile::AttributeFileInfoToBC(&fileAttributeData, info);
|
||||
}
|
||||
|
||||
// Fetch info using opened file handle
|
||||
auto filehandle = file->filehandle;
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION byHandleInfo;
|
||||
if (!::GetFileInformationByHandle(filehandle, &byHandleInfo)) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_HANDLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
file->hasInfo = true;
|
||||
|
||||
return WinFile::HandleFileInfoToBC(&byHandleInfo, info);
|
||||
}
|
||||
|
||||
bool GetFreeSpace(FileParms* parms) {
|
||||
auto filename = parms->filename;
|
||||
|
||||
if (filename == nullptr || *filename == '\0') {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto len = String::Length(filename) + 2;
|
||||
BC_FILE_PATH(systemPath);
|
||||
// UNC convert
|
||||
File::Path::MakeNativePath(filename, systemPath, BC_FILE_MAX_PATH);
|
||||
|
||||
// GetDiskFreeSpaceExA will fail without a trailing backslash
|
||||
File::Path::ForceTrailingSeparator(systemPath, BC_FILE_MAX_PATH, BC_FILE_SYSTEM_PATH_SEPARATOR);
|
||||
|
||||
ULARGE_INTEGER freeBytesAvailableToCaller = {};
|
||||
ULARGE_INTEGER totalNumberOfBytes = {};
|
||||
ULARGE_INTEGER totalNumberOfFreeBytes = {};
|
||||
|
||||
if (!GetDiskFreeSpaceExA(systemPath, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
parms->size64 = static_cast<uint64_t>(freeBytesAvailableToCaller.QuadPart);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetPos(FileParms* parms) {
|
||||
auto file = parms->stream;
|
||||
|
||||
if (file == nullptr || file->filehandle == INVALID_HANDLE_VALUE) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
LONG high = 0;
|
||||
DWORD low = ::SetFilePointer(file->filehandle, 0, &high, FILE_CURRENT);
|
||||
if (low == -1 && GetLastError()) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_HANDLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
ULARGE_INTEGER ul = {};
|
||||
ul.LowPart = low;
|
||||
ul.HighPart = high;
|
||||
|
||||
parms->position = ul.QuadPart;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetRootChars(FileParms* parms) {
|
||||
char cVar1 = '\0';
|
||||
int32_t counter = 0;
|
||||
int32_t size = 0;
|
||||
char *buffer = nullptr;
|
||||
const char *path = nullptr;
|
||||
char unixPathFast[256] = {0};
|
||||
const char *end = nullptr;
|
||||
|
||||
path = parms->filename;
|
||||
counter = String::Length(path);
|
||||
size = counter + 1;
|
||||
if (size > 256) {
|
||||
buffer = reinterpret_cast<char *>(Memory::Allocate(size));
|
||||
} else {
|
||||
buffer = unixPathFast;
|
||||
}
|
||||
|
||||
// Invalid without error
|
||||
if (size < 0x2) {
|
||||
parms->end = 0;
|
||||
parms->beginning = 0;
|
||||
} else {
|
||||
File::Path::MakeUnivPath(path, buffer, size);
|
||||
path = buffer + 1;
|
||||
// Get DOS canonical path
|
||||
if (buffer[1] == ':') {
|
||||
cVar1 = buffer[2];
|
||||
parms->beginning = 0;
|
||||
parms->end = (cVar1 == '/') + 2;
|
||||
} else {
|
||||
// Get UNC path
|
||||
if ((*buffer == '/') && (buffer[1] == '/')) {
|
||||
counter = 0;
|
||||
do {
|
||||
path = strchr(path + 1, '$');
|
||||
if (path == nullptr) {
|
||||
parms->end = size;
|
||||
parms->beginning = 0;
|
||||
if (buffer != unixPathFast) {
|
||||
Memory::Free(buffer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
counter = counter + 1;
|
||||
} while (counter < 2);
|
||||
parms->end = intptr_t(path) + (1 - (intptr_t)buffer);
|
||||
} else {
|
||||
parms->end = 0;
|
||||
}
|
||||
parms->beginning = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer != unixPathFast) {
|
||||
Memory::Free(buffer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsAbsolutePath(FileParms* parms) {
|
||||
auto path = parms->filename;
|
||||
|
||||
if (!path) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto first = path[0];
|
||||
|
||||
if (
|
||||
// UNC
|
||||
(
|
||||
((first == '\\') || (first == '/')) &&
|
||||
((path[1] == '\\' || (path[1] == '/')))
|
||||
) &&
|
||||
(path[2] != '\0')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// DOS canonical
|
||||
if (isalpha(first) && (path[1] == ':')) {
|
||||
if (((path[2] == '\\') || (path[2] == '/')) && (path[3] != '\0')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsReadOnly(FileParms* parms) {
|
||||
auto filepath = parms->filename;
|
||||
if (!filepath) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
File::Path::QuickNative filepathNative(filepath);
|
||||
|
||||
auto dwFileAttributes = ::GetFileAttributes(filepathNative.Str());
|
||||
|
||||
if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
return (dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0;
|
||||
}
|
||||
|
||||
bool MakeAbsolutePath(FileParms* parms) {
|
||||
BC_FILE_PATH(full);
|
||||
|
||||
auto path = parms->filename;
|
||||
|
||||
if (path == nullptr) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
::_fullpath(full, path, BC_FILE_MAX_PATH);
|
||||
|
||||
File::Path::ForceTrailingSeparator(full, BC_FILE_MAX_PATH, BC_FILE_SYSTEM_PATH_SEPARATOR);
|
||||
|
||||
String::Copy(parms->directory, full, parms->directorySize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateDirectory(FileParms* parms) {
|
||||
auto path = parms->filename;
|
||||
|
||||
char temp[300] = {0};
|
||||
auto p = path;
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
while (*p != '\0') {
|
||||
if (*p == '\\' || *p == '/') {
|
||||
count++;
|
||||
int32_t len = p - path;
|
||||
if (len == 0) {
|
||||
len = 1;
|
||||
}
|
||||
String::Copy(temp, path, len);
|
||||
temp[len] = '\0';
|
||||
|
||||
if (::GetFileAttributes(temp) == INVALID_FILE_ATTRIBUTES) {
|
||||
if (!::CreateDirectory(temp, nullptr)) {
|
||||
if (::GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
// No directories were made because there are no path separators.
|
||||
// Make only one directory:
|
||||
|
||||
String::Copy(temp, path, 300);
|
||||
|
||||
if (::GetFileAttributes(temp) == INVALID_FILE_ATTRIBUTES) {
|
||||
if (!::CreateDirectory(temp, nullptr)) {
|
||||
if (::GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Move(FileParms* parms) {
|
||||
auto source = parms->filename;
|
||||
auto destination = parms->destination;
|
||||
|
||||
File::Path::QuickNative sourceNative(source);
|
||||
File::Path::QuickNative destinationNative(destination);
|
||||
|
||||
BOOL ok = ::MoveFile(sourceNative.Str(), destinationNative.Str());
|
||||
|
||||
return ok != 0;
|
||||
}
|
||||
|
||||
bool Copy(FileParms* parms) {
|
||||
auto source = parms->filename;
|
||||
auto destination = parms->destination;
|
||||
|
||||
auto overwrite = parms->flag;
|
||||
|
||||
// file pointers
|
||||
File::StreamRecord* st_source = nullptr;
|
||||
File::StreamRecord* st_destination = nullptr;
|
||||
|
||||
// Flags for working with src and dst files
|
||||
auto flag_source = BC_FILE_OPEN_READ | BC_FILE_OPEN_MUST_EXIST;
|
||||
auto flag_destination = BC_FILE_OPEN_WRITE | BC_FILE_OPEN_CREATE;
|
||||
if (!overwrite) {
|
||||
// User commands that we cannot overwrite. Fail if file already exists
|
||||
flag_destination |= BC_FILE_OPEN_MUST_NOT_EXIST;
|
||||
} else {
|
||||
// We are supposed to overwrite, so truncate the file to 0 bytes.
|
||||
flag_destination |= BC_FILE_OPEN_TRUNCATE;
|
||||
}
|
||||
|
||||
// Open source file to be copied
|
||||
if (!File::Open(source, flag_source, st_source)) {
|
||||
// FileError(2)
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_FILE_NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open (or create if it doesn't exist) destination file
|
||||
if (!File::Open(destination, flag_destination, st_destination)) {
|
||||
File::Close(st_source);
|
||||
// FileError(4)
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_BUSY);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine buffer copy size
|
||||
auto sz_source = File::GetFileInfo(st_source)->size;
|
||||
|
||||
// copybuffer size upper limit is BC_FILE_SYSTEM_COPYBUFFER_SIZE
|
||||
size_t sz_copybuffer = std::min(sz_source, uint64_t(BC_FILE_SYSTEM_COPYBUFFER_SIZE));
|
||||
auto u8_copybuffer = reinterpret_cast<uint8_t*>(Memory::Allocate(sz_copybuffer));
|
||||
|
||||
// Loop through the source file, reading segments into copybuffer
|
||||
for (uint64_t index = 0; index < sz_source; index += sz_copybuffer) {
|
||||
// How many bytes to read
|
||||
size_t sz_bytesToRead = sz_source - std::min(index+sz_copybuffer, sz_source);
|
||||
size_t sz_bytesRead = 0;
|
||||
size_t sz_bytesWritten = 0;
|
||||
// Read data segment into copybuffer
|
||||
auto status = File::Read(st_source, u8_copybuffer, sz_bytesToRead, &sz_bytesRead, 0);
|
||||
if (status) {
|
||||
// Write copied segment to destination file
|
||||
status = File::Write(st_destination, u8_copybuffer, sz_bytesRead, &sz_bytesWritten, 0);
|
||||
}
|
||||
|
||||
if (!status) {
|
||||
// either read or write failed: cleanup copy buffer
|
||||
Memory::Free(u8_copybuffer);
|
||||
// close files
|
||||
File::Close(st_source);
|
||||
File::Close(st_destination);
|
||||
// Delete malformed file
|
||||
File::Delete(destination);
|
||||
// return bad status, but without creating a file error.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Memory::Free(u8_copybuffer);
|
||||
// close files
|
||||
File::Close(st_source);
|
||||
File::Close(st_destination);
|
||||
|
||||
// Success!
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Open(FileParms* parms) {
|
||||
// Path convert
|
||||
auto path = parms->filename;
|
||||
File::Path::QuickNative pathNative(path);
|
||||
|
||||
// Open file HANDLE
|
||||
auto flags = parms->flag;
|
||||
bool nocache = parms->mode & File::Mode::nocache;
|
||||
HANDLE handle = WinFile::Open(pathNative.Str(), flags, nocache);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = 0;
|
||||
if (err = ::GetLastError()) {
|
||||
BC_FILE_SET_ERROR_MSG(BC_FILE_ERROR_GENERIC_FAILURE, "Win32 Open %s", parms->filename);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Successfully opened file handle. Allocate StreamRecord + path str at the end.
|
||||
auto recordSize = (sizeof(File::StreamRecord) - File::StreamRecord::s_padPath) + (1 + pathNative.Size());
|
||||
auto fileData = Memory::Allocate(recordSize);
|
||||
// Memory could not be allocated
|
||||
if (fileData == nullptr) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_OOM);
|
||||
return false;
|
||||
}
|
||||
// Clear extra data
|
||||
String::MemFill(fileData, recordSize, 0);
|
||||
|
||||
// Populate fields
|
||||
auto file = reinterpret_cast<File::StreamRecord*>(fileData);
|
||||
file->flags = flags;
|
||||
file->filehandle = handle;
|
||||
String::Copy(file->path, path, pathNative.Size());
|
||||
File::GetFileInfo(file);
|
||||
|
||||
parms->stream = file;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Read(File::StreamRecord* file, void* data, int64_t offset, size_t* bytes) {
|
||||
// File descriptor must be initialized!
|
||||
BLIZZARD_ASSERT(file != nullptr && file->filehandle != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (bytes == nullptr || *bytes == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (offset > -1) {
|
||||
if (!File::SetPos(file, offset, BC_FILE_SEEK_START)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD dwRead = 0;
|
||||
|
||||
BOOL ok = ::ReadFile(file->filehandle, data, *bytes, &dwRead, nullptr);
|
||||
|
||||
if (ok == 0) {
|
||||
// append any Win32 failure to the error log
|
||||
BC_FILE_SET_ERROR_MSG(BC_FILE_ERROR_BAD_FILE, "Win32 Read %p - %s", GetLastError(), file->path);
|
||||
return false;
|
||||
}
|
||||
|
||||
*bytes = static_cast<size_t>(dwRead);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Read(FileParms* parms) {
|
||||
return Read(parms->stream, parms->param, -1, &parms->size);
|
||||
}
|
||||
|
||||
bool ReadP(FileParms* parms) {
|
||||
return Read(parms->stream, parms->param, parms->position, &parms->size);
|
||||
}
|
||||
|
||||
bool RemoveDirectory(FileParms* parms) {
|
||||
auto dirpath = parms->filename;
|
||||
if (dirpath == nullptr) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
File::Path::QuickNative pathNative(dirpath);
|
||||
|
||||
BOOL ok = ::RemoveDirectory(dirpath);
|
||||
|
||||
return ok != 0;
|
||||
}
|
||||
|
||||
bool SetCacheMode(FileParms* parms) {
|
||||
auto file = parms->stream;
|
||||
|
||||
if (file == nullptr) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file->filehandle == INVALID_HANDLE_VALUE) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_HANDLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
File::Path::QuickNative pathNative(file->path);
|
||||
|
||||
// Close handle and reopen
|
||||
CloseHandle(file->filehandle);
|
||||
|
||||
bool nocache = (parms->mode & File::Mode::nocache) != 0;
|
||||
|
||||
file->filehandle = WinFile::Open(pathNative.Str(), file->flags, nocache);
|
||||
|
||||
if (file->filehandle == INVALID_HANDLE_VALUE) {
|
||||
BC_FILE_SET_ERROR_MSG(4, "Win32 SetCacheMode - %s", file->path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nocache) {
|
||||
parms->mode &= ~(File::Mode::nocache);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetEOF(FileParms* parms) {
|
||||
auto file = parms->stream;
|
||||
|
||||
if (file == nullptr || file->filehandle == INVALID_HANDLE_VALUE) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save current pos
|
||||
int64_t originalpos = 0;
|
||||
|
||||
if (!File::GetPos(file, originalpos)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t newpos = parms->position;
|
||||
auto whence = parms->whence;
|
||||
|
||||
if (!File::SetPos(file, newpos, whence)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL b = ::SetEndOfFile(file->filehandle);
|
||||
|
||||
if (!b) {
|
||||
BC_FILE_SET_ERROR_MSG(4, "Win32 SetEOF - %s", file->path);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restore original pos
|
||||
return File::SetPos(file, originalpos, BC_FILE_SEEK_START);
|
||||
}
|
||||
|
||||
bool SetAttributes(FileParms* parms) {
|
||||
auto info = parms->info;
|
||||
|
||||
if (info == nullptr) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto mode = parms->mode;
|
||||
auto attributes = info->attributes;
|
||||
int32_t status = 0;
|
||||
auto file = parms->stream;
|
||||
auto path = parms->filename;
|
||||
|
||||
if (mode & File::Mode::settimes) {
|
||||
auto modTime = info->modificationTime;
|
||||
|
||||
FILETIME ft = WinFile::PackTime(Time::ToWinFiletime(modTime));
|
||||
|
||||
if (::SetFileTime(file->filehandle, nullptr, nullptr, &ft)) {
|
||||
file->info.modificationTime = modTime;
|
||||
|
||||
parms->mode &= ~(File::Mode::settimes);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & File::Mode::setperms) {
|
||||
File::Path::QuickNative pathNative(parms->filename);
|
||||
|
||||
DWORD dwAttributes = WinFile::AttributesToWin(info->attributes);
|
||||
|
||||
BOOL ok = ::SetFileAttributes(pathNative.Str(), dwAttributes);
|
||||
|
||||
if (!ok) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
parms->mode &= ~(File::Mode::setperms);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetPos(FileParms* parms) {
|
||||
auto file = parms->stream;
|
||||
|
||||
if (file == nullptr || file->filehandle == INVALID_HANDLE_VALUE) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto offset = parms->position;
|
||||
auto whence = parms->whence;
|
||||
|
||||
auto offsetLow = static_cast<LONG>(offset);
|
||||
auto offsetHigh = static_cast<LONG>(offset >> 32);
|
||||
|
||||
DWORD res = ::SetFilePointer(file->filehandle, offsetLow, &offsetHigh, static_cast<DWORD>(whence));
|
||||
if (res == INVALID_SET_FILE_POINTER) {
|
||||
res = GetLastError();
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Delete(FileParms* parms) {
|
||||
auto deletePath = parms->filename;
|
||||
|
||||
if (deletePath == nullptr) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
File::Path::QuickNative deletePathNative(deletePath);
|
||||
|
||||
BOOL ok = ::DeleteFile(deletePathNative.Str());
|
||||
|
||||
return ok != 0;
|
||||
}
|
||||
|
||||
bool Write(FileParms* parms) {
|
||||
auto file = parms->stream;
|
||||
auto data = parms->param;
|
||||
auto size = parms->size;
|
||||
|
||||
if (file == nullptr || file->filehandle == INVALID_HANDLE_VALUE) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD numberOfBytesWritten = 0;
|
||||
|
||||
BOOL ok = WriteFile(file->filehandle, data, size, &numberOfBytesWritten, nullptr);
|
||||
|
||||
return ok != 0;
|
||||
}
|
||||
|
||||
bool WriteP(FileParms* parms) {
|
||||
auto file = parms->stream;
|
||||
auto data = parms->param;
|
||||
auto position = parms->position;
|
||||
auto size = parms->size;
|
||||
|
||||
if (file == nullptr || file->filehandle == INVALID_HANDLE_VALUE) {
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_INVALID_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t origpos = 0;
|
||||
|
||||
if (!File::GetPos(file, origpos)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!File::SetPos(file, position, BC_FILE_SEEK_START)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD numberOfBytesWritten = 0;
|
||||
BOOL ok = WriteFile(file->filehandle, data, size, &numberOfBytesWritten, nullptr);
|
||||
if (ok == 0) {
|
||||
BC_FILE_SET_ERROR_MSG(BC_FILE_ERROR_BAD_FILE, "Win32 Write - %s", file->path);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return File::SetPos(file, origpos, BC_FILE_SEEK_START);
|
||||
}
|
||||
|
||||
} // namespace Stacked
|
||||
} // namespace System_File
|
||||
} // namespace Blizzard
|
||||
|
||||
/********************************
|
||||
* End of Win32 Stacked functions *
|
||||
*********************************/
|
||||
12
bc/system/file/win/Support.hpp
Normal file
12
bc/system/file/win/Support.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef BC_FILE_SYSTEM_WIN_SUPPORT_HPP
|
||||
#define BC_FILE_SYSTEM_WIN_SUPPORT_HPP
|
||||
|
||||
// Lowercase windows.h macros fight with BlizzardCore file function names
|
||||
// Get out of here
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
#if defined(GetFreeSpace)
|
||||
#undef GetFreeSpace
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
142
bc/system/file/win/System_File.cpp
Normal file
142
bc/system/file/win/System_File.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#include "bc/file/system/System_File.hpp"
|
||||
#include "bc/file/system/Stacked.hpp"
|
||||
#include "bc/file/File.hpp"
|
||||
#include "bc/file/Defines.hpp"
|
||||
#include "bc/Debug.hpp"
|
||||
#include "bc/String.hpp"
|
||||
|
||||
#include <storm/String.hpp>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace System_File {
|
||||
|
||||
/******************************************
|
||||
* Begin Win32 System_File stack functions *
|
||||
*******************************************/
|
||||
|
||||
// Change current process's working directory to parms->filename.
|
||||
bool SetWorkingDirectory(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::SetWorkingDirectory(parms);
|
||||
}
|
||||
|
||||
// Close parms->stream file handle.
|
||||
bool Close(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::Close(parms);
|
||||
}
|
||||
|
||||
bool Create(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
// System_File::FileError(9)
|
||||
BC_FILE_SET_ERROR(BC_FILE_ERROR_UNIMPLEMENTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetWorkingDirectory(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::GetWorkingDirectory(parms);
|
||||
}
|
||||
|
||||
bool ProcessDirFast(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::ProcessDirFast(parms);
|
||||
}
|
||||
|
||||
bool Exists(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::Exists(parms);
|
||||
}
|
||||
|
||||
bool Flush(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::Flush(parms);
|
||||
}
|
||||
|
||||
bool GetFileInfo(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::GetFileInfo(parms);
|
||||
}
|
||||
|
||||
bool GetFreeSpace(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::GetFreeSpace(parms);
|
||||
}
|
||||
|
||||
bool GetPos(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::GetPos(parms);
|
||||
}
|
||||
|
||||
bool GetRootChars(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::GetRootChars(parms);
|
||||
}
|
||||
|
||||
bool IsAbsolutePath(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::IsAbsolutePath(parms);
|
||||
}
|
||||
|
||||
bool IsReadOnly(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::IsReadOnly(parms);
|
||||
}
|
||||
|
||||
bool MakeAbsolutePath(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::MakeAbsolutePath(parms);
|
||||
}
|
||||
|
||||
bool CreateDirectory(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::CreateDirectory(parms);
|
||||
}
|
||||
|
||||
bool Move(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::Move(parms);
|
||||
}
|
||||
|
||||
bool Copy(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::Copy(parms);
|
||||
}
|
||||
|
||||
bool Open(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::Open(parms);
|
||||
}
|
||||
|
||||
bool Read(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::Read(parms);
|
||||
}
|
||||
|
||||
bool ReadP(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::ReadP(parms);
|
||||
}
|
||||
|
||||
bool RemoveDirectory(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::RemoveDirectory(parms);
|
||||
}
|
||||
|
||||
bool SetCacheMode(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::SetCacheMode(parms);
|
||||
}
|
||||
|
||||
bool SetEOF(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::SetEOF(parms);
|
||||
}
|
||||
|
||||
bool SetAttributes(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::SetAttributes(parms);
|
||||
}
|
||||
|
||||
bool SetPos(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::SetPos(parms);
|
||||
}
|
||||
|
||||
bool Delete(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::Delete(parms);
|
||||
}
|
||||
|
||||
bool Write(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::Write(parms);
|
||||
}
|
||||
|
||||
bool WriteP(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return Stacked::WriteP(parms);
|
||||
}
|
||||
|
||||
bool Shutdown(File::Filesystem* fs, Stacked::FileParms* parms) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* End Win32 System_File stack functions *
|
||||
*****************************************/
|
||||
|
||||
} // namespace System_File
|
||||
} // namespace Blizzard
|
||||
181
bc/system/file/win/WinFile.cpp
Normal file
181
bc/system/file/win/WinFile.cpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
#include "bc/file/Defines.hpp"
|
||||
#include "bc/file/system/win/Utils.hpp"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace WinFile {
|
||||
|
||||
// Translate Win32 file bits into Blizzard file bits.
|
||||
uint32_t AttributesToBC(DWORD dwFileAttributes) {
|
||||
uint32_t fileAttributes = 0;
|
||||
if (dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
|
||||
fileAttributes |= BC_FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
|
||||
fileAttributes |= BC_FILE_ATTRIBUTE_HIDDEN;
|
||||
}
|
||||
|
||||
if (dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
|
||||
fileAttributes |= BC_FILE_ATTRIBUTE_SYSTEM;
|
||||
}
|
||||
|
||||
if (dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
|
||||
fileAttributes |= BC_FILE_ATTRIBUTE_TEMPORARY;
|
||||
}
|
||||
|
||||
if (dwFileAttributes & FILE_ATTRIBUTE_NORMAL) {
|
||||
fileAttributes |= BC_FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
|
||||
if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
fileAttributes |= BC_FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
|
||||
return fileAttributes;
|
||||
}
|
||||
|
||||
// Translate Blizzard file attribute bits into Win32 attribute bits.
|
||||
DWORD AttributesToWin(uint32_t fileAttributes) {
|
||||
DWORD dwFileAttributes = 0;
|
||||
|
||||
if (fileAttributes & BC_FILE_ATTRIBUTE_READONLY) {
|
||||
dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
if (fileAttributes & BC_FILE_ATTRIBUTE_HIDDEN) {
|
||||
dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||
}
|
||||
|
||||
if (fileAttributes & BC_FILE_ATTRIBUTE_SYSTEM) {
|
||||
dwFileAttributes |= FILE_ATTRIBUTE_SYSTEM;
|
||||
}
|
||||
|
||||
if (fileAttributes & BC_FILE_ATTRIBUTE_ARCHIVE) {
|
||||
dwFileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
}
|
||||
|
||||
if (fileAttributes & BC_FILE_ATTRIBUTE_TEMPORARY) {
|
||||
dwFileAttributes |= FILE_ATTRIBUTE_TEMPORARY;
|
||||
}
|
||||
|
||||
if (fileAttributes & BC_FILE_ATTRIBUTE_NORMAL) {
|
||||
dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
|
||||
if (fileAttributes & BC_FILE_ATTRIBUTE_DIRECTORY) {
|
||||
dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
|
||||
return dwFileAttributes;
|
||||
}
|
||||
|
||||
// Convert FILETIME (two 32-bit values) into 64-bit unsigned integer.
|
||||
uint64_t UnpackTime(FILETIME ft) {
|
||||
ULARGE_INTEGER ul = {};
|
||||
ul.HighPart = ft.dwHighDateTime;
|
||||
ul.LowPart = ft.dwLowDateTime;
|
||||
return static_cast<uint64_t>(ul.QuadPart);
|
||||
}
|
||||
|
||||
// Convert 64-bit unsigned integer into FILETIME (two 32-bit values)
|
||||
FILETIME PackTime(uint64_t qw) {
|
||||
ULARGE_INTEGER ul = {};
|
||||
ul.QuadPart = qw;
|
||||
FILETIME ft = {};
|
||||
ft.dwHighDateTime = ul.HighPart;
|
||||
ft.dwLowDateTime = ul.LowPart;
|
||||
return ft;
|
||||
}
|
||||
|
||||
// Returns true if BY_HANDLE_FILE_INFORMATION is successfully converted to File::FileInfo.
|
||||
bool HandleFileInfoToBC(
|
||||
LPBY_HANDLE_FILE_INFORMATION winInfo,
|
||||
Blizzard::File::FileInfo* info) {
|
||||
if (!info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
info->attributes = AttributesToBC(winInfo->dwFileAttributes);
|
||||
info->device = static_cast<uint32_t>(winInfo->dwVolumeSerialNumber);
|
||||
info->size = (static_cast<uint64_t>(winInfo->nFileSizeHigh) << 32ULL) | static_cast<uint64_t>(winInfo->nFileSizeLow);
|
||||
|
||||
info->accessTime = Blizzard::Time::FromWinFiletime(UnpackTime(winInfo->ftLastAccessTime));
|
||||
info->modificationTime = Blizzard::Time::FromWinFiletime(UnpackTime(winInfo->ftLastWriteTime));
|
||||
info->attributeModificationTime = Blizzard::Time::FromWinFiletime(UnpackTime(winInfo->ftCreationTime));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if WIN32_FILE_ATTRIBUTE_DATA is successfully converted to File::FileInfo.
|
||||
bool AttributeFileInfoToBC(
|
||||
LPWIN32_FILE_ATTRIBUTE_DATA winInfo,
|
||||
Blizzard::File::FileInfo* info) {
|
||||
|
||||
if (!info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
info->attributes = AttributesToBC(winInfo->dwFileAttributes);
|
||||
info->device = 0;
|
||||
info->size = (static_cast<uint64_t>(winInfo->nFileSizeHigh) << 32ULL) | static_cast<uint64_t>(winInfo->nFileSizeLow);
|
||||
|
||||
info->accessTime = Blizzard::Time::FromWinFiletime(UnpackTime(winInfo->ftLastAccessTime));
|
||||
info->modificationTime = Blizzard::Time::FromWinFiletime(UnpackTime(winInfo->ftLastWriteTime));
|
||||
info->attributeModificationTime = Blizzard::Time::FromWinFiletime(UnpackTime(winInfo->ftCreationTime));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Open a HANDLE to a file, using BlizzardCore flags.
|
||||
HANDLE Open(const char* systemPath, uint32_t flags, bool nocache) {
|
||||
// expand flags
|
||||
bool read = flags & BC_FILE_OPEN_READ;
|
||||
bool write = flags & BC_FILE_OPEN_WRITE;
|
||||
bool shareRead = flags & BC_FILE_OPEN_SHARE_READ;
|
||||
bool shareRead = flags & BC_FILE_OPEN_SHARE_WRITE;
|
||||
bool write = flags & BC_FILE_OPEN_WRITE;
|
||||
bool mustNotExist = flags & BC_FILE_OPEN_MUST_NOT_EXIST;
|
||||
bool mustExist = flags & BC_FILE_OPEN_MUST_EXIST;
|
||||
bool create = flags & BC_FILE_OPEN_CREATE;
|
||||
bool truncate = flags & BC_FILE_OPEN_TRUNCATE;
|
||||
|
||||
// BLIZZARD_ASSERT(read || write);
|
||||
|
||||
// Start building arguments to CreateFile()
|
||||
DWORD desiredAccess = 0;
|
||||
DWORD shareMode = 0;
|
||||
DWORD createDisposition = 0;
|
||||
DWORD flagsAndAttributes = 0;
|
||||
|
||||
if (nocache) {
|
||||
flagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
|
||||
}
|
||||
|
||||
// Setup desired access
|
||||
if (read) {
|
||||
desiredAccess |= GENERIC_READ;
|
||||
}
|
||||
if (write) {
|
||||
desiredAccess |= GENERIC_WRITE;
|
||||
}
|
||||
|
||||
// Setup create disposition
|
||||
if (create && mustNotExist) {
|
||||
createDisposition = CREATE_NEW;
|
||||
} else if (create && !mustNotExist) {
|
||||
createDisposition = CREATE_ALWAYS;
|
||||
} else if (truncate) {
|
||||
createDisposition = TRUNCATE_EXISTING;
|
||||
} else if (mustExist) {
|
||||
createDisposition = OPEN_EXISTING;
|
||||
} else {
|
||||
createDisposition = OPEN_ALWAYS;
|
||||
}
|
||||
|
||||
return CreateFileA(systemPath, desiredAccess, shareMode, nullptr, createDisposition, flagsAndAttributes, 0);
|
||||
}
|
||||
|
||||
} // namespace WinFile
|
||||
} // namespace Blizzard
|
||||
36
bc/system/file/win/WinFile.hpp
Normal file
36
bc/system/file/win/WinFile.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef BC_FILE_SYSTEM_WIN_UTILS_HPP
|
||||
#define BC_FILE_SYSTEM_WIN_UTILS_HPP
|
||||
|
||||
#include "bc/file/Types.hpp"
|
||||
|
||||
#include <windows.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace WinFile {
|
||||
|
||||
// Translate Win32 file bits into Blizzard file bits.
|
||||
uint32_t AttributesToBC(DWORD dwFileAttributes);
|
||||
|
||||
DWORD AttributesToWin(uint32_t attributes);
|
||||
|
||||
uint64_t UnpackTime(FILETIME ft);
|
||||
|
||||
FILETIME PackTime(uint64_t qw);
|
||||
|
||||
// Returns true if BY_HANDLE_FILE_INFORMATION is successfully converted to File::FileInfo.
|
||||
bool HandleFileInfoToBC(
|
||||
LPBY_HANDLE_FILE_INFORMATION winInfo,
|
||||
Blizzard::File::FileInfo* info);
|
||||
|
||||
// Returns true if WIN32_FILE_ATTRIBUTE_DATA is successfully converted to File::FileInfo.
|
||||
bool AttributeFileInfoToBC(
|
||||
LPWIN32_FILE_ATTRIBUTE_DATA winInfo,
|
||||
Blizzard::File::FileInfo* info);
|
||||
|
||||
HANDLE Open(const char* systemPath, uint32_t flags, bool nocache);
|
||||
|
||||
} // namespace WinFile
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue