2015-02-27 02:40:45 +01:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Os-specific function wrapper
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2015-02-27 02:40:45 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2023-01-01 16:18:39 +01:00
|
|
|
// Copyright 2003-2023 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2015-02-27 02:40:45 +01:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2015-02-27 02:40:45 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
// clang-format off
|
2019-12-28 17:44:24 +01:00
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
|
|
|
|
# ifndef PSAPI_VERSION
|
|
|
|
|
# define PSAPI_VERSION 1 // Needed for compatibility with Windows 7
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(__MINGW32__)
|
|
|
|
|
# define MINGW_HAS_SECURE_API 1 // Needed to expose a "secure" POSIX-like API
|
|
|
|
|
#endif
|
2020-04-15 01:55:00 +02:00
|
|
|
// clang-format on
|
2019-12-28 17:44:24 +01:00
|
|
|
|
2015-02-27 02:40:45 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2019-10-03 03:38:06 +02:00
|
|
|
// Limited V3 headers here - this is a base class for Vlc etc
|
2018-10-14 19:43:24 +02:00
|
|
|
#include "V3Os.h"
|
2022-09-18 21:53:42 +02:00
|
|
|
#include "V3String.h"
|
|
|
|
|
|
|
|
|
|
#ifndef V3ERROR_NO_GLOBAL_
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
#endif
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2018-10-14 13:04:18 +02:00
|
|
|
#include <cerrno>
|
2020-06-04 22:08:32 +02:00
|
|
|
#include <climits> // PATH_MAX (especially on FreeBSD)
|
2018-10-14 13:04:18 +02:00
|
|
|
#include <cstdarg>
|
2022-12-14 13:07:25 +01:00
|
|
|
#ifdef _MSC_VER
|
2022-12-14 13:08:19 +01:00
|
|
|
#include <filesystem> // C++17
|
|
|
|
|
#define PATH_MAX MAX_PATH
|
2022-12-14 13:07:25 +01:00
|
|
|
#else
|
2022-12-14 13:08:19 +01:00
|
|
|
#include <dirent.h>
|
2023-11-22 03:22:35 +01:00
|
|
|
#include <utime.h>
|
2022-12-14 13:07:25 +01:00
|
|
|
#endif
|
2019-10-06 19:24:21 +02:00
|
|
|
#include <fstream>
|
2015-02-27 02:40:45 +01:00
|
|
|
#include <memory>
|
2022-09-18 21:53:42 +02:00
|
|
|
|
2018-10-14 13:04:18 +02:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/types.h>
|
2015-02-27 02:40:45 +01:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
// clang-format off
|
2019-03-05 02:29:01 +01:00
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
2020-03-29 18:29:40 +02:00
|
|
|
# include <windows.h> // LONG for bcrypt.h on MINGW
|
2019-12-28 17:44:24 +01:00
|
|
|
# include <bcrypt.h> // BCryptGenRandom
|
|
|
|
|
# include <chrono>
|
2015-02-27 02:40:45 +01:00
|
|
|
# include <direct.h> // mkdir
|
2023-11-22 03:22:35 +01:00
|
|
|
# include <io.h> // open, read, write, close
|
2019-12-28 17:44:24 +01:00
|
|
|
# include <psapi.h> // GetProcessMemoryInfo
|
|
|
|
|
# include <thread>
|
2020-10-27 18:33:25 +01:00
|
|
|
// These macros taken from gdbsupport/gdb_wait.h in binutils-gdb
|
|
|
|
|
# ifndef WIFEXITED
|
|
|
|
|
# ifdef __MINGW32__
|
2022-01-08 18:01:39 +01:00
|
|
|
# define WIFEXITED(w) (((w) & 0xC0000000) == 0)
|
|
|
|
|
# define WEXITSTATUS(w) ((w) & ~0xC0000000)
|
2020-10-27 18:33:25 +01:00
|
|
|
# else
|
2022-01-08 18:01:39 +01:00
|
|
|
# define WIFEXITED(w) (((w) & 0377) == 0)
|
|
|
|
|
# define WEXITSTATUS(w) (((w) >> 8) & 0377)
|
2020-10-27 18:33:25 +01:00
|
|
|
# endif
|
|
|
|
|
# endif
|
2019-12-28 17:44:24 +01:00
|
|
|
#else
|
|
|
|
|
# include <sys/time.h>
|
2022-01-08 18:01:39 +01:00
|
|
|
# include <sys/wait.h> // Needed on FreeBSD for WIFEXITED
|
2019-12-28 17:44:24 +01:00
|
|
|
# include <unistd.h> // usleep
|
2023-11-22 03:22:35 +01:00
|
|
|
# include <fcntl.h>
|
2015-02-27 02:40:45 +01:00
|
|
|
#endif
|
2020-04-15 01:55:00 +02:00
|
|
|
// clang-format on
|
2015-02-27 02:40:45 +01:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Environment
|
|
|
|
|
|
|
|
|
|
string V3Os::getenvStr(const string& envvar, const string& defaultValue) {
|
2022-11-20 16:25:41 +01:00
|
|
|
string ret = "";
|
2019-12-28 17:44:24 +01:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
|
// Note: MinGW does not offer _dupenv_s
|
2022-11-13 14:35:06 +01:00
|
|
|
const char* envvalue = nullptr;
|
2022-12-13 00:46:23 +01:00
|
|
|
_dupenv_s((char**)&envvalue, nullptr, envvar.c_str());
|
2020-05-28 23:39:20 +02:00
|
|
|
if (envvalue != nullptr) {
|
2019-12-28 17:44:24 +01:00
|
|
|
const std::string result{envvalue};
|
2022-12-13 00:46:23 +01:00
|
|
|
free((void*)envvalue);
|
2022-11-20 16:25:41 +01:00
|
|
|
ret = result;
|
2019-12-28 17:44:24 +01:00
|
|
|
} else {
|
2022-11-20 16:25:41 +01:00
|
|
|
ret = defaultValue;
|
2019-12-28 17:44:24 +01:00
|
|
|
}
|
|
|
|
|
#else
|
2021-11-13 19:50:44 +01:00
|
|
|
if (const char* const envvalue = getenv(envvar.c_str())) {
|
2022-11-20 16:25:41 +01:00
|
|
|
ret = envvalue;
|
2015-02-27 02:40:45 +01:00
|
|
|
} else {
|
2022-11-20 16:25:41 +01:00
|
|
|
ret = defaultValue;
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
2019-12-28 17:44:24 +01:00
|
|
|
#endif
|
2022-11-20 16:25:41 +01:00
|
|
|
return VString::escapeStringForPath(ret);
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3Os::setenvStr(const string& envvar, const string& value, const string& why) {
|
|
|
|
|
if (why != "") {
|
2020-04-15 01:55:00 +02:00
|
|
|
UINFO(1, "export " << envvar << "=" << value << " # " << why << endl);
|
2015-02-27 02:40:45 +01:00
|
|
|
} else {
|
2020-04-15 01:55:00 +02:00
|
|
|
UINFO(1, "export " << envvar << "=" << value << endl);
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
2019-12-28 17:44:24 +01:00
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
|
|
|
|
_putenv_s(envvar.c_str(), value.c_str());
|
|
|
|
|
#elif defined(_BSD_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L)
|
2019-05-19 22:13:13 +02:00
|
|
|
setenv(envvar.c_str(), value.c_str(), true);
|
2015-02-27 02:40:45 +01:00
|
|
|
#else
|
2020-04-15 01:55:00 +02:00
|
|
|
// setenv() replaced by putenv() in Solaris environment. Prototype is different
|
|
|
|
|
// putenv() requires NAME=VALUE format
|
2021-06-21 00:32:57 +02:00
|
|
|
const string vareq = envvar + "=" + value;
|
2015-02-27 02:40:45 +01:00
|
|
|
putenv(const_cast<char*>(vareq.c_str()));
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2017-09-12 01:18:58 +02:00
|
|
|
// Generic filename utilities
|
2015-02-27 02:40:45 +01:00
|
|
|
|
2023-09-26 21:42:15 +02:00
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
|
|
|
|
static constexpr char V3OS_SLASH = '\\';
|
|
|
|
|
#else
|
|
|
|
|
static constexpr char V3OS_SLASH = '/';
|
|
|
|
|
#endif
|
2023-08-16 13:34:57 +02:00
|
|
|
|
2023-09-26 21:42:15 +02:00
|
|
|
static bool isSlash(char ch) VL_PURE {
|
|
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
|
|
|
|
return ch == '/' || ch == '\\';
|
|
|
|
|
#else
|
|
|
|
|
return ch == '/';
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string V3Os::filenameCleanup(const string& filename) VL_PURE {
|
|
|
|
|
string str;
|
|
|
|
|
str.reserve(filename.length());
|
|
|
|
|
bool lastIsSlash = false;
|
|
|
|
|
for (const char ch : filename) {
|
|
|
|
|
const bool lastIsSlashOld = lastIsSlash;
|
|
|
|
|
lastIsSlash = isSlash(ch);
|
|
|
|
|
if (lastIsSlash && lastIsSlashOld) continue;
|
|
|
|
|
str += ch;
|
2020-04-15 01:55:00 +02:00
|
|
|
}
|
2023-09-26 21:42:15 +02:00
|
|
|
if (str.size() > 1 && isSlash(str.back())) str.pop_back();
|
|
|
|
|
while (str.size() > 2 && str[0] == '.' && isSlash(str[1])) str.erase(0, 2);
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string V3Os::filenameJoin(std::initializer_list<const std::string> paths) VL_PURE {
|
|
|
|
|
string fullpath;
|
|
|
|
|
for (const auto& item : paths) {
|
|
|
|
|
if (item.empty() || item == ".") {
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
if (!fullpath.empty()) fullpath += V3OS_SLASH;
|
|
|
|
|
fullpath += item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return fullpath;
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
|
|
|
|
|
2023-08-16 13:34:57 +02:00
|
|
|
string V3Os::filenameDir(const string& filename) VL_PURE {
|
|
|
|
|
// std::filesystem::path::parent_path
|
|
|
|
|
auto it = filename.rbegin();
|
|
|
|
|
for (; it != filename.rend(); ++it) {
|
|
|
|
|
if (isSlash(*it)) break;
|
|
|
|
|
}
|
|
|
|
|
if (it.base() == filename.begin()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return ".";
|
2023-08-16 13:34:57 +02:00
|
|
|
} else {
|
2023-09-26 21:42:15 +02:00
|
|
|
return string{filename.begin(), (++it).base()};
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-17 00:48:56 +01:00
|
|
|
string V3Os::filenameNonDir(const string& filename) VL_PURE {
|
2023-08-16 13:34:57 +02:00
|
|
|
// std::filesystem::path::filename
|
|
|
|
|
auto it = filename.rbegin();
|
|
|
|
|
for (; it != filename.rend(); ++it) {
|
|
|
|
|
if (isSlash(*it)) break;
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
2023-08-16 13:34:57 +02:00
|
|
|
return string{it.base(), filename.end()};
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-17 00:48:56 +01:00
|
|
|
string V3Os::filenameNonExt(const string& filename) VL_PURE {
|
2015-02-27 02:40:45 +01:00
|
|
|
string base = filenameNonDir(filename);
|
|
|
|
|
string::size_type pos;
|
2020-04-15 01:55:00 +02:00
|
|
|
if ((pos = base.find('.')) != string::npos) base.erase(pos);
|
2015-02-27 02:40:45 +01:00
|
|
|
return base;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-26 21:42:15 +02:00
|
|
|
string V3Os::filenameNonDirExt(const string& filename) VL_PURE {
|
|
|
|
|
return filenameNonExt(filenameNonDir(filename));
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-25 15:52:45 +02:00
|
|
|
string V3Os::filenameSubstitute(const string& filename) {
|
2023-04-09 04:11:28 +02:00
|
|
|
string result;
|
2022-11-27 11:52:40 +01:00
|
|
|
// cppcheck-has-bug-suppress unusedLabel
|
2020-08-16 18:05:35 +02:00
|
|
|
enum : uint8_t { NONE, PAREN, CURLY } brackets = NONE;
|
2015-02-27 02:40:45 +01:00
|
|
|
for (string::size_type pos = 0; pos < filename.length(); ++pos) {
|
2020-04-15 01:55:00 +02:00
|
|
|
if ((filename[pos] == '$') && (pos + 1 < filename.length())) {
|
|
|
|
|
switch (filename[pos + 1]) {
|
|
|
|
|
case '{': brackets = CURLY; break;
|
|
|
|
|
case '(': brackets = PAREN; break;
|
|
|
|
|
default: brackets = NONE; break;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
if (brackets != NONE) pos = pos + 1;
|
|
|
|
|
string::size_type endpos = pos + 1;
|
|
|
|
|
while (((endpos + 1) < filename.length())
|
|
|
|
|
&& (((brackets == NONE)
|
2023-02-11 02:32:35 +01:00
|
|
|
&& (std::isalnum(filename[endpos + 1]) || filename[endpos + 1] == '_'))
|
2020-04-15 01:55:00 +02:00
|
|
|
|| ((brackets == CURLY) && (filename[endpos + 1] != '}'))
|
|
|
|
|
|| ((brackets == PAREN) && (filename[endpos + 1] != ')'))))
|
2019-05-19 22:13:13 +02:00
|
|
|
++endpos;
|
|
|
|
|
// Catch bracket errors
|
2020-04-15 01:55:00 +02:00
|
|
|
if (((brackets == CURLY) && (filename[endpos + 1] != '}'))
|
|
|
|
|
|| ((brackets == PAREN) && (filename[endpos + 1] != ')'))) {
|
|
|
|
|
v3fatal("Unmatched brackets in variable substitution in file: " + filename);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-06-21 00:32:57 +02:00
|
|
|
const string envvar = filename.substr(pos + 1, endpos - pos);
|
2019-12-28 17:44:24 +01:00
|
|
|
string envvalue;
|
2020-01-10 13:07:21 +01:00
|
|
|
if (!envvar.empty()) envvalue = getenvStr(envvar, "");
|
2019-12-28 17:44:24 +01:00
|
|
|
if (!envvalue.empty()) {
|
2023-04-09 04:11:28 +02:00
|
|
|
result += envvalue;
|
2020-04-15 01:55:00 +02:00
|
|
|
if (brackets == NONE) {
|
|
|
|
|
pos = endpos;
|
|
|
|
|
} else {
|
|
|
|
|
pos = endpos + 1;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2023-04-09 04:11:28 +02:00
|
|
|
result += filename[pos]; // *pos == '$'
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2023-04-09 04:11:28 +02:00
|
|
|
result += filename[pos];
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
2023-04-09 04:11:28 +02:00
|
|
|
return result;
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
|
|
|
|
|
2023-08-16 13:34:57 +02:00
|
|
|
string V3Os::filenameRealPath(const string& filename) VL_PURE {
|
2017-02-10 00:33:18 +01:00
|
|
|
// Get rid of all the ../ behavior in the middle of the paths.
|
|
|
|
|
// If there is a ../ that goes down from the 'root' of this path it is preserved.
|
|
|
|
|
char retpath[PATH_MAX];
|
2017-03-16 01:08:19 +01:00
|
|
|
if (
|
2019-12-28 17:44:24 +01:00
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
|
|
|
|
_fullpath(retpath, filename.c_str(), PATH_MAX)
|
2017-03-16 01:08:19 +01:00
|
|
|
#else
|
2019-05-19 22:13:13 +02:00
|
|
|
realpath(filename.c_str(), retpath)
|
2017-03-16 01:08:19 +01:00
|
|
|
#endif
|
2020-04-15 01:55:00 +02:00
|
|
|
) {
|
2022-08-30 07:02:39 +02:00
|
|
|
return std::string{retpath};
|
2017-02-14 00:11:22 +01:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
return filename;
|
2017-02-14 00:11:22 +01:00
|
|
|
}
|
2017-02-10 00:33:18 +01:00
|
|
|
}
|
|
|
|
|
|
2023-08-16 13:34:57 +02:00
|
|
|
bool V3Os::filenameIsRel(const string& filename) VL_PURE {
|
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
|
return std::filesystem::path(filename).is_relative();
|
|
|
|
|
#else
|
2020-04-15 01:55:00 +02:00
|
|
|
return (filename.length() > 0 && filename[0] != '/');
|
2023-08-16 13:34:57 +02:00
|
|
|
#endif
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2018-11-27 01:09:08 +01:00
|
|
|
// File utilities
|
|
|
|
|
|
|
|
|
|
string V3Os::getline(std::istream& is, char delim) {
|
|
|
|
|
string line;
|
|
|
|
|
#if defined(__CYGWIN__) // Work around buggy implementation of getline
|
|
|
|
|
char buf[65536];
|
|
|
|
|
is.getline(buf, 65535, delim);
|
|
|
|
|
line = buf;
|
|
|
|
|
#else
|
|
|
|
|
std::getline(is, line, delim);
|
|
|
|
|
#endif
|
|
|
|
|
return line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2015-02-27 02:40:45 +01:00
|
|
|
// Directory utilities
|
|
|
|
|
|
|
|
|
|
void V3Os::createDir(const string& dirname) {
|
|
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
2019-12-28 17:44:24 +01:00
|
|
|
_mkdir(dirname.c_str());
|
2015-02-27 02:40:45 +01:00
|
|
|
#else
|
|
|
|
|
mkdir(dirname.c_str(), 0777);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-22 03:22:35 +01:00
|
|
|
void V3Os::filesystemFlush(const string& dirname) {
|
|
|
|
|
// NFS caches stat() calls so to get up-to-date information must
|
|
|
|
|
// do a open or opendir on the filename.
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
if (int fd = ::open(filename.c_str(), O_RDONLY)) { // LCOV_EXCL_BR_LINE
|
|
|
|
|
if (fd > 0) ::close(fd);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
{
|
|
|
|
|
// Linux kernel may not reread from NFS unless timestamp modified
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
|
const int err = utimes(dirname.c_str(), &tv);
|
|
|
|
|
// Not an error
|
|
|
|
|
if (err != 0) UINFO(1, "-Info: File not statable: " << dirname << endl);
|
|
|
|
|
}
|
|
|
|
|
// Faster to just try both rather than check if a file is a dir.
|
|
|
|
|
if (DIR* const dirp = opendir(dirname.c_str())) { // LCOV_EXCL_BR_LINE
|
|
|
|
|
closedir(dirp); // LCOV_EXCL_LINE
|
|
|
|
|
} else if (int fd = ::open(dirname.c_str(), O_RDONLY)) { // LCOV_EXCL_BR_LINE
|
|
|
|
|
if (fd > 0) ::close(fd);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-27 02:40:45 +01:00
|
|
|
void V3Os::unlinkRegexp(const string& dir, const string& regexp) {
|
2022-12-14 13:07:25 +01:00
|
|
|
#ifdef _MSC_VER
|
2023-08-16 13:34:57 +02:00
|
|
|
try {
|
|
|
|
|
for (const auto& dirEntry : std::filesystem::directory_iterator(dir.c_str())) {
|
|
|
|
|
if (VString::wildmatch(dirEntry.path().filename().string(), regexp.c_str())) {
|
|
|
|
|
const string fullname = dir + "/" + dirEntry.path().filename().string();
|
|
|
|
|
_unlink(fullname.c_str());
|
|
|
|
|
}
|
2022-12-14 13:07:25 +01:00
|
|
|
}
|
2023-08-16 13:34:57 +02:00
|
|
|
} catch (std::filesystem::filesystem_error const& ex) {}
|
2022-12-14 13:07:25 +01:00
|
|
|
#else
|
2021-07-12 00:42:01 +02:00
|
|
|
if (DIR* const dirp = opendir(dir.c_str())) {
|
|
|
|
|
while (struct dirent* const direntp = readdir(dirp)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (VString::wildmatch(direntp->d_name, regexp.c_str())) {
|
2022-08-30 07:02:39 +02:00
|
|
|
const string fullname = dir + "/" + std::string{direntp->d_name};
|
2019-12-28 17:44:24 +01:00
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
|
|
|
|
_unlink(fullname.c_str());
|
|
|
|
|
#else
|
2018-08-25 15:52:45 +02:00
|
|
|
unlink(fullname.c_str());
|
2019-12-28 17:44:24 +01:00
|
|
|
#endif
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
closedir(dirp);
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
2022-12-14 13:07:25 +01:00
|
|
|
#endif
|
2015-02-27 02:40:45 +01:00
|
|
|
}
|
2017-09-18 04:52:57 +02:00
|
|
|
|
2018-09-21 00:09:19 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// METHODS (random)
|
|
|
|
|
|
2022-03-27 21:27:40 +02:00
|
|
|
uint64_t V3Os::rand64(std::array<uint64_t, 2>& stater) {
|
2018-09-21 00:09:19 +02:00
|
|
|
// Xoroshiro128+ algorithm
|
2022-03-27 21:27:40 +02:00
|
|
|
const uint64_t result = stater[0] + stater[1];
|
2020-11-15 22:21:26 +01:00
|
|
|
stater[1] ^= stater[0];
|
|
|
|
|
stater[0] = (((stater[0] << 55) | (stater[0] >> 9)) ^ stater[1] ^ (stater[1] << 14));
|
|
|
|
|
stater[1] = (stater[1] << 36) | (stater[1] >> 28);
|
2018-09-21 00:09:19 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-18 01:24:15 +01:00
|
|
|
string V3Os::trueRandom(size_t size) VL_MT_SAFE {
|
2019-12-28 17:44:24 +01:00
|
|
|
string result(size, '\xFF');
|
2020-04-15 01:55:00 +02:00
|
|
|
char* const data = const_cast<char*>(result.data());
|
2019-12-28 17:44:24 +01:00
|
|
|
// Note: std::string.data() returns a non-const Char* from C++17 onwards.
|
|
|
|
|
// For pre-C++17, this cast is OK in practice, even though it's UB.
|
|
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
2021-06-21 00:32:57 +02:00
|
|
|
const NTSTATUS hr = BCryptGenRandom(nullptr, reinterpret_cast<BYTE*>(data), size,
|
|
|
|
|
BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
2021-02-22 03:25:21 +01:00
|
|
|
if (!BCRYPT_SUCCESS(hr)) v3fatal("Could not acquire random data.");
|
2019-12-28 17:44:24 +01:00
|
|
|
#else
|
2021-07-12 00:42:01 +02:00
|
|
|
std::ifstream is{"/dev/urandom", std::ios::in | std::ios::binary};
|
2019-12-28 17:44:24 +01:00
|
|
|
// This read uses the size of the buffer.
|
|
|
|
|
// Flawfinder: ignore
|
2020-05-17 00:02:54 +02:00
|
|
|
if (VL_UNCOVERABLE(!is.read(data, size))) {
|
|
|
|
|
v3fatal("Could not open /dev/urandom, no source of randomness. " // LCOV_EXCL_LINE
|
2020-04-15 01:55:00 +02:00
|
|
|
"Try specifying a key instead.");
|
2019-10-06 19:24:21 +02:00
|
|
|
}
|
2019-12-28 17:44:24 +01:00
|
|
|
#endif
|
|
|
|
|
return result;
|
2019-10-06 19:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-18 04:52:57 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// METHODS (performance)
|
|
|
|
|
|
|
|
|
|
uint64_t V3Os::timeUsecs() {
|
|
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
2019-12-28 17:44:24 +01:00
|
|
|
// Microseconds between 1601-01-01 00:00:00 UTC and 1970-01-01 00:00:00 UTC
|
2020-04-16 03:47:37 +02:00
|
|
|
static const uint64_t EPOCH_DIFFERENCE_USECS = 11644473600000000ULL;
|
2019-12-28 17:44:24 +01:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
FILETIME ft; // contains number of 0.1us intervals since the beginning of 1601 UTC.
|
2019-12-28 17:44:24 +01:00
|
|
|
GetSystemTimeAsFileTime(&ft);
|
2020-04-15 01:55:00 +02:00
|
|
|
uint64_t us
|
2020-04-16 03:47:37 +02:00
|
|
|
= ((static_cast<uint64_t>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime + 5ULL) / 10ULL;
|
2019-12-28 17:44:24 +01:00
|
|
|
return us - EPOCH_DIFFERENCE_USECS;
|
2017-09-18 04:52:57 +02:00
|
|
|
#else
|
2018-10-15 00:39:33 +02:00
|
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
2017-09-18 04:52:57 +02:00
|
|
|
timeval tv;
|
2020-08-15 16:12:55 +02:00
|
|
|
if (gettimeofday(&tv, nullptr) < 0) return 0;
|
2020-04-15 01:55:00 +02:00
|
|
|
return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
2017-09-18 04:52:57 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t V3Os::memUsageBytes() {
|
|
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
2021-06-21 00:32:57 +02:00
|
|
|
const HANDLE process = GetCurrentProcess();
|
2019-12-28 17:44:24 +01:00
|
|
|
PROCESS_MEMORY_COUNTERS pmc;
|
|
|
|
|
if (GetProcessMemoryInfo(process, &pmc, sizeof(pmc))) {
|
|
|
|
|
// The best we can do using simple Windows APIs is to get the size of the working set.
|
|
|
|
|
return pmc.WorkingSetSize;
|
|
|
|
|
}
|
2017-09-18 04:52:57 +02:00
|
|
|
return 0;
|
|
|
|
|
#else
|
|
|
|
|
// Highly unportable. Sorry
|
2017-10-11 02:16:35 +02:00
|
|
|
const char* const statmFilename = "/proc/self/statm";
|
2019-05-19 22:13:13 +02:00
|
|
|
FILE* fp = fopen(statmFilename, "r");
|
2020-04-15 01:55:00 +02:00
|
|
|
if (!fp) return 0;
|
2022-03-27 21:27:40 +02:00
|
|
|
uint64_t size, resident, share, text, lib, data, dt; // All in pages
|
2022-01-01 22:04:20 +01:00
|
|
|
const int items = fscanf(
|
|
|
|
|
fp, "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64,
|
|
|
|
|
&size, &resident, &share, &text, &lib, &data, &dt);
|
2017-10-14 20:51:57 +02:00
|
|
|
fclose(fp);
|
2020-05-17 00:02:54 +02:00
|
|
|
if (VL_UNCOVERABLE(7 != items)) return 0;
|
2017-09-18 04:52:57 +02:00
|
|
|
return (text + data) * getpagesize();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2019-12-28 17:44:24 +01:00
|
|
|
|
|
|
|
|
void V3Os::u_sleep(int64_t usec) {
|
|
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(usec));
|
|
|
|
|
#else
|
|
|
|
|
// cppcheck-suppress obsoleteFunctionsusleep
|
|
|
|
|
// Flawfinder: ignore
|
|
|
|
|
::usleep(usec);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2020-04-15 23:44:21 +02:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// METHODS (sub command)
|
|
|
|
|
|
|
|
|
|
int V3Os::system(const string& command) {
|
|
|
|
|
UINFO(1, "Running system: " << command << endl);
|
|
|
|
|
const int ret = ::system(command.c_str());
|
2020-05-30 01:35:54 +02:00
|
|
|
if (VL_UNCOVERABLE(ret == -1)) {
|
|
|
|
|
v3fatal("Failed to execute command:" // LCOV_EXCL_LINE
|
2022-09-15 03:10:19 +02:00
|
|
|
<< command << " " << std::strerror(errno));
|
2020-05-30 01:35:54 +02:00
|
|
|
return -1; // LCOV_EXCL_LINE
|
2020-04-15 23:44:21 +02:00
|
|
|
} else {
|
|
|
|
|
UASSERT(WIFEXITED(ret), "system(" << command << ") returned unexpected value of " << ret);
|
|
|
|
|
const int exit_code = WEXITSTATUS(ret);
|
|
|
|
|
UINFO(1, command << " returned exit code of " << exit_code << std::endl);
|
|
|
|
|
UASSERT(exit_code >= 0, "exit code must not be negative");
|
|
|
|
|
return exit_code;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-26 21:42:15 +02:00
|
|
|
|
|
|
|
|
void V3Os::selfTest() {
|
|
|
|
|
#ifdef VL_DEBUG
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup(""), "");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("."), ".");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup(".."), "..");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("/"), "/");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("../"), "..");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("//"), "/");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("//."), "/.");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("./"), ".");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("././"), ".");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup(".///"), ".");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("a"), "a");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("a/"), "a");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("a/b"), "a/b");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("././//./a/b"), "a/b");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup(".//./a///"), "a");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("///a/./b///."), "/a/./b/.");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("aaa/bbb/ccc/"), "aaa/bbb/ccc");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("./aaa/bbb/ccc/"), "aaa/bbb/ccc");
|
|
|
|
|
UASSERT_SELFTEST(string, filenameCleanup("../aaa/bbb/ccc/"), "../aaa/bbb/ccc");
|
|
|
|
|
#endif
|
|
|
|
|
}
|