2021-06-27 21:25:29 +00:00
|
|
|
/***
|
|
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
File: FS.NT.cpp
|
2021-06-27 21:25:29 +00:00
|
|
|
Date: 2021-6-12
|
|
|
|
Author: Reece
|
|
|
|
***/
|
2021-09-30 14:57:41 +00:00
|
|
|
#include <Source/RuntimeInternal.hpp>
|
2021-06-27 21:25:29 +00:00
|
|
|
#include "FS.hpp"
|
|
|
|
#include "FS.Generic.hpp"
|
2021-09-30 14:57:41 +00:00
|
|
|
#include <Source/Time/Time.hpp>
|
2021-06-27 21:25:29 +00:00
|
|
|
|
|
|
|
#if !defined(_AURUNTIME_GENERICFS)
|
|
|
|
namespace Aurora::IO::FS
|
|
|
|
{
|
2021-09-13 20:11:12 +00:00
|
|
|
static const AuUInt64 kFileCopyBlock = 0xFFFF; // 64KiB
|
2021-06-27 21:25:29 +00:00
|
|
|
|
|
|
|
bool _MkDir(const AuString &str)
|
|
|
|
{
|
|
|
|
return CreateDirectoryW(Locale::ConvertFromUTF8(str).c_str(), NULL);
|
|
|
|
}
|
|
|
|
|
2022-07-23 06:41:47 +00:00
|
|
|
struct ReadDirStructure : IReadDir
|
|
|
|
{
|
|
|
|
HANDLE hFind {INVALID_HANDLE_VALUE};
|
|
|
|
WIN32_FIND_DATAW ffd;
|
|
|
|
bool bFirstTick {true};
|
|
|
|
bool bDead {false};
|
|
|
|
StatEx stat;
|
|
|
|
AuString sPath;
|
|
|
|
|
|
|
|
~ReadDirStructure()
|
|
|
|
{
|
|
|
|
::FindClose(this->hFind);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual StatEx *Next() override
|
|
|
|
{
|
|
|
|
if (!AuExchange(this->bFirstTick, false))
|
|
|
|
{
|
|
|
|
if (::FindNextFileW(this->hFind, &this->ffd) == 0)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->bDead)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->ffd.cFileName == std::wstring(L".") ||
|
|
|
|
this->ffd.cFileName == std::wstring(L".."))
|
|
|
|
{
|
|
|
|
return Next();
|
|
|
|
}
|
|
|
|
|
2022-08-20 06:53:48 +00:00
|
|
|
stat.bExists = true;
|
2022-07-23 06:41:47 +00:00
|
|
|
|
|
|
|
stat.fileName = Locale::ConvertFromWChar(this->ffd.cFileName);
|
|
|
|
if (stat.fileName.empty())
|
|
|
|
{
|
|
|
|
this->bDead = true;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-08-20 06:53:48 +00:00
|
|
|
stat.path = NormalizePathRet(this->sPath + stat.fileName);
|
2022-07-23 06:41:47 +00:00
|
|
|
if (stat.path.empty())
|
|
|
|
{
|
|
|
|
this->bDead = true;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-08-20 06:53:48 +00:00
|
|
|
stat.bExistsDirectory = this->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
|
|
|
stat.bExistsFile = !stat.bExistsDirectory;
|
|
|
|
stat.bSymLink = this->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT;
|
|
|
|
|
|
|
|
stat.uSize = AuUInt64(this->ffd.nFileSizeLow) | (AuUInt64(this->ffd.nFileSizeHigh) << 32);
|
|
|
|
|
2023-05-03 07:57:21 +00:00
|
|
|
stat.createdNs = Time::ConvertTimestampNs(this->ffd.ftCreationTime);
|
|
|
|
stat.modifiedNs = Time::ConvertTimestampNs(this->ffd.ftLastWriteTime);
|
|
|
|
stat.accessedNs = Time::ConvertTimestampNs(this->ffd.ftLastAccessTime);
|
2022-07-23 06:41:47 +00:00
|
|
|
|
|
|
|
return &stat;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AUKN_SYM AuSPtr<IReadDir> ReadDir(const AuString &string)
|
|
|
|
{
|
|
|
|
auto pObj = AuMakeShared<ReadDirStructure>();
|
|
|
|
if (!pObj)
|
|
|
|
{
|
|
|
|
SysPushErrorMem();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!AuIOFS::NormalizePath(pObj->sPath, string))
|
|
|
|
{
|
|
|
|
SysPushErrorMem();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!AuTryInsert(pObj->sPath, '\\'))
|
|
|
|
{
|
|
|
|
SysPushErrorMem();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
pObj->hFind = ::FindFirstFileW(AuLocale::ConvertFromUTF8(pObj->sPath + "*").c_str(), &pObj->ffd);
|
|
|
|
if (INVALID_HANDLE_VALUE == pObj->hFind)
|
|
|
|
{
|
|
|
|
SysPushErrorIO();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return pObj;
|
|
|
|
}
|
|
|
|
|
2021-06-27 21:25:29 +00:00
|
|
|
AUKN_SYM bool FilesInDirectory(const AuString &string, AuList<AuString> &files)
|
|
|
|
{
|
2022-07-23 06:41:47 +00:00
|
|
|
auto itr = ReadDir(string);
|
|
|
|
if (!itr)
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
2022-07-23 06:41:47 +00:00
|
|
|
return false;
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 06:41:47 +00:00
|
|
|
// SECURITY(): if next fails, its indistinguishable from end of file list, and will return true. it kinda sucks
|
|
|
|
while (auto stat = itr->Next())
|
|
|
|
{
|
2022-08-20 06:53:48 +00:00
|
|
|
if (!stat->bExistsFile)
|
2022-07-23 06:41:47 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!AuTryInsert(files, stat->fileName))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2022-07-23 06:41:47 +00:00
|
|
|
return true;
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM bool DirsInDirectory(const AuString &string, AuList<AuString> &dirs)
|
|
|
|
{
|
2022-07-23 06:41:47 +00:00
|
|
|
auto itr = ReadDir(string);
|
|
|
|
if (!itr)
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
2022-07-23 06:41:47 +00:00
|
|
|
return false;
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 06:41:47 +00:00
|
|
|
// SECURITY(): if next fails, its indistinguishable from end of file list, and will return true. it kinda sucks
|
|
|
|
while (auto stat = itr->Next())
|
|
|
|
{
|
2022-08-20 06:53:48 +00:00
|
|
|
if (!stat->bExistsDirectory)
|
2022-07-23 06:41:47 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!AuTryInsert(dirs, stat->fileName))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2022-07-23 06:41:47 +00:00
|
|
|
return true;
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
2022-01-20 17:45:52 +00:00
|
|
|
AUKN_SYM bool ReadFile(const AuString &path, AuByteBuffer &buffer)
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
std::wstring win32Path;
|
|
|
|
LARGE_INTEGER length;
|
|
|
|
bool status;
|
2022-09-19 05:42:39 +00:00
|
|
|
AuMemoryViewWrite writeView;
|
2021-09-06 10:58:08 +00:00
|
|
|
size_t offset;
|
|
|
|
|
|
|
|
status = false;
|
|
|
|
offset = 0;
|
|
|
|
win32Path = Locale::ConvertFromUTF8(NormalizePathRet(path));
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2022-02-20 21:08:44 +00:00
|
|
|
if (win32Path.empty())
|
2022-01-24 18:37:06 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-02-04 19:43:01 +00:00
|
|
|
auto fileHandle = ::CreateFileW(win32Path.c_str(),
|
|
|
|
GENERIC_READ,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
NULL,
|
|
|
|
OPEN_EXISTING,
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
NULL);
|
2021-06-30 16:34:49 +00:00
|
|
|
if (fileHandle == INVALID_HANDLE_VALUE)
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
|
|
|
SysPushErrorIO("Couldn't open handle: {}", path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-02-04 19:43:01 +00:00
|
|
|
if (!::GetFileSizeEx(fileHandle, &length))
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
|
|
|
SysPushErrorIO();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2022-09-19 05:42:39 +00:00
|
|
|
writeView = buffer.GetOrAllocateLinearWriteable(length.QuadPart);
|
|
|
|
if (!writeView)
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
2022-09-22 23:59:08 +00:00
|
|
|
SysPushErrorMem();
|
|
|
|
goto out;
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while (length.QuadPart)
|
|
|
|
{
|
|
|
|
DWORD read;
|
|
|
|
|
2022-01-19 17:08:13 +00:00
|
|
|
int blockSize = AuMin(static_cast<AuUInt64>(kFileCopyBlock), static_cast<AuUInt64>(length.QuadPart));
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2022-09-19 05:42:39 +00:00
|
|
|
if (!::ReadFile(fileHandle, buffer.writePtr, blockSize, &read, NULL))
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
2022-01-24 18:37:06 +00:00
|
|
|
AuLogWarn("ReadFile IO Error: 0x{:x} {}", GetLastError(), path);
|
2021-06-27 21:25:29 +00:00
|
|
|
SysPushErrorIO();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2022-09-19 05:42:39 +00:00
|
|
|
buffer.writePtr += read;
|
2021-06-27 21:25:29 +00:00
|
|
|
offset += read;
|
|
|
|
length.QuadPart -= read;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = true;
|
|
|
|
|
|
|
|
out:
|
2021-09-13 20:11:12 +00:00
|
|
|
AuWin32CloseHandle(fileHandle);
|
2021-06-27 21:25:29 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM bool FileExists(const AuString &path)
|
|
|
|
{
|
2022-01-24 18:37:06 +00:00
|
|
|
try
|
|
|
|
{
|
2023-02-04 19:43:01 +00:00
|
|
|
DWORD dwAttrib = ::GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str());
|
2022-01-24 18:37:06 +00:00
|
|
|
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) &&
|
|
|
|
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM bool DirExists(const AuString &path)
|
|
|
|
{
|
2022-01-24 18:37:06 +00:00
|
|
|
try
|
|
|
|
{
|
2023-02-04 19:43:01 +00:00
|
|
|
DWORD dwAttrib = ::GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str());
|
2022-01-24 18:37:06 +00:00
|
|
|
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) &&
|
|
|
|
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM bool DirMk(const AuString &path)
|
|
|
|
{
|
2022-01-24 18:37:06 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
return CreateDirectories(NormalizePathRet(path), false);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM bool Remove(const AuString &path)
|
|
|
|
{
|
2022-01-24 18:37:06 +00:00
|
|
|
try
|
|
|
|
{
|
2022-02-20 21:52:39 +00:00
|
|
|
auto translatedPath = Locale::ConvertFromUTF8(NormalizePathRet(path));
|
2022-07-23 06:41:47 +00:00
|
|
|
if (::DeleteFileW(translatedPath.c_str()))
|
2022-02-20 21:52:39 +00:00
|
|
|
{
|
2022-07-23 06:41:47 +00:00
|
|
|
return true;
|
2022-02-20 21:52:39 +00:00
|
|
|
}
|
2022-07-23 06:41:47 +00:00
|
|
|
|
|
|
|
if (::RemoveDirectoryW(translatedPath.c_str()))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-02-27 07:45:35 +00:00
|
|
|
return false;
|
2022-01-24 18:37:06 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM bool Relink(const AuString &src, const AuString &dest)
|
|
|
|
{
|
2022-01-24 18:37:06 +00:00
|
|
|
try
|
|
|
|
{
|
2023-01-23 21:18:58 +00:00
|
|
|
auto srcPathNormalized = NormalizePathRet(src);
|
|
|
|
auto destPathNormalized = NormalizePathRet(dest);
|
|
|
|
CreateDirectories(destPathNormalized, true);
|
|
|
|
|
2023-02-04 19:43:01 +00:00
|
|
|
return ::MoveFileW(Locale::ConvertFromUTF8(srcPathNormalized).c_str(),
|
|
|
|
Locale::ConvertFromUTF8(destPathNormalized).c_str());
|
2022-01-24 18:37:06 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM bool Copy(const AuString &src, const AuString &dest)
|
|
|
|
{
|
2022-01-24 18:37:06 +00:00
|
|
|
try
|
|
|
|
{
|
2023-01-23 21:18:58 +00:00
|
|
|
auto srcPathNormalized = NormalizePathRet(src);
|
|
|
|
auto destPathNormalized = NormalizePathRet(dest);
|
|
|
|
CreateDirectories(destPathNormalized, true);
|
|
|
|
|
2023-02-04 19:43:01 +00:00
|
|
|
return ::CopyFileW(Locale::ConvertFromUTF8(srcPathNormalized).c_str(),
|
|
|
|
Locale::ConvertFromUTF8(destPathNormalized).c_str(), true);
|
2022-01-24 18:37:06 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM bool StatFile(const AuString &path, Stat &stat)
|
|
|
|
{
|
|
|
|
WIN32_FILE_ATTRIBUTE_DATA data;
|
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
stat = {};
|
|
|
|
|
2023-02-04 19:43:01 +00:00
|
|
|
if (!::GetFileAttributesExW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str(), GetFileExInfoStandard, &data))
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
2022-08-20 06:53:48 +00:00
|
|
|
stat.bExists = false;
|
2021-06-27 21:25:29 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-08-20 06:53:48 +00:00
|
|
|
stat.bExists = true;
|
|
|
|
stat.bExistsDirectory = data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
|
|
|
stat.bExistsFile = !stat.bExistsDirectory;
|
|
|
|
stat.bSymLink = data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT;
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2022-08-20 06:53:48 +00:00
|
|
|
stat.uSize = AuUInt64(data.nFileSizeLow) | (AuUInt64(data.nFileSizeHigh) << 32);
|
|
|
|
|
2023-05-03 07:57:21 +00:00
|
|
|
stat.createdNs = Time::ConvertTimestampNs(data.ftCreationTime);
|
|
|
|
stat.modifiedNs = Time::ConvertTimestampNs(data.ftLastWriteTime);
|
|
|
|
stat.accessedNs = Time::ConvertTimestampNs(data.ftLastAccessTime);
|
2021-06-27 21:25:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|