|
|
|
|
@ -21,6 +21,20 @@
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
#include <shlobj.h>
|
|
|
|
|
|
|
|
|
|
#if defined(_UWP)
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <io.h>
|
|
|
|
|
|
|
|
|
|
#include <winrt/Windows.ApplicationModel.h>
|
|
|
|
|
#include <winrt/Windows.Devices.Enumeration.h>
|
|
|
|
|
#include <winrt/Windows.Foundation.Collections.h>
|
|
|
|
|
#include <winrt/Windows.Foundation.h>
|
|
|
|
|
#include <winrt/Windows.Storage.FileProperties.h>
|
|
|
|
|
#include <winrt/Windows.Storage.Search.h>
|
|
|
|
|
#include <winrt/Windows.Storage.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
#include <dirent.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
@ -713,7 +727,7 @@ std::vector<std::string> GetRootDirectoryList()
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string> results;
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#if defined(_WIN32) && !defined(_UWP)
|
|
|
|
|
char buf[256];
|
|
|
|
|
if (GetLogicalDriveStringsA(sizeof(buf), buf) != 0)
|
|
|
|
|
{
|
|
|
|
|
@ -725,6 +739,28 @@ std::vector<std::string> GetRootDirectoryList()
|
|
|
|
|
ptr += len + 1u;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#elif defined(_UWP)
|
|
|
|
|
if (const auto install_location = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation();
|
|
|
|
|
install_location)
|
|
|
|
|
{
|
|
|
|
|
if (const auto path = install_location.Path(); !path.empty())
|
|
|
|
|
results.push_back(StringUtil::WideStringToUTF8String(path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (const auto local_location = winrt::Windows::Storage::ApplicationData::Current().LocalFolder(); local_location)
|
|
|
|
|
{
|
|
|
|
|
if (const auto path = local_location.Path(); !path.empty())
|
|
|
|
|
results.push_back(StringUtil::WideStringToUTF8String(path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto devices = winrt::Windows::Storage::KnownFolders::RemovableDevices();
|
|
|
|
|
const auto folders_task(devices.GetFoldersAsync());
|
|
|
|
|
for (const auto& storage_folder : folders_task.get())
|
|
|
|
|
{
|
|
|
|
|
const auto path = storage_folder.Path();
|
|
|
|
|
if (!path.empty())
|
|
|
|
|
results.push_back(StringUtil::WideStringToUTF8String(path));
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
const char* home_path = std::getenv("HOME");
|
|
|
|
|
if (home_path)
|
|
|
|
|
@ -772,6 +808,106 @@ FileSystem::ManagedCFilePtr OpenManagedCFile(const char* filename, const char* m
|
|
|
|
|
return ManagedCFilePtr(OpenCFile(filename, mode), [](std::FILE* fp) { std::fclose(fp); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef _UWP
|
|
|
|
|
std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
|
|
|
|
|
{
|
|
|
|
|
DWORD access = 0;
|
|
|
|
|
DWORD share = 0;
|
|
|
|
|
DWORD disposition = 0;
|
|
|
|
|
|
|
|
|
|
int flags = 0;
|
|
|
|
|
const wchar_t* tmode = mode;
|
|
|
|
|
while (*tmode)
|
|
|
|
|
{
|
|
|
|
|
if (*tmode == L'r' && *(tmode + 1) == L'+')
|
|
|
|
|
{
|
|
|
|
|
access = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
|
share = 0;
|
|
|
|
|
disposition = OPEN_EXISTING;
|
|
|
|
|
flags |= _O_RDWR;
|
|
|
|
|
tmode += 2;
|
|
|
|
|
}
|
|
|
|
|
else if (*tmode == L'w' && *(tmode + 1) == L'+')
|
|
|
|
|
{
|
|
|
|
|
access = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
|
share = 0;
|
|
|
|
|
disposition = CREATE_ALWAYS;
|
|
|
|
|
flags |= _O_RDWR | _O_CREAT | _O_TRUNC;
|
|
|
|
|
tmode += 2;
|
|
|
|
|
}
|
|
|
|
|
else if (*tmode == L'a' && *(tmode + 1) == L'+')
|
|
|
|
|
{
|
|
|
|
|
access = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
|
share = 0;
|
|
|
|
|
disposition = CREATE_ALWAYS;
|
|
|
|
|
flags |= _O_RDWR | _O_APPEND | _O_CREAT | _O_TRUNC;
|
|
|
|
|
tmode += 2;
|
|
|
|
|
}
|
|
|
|
|
else if (*tmode == L'r')
|
|
|
|
|
{
|
|
|
|
|
access = GENERIC_READ;
|
|
|
|
|
share = 0;
|
|
|
|
|
disposition = OPEN_EXISTING;
|
|
|
|
|
flags |= _O_RDONLY;
|
|
|
|
|
tmode++;
|
|
|
|
|
}
|
|
|
|
|
else if (*tmode == L'w')
|
|
|
|
|
{
|
|
|
|
|
access = GENERIC_WRITE;
|
|
|
|
|
share = 0;
|
|
|
|
|
disposition = CREATE_ALWAYS;
|
|
|
|
|
flags |= _O_WRONLY | _O_CREAT | _O_TRUNC;
|
|
|
|
|
tmode++;
|
|
|
|
|
}
|
|
|
|
|
else if (*tmode == L'a')
|
|
|
|
|
{
|
|
|
|
|
access = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
|
share = 0;
|
|
|
|
|
disposition = CREATE_ALWAYS;
|
|
|
|
|
flags |= _O_WRONLY | _O_APPEND | _O_CREAT | _O_TRUNC;
|
|
|
|
|
tmode++;
|
|
|
|
|
}
|
|
|
|
|
else if (*tmode == L'b')
|
|
|
|
|
{
|
|
|
|
|
flags |= _O_BINARY;
|
|
|
|
|
tmode++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Log_ErrorPrintf("Unknown mode flags: '%s'", StringUtil::WideStringToUTF8String(mode).c_str());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HANDLE hFile = CreateFileFromAppW(wfilename, access, share, nullptr, disposition, 0, nullptr);
|
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
if (flags & _O_APPEND && !SetFilePointerEx(hFile, LARGE_INTEGER{}, nullptr, FILE_END))
|
|
|
|
|
{
|
|
|
|
|
Log_ErrorPrintf("SetFilePointerEx() failed: %08X", GetLastError());
|
|
|
|
|
CloseHandle(hFile);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int fd = _open_osfhandle(reinterpret_cast<intptr_t>(hFile), flags);
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
{
|
|
|
|
|
CloseHandle(hFile);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::FILE* fp = _wfdopen(fd, mode);
|
|
|
|
|
if (!fp)
|
|
|
|
|
{
|
|
|
|
|
_close(fd);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fp;
|
|
|
|
|
}
|
|
|
|
|
#endif // _UWP
|
|
|
|
|
|
|
|
|
|
std::FILE* OpenCFile(const char* filename, const char* mode)
|
|
|
|
|
{
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
@ -789,9 +925,16 @@ std::FILE* OpenCFile(const char* filename, const char* mode)
|
|
|
|
|
{
|
|
|
|
|
wfilename[wlen] = 0;
|
|
|
|
|
wmode[wmodelen] = 0;
|
|
|
|
|
|
|
|
|
|
std::FILE* fp;
|
|
|
|
|
if (_wfopen_s(&fp, wfilename, wmode) != 0)
|
|
|
|
|
{
|
|
|
|
|
#ifdef _UWP
|
|
|
|
|
return OpenCFileUWP(wfilename, wmode);
|
|
|
|
|
#else
|
|
|
|
|
return nullptr;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fp;
|
|
|
|
|
}
|
|
|
|
|
@ -1052,6 +1195,19 @@ static u32 TranslateWin32Attributes(u32 Win32Attributes)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static DWORD WrapGetFileAttributes(const wchar_t* path)
|
|
|
|
|
{
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
return GetFileAttributesW(path);
|
|
|
|
|
#else
|
|
|
|
|
WIN32_FILE_ATTRIBUTE_DATA fad;
|
|
|
|
|
if (!GetFileAttributesExFromAppW(path, GetFileExInfoStandard, &fad))
|
|
|
|
|
return INVALID_FILE_ATTRIBUTES;
|
|
|
|
|
|
|
|
|
|
return fad.dwFileAttributes;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const u32 READ_DIRECTORY_CHANGES_NOTIFY_FILTER = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
|
|
|
|
|
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE |
|
|
|
|
|
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION;
|
|
|
|
|
@ -1064,7 +1220,7 @@ public:
|
|
|
|
|
m_directoryChangeQueued(false)
|
|
|
|
|
{
|
|
|
|
|
m_bufferSize = 16384;
|
|
|
|
|
m_pBuffer = new byte[m_bufferSize];
|
|
|
|
|
m_pBuffer = new u8[m_bufferSize];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ~ChangeNotifierWin32()
|
|
|
|
|
@ -1103,7 +1259,7 @@ public:
|
|
|
|
|
// has any bytes?
|
|
|
|
|
if (bytesRead > 0)
|
|
|
|
|
{
|
|
|
|
|
const byte* pCurrentPointer = m_pBuffer;
|
|
|
|
|
const u8* pCurrentPointer = m_pBuffer;
|
|
|
|
|
PathString fileName;
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
@ -1176,15 +1332,26 @@ private:
|
|
|
|
|
HANDLE m_hDirectory;
|
|
|
|
|
OVERLAPPED m_overlapped;
|
|
|
|
|
bool m_directoryChangeQueued;
|
|
|
|
|
byte* m_pBuffer;
|
|
|
|
|
u8* m_pBuffer;
|
|
|
|
|
u32 m_bufferSize;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<ChangeNotifier> CreateChangeNotifier(const char* path, bool recursiveWatch)
|
|
|
|
|
{
|
|
|
|
|
// open the directory up
|
|
|
|
|
HANDLE hDirectory = CreateFileA(path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
|
|
|
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr);
|
|
|
|
|
std::wstring path_wstr(StringUtil::UTF8StringToWideString(path));
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
HANDLE hDirectory =
|
|
|
|
|
CreateFileW(path_wstr.c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
|
|
|
|
|
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr);
|
|
|
|
|
#else
|
|
|
|
|
CREATEFILE2_EXTENDED_PARAMETERS ep = {};
|
|
|
|
|
ep.dwSize = sizeof(ep);
|
|
|
|
|
ep.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
|
ep.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
|
|
|
|
|
HANDLE hDirectory = CreateFile2FromAppW(path_wstr.c_str(), FILE_LIST_DIRECTORY,
|
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, OPEN_EXISTING, &ep);
|
|
|
|
|
#endif
|
|
|
|
|
if (hDirectory == nullptr)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
@ -1212,8 +1379,18 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
|
|
|
|
|
tempStr = StringUtil::StdStringFromFormat("%s\\*", OriginPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// holder for utf-8 conversion
|
|
|
|
|
WIN32_FIND_DATAW wfd;
|
|
|
|
|
std::string utf8_filename;
|
|
|
|
|
utf8_filename.reserve(countof(wfd.cFileName) * 2);
|
|
|
|
|
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
HANDLE hFind = FindFirstFileW(StringUtil::UTF8StringToWideString(tempStr).c_str(), &wfd);
|
|
|
|
|
#else
|
|
|
|
|
HANDLE hFind = FindFirstFileExFromAppW(StringUtil::UTF8StringToWideString(tempStr).c_str(), FindExInfoBasic, &wfd,
|
|
|
|
|
FindExSearchNameMatch, nullptr, 0);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
@ -1227,10 +1404,6 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
|
|
|
|
|
wildCardMatchAll = !(std::strcmp(Pattern, "*"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// holder for utf-8 conversion
|
|
|
|
|
std::string utf8_filename;
|
|
|
|
|
utf8_filename.reserve(countof(wfd.cFileName) * 2);
|
|
|
|
|
|
|
|
|
|
// iterate results
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
@ -1360,6 +1533,7 @@ bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* pStatData)
|
|
|
|
|
|
|
|
|
|
wpath[wlen] = 0;
|
|
|
|
|
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
// determine attributes for the path. if it's a directory, things have to be handled differently..
|
|
|
|
|
DWORD fileAttributes = GetFileAttributesW(wpath);
|
|
|
|
|
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
|
|
|
|
|
@ -1398,6 +1572,16 @@ bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* pStatData)
|
|
|
|
|
pStatData->ModificationTime.SetWindowsFileTime(&bhfi.ftLastWriteTime);
|
|
|
|
|
pStatData->Size = ((u64)bhfi.nFileSizeHigh) << 32 | (u64)bhfi.nFileSizeLow;
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
WIN32_FILE_ATTRIBUTE_DATA fad;
|
|
|
|
|
if (!GetFileAttributesExFromAppW(wpath, GetFileExInfoStandard, &fad))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
pStatData->Attributes = TranslateWin32Attributes(fad.dwFileAttributes);
|
|
|
|
|
pStatData->ModificationTime.SetWindowsFileTime(&fad.ftLastWriteTime);
|
|
|
|
|
pStatData->Size = ((u64)fad.nFileSizeHigh) << 32 | (u64)fad.nFileSizeLow;
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FileSystem::StatFile(std::FILE* fp, FILESYSTEM_STAT_DATA* pStatData)
|
|
|
|
|
@ -1447,7 +1631,7 @@ bool FileSystem::FileExists(const char* path)
|
|
|
|
|
wpath[wlen] = 0;
|
|
|
|
|
|
|
|
|
|
// determine attributes for the path. if it's a directory, things have to be handled differently..
|
|
|
|
|
DWORD fileAttributes = GetFileAttributesW(wpath);
|
|
|
|
|
DWORD fileAttributes = WrapGetFileAttributes(wpath);
|
|
|
|
|
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
@ -1477,7 +1661,7 @@ bool FileSystem::DirectoryExists(const char* path)
|
|
|
|
|
wpath[wlen] = 0;
|
|
|
|
|
|
|
|
|
|
// determine attributes for the path. if it's a directory, things have to be handled differently..
|
|
|
|
|
DWORD fileAttributes = GetFileAttributesW(wpath);
|
|
|
|
|
DWORD fileAttributes = WrapGetFileAttributes(wpath);
|
|
|
|
|
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
@ -1495,16 +1679,21 @@ bool FileSystem::CreateDirectory(const char* Path, bool Recursive)
|
|
|
|
|
if (wpath[0] == L'\0')
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// try just flat-out, might work if there's no other segments that have to be made
|
|
|
|
|
// try just flat-out, might work if there's no other segments that have to be made
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
if (CreateDirectoryW(wpath.c_str(), nullptr))
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
if (CreateDirectoryFromAppW(wpath.c_str(), nullptr))
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// check error
|
|
|
|
|
DWORD lastError = GetLastError();
|
|
|
|
|
if (lastError == ERROR_ALREADY_EXISTS)
|
|
|
|
|
{
|
|
|
|
|
// check the attributes
|
|
|
|
|
u32 Attributes = GetFileAttributesW(wpath.c_str());
|
|
|
|
|
u32 Attributes = WrapGetFileAttributes(wpath.c_str());
|
|
|
|
|
if (Attributes != INVALID_FILE_ATTRIBUTES && Attributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
|
return true;
|
|
|
|
|
else
|
|
|
|
|
@ -1523,7 +1712,13 @@ bool FileSystem::CreateDirectory(const char* Path, bool Recursive)
|
|
|
|
|
if (wpath[i] == L'\\' || wpath[i] == L'/')
|
|
|
|
|
{
|
|
|
|
|
tempStr[i] = L'\0';
|
|
|
|
|
if (!CreateDirectoryW(tempStr, nullptr))
|
|
|
|
|
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
const BOOL result = CreateDirectoryW(tempStr, nullptr);
|
|
|
|
|
#else
|
|
|
|
|
const BOOL result = CreateDirectoryFromAppW(tempStr, nullptr);
|
|
|
|
|
#endif
|
|
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
lastError = GetLastError();
|
|
|
|
|
if (lastError != ERROR_ALREADY_EXISTS) // fine, continue to next path segment
|
|
|
|
|
@ -1537,7 +1732,12 @@ bool FileSystem::CreateDirectory(const char* Path, bool Recursive)
|
|
|
|
|
// re-create the end if it's not a separator, check / as well because windows can interpret them
|
|
|
|
|
if (wpath[pathLength - 1] != L'\\' && wpath[pathLength - 1] != L'/')
|
|
|
|
|
{
|
|
|
|
|
if (!CreateDirectoryW(wpath.c_str(), nullptr))
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
const BOOL result = CreateDirectoryW(wpath.c_str(), nullptr);
|
|
|
|
|
#else
|
|
|
|
|
const BOOL result = CreateDirectoryFromAppW(wpath.c_str(), nullptr);
|
|
|
|
|
#endif
|
|
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
lastError = GetLastError();
|
|
|
|
|
if (lastError != ERROR_ALREADY_EXISTS)
|
|
|
|
|
@ -1561,14 +1761,15 @@ bool FileSystem::DeleteFile(const char* Path)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const std::wstring wpath(StringUtil::UTF8StringToWideString(Path));
|
|
|
|
|
DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
|
|
|
|
|
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
|
|
|
|
|
const DWORD fileAttributes = WrapGetFileAttributes(wpath.c_str());
|
|
|
|
|
if (fileAttributes == INVALID_FILE_ATTRIBUTES || fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!(fileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
|
|
|
return (DeleteFileW(wpath.c_str()) == TRUE);
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
return (DeleteFileW(wpath.c_str()) == TRUE);
|
|
|
|
|
#else
|
|
|
|
|
return (DeleteFileFromAppW(wpath.c_str()) == TRUE);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FileSystem::RenamePath(const char* OldPath, const char* NewPath)
|
|
|
|
|
@ -1576,11 +1777,19 @@ bool FileSystem::RenamePath(const char* OldPath, const char* NewPath)
|
|
|
|
|
const std::wstring old_wpath(StringUtil::UTF8StringToWideString(OldPath));
|
|
|
|
|
const std::wstring new_wpath(StringUtil::UTF8StringToWideString(NewPath));
|
|
|
|
|
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
if (!MoveFileExW(old_wpath.c_str(), new_wpath.c_str(), MOVEFILE_REPLACE_EXISTING))
|
|
|
|
|
{
|
|
|
|
|
Log_ErrorPrintf("MoveFileEx('%s', '%s') failed: %08X", OldPath, NewPath, GetLastError());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (!ReplaceFileFromAppW(old_wpath.c_str(), new_wpath.c_str(), nullptr, 0, nullptr, nullptr))
|
|
|
|
|
{
|
|
|
|
|
Log_ErrorPrintf("MoveFileFromAppW('%s', '%s') failed: %08X", OldPath, NewPath, GetLastError());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
@ -1588,13 +1797,19 @@ bool FileSystem::RenamePath(const char* OldPath, const char* NewPath)
|
|
|
|
|
static bool RecursiveDeleteDirectory(const std::wstring& wpath, bool Recursive)
|
|
|
|
|
{
|
|
|
|
|
// ensure it exists
|
|
|
|
|
DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
|
|
|
|
|
if (fileAttributes == INVALID_FILE_ATTRIBUTES || !(fileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
|
|
|
const DWORD fileAttributes = WrapGetFileAttributes(wpath.c_str());
|
|
|
|
|
if (fileAttributes == INVALID_FILE_ATTRIBUTES || fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// non-recursive case just try removing the directory
|
|
|
|
|
if (!Recursive)
|
|
|
|
|
{
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
return (RemoveDirectoryW(wpath.c_str()) == TRUE);
|
|
|
|
|
#else
|
|
|
|
|
return (RemoveDirectoryFromAppW(wpath.c_str()) == TRUE);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// doing a recursive delete
|
|
|
|
|
std::wstring fileName = wpath;
|
|
|
|
|
@ -1602,7 +1817,12 @@ static bool RecursiveDeleteDirectory(const std::wstring& wpath, bool Recursive)
|
|
|
|
|
|
|
|
|
|
// is there any files?
|
|
|
|
|
WIN32_FIND_DATAW findData;
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
HANDLE hFind = FindFirstFileW(fileName.c_str(), &findData);
|
|
|
|
|
#else
|
|
|
|
|
HANDLE hFind =
|
|
|
|
|
FindFirstFileExFromAppW(fileName.c_str(), FindExInfoBasic, &findData, FindExSearchNameMatch, nullptr, 0);
|
|
|
|
|
#endif
|
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
@ -1634,7 +1854,12 @@ static bool RecursiveDeleteDirectory(const std::wstring& wpath, bool Recursive)
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// found a file, so delete it
|
|
|
|
|
if (!DeleteFileW(fileName.c_str()))
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
const BOOL result = DeleteFileW(fileName.c_str());
|
|
|
|
|
#else
|
|
|
|
|
const BOOL result = DeleteFileFromAppW(fileName.c_str());
|
|
|
|
|
#endif
|
|
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
FindClose(hFind);
|
|
|
|
|
return false;
|
|
|
|
|
@ -1644,7 +1869,12 @@ static bool RecursiveDeleteDirectory(const std::wstring& wpath, bool Recursive)
|
|
|
|
|
FindClose(hFind);
|
|
|
|
|
|
|
|
|
|
// nuke the directory itself
|
|
|
|
|
if (!RemoveDirectoryW(wpath.c_str()))
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
const BOOL result = RemoveDirectoryW(wpath.c_str());
|
|
|
|
|
#else
|
|
|
|
|
const BOOL result = RemoveDirectoryFromAppW(wpath.c_str());
|
|
|
|
|
#endif
|
|
|
|
|
if (!result)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// done
|
|
|
|
|
@ -1664,8 +1894,10 @@ std::string GetProgramPath()
|
|
|
|
|
|
|
|
|
|
// Fall back to the main module if this fails.
|
|
|
|
|
HMODULE module = nullptr;
|
|
|
|
|
#ifndef _UWP
|
|
|
|
|
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
|
|
|
|
reinterpret_cast<LPCWSTR>(&GetProgramPath), &module);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
|