28#include <opendht/crypto.h>
31#include <TargetConditionals.h>
34#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
65#if !defined __ANDROID__ && !defined _WIN32
69#include <nettle/sha3.h>
85#include <pjlib-util/md5.h>
88#define PROTECTED_GETENV(str) \
90 char* envvar_ = getenv((str)); \
91 envvar_ ? envvar_ : ""; \
94#define XDG_DATA_HOME (PROTECTED_GETENV("XDG_DATA_HOME"))
95#define XDG_CONFIG_HOME (PROTECTED_GETENV("XDG_CONFIG_HOME"))
96#define XDG_CACHE_HOME (PROTECTED_GETENV("XDG_CACHE_HOME"))
99winGetEnv(
const wchar_t* name)
101 const DWORD buffSize = 65535;
102 static wchar_t buffer[buffSize];
103 if (GetEnvironmentVariable(name, buffer, buffSize)) {
110#define PROTECTED_GETENV(str) winGetEnv(str)
112#define JAMI_DATA_HOME PROTECTED_GETENV(L"JAMI_DATA_HOME")
113#define JAMI_CONFIG_HOME PROTECTED_GETENV(L"JAMI_CONFIG_HOME")
114#define JAMI_CACHE_HOME PROTECTED_GETENV(L"JAMI_CACHE_HOME")
117#define PIDFILE ".ring.pid"
118#define ERASE_BLOCK 4096
131const std::filesystem::path&
141#if defined __ANDROID__ || defined _MSC_VER || defined WIN32 || defined __APPLE__
142 JAMI_ERR(
"Path expansion not implemented, returning original");
153 JAMI_ERR(
"Illegal occurrence of newline or one of |, &, ;, <, >, "
157 JAMI_ERR(
"An undefined shell variable was referenced");
160 JAMI_ERR(
"Command substitution occurred");
171 result = std::string(p.we_wordv[0]);
235 std::string_view result;
236 auto sep = filename.find_last_of(
'.');
237 if (
sep != std::string_view::npos &&
sep != filename.size() - 1)
238 result = filename.substr(
sep + 1);
239 if (result.size() >= 8)
247 return not path.empty()
and path.is_relative();
253 if (base.empty()
or path.size() < base.size())
257 return path.substr(
base_sep.size());
263getFullPath(
const std::filesystem::path& base,
const std::filesystem::path& path)
289 throw std::runtime_error(
"Unable to read file: " + path.string());
291 file.seekg(0, std::ios::end);
293 if (
size > std::numeric_limits<unsigned>::max())
294 throw std::runtime_error(
"File is too big: " + path.string());
296 file.seekg(0, std::ios::beg);
298 throw std::runtime_error(
"Unable to load file: " + path.string());
308 std::ofstream
file(path, std::ios::trunc | std::ios::binary);
309 if (!
file.is_open()) {
310 JAMI_ERROR(
"Unable to write data to {}", path);
316 if (
chmod(path.c_str(), mode) < 0)
326 auto writeTime = std::filesystem::last_write_time(path,
ec);
328 throw std::runtime_error(
"unable to get last write time of file");
331 throw std::runtime_error(
"file too old " + dht::print_time_relative(
now,
writeTime));
333 JAMI_LOG(
"Loading cache file '{}'", path);
334 return dhtnet::fileutils::loadFile(path);
342 auto writeTime = std::filesystem::last_write_time(path,
ec);
344 throw std::runtime_error(
"unable to get last write time of file");
347 throw std::runtime_error(
"file too old " + dht::print_time_relative(
now,
writeTime));
349 JAMI_LOG(
"Loading cache file '{}'", path);
354readArchive(
const std::filesystem::path& path, std::string_view scheme,
const std::string&
pwd)
356 JAMI_LOG(
"Reading archive from {} with scheme '{}'", path, scheme);
364 return data.size() > 3 && data[0] == 0x1f && data[1] == 0x8b && data[2] == 0x08;
367 auto decompress = [](std::vector<uint8_t>& data) {
370 }
catch (
const std::exception&
e) {
371 JAMI_ERROR(
"Error decrypting archive: {}",
e.what());
381 }
catch (
const std::exception&
e) {
388 JAMI_WARNING(
"A gunzip in a gunzip is detected. A webserver may have a bad config");
402 }
catch (
const std::exception&
e) {
403 JAMI_ERROR(
"Error decrypting archive: {}",
e.what());
410 }
catch (
const std::exception&
e) {
411 JAMI_ERROR(
"Error decrypting archive: {}",
e.what());
417 JAMI_WARNING(
"A gunzip in a gunzip is detected. A webserver may have a bad config");
426 const std::filesystem::path& path,
427 std::string_view scheme,
428 const std::string& password,
429 const std::vector<uint8_t>& password_salt)
431 JAMI_LOG(
"Writing archive to {} using scheme '{}'", path, scheme);
439 }
catch (
const std::runtime_error&
ex) {
450 }
catch (
const std::runtime_error&
ex) {
467#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
468 std::vector<std::string>
paths;
474#elif defined(__APPLE__)
490const std::filesystem::path&
500#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
501 std::vector<std::string>
paths;
533const std::filesystem::path&
543#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
544 std::vector<std::string>
paths;
550#elif defined(__APPLE__)
572const std::filesystem::path&
583#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
584 std::vector<std::string>
paths;
588#elif defined(__APPLE__)
606 if (!dhtnet::fileutils::recursive_mkdir(
configdir, 0700)) {
614const std::filesystem::path&
632 JAMI_WARN(
"Unable to open file %s for erasing.", path.c_str());
638 JAMI_WARN(
"Unable to erase file %s: GetFileSizeEx() failed.", path.c_str());
642 if (
size.QuadPart == 0) {
654 }
catch (std::bad_alloc&
ba) {
655 JAMI_WARN(
"Unable to allocate buffer for erasing %s.", path.c_str());
662 if (
size.QuadPart < (1024 - 42)) {
670 ovlp.Offset = offset & 0x00000000FFFFFFFF;
671 ovlp.OffsetHigh = offset >> 32;
690 if (
stat(path.c_str(), &
st) == -1) {
691 JAMI_WARN(
"Unable to erase file %s: fstat() failed.", path.c_str());
699 JAMI_WARN(
"Unable to open file %s for erasing.", path.c_str());
703 if (
st.st_size == 0) {
710 std::array<char, ERASE_BLOCK>
buffer;
716 JAMI_WARNING(
"Error while overriding file with zeros.");
741remove(
const std::filesystem::path& path,
bool erase)
743 if (erase
and dhtnet::fileutils::isFile(path,
false)
and !dhtnet::fileutils::hasHardLink(path))
748 if (std::filesystem::is_directory(path))
752 return std::remove(path.string().c_str());
756size(
const std::filesystem::path& path)
760 std::ifstream
file(path, std::ios::binary | std::ios::in);
761 file.seekg(0, std::ios_base::end);
776 if (
not std::filesystem::is_regular_file(path)) {
777 JAMI_ERROR(
"Unable to compute sha3sum of {}: not a regular file", path);
780 std::ifstream
file(path, std::ios::binary | std::ios::in);
782 JAMI_ERROR(
"Unable to compute sha3sum of {}: failed to open file", path);
785 std::vector<char>
buffer(8192, 0);
786 while (!
file.eof()) {
791 }
catch (
const std::exception&
e) {
792 JAMI_ERROR(
"Unable to compute sha3sum of {}: {}", path,
e.what());
837 return std::chrono::duration_cast<std::chrono::seconds>(
lastWrite.time_since_epoch()).count();
#define PROTECTED_GETENV(str)
#define DIR_SEPARATOR_STR
#define JAMI_ERROR(formatstr,...)
#define JAMI_WARNING(formatstr,...)
#define JAMI_LOG(formatstr,...)
void compressGzip(const std::string &str, const std::string &path)
Compress string to a Gzip file.
std::vector< uint8_t > decompress(const std::vector< uint8_t > &str)
Decompress an STL string using zlib and return the original data.
std::vector< uint8_t > compress(const std::string &str)
Compress a STL string using zlib with given compression level and return the binary data.
std::vector< uint8_t > decode(std::string_view str)
bool createSymlink(const std::filesystem::path &linkFile, const std::filesystem::path &target)
const std::filesystem::path & get_data_dir()
void set_resource_dir_path(const std::filesystem::path &resourceDirPath)
Set the program's resource directory path.
std::vector< uint8_t > loadCacheFile(const std::filesystem::path &path, std::chrono::system_clock::duration maxAge)
static constexpr auto ARCHIVE_AUTH_SCHEME_PASSWORD
int accessFile(const std::string &file, int mode)
Windows compatibility wrapper for checking read-only attribute.
std::string sha3File(const std::filesystem::path &path)
std::filesystem::path get_home_dir_impl()
int remove(const std::filesystem::path &path, bool erase)
bool createFileLink(const std::filesystem::path &linkFile, const std::filesystem::path &target, bool hard)
void saveFile(const std::filesystem::path &path, const uint8_t *data, size_t data_size, mode_t UNUSED mode)
bool eraseFile(const std::string &path, bool dosync)
static constexpr auto ARCHIVE_AUTH_SCHEME_NONE
std::string getCleanPath(const std::string &base, const std::string &path)
If path is contained in base, return the suffix, otherwise return the full path.
int64_t size(const std::filesystem::path &path)
ArchiveStorageData readArchive(const std::filesystem::path &path, std::string_view scheme, const std::string &pwd)
static std::filesystem::path resource_dir_path
const std::filesystem::path & get_config_dir()
bool createHardlink(const std::filesystem::path &linkFile, const std::filesystem::path &target)
std::string loadCacheTextFile(const std::filesystem::path &path, std::chrono::system_clock::duration maxAge)
std::vector< uint8_t > loadFile(const std::filesystem::path &path, const std::filesystem::path &default_dir)
Read the full content of a file at path.
uint64_t lastWriteTimeInSeconds(const std::filesystem::path &filePath)
Return the last write time (epoch time) of a given file path (in seconds).
static constexpr auto ARCHIVE_AUTH_SCHEME_KEY
bool isPathRelative(const std::filesystem::path &path)
std::string sha3sum(const uint8_t *data, size_t size)
std::string_view getFileExtension(std::string_view filename)
const std::filesystem::path & get_cache_dir()
bool isDirectoryWritable(const std::string &directory)
std::filesystem::path getFullPath(const std::filesystem::path &base, const std::filesystem::path &path)
If path is relative, it is appended to base.
bool writeArchive(const std::string &archive_str, const std::filesystem::path &path, std::string_view scheme, const std::string &password, const std::vector< uint8_t > &password_salt)
const std::filesystem::path & get_resource_dir_path()
Get the resource directory path that was set with set_resource_dir_path.
std::string expand_path(const std::string &path)
Expand the given path.
const std::filesystem::path & get_home_dir()
std::string loadTextFile(const std::filesystem::path &path, const std::filesystem::path &default_dir)
bool eraseFile_posix(const std::string &path, bool dosync)
void emitSignal(Args... args)
std::string to_string(double value)
std::vector< uint8_t > salt