bc/bc/system/file/win/Stacked.cpp

827 lines
24 KiB
C++

#if defined(WHOA_SYSTEM_WIN)
#include "bc/Memory.hpp"
#include <windows.h>
#include <sddl.h>
#include "bc/File.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/Debug.hpp"
#include "bc/String.hpp"
#include "bc/Unicode.hpp"
#include "bc/time/Time.hpp"
#include <algorithm>
#include "bc/system/file/win/Support.hpp"
#define PATH(name) Blizzard::String::QuickNativePath<300UL>(name).ToString()
#define MAKEU64(high, low) static_cast<uint64_t>(high) << 32ULL | static_cast<uint64_t>(low)
#define BREAKU64(qw, high, low) \
high = static_cast<uint32_t>(qw >> 32); \
low = static_cast<uint32_t>(qw)
#define BREAKFILEPOINTER(qw, high, low) \
high = static_cast<LONG>(qw >> 32); \
low = static_cast<LONG>(qw)
namespace System_File {
// converts file name from local Windows format into UTF-8
void FromNativeName(char* buffer, int32_t buffersize, const char* name) {
uint16_t widenamebuffer[300];
auto len = name ? Blizzard::String::Length(name) : 0;
auto widename = len + 1 > 300
? new uint16_t[2 * (len + 1)]
: widenamebuffer;
widename[MultiByteToWideChar(CP_ACP, 0, name, len, reinterpret_cast<LPWSTR>(widename), len + 1)] = 0;
Blizzard::Unicode::ConvertUTF16to8(reinterpret_cast<uint8_t*>(buffer), buffersize, widenamebuffer, 0xFFFFFFFF, nullptr, nullptr);
if (widenamebuffer != widename) {
delete widename;
}
}
// translate Win32 file bits into Blizzard file bits
uint32_t FromNativeAttributes(DWORD a) {
uint32_t b = 0;
if (a & FILE_ATTRIBUTE_READONLY) {
b |= BC_FILE_ATTRIBUTE_READONLY;
}
if (a & FILE_ATTRIBUTE_HIDDEN) {
b |= BC_FILE_ATTRIBUTE_HIDDEN;
}
if (a & FILE_ATTRIBUTE_SYSTEM) {
b |= BC_FILE_ATTRIBUTE_SYSTEM;
}
if (a & FILE_ATTRIBUTE_ARCHIVE) {
b |= BC_FILE_ATTRIBUTE_ARCHIVE;
}
if (a & FILE_ATTRIBUTE_TEMPORARY) {
b |= BC_FILE_ATTRIBUTE_TEMPORARY;
}
if (a & FILE_ATTRIBUTE_DIRECTORY) {
b |= BC_FILE_ATTRIBUTE_DIRECTORY;
}
if ((a & FILE_ATTRIBUTE_NORMAL) != 0 || (a & FILE_ATTRIBUTE_DIRECTORY) == 0) {
b |= BC_FILE_ATTRIBUTE_NORMAL;
}
return b;
}
// translate Blizzard file attribute bits into Win32 attribute bits.
DWORD ToNativeAttributes(uint32_t a) {
DWORD b = 0;
if (a & BC_FILE_ATTRIBUTE_READONLY) {
b |= FILE_ATTRIBUTE_READONLY;
}
if (a & BC_FILE_ATTRIBUTE_HIDDEN) {
b |= FILE_ATTRIBUTE_HIDDEN;
}
if (a & BC_FILE_ATTRIBUTE_SYSTEM) {
b |= FILE_ATTRIBUTE_SYSTEM;
}
if (a & BC_FILE_ATTRIBUTE_ARCHIVE) {
b |= FILE_ATTRIBUTE_ARCHIVE;
}
if (a & BC_FILE_ATTRIBUTE_TEMPORARY) {
b |= FILE_ATTRIBUTE_TEMPORARY;
}
if (a & BC_FILE_ATTRIBUTE_NORMAL) {
b |= FILE_ATTRIBUTE_NORMAL;
}
if (a & BC_FILE_ATTRIBUTE_DIRECTORY) {
b |= FILE_ATTRIBUTE_DIRECTORY;
}
return b;
}
// convert FILETIME (two 32-bit values) into 64-bit unsigned integer
inline uint64_t MakeFileTime(FILETIME ft) {
return MAKEU64(ft.dwHighDateTime, ft.dwLowDateTime);
}
// convert 64-bit unsigned integer into FILETIME (two 32-bit values)
inline FILETIME BreakFileTime(uint64_t qw) {
FILETIME ft;
BREAKU64(qw, ft.dwHighDateTime, ft.dwLowDateTime);
return ft;
}
void GetFileInfoByFile(Blizzard::File::StreamRecord* file) {
if (!file->haveinfo) {
file->haveinfo = false;
DWORD filesizehigh;
auto filesize = static_cast<uint64_t>(GetFileSize(file->filehandle, &filesizehigh));
if (filesize == INVALID_FILE_SIZE && GetLastError()) {
return;
}
auto info = &file->info;
// TODO: ??????
if (!file->unk48 || !*file->unk48) {
info->size = MAKEU64(filesizehigh, filesize);
}
WIN32_FILE_ATTRIBUTE_DATA fileinfo;
if (::GetFileAttributesEx(PATH(file->name), GetFileExInfoStandard, &fileinfo)) {
info->createtime = Blizzard::Time::FromFileTime(MakeFileTime(fileinfo.ftCreationTime));
info->writetime = Blizzard::Time::FromFileTime(MakeFileTime(fileinfo.ftLastWriteTime));
info->accesstime = Blizzard::Time::FromFileTime(MakeFileTime(fileinfo.ftLastAccessTime));
info->attributes = FromNativeAttributes(fileinfo.dwFileAttributes);
info->normal = (info->attributes & BC_FILE_ATTRIBUTE_NORMAL) != 0;
if (fileinfo.dwFileAttributes == 0xFFFFFFFF) {
info->filetype = 0;
} else {
info->filetype = ((info->attributes & BC_FILE_ATTRIBUTE_DIRECTORY) != 0) + 1;
}
}
}
file->haveinfo = true;
}
bool ToCreateFlags(int32_t mode, DWORD& sharemode, DWORD& desiredaccess, DWORD& creationdisposition, DWORD& flagsandattributes) {
sharemode = (mode >> 2) & 3;
desiredaccess = ((mode << 2) | mode & Blizzard::File::Mode::write) << 29;
creationdisposition = 0;
if ((mode & Blizzard::File::Mode::truncate) == 0 && (mode & Blizzard::File::Mode::create) == 0) {
if ((mode & Blizzard::File::Mode::mustnotexist) == 0) {
creationdisposition = mode & Blizzard::File::Mode::mustexist ? OPEN_EXISTING : OPEN_ALWAYS;
} else {
creationdisposition = CREATE_NEW;
}
} else if (mode & Blizzard::File::Mode::mustnotexist) {
creationdisposition = CREATE_NEW;
} else {
creationdisposition = CREATE_ALWAYS;
}
flagsandattributes = FILE_ATTRIBUTE_NORMAL | (mode & Blizzard::File::Mode::temporary ? FILE_ATTRIBUTE_TEMPORARY : 0) | (mode & Blizzard::File::Mode::nocache ? FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING : 0);
return true;
}
namespace Stacked {
// begin stacked file functions
bool SetWorkingDirectory(FileParms* parms) {
BC_ASSERT(parms->name);
if (!parms->name) {
BC_FILE_SET_ERROR(8);
return false;
}
return ::SetCurrentDirectory(PATH(parms->name)) != 0;
}
bool Close(FileParms* parms) {
auto file = parms->file;
if (file->filehandle != INVALID_HANDLE_VALUE) {
::CloseHandle(file->filehandle);
}
FREE(file);
return true;
}
bool Create(FileParms* parms) {
BC_FILE_SET_ERROR(9);
return false;
}
bool GetWorkingDirectory(FileParms* parms) {
if (!parms->buffer || !parms->buffersize) {
// System_File::FileError(8)
BC_FILE_SET_ERROR(8);
return false;
}
char cwd[BC_FILE_MAX_PATH];
::GetCurrentDirectory(BC_FILE_MAX_PATH, cwd);
FromNativeName(parms->buffer, parms->buffersize, cwd);
return true;
}
bool ProcessDirFast(FileParms* parms) {
char dirfindpattern[512];
Blizzard::String::Format(dirfindpattern, 512, "%s\\*", parms->name);
WIN32_FIND_DATA findData;
auto hFindFile = ::FindFirstFile(PATH(dirfindpattern), &findData);
if (hFindFile == INVALID_HANDLE_VALUE) {
BC_FILE_SET_ERROR_MSG(8, "failed to open %s\n", parms->name);
return false;
}
Blizzard::File::ProcessDirParms dirwalkparms;
dirwalkparms.dir = parms->name;
dirwalkparms.param = parms->dirwalkparam;
char item[BC_FILE_MAX_PATH];
while (true) {
// ignore .. and .
if (findData.cFileName[0] != '.' || findData.cFileName[1] && (findData.cFileName[1] != '.' || findData.cFileName[2])) {
FromNativeName(item, BC_FILE_MAX_PATH, findData.cFileName);
dirwalkparms.item = item;
dirwalkparms.isdir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
if (!parms->dirwalkcallback(dirwalkparms)) {
::FindClose(hFindFile);
return true;
}
}
if (!::FindNextFile(hFindFile, &findData)) {
break;
}
}
::FindClose(hFindFile);
return false;
}
bool Exists(FileParms* parms) {
char name[BC_FILE_MAX_PATH];
if (parms->name) {
Blizzard::String::MakeBackslashPath(parms->name, name, sizeof(name));
} else {
name[0] = '\0';
}
auto dwFileAttributes = ::GetFileAttributes(static_cast<LPCSTR>(PATH(name)));
if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
parms->info->filetype = 0;
return true;
}
parms->info->filetype = dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? 2 : 1;
return true;
}
bool Flush(FileParms* parms) {
auto file = parms->file;
if (file->filehandle == INVALID_HANDLE_VALUE) {
BC_FILE_SET_ERROR(8);
return false;
}
return ::FlushFileBuffers(file->filehandle) != 0;
}
bool GetFileInfo(FileParms* parms) {
if (parms->name) {
WIN32_FILE_ATTRIBUTE_DATA fileinfo;
if (!::GetFileAttributesEx(PATH(parms->name), GetFileExInfoStandard, &fileinfo)) {
BC_FILE_SET_ERROR(8);
return false;
}
auto info = parms->info;
info->size = MAKEU64(fileinfo.nFileSizeHigh, fileinfo.nFileSizeLow);
info->createtime = Blizzard::Time::FromFileTime(MakeFileTime(fileinfo.ftCreationTime));
info->writetime = Blizzard::Time::FromFileTime(MakeFileTime(fileinfo.ftLastWriteTime));
info->accesstime = Blizzard::Time::FromFileTime(MakeFileTime(fileinfo.ftLastAccessTime));
info->name = nullptr;
info->attributes = FromNativeAttributes(fileinfo.dwFileAttributes);
info->normal = (info->attributes & BC_FILE_ATTRIBUTE_NORMAL) != 0;
if (fileinfo.dwFileAttributes == 0xFFFFFFFF) {
info->filetype = 0;
} else {
info->filetype = ((info->attributes & BC_FILE_ATTRIBUTE_DIRECTORY) != 0) + 1;
}
return true;
} else if (parms->file) {
auto file = parms->file;
GetFileInfoByFile(file);
parms->info = &file->info;
if (!file->info.name) {
file->info.name = file->name;
}
return true;
}
BC_FILE_SET_ERROR(8);
return false;
}
bool GetFreeSpace(FileParms* parms) {
auto name = parms->name;
if (name == nullptr || *name == '\0') {
BC_FILE_SET_ERROR(8);
return false;
}
char path[MAX_PATH];
char shortpath[MAX_PATH];
Blizzard::String::Copy(path, name, std::min(static_cast<int32_t>((Blizzard::String::FindFilename(name) + 1) - name), MAX_PATH));
ULARGE_INTEGER freebytesavailable;
ULARGE_INTEGER totalbytesavailable;
auto shortpathchars = ::GetShortPathName(PATH(path), shortpath, MAX_PATH);
if (shortpathchars && shortpathchars < MAX_PATH) {
if (!GetDiskFreeSpaceEx(shortpath, &freebytesavailable, &totalbytesavailable, nullptr)) {
BC_FILE_SET_ERROR(8);
return false;
}
} else {
if (!GetDiskFreeSpaceEx(PATH(path), &freebytesavailable, &totalbytesavailable, nullptr)) {
BC_FILE_SET_ERROR(8);
return false;
}
}
parms->offset = static_cast<int64_t>(freebytesavailable.QuadPart);
return true;
}
bool GetPos(FileParms* parms) {
auto file = parms->file;
if (file == nullptr || file->filehandle == INVALID_HANDLE_VALUE) {
BC_FILE_SET_ERROR(8);
return false;
}
LONG high = 0;
auto low = ::SetFilePointer(file->filehandle, 0, &high, FILE_CURRENT);
if (low == INVALID_SET_FILE_POINTER && GetLastError()) {
BC_FILE_SET_ERROR(8);
return false;
}
parms->offset = MAKEU64(high, low);
return true;
}
bool GetRootChars(FileParms* parms) {
char pathbuffer[256];
auto pathsize = Blizzard::String::Length(parms->name) + 1;
auto path = pathsize > 256 ? new char[pathsize] : pathbuffer;
if (pathsize > 2) {
Blizzard::String::MakeUnivPath(parms->name, path, pathsize);
if (path[1] == ':') {
parms->offset = (path[2] == '/') + 2;
} else if (path[0] == '/' && path[1] == '/') {
uint32_t i = 0;
auto cur = path + 1;
for (uint32_t i = 0; i < 2; i++) {
cur = strchr(cur + 1, '/');
if (!cur) {
parms->offset = pathsize;
if (path != pathbuffer) {
delete path;
}
return true;
}
}
parms->offset = (cur - path) + 1;
} else {
parms->offset = 0LL;
}
}
if (path != pathbuffer) {
delete path;
}
return true;
}
bool IsAbsolutePath(FileParms* parms) {
auto path = parms->name;
auto first = path[0];
// UNC
if (((first == '\\' || first == '/') && ((path[1] == '\\' || path[1] == '/'))) && path[2] != '\0') {
return true;
}
// DOS canonical
if (isalpha(first) && (path[1] == ':') && (((path[2] == '\\') || (path[2] == '/')) && path[3] != '\0')) {
return true;
}
BC_FILE_SET_ERROR(8);
return false;
}
bool IsReadOnly(FileParms* parms) {
if (!parms->name) {
BC_FILE_SET_ERROR(8);
return false;
}
auto dwFileAttributes = ::GetFileAttributes(PATH(parms->name));
if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
BC_FILE_SET_ERROR(8);
return false;
}
return dwFileAttributes & FILE_ATTRIBUTE_READONLY;
}
bool MakeAbsolutePath(FileParms* parms) {
if (!parms->name) {
BC_FILE_SET_ERROR(8);
return false;
}
char full[BC_FILE_MAX_PATH];
::_fullpath(full, PATH(parms->name), BC_FILE_MAX_PATH);
FromNativeName(parms->buffer, parms->buffersize, full);
Blizzard::String::ForceTrailingSeparator(parms->buffer, parms->buffersize, '\0');
return true;
}
bool CreateDirectory(FileParms* parms) {
if (!parms->name) {
BC_FILE_SET_ERROR(8);
return false;
}
char pathbuffer[MAX_PATH];
auto pathsize = Blizzard::String::Length(parms->name) + 1;
auto path = pathsize > MAX_PATH ? new char[pathsize] : pathbuffer;
Blizzard::String::MakeBackslashPath(parms->name, path, pathsize);
SECURITY_ATTRIBUTES security_attr = {};
security_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
security_attr.bInheritHandle = FALSE;
if (parms->set_acl) {
ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:(A;OICI;GA;;;BU)", OWNER_SECURITY_INFORMATION, &security_attr.lpSecurityDescriptor, nullptr);
}
if (parms->recurse) {
char leadingpath[MAX_PATH];
for (auto s = path; *s && s < (s + Blizzard::String::Length(s)); s++) {
while (*s && *s != '\\') {
s++;
}
if (Blizzard::String::Copy(leadingpath, path, std::min(static_cast<int32_t>(s - path) + 2, MAX_PATH)) >= MAX_PATH) {
BC_FILE_SET_ERROR(8);
if (path != pathbuffer) {
delete path;
}
return false;
}
Blizzard::String::QuickNativePath<300UL> directorypath(leadingpath);
if (::CreateDirectoryA(directorypath.ToString(), parms->set_acl ? &security_attr : nullptr)) {
if (*s == '\0') {
break;
}
} else {
auto last_err = ::GetLastError();
if ((last_err != ERROR_ALREADY_EXISTS && last_err != ERROR_ACCESS_DENIED)) {
if (path != pathbuffer) {
delete path;
}
BC_FILE_SET_ERROR(8);
return false;
}
auto directoryattributes = GetFileAttributes(directorypath.ToString());
if (directoryattributes == INVALID_FILE_ATTRIBUTES || (directoryattributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
if (path != pathbuffer) {
delete path;
}
BC_FILE_SET_ERROR(8);
return false;
}
}
}
} else {
if (!::CreateDirectoryA(PATH(path), parms->set_acl ? &security_attr : nullptr)) {
auto last_err = ::GetLastError();
bool result = last_err == ERROR_ALREADY_EXISTS || last_err == ERROR_ACCESS_DENIED;
if (path != pathbuffer) {
delete path;
}
return result;
}
}
if (path != pathbuffer) {
delete path;
}
return true;
}
bool Move(FileParms* parms) {
char src[BC_FILE_MAX_PATH];
char dst[BC_FILE_MAX_PATH];
if (parms->name) {
Blizzard::String::MakeBackslashPath(parms->name, src, BC_FILE_MAX_PATH);
} else {
src[0] = '\0';
}
if (parms->newname) {
Blizzard::String::MakeBackslashPath(parms->newname, dst, BC_FILE_MAX_PATH);
} else {
dst[0] = '\0';
}
return ::MoveFile(PATH(src), PATH(dst)) != 0;
}
bool Copy(FileParms* parms) {
char srcname[BC_FILE_MAX_PATH];
char dstname[BC_FILE_MAX_PATH];
if (parms->name) {
Blizzard::String::MakeBackslashPath(parms->name, srcname, BC_FILE_MAX_PATH);
} else {
srcname[0] = '\0';
}
if (parms->newname) {
Blizzard::String::MakeBackslashPath(parms->newname, dstname, BC_FILE_MAX_PATH);
} else {
dstname[0] = '\0';
}
Blizzard::File::StreamRecord* src;
Blizzard::File::StreamRecord* dst;
if (!Blizzard::File::Open(srcname, Blizzard::File::Mode::read | Blizzard::File::Mode::shareread | Blizzard::File::Mode::mustexist, src)) {
BC_FILE_SET_ERROR(2); // TODO: find out what 2 is
return false;
}
if (!Blizzard::File::Open(dstname, Blizzard::File::Mode::write | (parms->overwrite ? Blizzard::File::Mode::create : Blizzard::File::Mode::create | Blizzard::File::Mode::mustnotexist), dst)) {
BC_FILE_SET_ERROR(4); // TODO: find out what 4 is
return false;
}
auto size = Blizzard::File::GetFileInfo(src)->size;
auto buffer = ALLOC(size > BC_SYSTEM_FILE_COPYBUFFER_SIZE ? BC_SYSTEM_FILE_COPYBUFFER_SIZE : size);
int64_t offset = 0;
bool result = true;
while (offset < size) {
auto count = static_cast<int32_t>(size - offset >= BC_SYSTEM_FILE_COPYBUFFER_SIZE ? BC_SYSTEM_FILE_COPYBUFFER_SIZE : size - offset);
if (!Blizzard::File::Read(src, buffer, offset, &count)) {
result = false;
break;
}
if (!Blizzard::File::Write(dst, buffer, offset, &count)) {
result = false;
break;
}
offset += static_cast<int64_t>(count);
}
FREE(buffer);
Blizzard::File::Close(src);
Blizzard::File::Close(dst);
if (!result) {
Blizzard::File::Delete(dstname);
}
return result;
}
bool Open(FileParms* parms) {
char name[BC_FILE_MAX_PATH];
if (parms->name) {
Blizzard::String::MakeBackslashPath(parms->name, name, BC_FILE_MAX_PATH);
} else {
name[0] = '\0';
}
DWORD sharemode;
DWORD desiredaccess;
DWORD creationdisposition;
DWORD flagsandattributes;
if (!ToCreateFlags(parms->mode, sharemode, desiredaccess, creationdisposition, flagsandattributes)) {
BC_FILE_SET_ERROR(8);
return false;
}
auto filehandle = CreateFile(
PATH(name),
desiredaccess,
sharemode,
nullptr,
creationdisposition,
flagsandattributes,
nullptr);
if (filehandle == INVALID_HANDLE_VALUE) {
BC_FILE_SET_ERROR_MSG(4, "Win32 Open - %s", name);
return false;
}
auto file = parms->file;
if (file == nullptr) {
// alloc(sizeof(StreamRecord) + len(name) + 1)
// block of memory holds file as well as C string of the filename
auto namesize = Blizzard::String::Length(name) + 1;
file = reinterpret_cast<Blizzard::File::StreamRecord*>(ALLOC_ZERO(sizeof(Blizzard::File::StreamRecord) + namesize));
// set the name pointer inside of StreamRecord to point to the end of StreamRecord (i.e. the start of the name cstring in the memory block)
auto filename = reinterpret_cast<char*>(file) + sizeof(Blizzard::File::StreamRecord);
file->name = filename;
// copy name into memory block
Blizzard::String::Copy(filename, name, namesize);
}
file->filehandle = filehandle;
file->mode = parms->mode;
file->haveinfo = false;
file->info.name = file->name;
GetFileInfoByFile(file);
if (parms->mode & Blizzard::File::Mode::append) {
Blizzard::File::SetPos(file, file->info.size, BC_FILE_SEEK_START);
}
parms->file = file;
return true;
}
bool RemoveDirectory(FileParms* parms) {
if (parms->recurse) {
return Blizzard::File::RemoveDirectoryAndContents(parms->name, false);
}
if (!parms->name) {
BC_FILE_SET_ERROR(8);
return false;
}
char namebuffer[MAX_PATH];
auto namesize = Blizzard::String::Length(parms->name) + 1;
auto name = namesize > MAX_PATH ? new char[namesize] : namebuffer;
Blizzard::String::MakeBackslashPath(parms->name, name, MAX_PATH);
auto removed = ::RemoveDirectoryA(PATH(name));
if (name != namebuffer) {
delete name;
}
return removed != 0;
}
bool SetCacheMode(FileParms* parms) {
auto file = parms->file;
parms->mode |= ~(Blizzard::File::Mode::nocache);
DWORD sharemode;
DWORD desiredaccess;
DWORD creationdisposition;
DWORD flagsandattributes;
if (!ToCreateFlags(parms->mode, sharemode, desiredaccess, creationdisposition, flagsandattributes)) {
BC_FILE_SET_ERROR(8);
return false;
}
::CloseHandle(file->filehandle);
file->filehandle = CreateFile(PATH(file->info.name), desiredaccess, sharemode, nullptr, creationdisposition, flagsandattributes, nullptr);
if (file->filehandle == INVALID_HANDLE_VALUE) {
BC_FILE_SET_ERROR_MSG(4, "Win32 Close");
return false;
}
return true;
}
bool SetEOF(FileParms* parms) {
auto file = parms->file;
int64_t offset;
if (!Blizzard::File::GetPos(file, offset) || !Blizzard::File::SetPos(file, parms->offset, parms->whence)) {
BC_FILE_SET_ERROR(8);
return false;
}
auto status = ::SetEndOfFile(file->filehandle);
Blizzard::File::SetPos(file, offset, BC_FILE_SEEK_START);
return status != 0;
}
bool SetAttributes(FileParms* parms) {
auto file = parms->file;
if (parms->setinfo & BC_SYSTEM_FILE_INFO_TIMES) {
auto info = parms->info;
auto createtime = BreakFileTime(Blizzard::Time::ToFileTime(info->createtime));
auto lastaccesstime = BreakFileTime(Blizzard::Time::ToFileTime(info->accesstime));
auto lastwritetime = BreakFileTime(Blizzard::Time::ToFileTime(info->writetime));
if (!::SetFileTime(file->filehandle, &createtime, &lastaccesstime, &lastwritetime)) {
BC_FILE_SET_ERROR(8);
return false;
}
parms->setinfo &= ~(BC_SYSTEM_FILE_INFO_TIMES);
}
if (parms->setinfo & BC_SYSTEM_FILE_INFO_ATTRIBUTES) {
if (!::SetFileAttributes(PATH(file->name), ToNativeAttributes(parms->info->attributes))) {
BC_FILE_SET_ERROR(8);
return false;
}
parms->setinfo &= ~(BC_SYSTEM_FILE_INFO_ATTRIBUTES);
}
return parms->setinfo == 0;
}
bool SetPos(FileParms* parms) {
auto file = parms->file;
if (file->filehandle == INVALID_HANDLE_VALUE) {
BC_FILE_SET_ERROR(8);
return false;
}
LONG distancetomovelow;
LONG distancetomovehigh;
BREAKFILEPOINTER(parms->offset, distancetomovehigh, distancetomovelow);
auto movemethod = static_cast<DWORD>(parms->whence);
movemethod = std::min(movemethod, static_cast<DWORD>(FILE_END));
if (::SetFilePointer(file->filehandle, distancetomovelow, &distancetomovehigh, movemethod) == INVALID_SET_FILE_POINTER) {
if (GetLastError()) {
return false;
}
}
return true;
}
bool Delete(FileParms* parms) {
char name[BC_FILE_MAX_PATH];
if (parms->name) {
Blizzard::String::MakeBackslashPath(parms->name, name, BC_FILE_MAX_PATH);
} else {
name[0] = '\0';
}
return ::DeleteFile(PATH(name)) != 0;
}
// shutdown
bool Shutdown(FileParms* parms) {
// ?
return true;
}
} // namespace Stacked
} // namespace System_File
#endif