15#include <system_error>
22namespace fs = std::filesystem;
25#if defined(__ISWINDOWS__)
31# include <sys/types.h>
34# if !defined(__powerpc__)
42 unsigned long long size = 0;
44 for (
const auto& entry : fs::recursive_directory_iterator(path, fs::directory_options::skip_permission_denied, ec)) {
45 if (!ec && entry.is_regular_file(ec) && !ec) {
46 size += entry.file_size(ec);
88 std::ifstream in(filename, std::ios::in | std::ios::binary);
90 std::vector<char> contents;
91 in.seekg(0, std::ios::end);
92 contents.resize((
unsigned int)in.tellg());
93 in.seekg(0, std::ios::beg);
94 in.read(&contents[0], contents.size());
115const std::uint64_t kProcessSalt = []() {
116 std::random_device rd;
117 return (
static_cast<std::uint64_t
>(rd()) << 32) |
static_cast<std::uint64_t
>(rd());
120std::filesystem::path make_temp_sibling(
const std::filesystem::path& target) {
121 static std::atomic<std::uint64_t> counter{0};
122 const auto seq = counter.fetch_add(1, std::memory_order_relaxed);
123 std::ostringstream oss;
124 oss <<
".tmp." << std::hex << kProcessSalt <<
'.' << seq;
132void write_bytes_atomic(
const std::filesystem::path& target,
const void* bytes, std::size_t size,
bool restrict_perms) {
133 const auto temp = make_temp_sibling(target);
135 std::ofstream out(temp, std::ios::binary | std::ios::trunc);
137 throw std::runtime_error(
"write_bytes_atomic: cannot open temp " + temp.string());
140 out.write(
reinterpret_cast<const char*
>(bytes),
static_cast<std::streamsize
>(size));
144 std::error_code ec_rm;
145 std::filesystem::remove(temp, ec_rm);
146 throw std::runtime_error(
"write_bytes_atomic: write failed for temp " + temp.string());
149 if (restrict_perms) {
150 std::error_code perm_ec;
151 std::filesystem::permissions(temp, std::filesystem::perms::owner_read | std::filesystem::perms::owner_write,
152 std::filesystem::perm_options::replace, perm_ec);
156 std::error_code rename_ec;
157 std::filesystem::rename(temp, target, rename_ec);
159 std::error_code ec_rm;
160 std::filesystem::remove(temp, ec_rm);
161 throw std::runtime_error(
"write_bytes_atomic: rename to " + target.string() +
" failed: " + rename_ec.message());
169 fs::create_directories(fs::path(file_path), ec);
207 return {1, fs::path::preferred_separator};
228#if defined(__ISLINUX__) || defined(__ISAPPLE__)
229 char* home =
nullptr;
230 home = getenv(
"HOME");
231# if defined(__ISAPPLE__)
233 struct passwd* pwd = getpwuid(getuid());
239 if (home ==
nullptr) {
243#elif defined(__ISWINDOWS__)
244# if defined(_MSC_VER)
245# pragma warning(push)
246# pragma warning(disable : 4996)
248 char* pUSERPROFILE = getenv(
"USERPROFILE");
249 if (pUSERPROFILE != NULL) {
250 return std::string(pUSERPROFILE);
252 char* pHOMEDRIVE = getenv(
"HOMEDRIVE");
253 char* pHOMEPATH = getenv(
"HOMEPATH");
254 if (pHOMEDRIVE != NULL && pHOMEPATH != NULL) {
255 return std::string(pHOMEDRIVE) + std::string(pHOMEPATH);
257 return std::string(
"");
260# if defined(_MSC_VER)
272 return fs::exists(fs::path(path), ec);
299std::string
join_path(
const std::string& one,
const std::string& two) {
300 return (fs::path(one) / two).string();
320 std::ifstream in(filename, std::ios::in | std::ios::binary);
322 std::string contents;
323 in.seekg(0, std::ios::end);
324 contents.resize((
unsigned int)in.tellg());
325 in.seekg(0, std::ios::beg);
326 in.read(&contents[0], contents.size());