From 1434507b41202a3e6b15a55731bee3ba4d747d25 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 27 Nov 2024 17:19:49 +1000 Subject: [PATCH] FileSystem: Add span overload for WriteBinaryFile() And normalize filename -> path parameter names. --- src/common/file_system.cpp | 153 ++++++++++++++++++++----------------- src/common/file_system.h | 39 +++++----- 2 files changed, 102 insertions(+), 90 deletions(-) diff --git a/src/common/file_system.cpp b/src/common/file_system.cpp index 279fdcdee..48ae9d7e0 100644 --- a/src/common/file_system.cpp +++ b/src/common/file_system.cpp @@ -608,14 +608,14 @@ std::string Path::ReplaceExtension(std::string_view path, std::string_view new_e return ret; } -static std::string_view::size_type GetLastSeperatorPosition(std::string_view filename, bool include_separator) +static std::string_view::size_type GetLastSeperatorPosition(std::string_view path, bool include_separator) { - std::string_view::size_type last_separator = filename.rfind('/'); + std::string_view::size_type last_separator = path.rfind('/'); if (include_separator && last_separator != std::string_view::npos) last_separator++; #if defined(_WIN32) - std::string_view::size_type other_last_separator = filename.rfind('\\'); + std::string_view::size_type other_last_separator = path.rfind('\\'); if (other_last_separator != std::string_view::npos) { if (include_separator) @@ -845,13 +845,13 @@ std::vector FileSystem::GetRootDirectoryList() return results; } -std::string Path::BuildRelativePath(std::string_view filename, std::string_view new_filename) +std::string Path::BuildRelativePath(std::string_view path, std::string_view new_filename) { std::string new_string; - std::string_view::size_type pos = GetLastSeperatorPosition(filename, true); + std::string_view::size_type pos = GetLastSeperatorPosition(path, true); if (pos != std::string_view::npos) - new_string.assign(filename, 0, pos); + new_string.assign(path, 0, pos); new_string.append(new_filename); return new_string; } @@ -873,10 +873,10 @@ std::string Path::Combine(std::string_view base, std::string_view next) return ret; } -std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode, Error* error) +std::FILE* FileSystem::OpenCFile(const char* path, const char* mode, Error* error) { #ifdef _WIN32 - const std::wstring wfilename = GetWin32Path(filename); + const std::wstring wfilename = GetWin32Path(path); const std::wstring wmode = StringUtil::UTF8StringToWideString(mode); if (!wfilename.empty() && !wmode.empty()) { @@ -892,7 +892,7 @@ std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode, Error* } std::FILE* fp; - const errno_t err = fopen_s(&fp, filename, mode); + const errno_t err = fopen_s(&fp, path, mode); if (err != 0) { Error::SetErrno(error, err); @@ -901,24 +901,24 @@ std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode, Error* return fp; #else - std::FILE* fp = std::fopen(filename, mode); + std::FILE* fp = std::fopen(path, mode); if (!fp) Error::SetErrno(error, errno); return fp; #endif } -std::FILE* FileSystem::OpenExistingOrCreateCFile(const char* filename, s32 retry_ms, Error* error /*= nullptr*/) +std::FILE* FileSystem::OpenExistingOrCreateCFile(const char* path, s32 retry_ms, Error* error /*= nullptr*/) { #ifdef _WIN32 - const std::wstring wfilename = GetWin32Path(filename); - if (wfilename.empty()) + const std::wstring wpath = GetWin32Path(path); + if (wpath.empty()) { Error::SetStringView(error, "Invalid path."); return nullptr; } - HANDLE file = CreateFileW(wfilename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, NULL); + HANDLE file = CreateFileW(wpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, NULL); // if there's a sharing violation, keep retrying if (file == INVALID_HANDLE_VALUE && GetLastError() == ERROR_SHARING_VIOLATION && retry_ms >= 0) @@ -927,7 +927,7 @@ std::FILE* FileSystem::OpenExistingOrCreateCFile(const char* filename, s32 retry while (retry_ms == 0 || timer.GetTimeMilliseconds() <= retry_ms) { Sleep(1); - file = CreateFileW(wfilename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, NULL); + file = CreateFileW(wpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, NULL); if (file != INVALID_HANDLE_VALUE || GetLastError() != ERROR_SHARING_VIOLATION) break; } @@ -936,11 +936,11 @@ std::FILE* FileSystem::OpenExistingOrCreateCFile(const char* filename, s32 retry if (file == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND) { // try creating it - file = CreateFileW(wfilename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_NEW, 0, NULL); + file = CreateFileW(wpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_NEW, 0, NULL); if (file == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_EXISTS) { // someone else beat us in the race, try again with existing. - file = CreateFileW(wfilename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, NULL); + file = CreateFileW(wpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, NULL); } } @@ -970,7 +970,7 @@ std::FILE* FileSystem::OpenExistingOrCreateCFile(const char* filename, s32 retry return cfile; #else - std::FILE* fp = std::fopen(filename, "r+b"); + std::FILE* fp = std::fopen(path, "r+b"); if (fp) return fp; @@ -982,13 +982,13 @@ std::FILE* FileSystem::OpenExistingOrCreateCFile(const char* filename, s32 retry } // try again, but create the file. mode "x" exists on all platforms. - fp = std::fopen(filename, "w+bx"); + fp = std::fopen(path, "w+bx"); if (fp) return fp; // if it already exists, someone else beat us in the race. try again with existing. if (errno == EEXIST) - fp = std::fopen(filename, "r+b"); + fp = std::fopen(path, "r+b"); if (!fp) { Error::SetErrno(error, errno); @@ -999,28 +999,28 @@ std::FILE* FileSystem::OpenExistingOrCreateCFile(const char* filename, s32 retry #endif } -int FileSystem::OpenFDFile(const char* filename, int flags, int mode, Error* error) +int FileSystem::OpenFDFile(const char* path, int flags, int mode, Error* error) { #ifdef _WIN32 - const std::wstring wfilename(GetWin32Path(filename)); - if (!wfilename.empty()) - return _wopen(wfilename.c_str(), flags, mode); + const std::wstring wpath = GetWin32Path(path); + if (!wpath.empty()) + return _wopen(wpath.c_str(), flags, mode); return -1; #else - const int fd = open(filename, flags, mode); + const int fd = open(path, flags, mode); if (fd < 0) Error::SetErrno(error, errno); return fd; #endif } -std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error) +std::FILE* FileSystem::OpenSharedCFile(const char* path, const char* mode, FileShareMode share_mode, Error* error) { #ifdef _WIN32 - const std::wstring wfilename = GetWin32Path(filename); + const std::wstring wpath = GetWin32Path(path); const std::wstring wmode = StringUtil::UTF8StringToWideString(mode); - if (wfilename.empty() || wmode.empty()) + if (wpath.empty() || wmode.empty()) return nullptr; int share_flags = 0; @@ -1041,14 +1041,14 @@ std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, F break; } - std::FILE* fp = _wfsopen(wfilename.c_str(), wmode.c_str(), share_flags); + std::FILE* fp = _wfsopen(wpath.c_str(), wmode.c_str(), share_flags); if (fp) return fp; Error::SetErrno(error, errno); return nullptr; #else - std::FILE* fp = std::fopen(filename, mode); + std::FILE* fp = std::fopen(path, mode); if (!fp) Error::SetErrno(error, errno); return fp; @@ -1165,8 +1165,8 @@ std::string Path::CreateFileURL(std::string_view path) return ret; } -FileSystem::AtomicRenamedFileDeleter::AtomicRenamedFileDeleter(std::string temp_filename, std::string final_filename) - : m_temp_filename(std::move(temp_filename)), m_final_filename(std::move(final_filename)) +FileSystem::AtomicRenamedFileDeleter::AtomicRenamedFileDeleter(std::string temp_path, std::string final_path) + : m_temp_path(std::move(temp_path)), m_final_path(std::move(final_path)) { } @@ -1180,11 +1180,11 @@ void FileSystem::AtomicRenamedFileDeleter::operator()(std::FILE* fp) Error error; // final filename empty => discarded. - if (!m_final_filename.empty()) + if (!m_final_path.empty()) { if (!commit(fp, &error)) { - ERROR_LOG("Failed to commit temporary file '{}', discarding. Error was {}.", Path::GetFileName(m_temp_filename), + ERROR_LOG("Failed to commit temporary file '{}', discarding. Error was {}.", Path::GetFileName(m_temp_path), error.GetDescription()); } @@ -1194,8 +1194,8 @@ void FileSystem::AtomicRenamedFileDeleter::operator()(std::FILE* fp) // we're discarding the file, don't care if it fails. std::fclose(fp); - if (!DeleteFile(m_temp_filename.c_str(), &error)) - ERROR_LOG("Failed to delete temporary file '{}': {}", Path::GetFileName(m_temp_filename), error.GetDescription()); + if (!DeleteFile(m_temp_path.c_str(), &error)) + ERROR_LOG("Failed to delete temporary file '{}': {}", Path::GetFileName(m_temp_path), error.GetDescription()); } bool FileSystem::AtomicRenamedFileDeleter::commit(std::FILE* fp, Error* error) @@ -1209,38 +1209,38 @@ bool FileSystem::AtomicRenamedFileDeleter::commit(std::FILE* fp, Error* error) if (std::fclose(fp) != 0) { Error::SetErrno(error, "fclose() failed: ", errno); - m_final_filename.clear(); + m_final_path.clear(); } // Should not have been discarded. - if (!m_final_filename.empty()) + if (!m_final_path.empty()) { - return RenamePath(m_temp_filename.c_str(), m_final_filename.c_str(), error); + return RenamePath(m_temp_path.c_str(), m_final_path.c_str(), error); } else { Error::SetStringView(error, "File has already been discarded."); - return DeleteFile(m_temp_filename.c_str(), error); + return DeleteFile(m_temp_path.c_str(), error); } } void FileSystem::AtomicRenamedFileDeleter::discard() { - m_final_filename = {}; + m_final_path = {}; } -FileSystem::AtomicRenamedFile FileSystem::CreateAtomicRenamedFile(std::string filename, Error* error /*= nullptr*/) +FileSystem::AtomicRenamedFile FileSystem::CreateAtomicRenamedFile(std::string path, Error* error /*= nullptr*/) { - std::string temp_filename; + std::string temp_path; std::FILE* fp = nullptr; - if (!filename.empty()) + if (!path.empty()) { // this is disgusting, but we need null termination, and std::string::data() does not guarantee it. - const size_t filename_length = filename.length(); - const size_t name_buf_size = filename_length + 8; + const size_t path_length = path.length(); + const size_t name_buf_size = path_length + 8; std::unique_ptr name_buf = std::make_unique(name_buf_size); - std::memcpy(name_buf.get(), filename.c_str(), filename_length); - StringUtil::Strlcpy(name_buf.get() + filename_length, ".XXXXXX", name_buf_size); + std::memcpy(name_buf.get(), path.c_str(), path_length); + StringUtil::Strlcpy(name_buf.get() + path_length, ".XXXXXX", name_buf_size); #ifdef _WIN32 const errno_t err = _mktemp_s(name_buf.get(), name_buf_size); @@ -1267,18 +1267,18 @@ FileSystem::AtomicRenamedFile FileSystem::CreateAtomicRenamedFile(std::string fi #endif if (fp) - temp_filename.assign(name_buf.get(), name_buf_size - 1); + temp_path.assign(name_buf.get(), name_buf_size - 1); else - filename.clear(); + path.clear(); } - return AtomicRenamedFile(fp, AtomicRenamedFileDeleter(std::move(temp_filename), std::move(filename))); + return AtomicRenamedFile(fp, AtomicRenamedFileDeleter(std::move(temp_path), std::move(path))); } -bool FileSystem::WriteAtomicRenamedFile(std::string filename, const void* data, size_t data_length, +bool FileSystem::WriteAtomicRenamedFile(std::string path, const void* data, size_t data_length, Error* error /*= nullptr*/) { - AtomicRenamedFile fp = CreateAtomicRenamedFile(std::move(filename), error); + AtomicRenamedFile fp = CreateAtomicRenamedFile(std::move(path), error); if (!fp) return false; @@ -1292,6 +1292,11 @@ bool FileSystem::WriteAtomicRenamedFile(std::string filename, const void* data, return true; } +bool FileSystem::WriteAtomicRenamedFile(std::string path, const std::span data, Error* error /* = nullptr */) +{ + return WriteAtomicRenamedFile(std::move(path), data.empty() ? nullptr : data.data(), data.size(), error); +} + void FileSystem::DiscardAtomicRenamedFile(AtomicRenamedFile& file) { file.get_deleter().discard(); @@ -1306,21 +1311,20 @@ bool FileSystem::CommitAtomicRenamedFile(AtomicRenamedFile& file, Error* error) return false; } -FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, const char* mode, Error* error) +FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* path, const char* mode, Error* error) { - return ManagedCFilePtr(OpenCFile(filename, mode, error)); + return ManagedCFilePtr(OpenCFile(path, mode, error)); } -FileSystem::ManagedCFilePtr FileSystem::OpenExistingOrCreateManagedCFile(const char* filename, s32 retry_ms, - Error* error) +FileSystem::ManagedCFilePtr FileSystem::OpenExistingOrCreateManagedCFile(const char* path, s32 retry_ms, Error* error) { - return ManagedCFilePtr(OpenExistingOrCreateCFile(filename, retry_ms, error)); + return ManagedCFilePtr(OpenExistingOrCreateCFile(path, retry_ms, error)); } -FileSystem::ManagedCFilePtr FileSystem::OpenManagedSharedCFile(const char* filename, const char* mode, +FileSystem::ManagedCFilePtr FileSystem::OpenManagedSharedCFile(const char* path, const char* mode, FileShareMode share_mode, Error* error) { - return ManagedCFilePtr(OpenSharedCFile(filename, mode, share_mode, error)); + return ManagedCFilePtr(OpenSharedCFile(path, mode, share_mode, error)); } int FileSystem::FSeek64(std::FILE* fp, s64 offset, int whence) @@ -1443,20 +1447,20 @@ bool FileSystem::FTruncate64(std::FILE* fp, s64 size, Error* error) #endif } -s64 FileSystem::GetPathFileSize(const char* Path) +s64 FileSystem::GetPathFileSize(const char* path) { FILESYSTEM_STAT_DATA sd; - if (!StatFile(Path, &sd)) + if (!StatFile(path, &sd)) return -1; return sd.Size; } -std::optional> FileSystem::ReadBinaryFile(const char* filename, Error* error) +std::optional> FileSystem::ReadBinaryFile(const char* path, Error* error) { std::optional> ret; - ManagedCFilePtr fp = OpenManagedCFile(filename, "rb", error); + ManagedCFilePtr fp = OpenManagedCFile(path, "rb", error); if (!fp) return ret; @@ -1506,11 +1510,11 @@ std::optional> FileSystem::ReadBinaryFile(std::FILE* fp, Er return ret; } -std::optional FileSystem::ReadFileToString(const char* filename, Error* error) +std::optional FileSystem::ReadFileToString(const char* path, Error* error) { std::optional ret; - ManagedCFilePtr fp = OpenManagedCFile(filename, "rb", error); + ManagedCFilePtr fp = OpenManagedCFile(path, "rb", error); if (!fp) return ret; @@ -1562,9 +1566,9 @@ std::optional FileSystem::ReadFileToString(std::FILE* fp, Error* er return ret; } -bool FileSystem::WriteBinaryFile(const char* filename, const void* data, size_t data_length, Error* error) +bool FileSystem::WriteBinaryFile(const char* path, const void* data, size_t data_length, Error* error) { - ManagedCFilePtr fp = OpenManagedCFile(filename, "wb", error); + ManagedCFilePtr fp = OpenManagedCFile(path, "wb", error); if (!fp) return false; @@ -1577,9 +1581,14 @@ bool FileSystem::WriteBinaryFile(const char* filename, const void* data, size_t return true; } -bool FileSystem::WriteStringToFile(const char* filename, std::string_view sv, Error* error) +bool FileSystem::WriteBinaryFile(const char* path, const std::span data, Error* error /*= nullptr*/) { - ManagedCFilePtr fp = OpenManagedCFile(filename, "wb", error); + return WriteBinaryFile(path, data.empty() ? nullptr : data.data(), data.size(), error); +} + +bool FileSystem::WriteStringToFile(const char* path, std::string_view sv, Error* error) +{ + ManagedCFilePtr fp = OpenManagedCFile(path, "wb", error); if (!fp) return false; @@ -2636,13 +2645,13 @@ bool FileSystem::DeleteDirectory(const char* path) std::string FileSystem::GetProgramPath() { #if defined(__linux__) - static const char* exeFileName = "/proc/self/exe"; + static const char* exe_path = "/proc/self/exe"; int curSize = PATH_MAX; char* buffer = static_cast(std::realloc(nullptr, curSize)); for (;;) { - int len = readlink(exeFileName, buffer, curSize); + int len = readlink(exe_path, buffer, curSize); if (len < 0) { std::free(buffer); diff --git a/src/common/file_system.h b/src/common/file_system.h index 3396f1307..c6e861921 100644 --- a/src/common/file_system.h +++ b/src/common/file_system.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -67,8 +68,8 @@ bool FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArra /// Stat file bool StatFile(const char* path, struct stat* st); bool StatFile(std::FILE* fp, struct stat* st); -bool StatFile(const char* path, FILESYSTEM_STAT_DATA* pStatData); -bool StatFile(std::FILE* fp, FILESYSTEM_STAT_DATA* pStatData); +bool StatFile(const char* path, FILESYSTEM_STAT_DATA* sd); +bool StatFile(std::FILE* fp, FILESYSTEM_STAT_DATA* sd); s64 GetPathFileSize(const char* path); /// File exists? @@ -99,14 +100,14 @@ struct FileDeleter /// open files using ManagedCFilePtr = std::unique_ptr; -ManagedCFilePtr OpenManagedCFile(const char* filename, const char* mode, Error* error = nullptr); -std::FILE* OpenCFile(const char* filename, const char* mode, Error* error = nullptr); +ManagedCFilePtr OpenManagedCFile(const char* path, const char* mode, Error* error = nullptr); +std::FILE* OpenCFile(const char* path, const char* mode, Error* error = nullptr); /// Atomically opens a file in read/write mode, and if the file does not exist, creates it. /// On Windows, if retry_ms is positive, this function will retry opening the file for this /// number of milliseconds. NOTE: The file is opened in binary mode. -std::FILE* OpenExistingOrCreateCFile(const char* filename, s32 retry_ms = -1, Error* error = nullptr); -ManagedCFilePtr OpenExistingOrCreateManagedCFile(const char* filename, s32 retry_ms = -1, Error* error = nullptr); +std::FILE* OpenExistingOrCreateCFile(const char* path, s32 retry_ms = -1, Error* error = nullptr); +ManagedCFilePtr OpenExistingOrCreateManagedCFile(const char* path, s32 retry_ms = -1, Error* error = nullptr); int FSeek64(std::FILE* fp, s64 offset, int whence); bool FSeek64(std::FILE* fp, s64 offset, int whence, Error* error); @@ -114,7 +115,7 @@ s64 FTell64(std::FILE* fp); s64 FSize64(std::FILE* fp, Error* error = nullptr); bool FTruncate64(std::FILE* fp, s64 size, Error* error = nullptr); -int OpenFDFile(const char* filename, int flags, int mode, Error* error = nullptr); +int OpenFDFile(const char* path, int flags, int mode, Error* error = nullptr); /// Sharing modes for OpenSharedCFile(). enum class FileShareMode @@ -127,15 +128,15 @@ enum class FileShareMode /// Opens a file in shareable mode (where other processes can access it concurrently). /// Only has an effect on Windows systems. -ManagedCFilePtr OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, +ManagedCFilePtr OpenManagedSharedCFile(const char* path, const char* mode, FileShareMode share_mode, Error* error = nullptr); -std::FILE* OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error = nullptr); +std::FILE* OpenSharedCFile(const char* path, const char* mode, FileShareMode share_mode, Error* error = nullptr); /// Atomically-updated file creation. class AtomicRenamedFileDeleter { public: - AtomicRenamedFileDeleter(std::string temp_filename, std::string final_filename); + AtomicRenamedFileDeleter(std::string temp_path, std::string final_path); ~AtomicRenamedFileDeleter(); void operator()(std::FILE* fp); @@ -143,12 +144,13 @@ public: void discard(); private: - std::string m_temp_filename; - std::string m_final_filename; + std::string m_temp_path; + std::string m_final_path; }; using AtomicRenamedFile = std::unique_ptr; -AtomicRenamedFile CreateAtomicRenamedFile(std::string filename, Error* error = nullptr); -bool WriteAtomicRenamedFile(std::string filename, const void* data, size_t data_length, Error* error = nullptr); +AtomicRenamedFile CreateAtomicRenamedFile(std::string path, Error* error = nullptr); +bool WriteAtomicRenamedFile(std::string path, const void* data, size_t data_length, Error* error = nullptr); +bool WriteAtomicRenamedFile(std::string path, const std::span data, Error* error = nullptr); bool CommitAtomicRenamedFile(AtomicRenamedFile& file, Error* error); void DiscardAtomicRenamedFile(AtomicRenamedFile& file); @@ -166,12 +168,13 @@ private: }; #endif -std::optional> ReadBinaryFile(const char* filename, Error* error = nullptr); +std::optional> ReadBinaryFile(const char* path, Error* error = nullptr); std::optional> ReadBinaryFile(std::FILE* fp, Error* error = nullptr); -std::optional ReadFileToString(const char* filename, Error* error = nullptr); +std::optional ReadFileToString(const char* path, Error* error = nullptr); std::optional ReadFileToString(std::FILE* fp, Error* error = nullptr); -bool WriteBinaryFile(const char* filename, const void* data, size_t data_length, Error* error = nullptr); -bool WriteStringToFile(const char* filename, std::string_view sv, Error* error = nullptr); +bool WriteBinaryFile(const char* path, const void* data, size_t data_length, Error* error = nullptr); +bool WriteBinaryFile(const char* path, const std::span data, Error* error = nullptr); +bool WriteStringToFile(const char* path, std::string_view sv, Error* error = nullptr); /// creates a directory in the local filesystem /// if the directory already exists, the return value will be true.