mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-03 13:31:27 +12:00
File utility improved
+ minor fixes
This commit is contained in:
parent
5029dff73a
commit
b3e3c68f15
75 changed files with 839 additions and 964 deletions
File diff suppressed because it is too large
Load diff
160
Utilities/File.h
160
Utilities/File.h
|
@ -1,15 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
enum class fsm : u32 // file seek mode
|
||||
{
|
||||
begin,
|
||||
cur,
|
||||
end,
|
||||
};
|
||||
|
||||
namespace fom // file open mode
|
||||
{
|
||||
enum : u32
|
||||
enum open_mode : u32
|
||||
{
|
||||
read = 1 << 0, // enable reading
|
||||
write = 1 << 1, // enable writing
|
||||
|
@ -18,19 +11,18 @@ namespace fom // file open mode
|
|||
trunc = 1 << 4, // clear opened file if it's not empty
|
||||
excl = 1 << 5, // failure if the file already exists (used with `create`)
|
||||
|
||||
rewrite = write | create | trunc, // write + create + trunc
|
||||
rewrite = write | create | trunc,
|
||||
};
|
||||
};
|
||||
|
||||
enum class fse : u32 // filesystem (file or dir) error
|
||||
{
|
||||
ok, // no error
|
||||
invalid_arguments,
|
||||
};
|
||||
|
||||
namespace fs
|
||||
{
|
||||
thread_local extern fse g_tls_error;
|
||||
enum seek_mode : u32 // file seek mode
|
||||
{
|
||||
seek_set,
|
||||
seek_cur,
|
||||
seek_end,
|
||||
};
|
||||
|
||||
struct stat_t
|
||||
{
|
||||
|
@ -42,6 +34,9 @@ namespace fs
|
|||
s64 ctime;
|
||||
};
|
||||
|
||||
// Get parent directory for the path (returns empty string on failure)
|
||||
std::string get_parent_dir(const std::string& path);
|
||||
|
||||
// Get file information
|
||||
bool stat(const std::string& path, stat_t& info);
|
||||
|
||||
|
@ -49,16 +44,16 @@ namespace fs
|
|||
bool exists(const std::string& path);
|
||||
|
||||
// Check whether the file exists and is NOT a directory
|
||||
bool is_file(const std::string& file);
|
||||
bool is_file(const std::string& path);
|
||||
|
||||
// Check whether the directory exists and is NOT a file
|
||||
bool is_dir(const std::string& dir);
|
||||
bool is_dir(const std::string& path);
|
||||
|
||||
// Delete empty directory
|
||||
bool remove_dir(const std::string& dir);
|
||||
bool remove_dir(const std::string& path);
|
||||
|
||||
// Create directory
|
||||
bool create_dir(const std::string& dir);
|
||||
bool create_dir(const std::string& path);
|
||||
|
||||
// Create directories
|
||||
bool create_path(const std::string& path);
|
||||
|
@ -70,10 +65,10 @@ namespace fs
|
|||
bool copy_file(const std::string& from, const std::string& to, bool overwrite);
|
||||
|
||||
// Delete file
|
||||
bool remove_file(const std::string& file);
|
||||
bool remove_file(const std::string& path);
|
||||
|
||||
// Change file size (possibly appending zeros)
|
||||
bool truncate_file(const std::string& file, u64 length);
|
||||
bool truncate_file(const std::string& path, u64 length);
|
||||
|
||||
class file final
|
||||
{
|
||||
|
@ -83,14 +78,15 @@ namespace fs
|
|||
|
||||
handle_type m_fd = null;
|
||||
|
||||
friend class file_ptr;
|
||||
friend class file_read_map;
|
||||
friend class file_write_map;
|
||||
|
||||
public:
|
||||
file() = default;
|
||||
|
||||
explicit file(const std::string& filename, u32 mode = fom::read)
|
||||
explicit file(const std::string& path, u32 mode = fom::read)
|
||||
{
|
||||
open(filename, mode);
|
||||
open(path, mode);
|
||||
}
|
||||
|
||||
file(file&& other)
|
||||
|
@ -120,7 +116,7 @@ namespace fs
|
|||
}
|
||||
|
||||
// Open specified file with specified mode
|
||||
bool open(const std::string& filename, u32 mode = fom::read);
|
||||
bool open(const std::string& path, u32 mode = fom::read);
|
||||
|
||||
// Change file size (possibly appending zero bytes)
|
||||
bool trunc(u64 size) const;
|
||||
|
@ -129,7 +125,7 @@ namespace fs
|
|||
bool stat(stat_t& info) const;
|
||||
|
||||
// Close the file explicitly (destructor automatically closes the file)
|
||||
bool close();
|
||||
void close();
|
||||
|
||||
// Read the data from the file and return the amount of data written in buffer
|
||||
u64 read(void* buffer, u64 count) const;
|
||||
|
@ -138,92 +134,102 @@ namespace fs
|
|||
u64 write(const void* buffer, u64 count) const;
|
||||
|
||||
// Move file pointer
|
||||
u64 seek(s64 offset, fsm seek_mode = fsm::begin) const;
|
||||
u64 seek(s64 offset, seek_mode whence = seek_set) const;
|
||||
|
||||
// Get file size
|
||||
u64 size() const;
|
||||
|
||||
// Write std::string
|
||||
const file& operator <<(const std::string& str) const
|
||||
// Write std::string unconditionally
|
||||
const file& write(const std::string& str) const
|
||||
{
|
||||
CHECK_ASSERTION(write(str.data(), str.size()) == str.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Write POD
|
||||
// Write POD unconditionally
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> operator <<(const T& data) const
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const T& data) const
|
||||
{
|
||||
CHECK_ASSERTION(write(std::addressof(data), sizeof(T)) == sizeof(T));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Write POD std::vector
|
||||
// Write POD std::vector unconditionally
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> operator <<(const std::vector<T>& vec) const
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const std::vector<T>& vec) const
|
||||
{
|
||||
CHECK_ASSERTION(write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Read std::string
|
||||
// Read std::string, size must be set by resize() method
|
||||
bool read(std::string& str) const
|
||||
{
|
||||
return read(&str[0], str.size()) == str.size();
|
||||
}
|
||||
|
||||
// Read POD
|
||||
// Read POD, sizeof(T) is used
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(T& data) const
|
||||
{
|
||||
return read(&data, sizeof(T)) == sizeof(T);
|
||||
}
|
||||
|
||||
// Read POD std::vector
|
||||
// Read POD std::vector, size must be set by resize() method
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(std::vector<T>& vec) const
|
||||
{
|
||||
return read(vec.data(), sizeof(T) * vec.size()) == sizeof(T) * vec.size();
|
||||
}
|
||||
|
||||
// Convert to std::string
|
||||
operator std::string() const
|
||||
// Read POD (experimental)
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, T> read() const
|
||||
{
|
||||
T result;
|
||||
CHECK_ASSERTION(read(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read full file to std::string
|
||||
std::string to_string() const
|
||||
{
|
||||
std::string result;
|
||||
result.resize(size() - seek(0, fsm::cur));
|
||||
CHECK_ASSERTION(read(result));
|
||||
result.resize(size());
|
||||
CHECK_ASSERTION(seek(0) != -1 && read(result));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class file_ptr final
|
||||
// TODO
|
||||
class file_read_map final
|
||||
{
|
||||
char* m_ptr = nullptr;
|
||||
u64 m_size;
|
||||
|
||||
public:
|
||||
file_ptr() = default;
|
||||
file_read_map() = default;
|
||||
|
||||
file_ptr(file_ptr&& right)
|
||||
file_read_map(file_read_map&& right)
|
||||
: m_ptr(right.m_ptr)
|
||||
, m_size(right.m_size)
|
||||
{
|
||||
right.m_ptr = 0;
|
||||
}
|
||||
|
||||
file_ptr& operator =(file_ptr&& right)
|
||||
file_read_map& operator =(file_read_map&& right)
|
||||
{
|
||||
std::swap(m_ptr, right.m_ptr);
|
||||
std::swap(m_size, right.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
file_ptr(const file& f)
|
||||
file_read_map(const file& f)
|
||||
{
|
||||
reset(f);
|
||||
}
|
||||
|
||||
~file_ptr()
|
||||
~file_read_map()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
@ -234,6 +240,52 @@ namespace fs
|
|||
// Close file mapping
|
||||
void reset();
|
||||
|
||||
// Get pointer
|
||||
operator const char*() const
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO
|
||||
class file_write_map final
|
||||
{
|
||||
char* m_ptr = nullptr;
|
||||
u64 m_size;
|
||||
|
||||
public:
|
||||
file_write_map() = default;
|
||||
|
||||
file_write_map(file_write_map&& right)
|
||||
: m_ptr(right.m_ptr)
|
||||
, m_size(right.m_size)
|
||||
{
|
||||
right.m_ptr = 0;
|
||||
}
|
||||
|
||||
file_write_map& operator =(file_write_map&& right)
|
||||
{
|
||||
std::swap(m_ptr, right.m_ptr);
|
||||
std::swap(m_size, right.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
file_write_map(const file& f)
|
||||
{
|
||||
reset(f);
|
||||
}
|
||||
|
||||
~file_write_map()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// Open file mapping
|
||||
void reset(const file& f);
|
||||
|
||||
// Close file mapping
|
||||
void reset();
|
||||
|
||||
// Get pointer
|
||||
operator char*() const
|
||||
{
|
||||
|
@ -285,7 +337,7 @@ namespace fs
|
|||
bool open(const std::string& dirname);
|
||||
|
||||
// Close the directory explicitly (destructor automatically closes the directory)
|
||||
bool close();
|
||||
void close();
|
||||
|
||||
// Get next directory entry (UTF-8 name and file stat)
|
||||
bool read(std::string& name, stat_t& info);
|
||||
|
@ -318,18 +370,16 @@ namespace fs
|
|||
return;
|
||||
}
|
||||
|
||||
bool is_ok;
|
||||
|
||||
if (mode_ == mode::from_first)
|
||||
{
|
||||
is_ok = m_parent->first(m_entry.name, m_entry.info);
|
||||
m_parent->first(m_entry.name, m_entry.info);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_ok = m_parent->read(m_entry.name, m_entry.info);
|
||||
m_parent->read(m_entry.name, m_entry.info);
|
||||
}
|
||||
|
||||
if (!is_ok)
|
||||
if (m_entry.name.empty())
|
||||
{
|
||||
m_parent = nullptr;
|
||||
}
|
||||
|
@ -364,8 +414,8 @@ namespace fs
|
|||
};
|
||||
|
||||
// Get configuration directory
|
||||
std::string get_config_dir();
|
||||
const std::string& get_config_dir();
|
||||
|
||||
// Get executable directory
|
||||
std::string get_executable_dir();
|
||||
const std::string& get_executable_dir();
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ struct FileListener : LogListener
|
|||
}
|
||||
}
|
||||
|
||||
mFile << text;
|
||||
mFile.write(text);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -261,25 +261,5 @@ void log_message(Log::LogType type, Log::Severity sev, const char* text)
|
|||
|
||||
void log_message(Log::LogType type, Log::Severity sev, std::string text)
|
||||
{
|
||||
if (g_log_manager)
|
||||
{
|
||||
g_log_manager->log({ type, sev, std::move(text) });
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto severity =
|
||||
sev == Severity::Notice ? "Notice" :
|
||||
sev == Severity::Warning ? "Warning" :
|
||||
sev == Severity::Success ? "Success" :
|
||||
sev == Severity::Error ? "Error" : "Unknown";
|
||||
|
||||
#ifdef _WIN32
|
||||
MessageBoxA(0, text.c_str(), severity,
|
||||
sev == Severity::Notice ? MB_ICONINFORMATION :
|
||||
sev == Severity::Warning ? MB_ICONEXCLAMATION :
|
||||
sev == Severity::Error ? MB_ICONERROR : MB_ICONINFORMATION);
|
||||
#else
|
||||
std::printf("[Log:%s] %s\n", severity, text.c_str());
|
||||
#endif
|
||||
}
|
||||
g_log_manager->log({ type, sev, std::move(text) });
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
void report_fatal_error(const std::string& msg)
|
||||
static void report_fatal_error(const std::string& msg)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const auto& text = msg + "\n\nPlease report this error to the developers. Press (Ctrl+C) to copy this message.";
|
||||
|
@ -1148,7 +1148,7 @@ void prepare_throw_access_violation(x64_context* context, const char* cause, u32
|
|||
|
||||
#ifdef _WIN32
|
||||
|
||||
const auto g_exception_handler = AddVectoredExceptionHandler(1, [](PEXCEPTION_POINTERS pExp) -> LONG
|
||||
static LONG exception_handler(PEXCEPTION_POINTERS pExp)
|
||||
{
|
||||
const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0);
|
||||
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||
|
@ -1161,9 +1161,9 @@ const auto g_exception_handler = AddVectoredExceptionHandler(1, [](PEXCEPTION_PO
|
|||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const auto g_exception_filter = SetUnhandledExceptionFilter([](PEXCEPTION_POINTERS pExp) -> LONG
|
||||
static LONG exception_filter(PEXCEPTION_POINTERS pExp)
|
||||
{
|
||||
std::string msg = fmt::format("Unhandled Win32 exception 0x%08X.\n", pExp->ExceptionRecord->ExceptionCode);
|
||||
|
||||
|
@ -1191,16 +1191,36 @@ const auto g_exception_filter = SetUnhandledExceptionFilter([](PEXCEPTION_POINTE
|
|||
}
|
||||
}
|
||||
|
||||
msg += fmt::format("Instruction address: %p.\n", pExp->ContextRecord->Rip);
|
||||
msg += fmt::format("Image base: %p.", GetModuleHandle(NULL));
|
||||
|
||||
// TODO: print registers and the callstack
|
||||
|
||||
// Report fatal error
|
||||
report_fatal_error(msg);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
});
|
||||
}
|
||||
|
||||
const bool g_exception_handler_set = []() -> bool
|
||||
{
|
||||
if (!AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)exception_handler))
|
||||
{
|
||||
report_fatal_error("AddVectoredExceptionHandler() failed.");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (!SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)exception_filter))
|
||||
{
|
||||
report_fatal_error("SetUnhandledExceptionFilter() failed.");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
||||
#else
|
||||
|
||||
void signal_handler(int sig, siginfo_t* info, void* uct)
|
||||
static void signal_handler(int sig, siginfo_t* info, void* uct)
|
||||
{
|
||||
x64_context* context = (ucontext_t*)uct;
|
||||
|
||||
|
@ -1230,17 +1250,21 @@ void signal_handler(int sig, siginfo_t* info, void* uct)
|
|||
}
|
||||
}
|
||||
|
||||
int setup_signal_handler()
|
||||
const bool g_exception_handler_set = []() -> bool
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
struct ::sigaction sa;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_sigaction = signal_handler;
|
||||
return sigaction(SIGSEGV, &sa, NULL);
|
||||
}
|
||||
|
||||
const int g_sigaction_result = setup_signal_handler();
|
||||
if (::sigaction(SIGSEGV, &sa, NULL) == -1)
|
||||
{
|
||||
std::printf("sigaction() failed (0x%x).", errno);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1253,16 +1277,6 @@ void thread_ctrl::initialize()
|
|||
{
|
||||
SetCurrentThreadDebugName(g_tls_this_thread->m_name().c_str());
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!g_exception_handler || !g_exception_filter)
|
||||
#else
|
||||
if (g_sigaction_result == -1)
|
||||
#endif
|
||||
{
|
||||
report_fatal_error("Exception handler is not set correctly.");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// TODO
|
||||
g_thread_count++;
|
||||
}
|
||||
|
|
|
@ -30,14 +30,14 @@ namespace convert
|
|||
{
|
||||
static bool func(const std::string& value)
|
||||
{
|
||||
return value == "true" ? true : false;
|
||||
return value == "true" ? true : value == "false" ? false : throw std::invalid_argument(__FUNCTION__);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, char>
|
||||
struct to_impl_t<std::string, signed char>
|
||||
{
|
||||
static std::string func(char value)
|
||||
static std::string func(signed char value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#ifndef _WIN32
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "rPlatform.h"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue