2015-04-24 21:38:11 +00:00
|
|
|
#pragma once
|
|
|
|
|
2015-08-12 01:52:26 +00:00
|
|
|
namespace fom // file open mode
|
2015-04-24 21:38:11 +00:00
|
|
|
{
|
2016-01-05 23:52:48 +00:00
|
|
|
enum open_mode : u32
|
2015-08-12 01:52:26 +00:00
|
|
|
{
|
2015-11-01 10:33:28 +00:00
|
|
|
read = 1 << 0, // enable reading
|
|
|
|
write = 1 << 1, // enable writing
|
|
|
|
append = 1 << 2, // enable appending (always write to the end of file)
|
|
|
|
create = 1 << 3, // create file if it doesn't exist
|
|
|
|
trunc = 1 << 4, // clear opened file if it's not empty
|
|
|
|
excl = 1 << 5, // failure if the file already exists (used with `create`)
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
rewrite = write | create | trunc,
|
2015-08-12 01:52:26 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2015-04-24 21:38:11 +00:00
|
|
|
namespace fs
|
|
|
|
{
|
2016-01-05 23:52:48 +00:00
|
|
|
enum seek_mode : u32 // file seek mode
|
|
|
|
{
|
|
|
|
seek_set,
|
|
|
|
seek_cur,
|
|
|
|
seek_end,
|
|
|
|
};
|
2015-08-12 01:52:26 +00:00
|
|
|
|
2015-04-24 21:38:11 +00:00
|
|
|
struct stat_t
|
|
|
|
{
|
|
|
|
bool is_directory;
|
|
|
|
bool is_writable;
|
2015-04-25 19:15:53 +00:00
|
|
|
u64 size;
|
2015-08-12 01:52:26 +00:00
|
|
|
s64 atime;
|
|
|
|
s64 mtime;
|
|
|
|
s64 ctime;
|
2015-04-24 21:38:11 +00:00
|
|
|
};
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// Get parent directory for the path (returns empty string on failure)
|
|
|
|
std::string get_parent_dir(const std::string& path);
|
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
// Get file information
|
2015-04-24 21:38:11 +00:00
|
|
|
bool stat(const std::string& path, stat_t& info);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Check whether a file or a directory exists (not recommended, use is_file() or is_dir() instead)
|
2015-04-24 21:38:11 +00:00
|
|
|
bool exists(const std::string& path);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Check whether the file exists and is NOT a directory
|
2016-01-05 23:52:48 +00:00
|
|
|
bool is_file(const std::string& path);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Check whether the directory exists and is NOT a file
|
2016-01-05 23:52:48 +00:00
|
|
|
bool is_dir(const std::string& path);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Delete empty directory
|
2016-01-05 23:52:48 +00:00
|
|
|
bool remove_dir(const std::string& path);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Create directory
|
2016-01-05 23:52:48 +00:00
|
|
|
bool create_dir(const std::string& path);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Create directories
|
2015-04-24 21:38:11 +00:00
|
|
|
bool create_path(const std::string& path);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Rename (move) file or directory
|
2015-04-24 21:38:11 +00:00
|
|
|
bool rename(const std::string& from, const std::string& to);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Copy file contents
|
2015-04-24 21:38:11 +00:00
|
|
|
bool copy_file(const std::string& from, const std::string& to, bool overwrite);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Delete file
|
2016-01-05 23:52:48 +00:00
|
|
|
bool remove_file(const std::string& path);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Change file size (possibly appending zeros)
|
2016-01-05 23:52:48 +00:00
|
|
|
bool truncate_file(const std::string& path, u64 length);
|
2015-04-24 21:38:11 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
class file final
|
2015-04-24 21:38:11 +00:00
|
|
|
{
|
2015-08-19 11:04:58 +00:00
|
|
|
using handle_type = std::intptr_t;
|
2015-04-25 19:15:53 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
constexpr static handle_type null = -1;
|
2015-04-24 21:38:11 +00:00
|
|
|
|
2015-04-25 19:15:53 +00:00
|
|
|
handle_type m_fd = null;
|
2015-04-24 21:38:11 +00:00
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
friend class file_read_map;
|
|
|
|
friend class file_write_map;
|
2015-11-01 10:33:28 +00:00
|
|
|
|
2015-04-24 21:38:11 +00:00
|
|
|
public:
|
2015-04-25 19:15:53 +00:00
|
|
|
file() = default;
|
2015-04-24 21:38:11 +00:00
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
explicit file(const std::string& path, u32 mode = fom::read)
|
2015-09-26 20:46:04 +00:00
|
|
|
{
|
2016-01-05 23:52:48 +00:00
|
|
|
open(path, mode);
|
2015-09-26 20:46:04 +00:00
|
|
|
}
|
2015-04-24 21:38:11 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
file(file&& other)
|
|
|
|
: m_fd(other.m_fd)
|
|
|
|
{
|
|
|
|
other.m_fd = null;
|
|
|
|
}
|
2015-04-24 21:38:11 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
file& operator =(file&& right)
|
|
|
|
{
|
|
|
|
std::swap(m_fd, right.m_fd);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
~file();
|
2015-04-24 21:38:11 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
// Check whether the handle is valid (opened file)
|
|
|
|
bool is_opened() const
|
|
|
|
{
|
|
|
|
return m_fd != null;
|
|
|
|
}
|
2015-04-24 21:38:11 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
// Check whether the handle is valid (opened file)
|
|
|
|
explicit operator bool() const
|
|
|
|
{
|
|
|
|
return is_opened();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open specified file with specified mode
|
2016-01-05 23:52:48 +00:00
|
|
|
bool open(const std::string& path, u32 mode = fom::read);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Change file size (possibly appending zero bytes)
|
|
|
|
bool trunc(u64 size) const;
|
|
|
|
|
|
|
|
// Get file information
|
|
|
|
bool stat(stat_t& info) const;
|
|
|
|
|
|
|
|
// Close the file explicitly (destructor automatically closes the file)
|
2016-01-05 23:52:48 +00:00
|
|
|
void close();
|
2015-04-24 21:38:11 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
// Read the data from the file and return the amount of data written in buffer
|
2015-04-24 21:38:11 +00:00
|
|
|
u64 read(void* buffer, u64 count) const;
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Write the data to the file and return the amount of data actually written
|
2015-04-24 21:38:11 +00:00
|
|
|
u64 write(const void* buffer, u64 count) const;
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Move file pointer
|
2016-01-05 23:52:48 +00:00
|
|
|
u64 seek(s64 offset, seek_mode whence = seek_set) const;
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Get file size
|
2015-04-24 21:38:11 +00:00
|
|
|
u64 size() const;
|
2015-11-01 10:33:28 +00:00
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// Write std::string unconditionally
|
|
|
|
const file& write(const std::string& str) const
|
2015-11-01 10:33:28 +00:00
|
|
|
{
|
|
|
|
CHECK_ASSERTION(write(str.data(), str.size()) == str.size());
|
|
|
|
return *this;
|
|
|
|
}
|
2015-12-16 19:50:45 +00:00
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// Write POD unconditionally
|
2015-12-16 19:50:45 +00:00
|
|
|
template<typename T>
|
2016-01-05 23:52:48 +00:00
|
|
|
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const T& data) const
|
2015-12-16 19:50:45 +00:00
|
|
|
{
|
|
|
|
CHECK_ASSERTION(write(std::addressof(data), sizeof(T)) == sizeof(T));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// Write POD std::vector unconditionally
|
2015-12-16 19:50:45 +00:00
|
|
|
template<typename T>
|
2016-01-05 23:52:48 +00:00
|
|
|
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const std::vector<T>& vec) const
|
2015-12-16 19:50:45 +00:00
|
|
|
{
|
|
|
|
CHECK_ASSERTION(write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// Read std::string, size must be set by resize() method
|
2015-12-16 19:50:45 +00:00
|
|
|
bool read(std::string& str) const
|
|
|
|
{
|
|
|
|
return read(&str[0], str.size()) == str.size();
|
|
|
|
}
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// Read POD, sizeof(T) is used
|
2015-12-16 19:50:45 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// Read POD std::vector, size must be set by resize() method
|
2015-12-16 19:50:45 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// Read POD (experimental)
|
|
|
|
template<typename T>
|
|
|
|
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, T> read() const
|
2015-12-16 19:50:45 +00:00
|
|
|
{
|
2016-01-05 23:52:48 +00:00
|
|
|
T result;
|
2015-12-16 19:50:45 +00:00
|
|
|
CHECK_ASSERTION(read(result));
|
|
|
|
return result;
|
|
|
|
}
|
2016-01-05 23:52:48 +00:00
|
|
|
|
|
|
|
// Read full file to std::string
|
|
|
|
std::string to_string() const
|
|
|
|
{
|
|
|
|
std::string result;
|
|
|
|
result.resize(size());
|
|
|
|
CHECK_ASSERTION(seek(0) != -1 && read(result));
|
|
|
|
return result;
|
|
|
|
}
|
2016-01-26 18:13:36 +00:00
|
|
|
|
|
|
|
// Read full file to std::vector
|
|
|
|
template<typename T>
|
|
|
|
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, std::vector<T>> to_vector() const
|
|
|
|
{
|
|
|
|
std::vector<T> result;
|
|
|
|
result.resize(size() / sizeof(T));
|
|
|
|
CHECK_ASSERTION(seek(0) != -1 && read(result));
|
|
|
|
return result;
|
|
|
|
}
|
2015-11-01 10:33:28 +00:00
|
|
|
};
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// TODO
|
|
|
|
class file_read_map final
|
2015-11-01 10:33:28 +00:00
|
|
|
{
|
|
|
|
char* m_ptr = nullptr;
|
|
|
|
u64 m_size;
|
|
|
|
|
|
|
|
public:
|
2016-01-05 23:52:48 +00:00
|
|
|
file_read_map() = default;
|
2015-11-01 10:33:28 +00:00
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
file_read_map(file_read_map&& right)
|
2015-11-01 10:33:28 +00:00
|
|
|
: m_ptr(right.m_ptr)
|
|
|
|
, m_size(right.m_size)
|
|
|
|
{
|
|
|
|
right.m_ptr = 0;
|
|
|
|
}
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
file_read_map& operator =(file_read_map&& right)
|
2015-11-01 10:33:28 +00:00
|
|
|
{
|
|
|
|
std::swap(m_ptr, right.m_ptr);
|
|
|
|
std::swap(m_size, right.m_size);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
file_read_map(const file& f)
|
2015-11-01 10:33:28 +00:00
|
|
|
{
|
|
|
|
reset(f);
|
|
|
|
}
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
~file_read_map()
|
2015-11-01 10:33:28 +00:00
|
|
|
{
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open file mapping
|
|
|
|
void reset(const file& f);
|
|
|
|
|
|
|
|
// Close file mapping
|
|
|
|
void reset();
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
// 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();
|
|
|
|
|
2015-11-01 10:33:28 +00:00
|
|
|
// Get pointer
|
|
|
|
operator char*() const
|
|
|
|
{
|
|
|
|
return m_ptr;
|
|
|
|
}
|
2015-04-24 21:38:11 +00:00
|
|
|
};
|
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
class dir final
|
2015-04-25 19:15:53 +00:00
|
|
|
{
|
2015-09-26 20:46:04 +00:00
|
|
|
std::unique_ptr<char[]> m_path;
|
|
|
|
std::intptr_t m_dd; // handle (aux)
|
2015-04-25 19:15:53 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
dir() = default;
|
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
explicit dir(const std::string& dirname)
|
|
|
|
{
|
|
|
|
open(dirname);
|
|
|
|
}
|
2015-04-25 19:15:53 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
dir(dir&& other)
|
|
|
|
: m_dd(other.m_dd)
|
|
|
|
, m_path(std::move(other.m_path))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
dir& operator =(dir&& right)
|
|
|
|
{
|
2015-10-16 00:25:39 +00:00
|
|
|
std::swap(m_dd, right.m_dd);
|
|
|
|
std::swap(m_path, right.m_path);
|
2015-09-26 20:46:04 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
~dir();
|
2015-04-25 19:15:53 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
// Check whether the handle is valid (opened directory)
|
|
|
|
bool is_opened() const
|
|
|
|
{
|
|
|
|
return m_path.operator bool();
|
|
|
|
}
|
2015-04-25 19:15:53 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
// Check whether the handle is valid (opened directory)
|
|
|
|
explicit operator bool() const
|
|
|
|
{
|
|
|
|
return is_opened();
|
|
|
|
}
|
2015-04-25 19:15:53 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
// Open specified directory
|
2015-04-25 19:15:53 +00:00
|
|
|
bool open(const std::string& dirname);
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Close the directory explicitly (destructor automatically closes the directory)
|
2016-01-05 23:52:48 +00:00
|
|
|
void close();
|
2015-04-25 19:15:53 +00:00
|
|
|
|
2015-09-26 20:46:04 +00:00
|
|
|
// Get next directory entry (UTF-8 name and file stat)
|
|
|
|
bool read(std::string& name, stat_t& info);
|
2015-12-22 19:24:35 +00:00
|
|
|
|
|
|
|
bool first(std::string& name, stat_t& info);
|
|
|
|
|
|
|
|
struct entry
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
stat_t info;
|
|
|
|
};
|
|
|
|
|
|
|
|
class iterator
|
|
|
|
{
|
|
|
|
entry m_entry;
|
|
|
|
dir* m_parent;
|
|
|
|
|
|
|
|
public:
|
|
|
|
enum class mode
|
|
|
|
{
|
|
|
|
from_first,
|
|
|
|
from_current
|
|
|
|
};
|
|
|
|
|
|
|
|
iterator(dir* parent, mode mode_ = mode::from_first)
|
|
|
|
: m_parent(parent)
|
|
|
|
{
|
|
|
|
if (!m_parent)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode_ == mode::from_first)
|
|
|
|
{
|
2016-01-05 23:52:48 +00:00
|
|
|
m_parent->first(m_entry.name, m_entry.info);
|
2015-12-22 19:24:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-01-05 23:52:48 +00:00
|
|
|
m_parent->read(m_entry.name, m_entry.info);
|
2015-12-22 19:24:35 +00:00
|
|
|
}
|
|
|
|
|
2016-01-05 23:52:48 +00:00
|
|
|
if (m_entry.name.empty())
|
2015-12-22 19:24:35 +00:00
|
|
|
{
|
|
|
|
m_parent = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
entry& operator *()
|
|
|
|
{
|
|
|
|
return m_entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator& operator++()
|
|
|
|
{
|
|
|
|
*this = { m_parent, mode::from_current };
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator !=(const iterator& rhs) const
|
|
|
|
{
|
|
|
|
return m_parent != rhs.m_parent;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
iterator begin()
|
|
|
|
{
|
|
|
|
return{ this };
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator end()
|
|
|
|
{
|
|
|
|
return{ nullptr };
|
|
|
|
}
|
2015-04-25 19:15:53 +00:00
|
|
|
};
|
2015-12-16 19:50:45 +00:00
|
|
|
|
|
|
|
// Get configuration directory
|
2016-01-05 23:52:48 +00:00
|
|
|
const std::string& get_config_dir();
|
2015-12-16 19:50:45 +00:00
|
|
|
|
|
|
|
// Get executable directory
|
2016-01-05 23:52:48 +00:00
|
|
|
const std::string& get_executable_dir();
|
2015-04-25 19:15:53 +00:00
|
|
|
}
|