Files
sashimono/src/util/util.cpp
2021-06-21 11:09:02 +05:30

216 lines
6.3 KiB
C++

#include "../pchheader.hpp"
#include "util.hpp"
namespace util
{
const std::string to_hex(const std::string_view bin)
{
// Allocate the target string.
std::string encoded_string;
encoded_string.resize(bin.size() * 2);
// Get encoded string.
sodium_bin2hex(
encoded_string.data(),
encoded_string.length() + 1, // + 1 because sodium writes ending '\0' character as well.
reinterpret_cast<const unsigned char *>(bin.data()),
bin.size());
return encoded_string;
}
const std::string to_bin(const std::string_view hex)
{
std::string bin;
bin.resize(hex.size() / 2);
const char *hex_end;
size_t bin_len;
if (sodium_hex2bin(
reinterpret_cast<unsigned char *>(bin.data()), bin.size(),
hex.data(), hex.size(),
"", &bin_len, &hex_end))
{
return ""; // Empty indicates error.
}
return bin;
}
/**
* Check whether given directory exists.
* @param path Directory path.
* @return Returns true if given directory exists otherwise false.
*/
bool is_dir_exists(std::string_view path)
{
struct stat st;
return (stat(path.data(), &st) == 0 && S_ISDIR(st.st_mode));
}
/**
* Check whether given file exists.
* @param path File path.
* @return Returns true if give file exists otherwise false.
*/
bool is_file_exists(std::string_view path)
{
struct stat st;
return (stat(path.data(), &st) == 0 && S_ISREG(st.st_mode));
}
/**
* Recursively creates directories and sub-directories if not exist.
* @param path Directory path.
* @return Returns 0 operations succeeded otherwise -1.
*/
int create_dir_tree_recursive(std::string_view path)
{
if (strcmp(path.data(), "/") == 0) // No need of checking if we are at root.
return 0;
// Check whether this dir exists or not.
struct stat st;
if (stat(path.data(), &st) != 0 || !S_ISDIR(st.st_mode))
{
// Check and create parent dir tree first.
char *path2 = strdup(path.data());
char *parent_dir_path = dirname(path2);
bool error_thrown = false;
if (create_dir_tree_recursive(parent_dir_path) == -1)
error_thrown = true;
free(path2);
// Create this dir.
if (!error_thrown && mkdir(path.data(), S_IRWXU | S_IRWXG | S_IROTH) == -1)
{
std::cerr << errno << ": Error in recursive dir creation. " << path << std::endl;
error_thrown = true;
}
if (error_thrown)
return -1;
}
return 0;
}
/**
* Reads the entire file from given file discriptor.
* @param fd File descriptor to be read.
* @param buf String buffer to be populated.
* @param offset Begin offset of the file to read.
* @return Returns number of bytes read in a successful read and -1 on error.
*/
int read_from_fd(const int fd, std::string &buf, const off_t offset)
{
struct stat st;
if (fstat(fd, &st) == -1)
{
std::cerr << errno << ": Error in stat for reading entire file." << std::endl;
return -1;
}
buf.resize(st.st_size - offset);
return pread(fd, buf.data(), buf.size(), offset);
}
/**
* Provide a safe std::string overload for realpath.
* @param path Path.
* @returns Returns the realpath as string.
*/
const std::string realpath(std::string_view path)
{
std::array<char, PATH_MAX> buffer;
::realpath(path.data(), buffer.data());
buffer[PATH_MAX] = '\0';
return buffer.data();
}
/**
* Clears signal mask and signal handlers from the caller.
* Called by other processes forked from sagent threads so they get detatched from
* the sagent signal setup.
*/
void fork_detach()
{
// Restore signal handlers to defaults.
signal(SIGINT, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
signal(SIGABRT, SIG_DFL);
// Remove any signal masks applied by sagent.
sigset_t mask;
sigemptyset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, NULL);
// Set process group id (so the terminal doesn't send kill signals to forked children).
setpgrp();
}
// Applies signal mask to the calling thread.
void mask_signal()
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
}
/**
* Sleeps the current thread for specified no. of milliseconds.
*/
void sleep(const uint64_t milliseconds)
{
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}
/**
* Returns current time in UNIX epoch milliseconds.
*/
uint64_t get_epoch_milliseconds()
{
return std::chrono::duration_cast<std::chrono::duration<std::uint64_t, std::milli>>(
std::chrono::system_clock::now().time_since_epoch())
.count();
}
/**
* Remove a directory recursively with it's content. FTW_DEPTH is provided so all of the files and subdirectories within
* The path will be processed. FTW_PHYS is provided so symbolic links won't be followed.
*/
int remove_directory_recursively(std::string_view dir_path)
{
return nftw(
dir_path.data(), [](const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{
return remove(fpath);
},
1, FTW_DEPTH | FTW_PHYS);
}
// Kill a process with a signal and if specified, wait until it stops running.
int kill_process(const pid_t pid, const bool wait, const int signal)
{
if (kill(pid, signal) == -1)
{
LOG_ERROR << errno << ": Error issuing signal to pid " << pid;
return -1;
}
const int wait_options = wait ? 0 : WNOHANG;
if (waitpid(pid, NULL, wait_options) == -1)
{
LOG_ERROR << errno << ": waitpid after kill (pid:" << pid << ") failed.";
return -1;
}
return 0;
}
} // namespace util