More MAX_PATH removals (#20113)

* Refactor FileScanner to lift a MAX_PATH limit

* Replace Platform::EnsureDirectoryExists with Path::CreateDirectory

* Remove MAX_PATH from Platform.Posix.cpp
This commit is contained in:
Silent 2023-05-09 21:08:46 +02:00 committed by GitHub
parent 58baa85a27
commit c4b70358c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 79 additions and 148 deletions

View File

@ -537,12 +537,12 @@ namespace ThemeManager
auto scanner = Path::ScanDirectory(themesPattern, true);
while (scanner->Next())
{
auto fileInfo = scanner->GetFileInfo();
auto name = Path::GetFileNameWithoutExtension(std::string(fileInfo->Name));
const auto& fileInfo = scanner->GetFileInfo();
auto name = Path::GetFileNameWithoutExtension(fileInfo.Name);
AvailableTheme theme{};
theme.Name = name;
theme.Path = GetThemeFileName(theme.Name);
theme.Path = GetThemeFileName(name);
outThemes->push_back(std::move(theme));
if (Path::Equals(CurrentThemePath, scanner->GetPath()))

View File

@ -19,7 +19,6 @@
#include <openrct2/localisation/Formatter.h>
#include <openrct2/localisation/Localisation.h>
#include <openrct2/object/ObjectManager.h>
#include <openrct2/platform/Platform.h>
#include <openrct2/ride/RideConstruction.h>
#include <openrct2/ride/RideData.h>
#include <openrct2/ride/TrackDesign.h>
@ -370,7 +369,7 @@ private:
{
auto env = OpenRCT2::GetContext()->GetPlatformEnvironment();
auto destPath = env->GetDirectoryPath(OpenRCT2::DIRBASE::USER, OpenRCT2::DIRID::TRACK);
if (!Platform::EnsureDirectoryExists(destPath.c_str()))
if (!Path::CreateDirectory(destPath))
{
LOG_ERROR("Unable to create directory '%s'", destPath.c_str());
ContextShowError(STR_CANT_SAVE_TRACK_DESIGN, STR_NONE, {});

View File

@ -882,7 +882,7 @@ public:
case WIDX_NEW_FOLDER:
{
const u8string path = Path::Combine(_directory, text);
if (!Platform::EnsureDirectoryExists(path))
if (!Path::CreateDirectory(path))
{
ContextShowError(STR_UNABLE_TO_CREATE_FOLDER, STR_NONE, {});
return;

View File

@ -15,9 +15,9 @@
#include "config/Config.h"
#include "core/Console.hpp"
#include "core/FileSystem.hpp"
#include "core/Path.hpp"
#include "core/String.hpp"
#include "object/AudioSampleTable.h"
#include "platform/Platform.h"
#include <cstdio>
@ -72,7 +72,7 @@ void AssetPackManager::Scan()
Scan(openrct2Dir);
auto userDirectory = fs::u8path(env->GetDirectoryPath(DIRBASE::USER, DIRID::ASSET_PACK));
Platform::EnsureDirectoryExists(userDirectory.u8string());
Path::CreateDirectory(userDirectory.u8string());
Scan(userDirectory);
}

View File

@ -20,7 +20,6 @@
#include "object/ObjectLimits.h"
#include "object/ObjectManager.h"
#include "object/ObjectRepository.h"
#include "platform/Platform.h"
#include "util/Util.h"
#include <cmath>
@ -370,7 +369,7 @@ int32_t CommandLineForSprite(const char** argv, int32_t argc)
return -1;
}
if (!Platform::EnsureDirectoryExists(outputPath))
if (!Path::CreateDirectory(outputPath))
{
fprintf(stderr, "Unable to create directory.\n");
return -1;
@ -430,7 +429,7 @@ int32_t CommandLineForSprite(const char** argv, int32_t argc)
auto& objManager = context->GetObjectManager();
const auto* const metaObject = objManager.GetLoadedObject(objectType, entryIndex);
if (!Platform::EnsureDirectoryExists(outputPath))
if (!Path::CreateDirectory(outputPath))
{
fprintf(stderr, "Unable to create directory.\n");
return -1;

View File

@ -1240,7 +1240,7 @@ namespace OpenRCT2
for (const auto& dirId : dirIds)
{
auto path = _env->GetDirectoryPath(dirBase, dirId);
if (!Platform::EnsureDirectoryExists(path.c_str()))
if (!Path::CreateDirectory(path))
LOG_ERROR("Unable to create directory '%s'.", path.c_str());
}
}
@ -1274,14 +1274,10 @@ namespace OpenRCT2
auto dstDirectory = Path::GetDirectory(dst);
// Create the directory if necessary
if (!Path::DirectoryExists(dstDirectory.c_str()))
if (!Path::CreateDirectory(dstDirectory))
{
Console::WriteLine("Creating directory '%s'", dstDirectory.c_str());
if (!Platform::EnsureDirectoryExists(dstDirectory.c_str()))
{
Console::Error::WriteLine("Could not create directory %s.", dstDirectory.c_str());
break;
}
Console::Error::WriteLine("Could not create directory %s.", dstDirectory.c_str());
break;
}
// Only copy the file if it doesn't already exist

View File

@ -704,7 +704,7 @@ void GameAutosave()
auto env = GetContext()->GetPlatformEnvironment();
auto autosaveDir = Path::Combine(env->GetDirectoryPath(DIRBASE::USER, subDirectory), u8"autosave");
Platform::EnsureDirectoryExists(autosaveDir.c_str());
Path::CreateDirectory(autosaveDir);
auto path = Path::Combine(autosaveDir, timeName);
auto backupFileName = u8string(u8"autosave") + fileExtension + u8".bak";

View File

@ -149,13 +149,13 @@ private:
auto scanner = Path::ScanDirectory(pattern, true);
while (scanner->Next())
{
auto fileInfo = scanner->GetFileInfo();
auto path = std::string(scanner->GetPath());
const auto& fileInfo = scanner->GetFileInfo();
auto path = scanner->GetPath();
stats.TotalFiles++;
stats.TotalFileSize += fileInfo->Size;
stats.FileDateModifiedChecksum ^= static_cast<uint32_t>(fileInfo->LastModified >> 32)
^ static_cast<uint32_t>(fileInfo->LastModified & 0xFFFFFFFF);
stats.TotalFileSize += fileInfo.Size;
stats.FileDateModifiedChecksum ^= static_cast<uint32_t>(fileInfo.LastModified >> 32)
^ static_cast<uint32_t>(fileInfo.LastModified & 0xFFFFFFFF);
stats.FileDateModifiedChecksum = Numerics::ror32(stats.FileDateModifiedChecksum, 5);
stats.PathChecksum += GetPathChecksum(path);

View File

@ -50,7 +50,7 @@ struct DirectoryChild
uint64_t LastModified = 0;
};
static uint32_t GetPathChecksum(const utf8* path);
static uint32_t GetPathChecksum(u8string_view path);
static bool MatchWildcard(const utf8* fileName, const utf8* pattern);
class FileScannerBase : public IFileScanner
@ -58,64 +58,54 @@ class FileScannerBase : public IFileScanner
private:
struct DirectoryState
{
std::string Path;
u8string Path;
std::vector<DirectoryChild> Listing;
int32_t Index = 0;
};
// Options
std::string _rootPath;
std::vector<std::string> _patterns;
bool _recurse;
const u8string _rootPath;
const std::vector<std::string> _patterns;
const bool _recurse;
// State
bool _started = false;
std::stack<DirectoryState> _directoryStack;
// Current
FileScanner::FileInfo* _currentFileInfo;
utf8* _currentPath;
FileScanner::FileInfo _currentFileInfo;
u8string _currentPath;
public:
FileScannerBase(const std::string& pattern, bool recurse)
FileScannerBase(u8string_view pattern, bool recurse)
: _rootPath(Path::GetDirectory(pattern))
, _patterns(GetPatterns(Path::GetFileName(pattern)))
, _recurse(recurse)
{
_rootPath = Path::GetDirectory(pattern);
_recurse = recurse;
_patterns = GetPatterns(Path::GetFileName(pattern));
_currentPath = Memory::Allocate<utf8>(MAX_PATH);
_currentFileInfo = Memory::Allocate<FileScanner::FileInfo>();
Reset();
}
~FileScannerBase() override
{
Memory::Free(_currentPath);
Memory::Free(_currentFileInfo);
}
~FileScannerBase() override = default;
const FileScanner::FileInfo* GetFileInfo() const override
const FileScanner::FileInfo& GetFileInfo() const override
{
return _currentFileInfo;
}
const utf8* GetPath() const override
const u8string& GetPath() const override
{
return _currentPath;
}
const utf8* GetPathRelative() const override
u8string GetPathRelative() const override
{
// +1 to remove the path separator
return _currentPath + _rootPath.size() + 1;
return Path::GetRelative(_currentPath, _rootPath);
}
void Reset() override
{
_started = false;
_directoryStack = std::stack<DirectoryState>();
_currentPath[0] = 0;
_directoryStack = {};
_currentPath.clear();
}
bool Next() override
@ -147,12 +137,11 @@ public:
}
else if (PatternMatch(child->Name))
{
auto path = Path::Combine(state->Path, child->Name);
String::Set(_currentPath, MAX_PATH, path.c_str());
_currentPath = Path::Combine(state->Path, child->Name);
_currentFileInfo->Name = child->Name.c_str();
_currentFileInfo->Size = child->Size;
_currentFileInfo->LastModified = child->LastModified;
_currentFileInfo.Name = child->Name;
_currentFileInfo.Size = child->Size;
_currentFileInfo.LastModified = child->LastModified;
return true;
}
}
@ -216,7 +205,7 @@ private:
class FileScannerWindows final : public FileScannerBase
{
public:
FileScannerWindows(const std::string& pattern, bool recurse)
FileScannerWindows(u8string_view pattern, bool recurse)
: FileScannerBase(pattern, recurse)
{
}
@ -269,7 +258,7 @@ private:
class FileScannerUnix final : public FileScannerBase
{
public:
FileScannerUnix(const std::string& pattern, bool recurse)
FileScannerUnix(u8string_view pattern, bool recurse)
: FileScannerBase(pattern, recurse)
{
}
@ -349,13 +338,13 @@ void Path::QueryDirectory(QueryDirectoryResult* result, const std::string& patte
auto scanner = Path::ScanDirectory(pattern, true);
while (scanner->Next())
{
const FileScanner::FileInfo* fileInfo = scanner->GetFileInfo();
const utf8* path = scanner->GetPath();
const FileScanner::FileInfo& fileInfo = scanner->GetFileInfo();
const u8string& path = scanner->GetPath();
result->TotalFiles++;
result->TotalFileSize += fileInfo->Size;
result->FileDateModifiedChecksum ^= static_cast<uint32_t>(fileInfo->LastModified >> 32)
^ static_cast<uint32_t>(fileInfo->LastModified & 0xFFFFFFFF);
result->TotalFileSize += fileInfo.Size;
result->FileDateModifiedChecksum ^= static_cast<uint32_t>(fileInfo.LastModified >> 32)
^ static_cast<uint32_t>(fileInfo.LastModified & 0xFFFFFFFF);
result->FileDateModifiedChecksum = Numerics::ror32(result->FileDateModifiedChecksum, 5);
result->PathChecksum += GetPathChecksum(path);
}
@ -380,12 +369,12 @@ std::vector<std::string> Path::GetDirectories(const std::string& path)
return subDirectories;
}
static uint32_t GetPathChecksum(const utf8* path)
static uint32_t GetPathChecksum(u8string_view path)
{
uint32_t hash = 0xD8430DED;
for (const utf8* ch = path; *ch != '\0'; ch++)
for (const utf8 ch : path)
{
hash += (*ch);
hash += ch;
hash += (hash << 10);
hash ^= (hash >> 6);
}

View File

@ -20,7 +20,7 @@ namespace FileScanner
{
struct FileInfo
{
const utf8* Name;
u8string Name;
uint64_t Size;
uint64_t LastModified;
};
@ -30,9 +30,9 @@ struct IFileScanner
{
virtual ~IFileScanner() = default;
virtual const FileScanner::FileInfo* GetFileInfo() const abstract;
virtual const utf8* GetPath() const abstract;
virtual const utf8* GetPathRelative() const abstract;
virtual const FileScanner::FileInfo& GetFileInfo() const abstract;
virtual const u8string& GetPath() const abstract;
virtual u8string GetPathRelative() const abstract;
virtual void Reset() abstract;
virtual bool Next() abstract;

View File

@ -53,9 +53,12 @@ namespace Path
return fs::u8path(path).parent_path().u8string();
}
void CreateDirectory(u8string_view path)
bool CreateDirectory(u8string_view path)
{
Platform::EnsureDirectoryExists(u8string(path).c_str());
std::error_code ec;
fs::create_directories(fs::u8path(path), ec);
// create_directories returns false if the directory already exists, but the error code is zero.
return ec.value() == 0;
}
bool DirectoryExists(u8string_view path)
@ -97,6 +100,12 @@ namespace Path
return fs::absolute(fs::u8path(relative), ec).u8string();
}
u8string GetRelative(u8string_view path, u8string_view base)
{
std::error_code ec;
return fs::relative(fs::u8path(path), fs::u8path(base), ec).u8string();
}
bool Equals(u8string_view a, u8string_view b)
{
return String::Equals(a, b, Platform::ShouldIgnoreCase());

View File

@ -24,7 +24,7 @@ namespace Path
}
u8string GetDirectory(u8string_view path);
void CreateDirectory(u8string_view path);
bool CreateDirectory(u8string_view path);
bool DirectoryExists(u8string_view path);
bool DeleteDirectory(u8string_view path);
u8string GetFileName(u8string_view origPath);
@ -33,6 +33,7 @@ namespace Path
u8string WithExtension(u8string_view path, u8string_view newExtension);
bool IsAbsolute(u8string_view path);
u8string GetAbsolute(u8string_view relative);
u8string GetRelative(u8string_view path, u8string_view base);
bool Equals(u8string_view a, u8string_view b);
/**

View File

@ -134,7 +134,7 @@ static std::string ScreenshotGetFormattedDateTime()
static std::optional<std::string> ScreenshotGetNextPath()
{
auto screenshotDirectory = ScreenshotGetDirectory();
if (!Platform::EnsureDirectoryExists(screenshotDirectory.c_str()))
if (!Path::CreateDirectory(screenshotDirectory))
{
LOG_ERROR("Unable to save screenshots in OpenRCT2 screenshot directory.");
return std::nullopt;

View File

@ -292,7 +292,7 @@ bool NetworkBase::BeginClient(const std::string& host, uint16_t port)
Console::WriteLine("Key generated, saving private bits as %s", keyPath.c_str());
const auto keysDirectory = NetworkGetKeysDirectory();
if (!Platform::EnsureDirectoryExists(keysDirectory.c_str()))
if (!Path::CreateDirectory(keysDirectory))
{
LOG_ERROR("Unable to create directory %s.", keysDirectory.c_str());
return false;
@ -1071,8 +1071,9 @@ std::string NetworkBase::BeginLog(const std::string& directory, const std::strin
throw std::runtime_error("strftime failed");
}
Platform::EnsureDirectoryExists(Path::Combine(directory, midName).c_str());
return Path::Combine(directory, midName, filename);
auto directoryMidName = Path::Combine(directory, midName);
Path::CreateDirectory(directoryMidName);
return Path::Combine(directoryMidName, filename);
}
void NetworkBase::AppendLog(std::ostream& fs, std::string_view s)
@ -2495,7 +2496,7 @@ void NetworkBase::Client_Handle_GAMESTATE(NetworkConnection& connection, Network
std::string outputPath = GetContext().GetPlatformEnvironment()->GetDirectoryPath(DIRBASE::USER, DIRID::LOG_DESYNCS);
Platform::EnsureDirectoryExists(outputPath.c_str());
Path::CreateDirectory(outputPath);
char uniqueFileName[128] = {};
snprintf(

View File

@ -31,9 +31,7 @@
# include <sys/time.h>
// The name of the mutex used to prevent multiple instances of the game from running
static constexpr u8string_view SINGLE_INSTANCE_MUTEX_NAME = u8"openrct2.lock";
static utf8 _userDataDirectoryPath[MAX_PATH] = { 0 };
static constexpr const utf8* SINGLE_INSTANCE_MUTEX_NAME = u8"openrct2.lock";
namespace Platform
{
@ -307,64 +305,13 @@ namespace Platform
# endif // __EMSCRIPTEN__
}
// Implement our own version of getumask(), as it is documented being
// "a vaporware GNU extension".
static mode_t openrct2_getumask()
{
mode_t mask = umask(0);
umask(mask);
return 0777 & ~mask; // Keep in mind 0777 is octal
}
bool EnsureDirectoryExists(u8string_view path)
{
mode_t mask = openrct2_getumask();
char buffer[MAX_PATH];
SafeStrCpy(buffer, u8string(path).c_str(), sizeof(buffer));
LOG_VERBOSE("Create directory: %s", buffer);
for (char* p = buffer + 1; *p != '\0'; p++)
{
if (*p == '/')
{
// Temporarily truncate
*p = '\0';
LOG_VERBOSE("mkdir(%s)", buffer);
if (mkdir(buffer, mask) != 0)
{
if (errno != EEXIST)
{
return false;
}
}
// Restore truncation
*p = '/';
}
}
LOG_VERBOSE("mkdir(%s)", buffer);
if (mkdir(buffer, mask) != 0)
{
if (errno != EEXIST)
{
return false;
}
}
return true;
}
bool LockSingleInstance()
{
auto pidFilePath = Path::Combine(_userDataDirectoryPath, SINGLE_INSTANCE_MUTEX_NAME);
// We will never close this file manually. The operating system will
// take care of that, because flock keeps the lock as long as the
// file is open and closes it automatically on file close.
// This is intentional.
int32_t pidFile = open(pidFilePath.c_str(), O_CREAT | O_RDWR, 0666);
int32_t pidFile = open(SINGLE_INSTANCE_MUTEX_NAME, O_CREAT | O_RDWR, 0666);
if (pidFile == -1)
{

View File

@ -786,13 +786,6 @@ namespace Platform
return !path.empty() ? Path::Combine(path, font.filename) : std::string();
}
bool EnsureDirectoryExists(u8string_view path)
{
auto wPath = String::ToWideChar(path);
auto success = CreateDirectoryW(wPath.c_str(), nullptr);
return success != FALSE || GetLastError() == ERROR_ALREADY_EXISTS;
}
bool LockSingleInstance()
{
// Check if operating system mutex exists

View File

@ -113,7 +113,6 @@ namespace Platform
u8string StrDecompToPrecomp(u8string_view input);
bool RequireNewWindow(bool openGL);
bool EnsureDirectoryExists(u8string_view path);
// Returns the bitmask of the GetLogicalDrives function for windows, 0 for other systems
int32_t GetDrives();
time_t FileGetModifiedTime(u8string_view path);

View File

@ -536,8 +536,7 @@ private:
*/
void ConvertMegaPark(const std::string& srcPath, const std::string& dstPath)
{
auto directory = Path::GetDirectory(dstPath);
Platform::EnsureDirectoryExists(directory.c_str());
Path::CreateDirectory(Path::GetDirectory(dstPath));
auto mpdat = File::ReadAllBytes(srcPath);

View File

@ -307,8 +307,7 @@ namespace OpenRCT2::Title
auto scanner = Path::ScanDirectory(pattern, true);
while (scanner->Next())
{
const utf8* path = scanner->GetPathRelative();
saves.push_back(path);
saves.push_back(scanner->GetPathRelative());
}
return saves;
}

View File

@ -57,7 +57,7 @@ static std::vector<ReplayTestData> GetReplayFiles()
while (scanner->Next())
{
ReplayTestData test;
test.name = sanitizeTestName(scanner->GetFileInfo()->Name);
test.name = sanitizeTestName(scanner->GetFileInfo().Name);
test.filePath = scanner->GetPath();
res.push_back(std::move(test));
}