mirror of https://github.com/oxen-io/lokinet
Merge pull request #2005 from jagerman/profiling-bencode-refactor
file slurp/dump and profiling refactorpull/2018/head
commit
fc07b8a10e
@ -1 +1 @@
|
|||||||
Subproject commit 79193e58fb26624d40cd2e95156f78160f2b9b3e
|
Subproject commit 707a83609fb64d09b61ed1e56c82bf692050d2a1
|
@ -0,0 +1,119 @@
|
|||||||
|
#include "file.hpp"
|
||||||
|
#include <fstream>
|
||||||
|
#include <ios>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <llarp/util/logging.hpp>
|
||||||
|
#include <llarp/util/formattable.hpp>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <io.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace llarp::util
|
||||||
|
{
|
||||||
|
static std::streampos
|
||||||
|
slurp_file_open(const fs::path& filename, fs::ifstream& in)
|
||||||
|
{
|
||||||
|
in.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||||
|
in.open(filename, std::ios::binary | std::ios::in);
|
||||||
|
in.seekg(0, std::ios::end);
|
||||||
|
auto size = in.tellg();
|
||||||
|
in.seekg(0, std::ios::beg);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
slurp_file(const fs::path& filename)
|
||||||
|
{
|
||||||
|
fs::ifstream in;
|
||||||
|
std::string contents;
|
||||||
|
auto size = slurp_file_open(filename, in);
|
||||||
|
contents.resize(size);
|
||||||
|
in.read(contents.data(), size);
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
slurp_file(const fs::path& filename, char* buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
fs::ifstream in;
|
||||||
|
auto size = slurp_file_open(filename, in);
|
||||||
|
if (static_cast<size_t>(size) > buffer_size)
|
||||||
|
throw std::length_error{"file is too large for buffer"};
|
||||||
|
in.read(buffer, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dump_file(const fs::path& filename, std::string_view contents)
|
||||||
|
{
|
||||||
|
fs::ofstream out;
|
||||||
|
out.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||||
|
out.open(filename, std::ios::binary | std::ios::out | std::ios::trunc);
|
||||||
|
out.write(contents.data(), static_cast<std::streamsize>(contents.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::error_code
|
||||||
|
errno_error()
|
||||||
|
{
|
||||||
|
int e = errno;
|
||||||
|
errno = 0;
|
||||||
|
return std::make_error_code(static_cast<std::errc>(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
error_code_t
|
||||||
|
EnsurePrivateFile(fs::path pathname)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
error_code_t ec = errno_error();
|
||||||
|
const auto str = pathname.string();
|
||||||
|
if (fs::exists(pathname, ec)) // file exists
|
||||||
|
{
|
||||||
|
auto st = fs::status(pathname);
|
||||||
|
auto perms = st.permissions();
|
||||||
|
if ((perms & fs::perms::others_exec) != fs::perms::none)
|
||||||
|
perms = perms ^ fs::perms::others_exec;
|
||||||
|
if ((perms & fs::perms::others_write) != fs::perms::none)
|
||||||
|
perms = perms ^ fs::perms::others_write;
|
||||||
|
if ((perms & fs::perms::others_write) != fs::perms::none)
|
||||||
|
perms = perms ^ fs::perms::others_write;
|
||||||
|
if ((perms & fs::perms::group_read) != fs::perms::none)
|
||||||
|
perms = perms ^ fs::perms::group_read;
|
||||||
|
if ((perms & fs::perms::others_read) != fs::perms::none)
|
||||||
|
perms = perms ^ fs::perms::others_read;
|
||||||
|
if ((perms & fs::perms::owner_exec) != fs::perms::none)
|
||||||
|
perms = perms ^ fs::perms::owner_exec;
|
||||||
|
|
||||||
|
fs::permissions(pathname, perms, ec);
|
||||||
|
if (ec)
|
||||||
|
llarp::LogError("failed to set permissions on ", pathname);
|
||||||
|
}
|
||||||
|
else // file is not there
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
int fd = ::open(str.c_str(), O_RDWR | O_CREAT, 0600);
|
||||||
|
ec = errno_error();
|
||||||
|
if (fd != -1)
|
||||||
|
{
|
||||||
|
::close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
if (ec)
|
||||||
|
llarp::LogError("failed to ensure ", str, ", ", ec.message());
|
||||||
|
return ec;
|
||||||
|
#else
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace llarp::util
|
@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "fs.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#include <dirent.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace llarp::util
|
||||||
|
{
|
||||||
|
/// Reads a binary file from disk into a string. Throws on error.
|
||||||
|
std::string
|
||||||
|
slurp_file(const fs::path& filename);
|
||||||
|
|
||||||
|
/// Reads a binary file from disk directly into a buffer. Throws a std::length_error if the
|
||||||
|
/// file is bigger than the buffer. Returns the bytes copied on success.
|
||||||
|
size_t
|
||||||
|
slurp_file(const fs::path& filename, char* buffer, size_t buffer_size);
|
||||||
|
|
||||||
|
/// Same, but for some non-char but single-byte char type (e.g. byte_t, std::byte, unsigned char).
|
||||||
|
template <
|
||||||
|
typename Char,
|
||||||
|
std::enable_if_t<sizeof(Char) == 1 and not std::is_same_v<Char, char>, int> = 1>
|
||||||
|
inline size_t
|
||||||
|
slurp_file(const fs::path& filename, Char* buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
return slurp_file(filename, reinterpret_cast<char*>(buffer), buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dumps binary string contents to disk. The file is overwritten if it already exists. Throws
|
||||||
|
/// on error.
|
||||||
|
void
|
||||||
|
dump_file(const fs::path& filename, std::string_view contents);
|
||||||
|
|
||||||
|
/// Same as above, but works via char-like buffer
|
||||||
|
template <typename Char, std::enable_if_t<sizeof(Char) == 1, int> = 0>
|
||||||
|
inline void
|
||||||
|
dump_file(const fs::path& filename, const Char* buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
return dump_file(
|
||||||
|
filename, std::string_view{reinterpret_cast<const char*>(buffer), buffer_size});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FileHash
|
||||||
|
{
|
||||||
|
size_t
|
||||||
|
operator()(const fs::path& f) const
|
||||||
|
{
|
||||||
|
std::hash<std::string> h;
|
||||||
|
return h(f.string());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using error_code_t = std::error_code;
|
||||||
|
|
||||||
|
/// Ensure that a file exists and has correct permissions
|
||||||
|
/// return any error code or success
|
||||||
|
error_code_t
|
||||||
|
EnsurePrivateFile(fs::path pathname);
|
||||||
|
|
||||||
|
/// open a stream to a file and ensure it exists before open
|
||||||
|
/// sets any permissions on creation
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T>
|
||||||
|
OpenFileStream(fs::path pathname, std::ios::openmode mode)
|
||||||
|
{
|
||||||
|
if (EnsurePrivateFile(pathname))
|
||||||
|
return {};
|
||||||
|
return std::make_optional<T>(pathname, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename PathVisitor>
|
||||||
|
static void
|
||||||
|
IterDir(const fs::path& path, PathVisitor visit)
|
||||||
|
{
|
||||||
|
DIR* d = opendir(path.string().c_str());
|
||||||
|
if (d == nullptr)
|
||||||
|
return;
|
||||||
|
struct dirent* ent = nullptr;
|
||||||
|
std::set<fs::path> entries;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ent = readdir(d);
|
||||||
|
if (not ent)
|
||||||
|
break;
|
||||||
|
if (ent->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
entries.emplace(path / fs::path{ent->d_name});
|
||||||
|
} while (ent);
|
||||||
|
closedir(d);
|
||||||
|
|
||||||
|
for (const auto& p : entries)
|
||||||
|
{
|
||||||
|
if (not visit(p))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace llarp::util
|
@ -1,76 +0,0 @@
|
|||||||
#include "fs.hpp"
|
|
||||||
|
|
||||||
#include <llarp/util/logging.hpp>
|
|
||||||
#include <llarp/util/formattable.hpp>
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <system_error>
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <io.h>
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace llarp
|
|
||||||
{
|
|
||||||
namespace util
|
|
||||||
{
|
|
||||||
static std::error_code
|
|
||||||
errno_error()
|
|
||||||
{
|
|
||||||
int e = errno;
|
|
||||||
errno = 0;
|
|
||||||
return std::make_error_code(static_cast<std::errc>(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
error_code_t
|
|
||||||
EnsurePrivateFile(fs::path pathname)
|
|
||||||
{
|
|
||||||
errno = 0;
|
|
||||||
error_code_t ec = errno_error();
|
|
||||||
const auto str = pathname.string();
|
|
||||||
if (fs::exists(pathname, ec)) // file exists
|
|
||||||
{
|
|
||||||
auto st = fs::status(pathname);
|
|
||||||
auto perms = st.permissions();
|
|
||||||
if ((perms & fs::perms::others_exec) != fs::perms::none)
|
|
||||||
perms = perms ^ fs::perms::others_exec;
|
|
||||||
if ((perms & fs::perms::others_write) != fs::perms::none)
|
|
||||||
perms = perms ^ fs::perms::others_write;
|
|
||||||
if ((perms & fs::perms::others_write) != fs::perms::none)
|
|
||||||
perms = perms ^ fs::perms::others_write;
|
|
||||||
if ((perms & fs::perms::group_read) != fs::perms::none)
|
|
||||||
perms = perms ^ fs::perms::group_read;
|
|
||||||
if ((perms & fs::perms::others_read) != fs::perms::none)
|
|
||||||
perms = perms ^ fs::perms::others_read;
|
|
||||||
if ((perms & fs::perms::owner_exec) != fs::perms::none)
|
|
||||||
perms = perms ^ fs::perms::owner_exec;
|
|
||||||
|
|
||||||
fs::permissions(pathname, perms, ec);
|
|
||||||
if (ec)
|
|
||||||
llarp::LogError("failed to set permissions on ", pathname);
|
|
||||||
}
|
|
||||||
else // file is not there
|
|
||||||
{
|
|
||||||
errno = 0;
|
|
||||||
int fd = ::open(str.c_str(), O_RDWR | O_CREAT, 0600);
|
|
||||||
ec = errno_error();
|
|
||||||
if (fd != -1)
|
|
||||||
{
|
|
||||||
::close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
if (ec)
|
|
||||||
llarp::LogError("failed to ensure ", str, ", ", ec.message());
|
|
||||||
return ec;
|
|
||||||
#else
|
|
||||||
return {};
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} // namespace util
|
|
||||||
} // namespace llarp
|
|
Loading…
Reference in New Issue