Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago Move string::absolute, directory, filename, filenameBase, and filenameExtension to system::getAbsolute, getDirectory, getFilename, getStem, and getExtension. Reimplement most system:: functions using std::experimental::filesystem. Add system::doesExist, getFileSize, and getTempDir.
4 years ago |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959 |
- #include <thread>
- #include <regex>
- #include <chrono>
- #include <ghc/filesystem.hpp>
-
- #include <dirent.h>
- #include <sys/stat.h>
- #include <cxxabi.h> // for abi::__cxa_demangle
-
- #if defined ARCH_LIN || defined ARCH_MAC
- #include <pthread.h>
- #include <time.h> // for clock_gettime
- #include <sched.h>
- #include <execinfo.h> // for backtrace and backtrace_symbols
- #include <unistd.h> // for execl
- #include <sys/utsname.h>
- #endif
-
- #if defined ARCH_MAC
- #include <mach/mach_init.h>
- #include <mach/thread_act.h>
- #include <mach/mach_time.h>
- #include <sys/sysctl.h>
- #endif
-
- #if defined ARCH_WIN
- #include <windows.h>
- #include <shellapi.h>
- #include <processthreadsapi.h>
- #include <dbghelp.h>
- #endif
-
- #include <archive.h>
- #include <archive_entry.h>
- #if defined ARCH_MAC
- #include <locale.h>
- #endif
-
- #include <system.hpp>
- #include <string.hpp>
-
-
- /*
- In C++17, this will be `std::filesystem`
- Important: When using `fs::path`, always convert strings to/from UTF-8 using
-
- fs::path p = fs::u8path(s);
- std::string s = p.generic_u8string();
- */
- namespace fs = ghc::filesystem;
-
-
- namespace rack {
- namespace system {
-
-
- std::string join(const std::string& path1, const std::string& path2) {
- return (fs::u8path(path1) / fs::u8path(path2)).generic_u8string();
- }
-
-
- static void appendEntries(std::vector<std::string>& entries, const fs::path& dir, int depth) {
- try {
- for (const auto& entry : fs::directory_iterator(dir)) {
- entries.push_back(entry.path().generic_u8string());
- // Recurse if depth > 0 (limited recursion) or depth < 0 (infinite recursion).
- if (depth != 0) {
- if (entry.is_directory()) {
- appendEntries(entries, entry.path(), depth - 1);
- }
- }
- }
- }
- catch (fs::filesystem_error& e) {}
- }
-
-
- std::vector<std::string> getEntries(const std::string& dirPath, int depth) {
- std::vector<std::string> entries;
- appendEntries(entries, fs::u8path(dirPath), depth);
- return entries;
- }
-
-
- bool exists(const std::string& path) {
- try {
- return fs::exists(fs::u8path(path));
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
- }
-
-
- bool isFile(const std::string& path) {
- try {
- return fs::is_regular_file(fs::u8path(path));
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
- }
-
-
- bool isDirectory(const std::string& path) {
- try {
- return fs::is_directory(fs::u8path(path));
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
- }
-
-
- uint64_t getFileSize(const std::string& path) {
- try {
- return fs::file_size(fs::u8path(path));
- }
- catch (fs::filesystem_error& e) {
- return 0;
- }
- }
-
-
- bool rename(const std::string& srcPath, const std::string& destPath) {
- try {
- fs::rename(fs::u8path(srcPath), fs::u8path(destPath));
- return true;
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
- }
-
-
- bool copy(const std::string& srcPath, const std::string& destPath) {
- try {
- fs::copy(fs::u8path(srcPath), fs::u8path(destPath), fs::copy_options::recursive | fs::copy_options::overwrite_existing);
- return true;
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
- }
-
-
- bool createDirectory(const std::string& path) {
- try {
- return fs::create_directory(fs::u8path(path));
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
- }
-
-
- bool createDirectories(const std::string& path) {
- try {
- return fs::create_directories(fs::u8path(path));
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
- }
-
-
- bool createSymbolicLink(const std::string& target, const std::string& link) {
- try {
- fs::create_symlink(fs::u8path(target), fs::u8path(link));
- return true;
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
- }
-
-
- bool remove(const std::string& path) {
- try {
- return fs::remove(fs::u8path(path));
- }
- catch (fs::filesystem_error& e) {
- return false;
- }
- }
-
-
- int removeRecursively(const std::string& pathStr) {
- fs::path path = fs::u8path(pathStr);
- try {
- // Make all entries writable before attempting to remove
- for (auto& entry : fs::recursive_directory_iterator(path)) {
- fs::permissions(entry.path(), fs::perms::owner_write, fs::perm_options::add);
- }
-
- return fs::remove_all(path);
- }
- catch (fs::filesystem_error& e) {
- return 0;
- }
- }
-
-
- std::string getWorkingDirectory() {
- try {
- return fs::current_path().generic_u8string();
- }
- catch (fs::filesystem_error& e) {
- return "";
- }
- }
-
-
- void setWorkingDirectory(const std::string& path) {
- try {
- fs::current_path(fs::u8path(path));
- }
- catch (fs::filesystem_error& e) {
- // Do nothing
- }
- }
-
-
- std::string getTempDirectory() {
- try {
- return fs::temp_directory_path().generic_u8string();
- }
- catch (fs::filesystem_error& e) {
- return "";
- }
- }
-
-
- std::string getAbsolute(const std::string& path) {
- try {
- return fs::absolute(fs::u8path(path)).generic_u8string();
- }
- catch (fs::filesystem_error& e) {
- return "";
- }
- }
-
-
- std::string getCanonical(const std::string& path) {
- try {
- return fs::canonical(fs::u8path(path)).generic_u8string();
- }
- catch (fs::filesystem_error& e) {
- return "";
- }
- }
-
-
- std::string getDirectory(const std::string& path) {
- try {
- return fs::u8path(path).parent_path().generic_u8string();
- }
- catch (fs::filesystem_error& e) {
- return "";
- }
- }
-
-
- std::string getFilename(const std::string& path) {
- try {
- return fs::u8path(path).filename().generic_u8string();
- }
- catch (fs::filesystem_error& e) {
- return "";
- }
- }
-
-
- std::string getStem(const std::string& path) {
- try {
- return fs::u8path(path).stem().generic_u8string();
- }
- catch (fs::filesystem_error& e) {
- return "";
- }
- }
-
-
- std::string getExtension(const std::string& path) {
- try {
- return fs::u8path(path).extension().generic_u8string();
- }
- catch (fs::filesystem_error& e) {
- return "";
- }
- }
-
-
- std::vector<uint8_t> readFile(const std::string& path) {
- std::vector<uint8_t> data;
- FILE* f = std::fopen(path.c_str(), "rb");
- if (!f)
- throw Exception("Cannot read file %s", path.c_str());
- DEFER({
- std::fclose(f);
- });
-
- // Get file size so we can make a single allocation
- std::fseek(f, 0, SEEK_END);
- size_t len = std::ftell(f);
- std::fseek(f, 0, SEEK_SET);
-
- data.resize(len);
- std::fread(data.data(), 1, len, f);
- return data;
- }
-
-
- uint8_t* readFile(const std::string& path, size_t* size) {
- FILE* f = std::fopen(path.c_str(), "rb");
- if (!f)
- throw Exception("Cannot read file %s", path.c_str());
- DEFER({
- std::fclose(f);
- });
-
- // Get file size so we can make a single allocation
- std::fseek(f, 0, SEEK_END);
- size_t len = std::ftell(f);
- std::fseek(f, 0, SEEK_SET);
-
- uint8_t* data = (uint8_t*) std::malloc(len);
- std::fread(data, 1, len, f);
- if (size)
- *size = len;
- return data;
- }
-
-
- void writeFile(const std::string& path, const std::vector<uint8_t>& data) {
- FILE* f = std::fopen(path.c_str(), "wb");
- if (!f)
- throw Exception("Cannot create file %s", path.c_str());
- DEFER({
- std::fclose(f);
- });
-
- std::fwrite(data.data(), 1, data.size(), f);
- }
-
-
- /** Returns `p` in relative path form, relative to `base`
- Limitation: `p` must be a descendant of `base`. Doesn't support adding `../` to the return path.
- */
- static std::string getRelativePath(std::string path, std::string base) {
- try {
- path = fs::absolute(fs::u8path(path)).generic_u8string();
- base = fs::absolute(fs::u8path(base)).generic_u8string();
- }
- catch (fs::filesystem_error& e) {
- throw Exception("%s", e.what());
- }
- if (path.size() < base.size())
- throw Exception("getRelativePath() error: path is shorter than base");
- if (!std::equal(base.begin(), base.end(), path.begin()))
- throw Exception("getRelativePath() error: path does not begin with base");
-
- // If path == base, this correctly returns "."
- return "." + std::string(path.begin() + base.size(), path.end());
- }
-
-
- static la_ssize_t archiveWriteVectorCallback(struct archive* a, void* client_data, const void* buffer, size_t length) {
- assert(client_data);
- std::vector<uint8_t>& data = *((std::vector<uint8_t>*) client_data);
- uint8_t* buf = (uint8_t*) buffer;
- data.insert(data.end(), buf, buf + length);
- return length;
- }
-
-
- static void archiveDirectory(const std::string& archivePath, std::vector<uint8_t>* archiveData, const std::string& dirPath, int compressionLevel) {
- // Based on minitar.c create() in libarchive examples
- int r;
-
- // Open archive for writing
- struct archive* a = archive_write_new();
- DEFER({archive_write_free(a);});
- // For some reason libarchive adds 10k of padding to archive_write_open() (but not archive_write_open_filename()) unless this is set to 0.
- archive_write_set_bytes_per_block(a, 0);
- archive_write_set_format_pax_restricted(a);
- archive_write_add_filter_zstd(a);
- if (!(0 <= compressionLevel && compressionLevel <= 19))
- throw Exception("Invalid Zstandard compression level");
- r = archive_write_set_filter_option(a, NULL, "compression-level", std::to_string(compressionLevel).c_str());
- if (r < ARCHIVE_OK)
- throw Exception("Archiver could not set filter option: %s", archive_error_string(a));
-
- if (archiveData) {
- // Open vector
- archive_write_open(a, (void*) archiveData, NULL, archiveWriteVectorCallback, NULL);
- }
- else {
- // Open file
- #if defined ARCH_WIN
- r = archive_write_open_filename_w(a, string::UTF8toUTF16(archivePath).c_str());
- #else
- r = archive_write_open_filename(a, archivePath.c_str());
- #endif
- if (r < ARCHIVE_OK)
- throw Exception("Archiver could not open archive %s for writing: %s", archivePath.c_str(), archive_error_string(a));
- }
- DEFER({archive_write_close(a);});
-
- // Open dir for reading
- struct archive* disk = archive_read_disk_new();
- DEFER({archive_read_free(disk);});
- #if defined ARCH_WIN
- r = archive_read_disk_open_w(disk, string::UTF8toUTF16(dirPath).c_str());
- #else
- r = archive_read_disk_open(disk, dirPath.c_str());
- #endif
- if (r < ARCHIVE_OK)
- throw Exception("Archiver could not open dir %s for reading: %s", dirPath.c_str(), archive_error_string(a));
- DEFER({archive_read_close(a);});
-
- // Iterate dir
- for (;;) {
- struct archive_entry* entry = archive_entry_new();
- DEFER({archive_entry_free(entry);});
-
- r = archive_read_next_header2(disk, entry);
- if (r == ARCHIVE_EOF)
- break;
- if (r < ARCHIVE_OK)
- throw Exception("Archiver could not get next entry from archive: %s", archive_error_string(disk));
-
- // Recurse dirs
- archive_read_disk_descend(disk);
-
- // Convert absolute path to relative path
- std::string entryPath;
- #if defined ARCH_WIN
- entryPath = string::UTF16toUTF8(archive_entry_pathname_w(entry));
- #else
- entryPath = archive_entry_pathname(entry);
- #endif
-
- entryPath = getRelativePath(entryPath, dirPath);
-
- #if defined ARCH_WIN
- // FIXME This doesn't seem to set UTF-8 paths on Windows.
- archive_entry_copy_pathname_w(entry, string::UTF8toUTF16(entryPath).c_str());
- #else
- archive_entry_set_pathname(entry, entryPath.c_str());
- #endif
-
- // Set uid and gid to 0 because we don't need to store these.
- archive_entry_set_uid(entry, 0);
- archive_entry_set_uname(entry, NULL);
- archive_entry_set_gid(entry, 0);
- archive_entry_set_gname(entry, NULL);
-
- // Write file to archive
- r = archive_write_header(a, entry);
- if (r < ARCHIVE_OK)
- throw Exception("Archiver could not write entry to archive: %s", archive_error_string(a));
-
- // Manually copy data
- #if defined ARCH_WIN
- std::string entrySourcePath = string::UTF16toUTF8(archive_entry_sourcepath_w(entry));
- #else
- std::string entrySourcePath = archive_entry_sourcepath(entry);
- #endif
- FILE* f = std::fopen(entrySourcePath.c_str(), "rb");
- DEFER({std::fclose(f);});
- char buf[1 << 16];
- ssize_t len;
- while ((len = std::fread(buf, 1, sizeof(buf), f)) > 0) {
- archive_write_data(a, buf, len);
- }
- }
- }
-
- void archiveDirectory(const std::string& archivePath, const std::string& dirPath, int compressionLevel) {
- archiveDirectory(archivePath, NULL, dirPath, compressionLevel);
- }
-
- std::vector<uint8_t> archiveDirectory(const std::string& dirPath, int compressionLevel) {
- std::vector<uint8_t> archiveData;
- archiveDirectory("", &archiveData, dirPath, compressionLevel);
- return archiveData;
- }
-
-
- struct ArchiveReadVectorData {
- const std::vector<uint8_t>* data = NULL;
- size_t pos = 0;
- };
-
- static la_ssize_t archiveReadVectorCallback(struct archive *a, void* client_data, const void** buffer) {
- assert(client_data);
- ArchiveReadVectorData* arvd = (ArchiveReadVectorData*) client_data;
- assert(arvd->data);
- const std::vector<uint8_t>& data = *arvd->data;
- *buffer = &data[arvd->pos];
- // Read up to some block size of bytes
- size_t len = std::min(data.size() - arvd->pos, size_t(1 << 16));
- arvd->pos += len;
- return len;
- }
-
- static void unarchiveToDirectory(const std::string& archivePath, const std::vector<uint8_t>* archiveData, const std::string& dirPathStr) {
- #if defined ARCH_MAC
- // libarchive depends on locale so set thread locale
- // If locale is not found, returns NULL which resets thread to global locale
- locale_t loc = newlocale(LC_CTYPE_MASK, "en_US.UTF-8", NULL);
- locale_t oldLoc = uselocale(loc);
- freelocale(loc);
- DEFER({
- uselocale(oldLoc);
- });
- #endif
-
- fs::path dirPath = fs::u8path(dirPathStr);
-
- // Based on minitar.c extract() in libarchive examples
- int r;
-
- // Open archive for reading
- struct archive* a = archive_read_new();
- if (!a)
- throw Exception("Unarchiver could not be created");
- DEFER({archive_read_free(a);});
- archive_read_support_filter_zstd(a);
- // archive_read_support_filter_all(a);
- archive_read_support_format_tar(a);
- // archive_read_support_format_all(a);
-
- ArchiveReadVectorData arvd;
- if (archiveData) {
- // Open vector
- arvd.data = archiveData;
- archive_read_open(a, &arvd, NULL, archiveReadVectorCallback, NULL);
- }
- else {
- // Open file
- const size_t blockSize = 1 << 16;
- #if defined ARCH_WIN
- r = archive_read_open_filename_w(a, string::UTF8toUTF16(archivePath).c_str(), blockSize);
- #else
- r = archive_read_open_filename(a, archivePath.c_str(), blockSize);
- #endif
- if (r < ARCHIVE_OK)
- throw Exception("Unarchiver could not open archive %s: %s", archivePath.c_str(), archive_error_string(a));
- }
- DEFER({archive_read_close(a);});
-
- // Open dir for writing
- struct archive* disk = archive_write_disk_new();
- DEFER({archive_write_free(disk);});
- // Don't restore timestamps
- int flags = 0;
- // Delete existing files instead of truncating and rewriting
- flags |= ARCHIVE_EXTRACT_UNLINK;
- archive_write_disk_set_options(disk, flags);
- DEFER({archive_write_close(disk);});
-
- // Iterate archive
- for (;;) {
- // Get next entry
- struct archive_entry* entry;
- r = archive_read_next_header(a, &entry);
- if (r == ARCHIVE_EOF)
- break;
- if (r < ARCHIVE_OK)
- throw Exception("Unarchiver could not read entry from archive: %s", archive_error_string(a));
-
- // Convert relative pathname to absolute based on dirPath
- fs::path entryPath = fs::u8path(archive_entry_pathname(entry));
- // DEBUG("entryPath: %s", entryPath.generic_u8string().c_str());
- if (!entryPath.is_relative())
- throw Exception("Unarchiver does not support absolute tar paths: %s", entryPath.u8string().c_str());
-
- entryPath = dirPath / entryPath;
- #if defined ARCH_WIN
- archive_entry_copy_pathname_w(entry, string::UTF8toUTF16(entryPath.u8string()).c_str());
- #else
- archive_entry_set_pathname(entry, entryPath.u8string().c_str());
- #endif
-
- mode_t mode = archive_entry_mode(entry);
- mode_t filetype = archive_entry_filetype(entry);
- int64_t size = archive_entry_size(entry);
-
- // Force minimum modes
- if (filetype == AE_IFREG) {
- mode |= 0644;
- }
- else if (filetype == AE_IFDIR) {
- mode |= 0755;
- }
- archive_entry_set_mode(entry, mode);
-
- // Delete zero-byte files
- if (filetype == AE_IFREG && size == 0) {
- remove(entryPath.generic_u8string());
- continue;
- }
-
- // Write entry to disk
- r = archive_write_header(disk, entry);
- if (r < ARCHIVE_OK)
- throw Exception("Unarchiver could not write file to dir: %s", archive_error_string(disk));
-
- // Copy data to file
- for (;;) {
- const void* buf;
- size_t size;
- int64_t offset;
- // Read data from archive
- r = archive_read_data_block(a, &buf, &size, &offset);
- if (r == ARCHIVE_EOF)
- break;
- if (r < ARCHIVE_OK)
- throw Exception("Unarchiver could not read data from archive: %s", archive_error_string(a));
-
- // Write data to file
- r = archive_write_data_block(disk, buf, size, offset);
- if (r < ARCHIVE_OK)
- throw Exception("Unarchiver could not write data to file: %s", archive_error_string(disk));
- }
-
- // Close file
- r = archive_write_finish_entry(disk);
- if (r < ARCHIVE_OK)
- throw Exception("Unarchiver could not close file: %s", archive_error_string(disk));
- }
- }
-
- void unarchiveToDirectory(const std::string& archivePath, const std::string& dirPath) {
- unarchiveToDirectory(archivePath, NULL, dirPath);
- }
-
- void unarchiveToDirectory(const std::vector<uint8_t>& archiveData, const std::string& dirPath) {
- unarchiveToDirectory("", &archiveData, dirPath);
- }
-
-
- int getLogicalCoreCount() {
- return std::thread::hardware_concurrency();
- }
-
-
- void setThreadName(const std::string& name) {
- #if defined ARCH_LIN
- pthread_setname_np(pthread_self(), name.substr(0, 15).c_str());
- #elif defined ARCH_MAC
- // Not supported (yet) on Mac
- #elif defined ARCH_WIN
- // Not supported on Windows
- #endif
- }
-
-
- std::string getStackTrace() {
- void* stack[128];
- int stackLen = LENGTHOF(stack);
- std::string s;
-
- #if defined ARCH_LIN || defined ARCH_MAC
- stackLen = backtrace(stack, stackLen);
- char** strings = backtrace_symbols(stack, stackLen);
- if (!strings)
- return "";
-
- // Skip the first line because it's this function.
- for (int i = 1; i < stackLen; i++) {
- s += string::f("%d: ", stackLen - i - 1);
- std::string line = strings[i];
- #if ARCH_LIN
- // Parse line, e.g.
- // ./main(__mangled_symbol+0x100) [0x12345678]
- std::regex r(R"((.+?)\((.*?)\+(.+?)\) (.+?))");
- std::smatch match;
- if (std::regex_match(line, match, r)) {
- s += match[1].str();
- s += "(";
- std::string symbol = match[2].str();
- // Demangle symbol
- char* symbolD = abi::__cxa_demangle(symbol.c_str(), NULL, NULL, NULL);
- if (symbolD) {
- symbol = symbolD;
- free(symbolD);
- }
- s += symbol;
- s += "+";
- s += match[3].str();
- s += ")";
- }
- else {
- // If regex fails, just use the raw line
- s += line;
- }
- #elif ARCH_MAC
- // Parse line, e.g.
- // 1 Rack 0x0000000002ddc3eb _mangled_symbol + 27
- std::regex r(R"((\d+)\s+(.+?)\s+(.+?) (.*?) \+ (.+?))");
- std::smatch match;
- if (std::regex_match(line, match, r)) {
- s += match[2].str();
- s += "(";
- std::string symbol = match[4].str();
- // Demangle symbol
- char* symbolD = abi::__cxa_demangle(symbol.c_str(), NULL, NULL, NULL);
- if (symbolD) {
- symbol = symbolD;
- free(symbolD);
- }
- s += symbol;
- s += "+";
- s += match[5].str();
- s += ")";
- }
- else {
- // If regex fails, just use the raw line
- s += line;
- }
- #endif
- s += "\n";
- }
- free(strings);
-
- #elif defined ARCH_WIN
- HANDLE process = GetCurrentProcess();
- SymInitialize(process, NULL, true);
- stackLen = CaptureStackBackTrace(0, stackLen, stack, NULL);
-
- SYMBOL_INFO* symbol = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 256, 1);
- symbol->MaxNameLen = 255;
- symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
-
- for (int i = 1; i < stackLen; i++) {
- SymFromAddr(process, (DWORD64) stack[i], 0, symbol);
- s += string::f("%d: %s 0x%" PRIx64 "\n", stackLen - i - 1, symbol->Name, symbol->Address);
- }
- free(symbol);
- #endif
-
- return s;
- }
-
-
- #if defined ARCH_WIN
- static int64_t startCounter = 0;
- static double counterTime = 0.0;
- #endif
- #if defined ARCH_LIN
- static int64_t startTime = 0;
- #endif
- #if defined ARCH_MAC
- static int64_t startCounter = 0;
- static double counterTime = 0.0;
- #endif
-
- static void initTime() {
- #if defined ARCH_WIN
- LARGE_INTEGER counter;
- QueryPerformanceCounter(&counter);
- startCounter = counter.QuadPart;
-
- LARGE_INTEGER frequency;
- QueryPerformanceFrequency(&frequency);
- counterTime = 1.0 / frequency.QuadPart;
- #endif
- #if defined ARCH_LIN
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
- startTime = int64_t(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
- #endif
- #if defined ARCH_MAC
- startCounter = mach_absolute_time();
-
- mach_timebase_info_data_t tb;
- mach_timebase_info(&tb);
- counterTime = 1e-9 * (double) tb.numer / tb.denom;
- #endif
- }
-
-
- double getTime() {
- #if defined ARCH_WIN
- LARGE_INTEGER counter;
- QueryPerformanceCounter(&counter);
- return (counter.QuadPart - startCounter) * counterTime;
- #elif defined ARCH_LIN
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
- int64_t time = int64_t(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
- return (time - startTime) / 1e9;
- #elif defined ARCH_MAC
- int64_t counter = mach_absolute_time();
- return (counter - startCounter) * counterTime;
- #else
- return 0.0;
- #endif
- }
-
-
- double getUnixTime() {
- // This is not guaranteed to return the time since 1970 in C++11. (It only does in C++20).
- // However, it does on all platforms I care about.
- auto duration = std::chrono::system_clock::now().time_since_epoch();
- return std::chrono::duration<double>(duration).count();
- }
-
-
- double getThreadTime() {
- #if defined ARCH_LIN
- struct timespec ts;
- clockid_t cid;
- pthread_getcpuclockid(pthread_self(), &cid);
- clock_gettime(cid, &ts);
- return ts.tv_sec + ts.tv_nsec * 1e-9;
- #elif defined ARCH_MAC
- mach_port_t thread = mach_thread_self();
- mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
- thread_basic_info_data_t info;
- kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t) &info, &count);
- if (kr != KERN_SUCCESS || (info.flags & TH_FLAGS_IDLE) != 0)
- return 0.0;
- return info.user_time.seconds + info.user_time.microseconds * 1e-6;
- #elif defined ARCH_WIN
- FILETIME creationTime;
- FILETIME exitTime;
- FILETIME kernelTime;
- FILETIME userTime;
- if (GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime, &userTime) == 0)
- return 0.0;
- return ((uint64_t(userTime.dwHighDateTime) << 32) + userTime.dwLowDateTime) * 1e-7;
- #else
- return 0.0;
- #endif
- }
-
-
- void sleep(double time) {
- std::this_thread::sleep_for(std::chrono::duration<double>(time));
- }
-
-
- std::string getOperatingSystemInfo() {
- #if defined ARCH_LIN
- struct utsname u;
- uname(&u);
- return string::f("%s %s %s %s", u.sysname, u.release, u.version, u.machine);
- #elif defined ARCH_MAC
- // From https://opensource.apple.com/source/cctools/cctools-973.0.1/libstuff/macosx_deployment_target.c.auto.html
- char osversion[32];
- int osversion_name[2] = {CTL_KERN, KERN_OSRELEASE};
- size_t osversion_len = sizeof(osversion) - 1;
- if (sysctl(osversion_name, 2, osversion, &osversion_len, NULL, 0) != 0)
- return "Mac";
-
- int major = 0;
- int minor = 0;
- if (sscanf(osversion, "%d.%d", &major, &minor) != 2)
- return "Mac";
-
- // Try to match version numbers to retail versions
- if (major >= 20) {
- if (major >= 22) {
- minor -= 1;
- }
- major -= 9;
- return string::f("Mac %d.%d", major, minor);
- }
- else {
- major -= 4;
- return string::f("Mac 10.%d.%d", major, minor);
- }
- #elif defined ARCH_WIN
- OSVERSIONINFOW info;
- ZeroMemory(&info, sizeof(info));
- info.dwOSVersionInfoSize = sizeof(info);
- GetVersionExW(&info);
- // See https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_osversioninfoa for a list of Windows version numbers.
- return string::f("Windows %lu.%lu", info.dwMajorVersion, info.dwMinorVersion);
- #endif
- }
-
-
- void openBrowser(const std::string& url) {
- if (url.empty())
- return;
-
- std::string urlL = url;
- std::thread t([=] {
- #if defined ARCH_LIN
- std::string command = "xdg-open \"" + urlL + "\"";
- (void) std::system(command.c_str());
- #endif
- #if defined ARCH_MAC
- std::string command = "open \"" + urlL + "\"";
- std::system(command.c_str());
- #endif
- #if defined ARCH_WIN
- ShellExecuteW(NULL, L"open", string::UTF8toUTF16(urlL).c_str(), NULL, NULL, SW_SHOWDEFAULT);
- #endif
- });
- t.detach();
- }
-
-
- void openDirectory(const std::string& path) {
- if (path.empty())
- return;
-
- std::string pathL = path;
- std::thread t([=] {
- #if defined ARCH_LIN
- std::string command = "xdg-open \"" + pathL + "\"";
- (void) std::system(command.c_str());
- #endif
- #if defined ARCH_MAC
- std::string command = "open \"" + pathL + "\"";
- std::system(command.c_str());
- #endif
- #if defined ARCH_WIN
- ShellExecuteW(NULL, L"explore", string::UTF8toUTF16(pathL).c_str(), NULL, NULL, SW_SHOWDEFAULT);
- #endif
- });
- t.detach();
- }
-
-
- void runProcessDetached(const std::string& path) {
- #if defined ARCH_WIN
- SHELLEXECUTEINFOW shExInfo;
- ZeroMemory(&shExInfo, sizeof(shExInfo));
- shExInfo.cbSize = sizeof(shExInfo);
- shExInfo.lpVerb = L"runas";
-
- std::wstring pathW = string::UTF8toUTF16(path);
- shExInfo.lpFile = pathW.c_str();
- shExInfo.nShow = SW_SHOW;
-
- if (ShellExecuteExW(&shExInfo)) {
- // Do nothing
- }
- #else
- // Not implemented on Linux or Mac
- assert(0);
- #endif
- }
-
-
- void init() {
- initTime();
- }
-
-
- } // namespace system
- } // namespace rack
|