// SPDX-License-Identifier: LGPL-3.0-or-other // Copyright (C) 2021 Contributors to the SLS Detector Package #include "sls/file_utils.h" #include "sls/ToString.h" #include "sls/container_utils.h" #include "sls/logger.h" #include "sls/sls_detector_exceptions.h" #include #include #include #include // dirname #include #include #include #include #include //readlink #if defined(__APPLE__) #include #endif namespace sls { std::vector readBinaryFile(const std::string &fname, const std::string &errorPrefix) { // check if it exists struct stat st; if (stat(fname.c_str(), &st) != 0) { throw RuntimeError(errorPrefix + std::string(" (file does not exist)")); } FILE *fp = fopen(fname.c_str(), "rb"); if (fp == nullptr) { throw RuntimeError(errorPrefix + std::string(" (Could not open file: ") + fname + std::string(")")); } // get file size to print progress ssize_t filesize = getFileSize(fp, errorPrefix); std::vector buffer(filesize, 0); if ((ssize_t)fread(buffer.data(), sizeof(char), filesize, fp) != filesize) { throw RuntimeError(errorPrefix + std::string(" (Could not read file)")); } if (fclose(fp) != 0) { throw RuntimeError(errorPrefix + std::string(" (Could not close file)")); } LOG(logDEBUG1) << "Read file into memory"; return buffer; } void mkdir_p(const std::string &path, std::string dir) { if (path.length() == 0) return; size_t i = 0; for (; i < path.length(); i++) { dir += path[i]; if (path[i] == '/') break; } if (mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) { if (errno != EEXIST) throw RuntimeError("Could not create: " + dir); } if (i + 1 < path.length()) mkdir_p(path.substr(i + 1), dir); } int getFileSize(std::ifstream &ifs) { auto current_pos = ifs.tellg(); ifs.seekg(0, std::ios::end); int file_size = ifs.tellg(); ifs.seekg(current_pos); return file_size; } std::string getFileNameFromFilePath(const std::string &fpath) { std::string fname(fpath); std::size_t slashPos = fpath.rfind('/'); if (slashPos != std::string::npos) { fname = fpath.substr(slashPos + 1, fpath.size() - 1); } return fname; } ssize_t getFileSize(FILE *fd, const std::string &prependErrorString) { if (fseek(fd, 0, SEEK_END) != 0) { throw RuntimeError(prependErrorString + std::string(" (Seek error in src file)")); } size_t fileSize = ftell(fd); if (fileSize <= 0) { throw RuntimeError( prependErrorString + std::string(" (Could not get length of source file)")); } rewind(fd); return fileSize; } std::vector getChannelsFromStringList(const std::vector list) { std::vector channels; for (auto line : list) { // replace comma with space std::replace_if( begin(line), end(line), [](char c) { return (c == ','); }, ' '); // split line (delim space) std::vector vec = split(line, ' '); // for every channel separated by space for (auto it : vec) { // find range and replace with sequence of x to y auto result = it.find(':'); if (result != std::string::npos) { try { int istart = StringTo(it.substr(0, result)); int istop = StringTo( it.substr(result + 1, it.length() - result - 1)); LOG(logDEBUG1) << "istart:" << istart << " istop:" << istop; std::vector range(istop - istart); std::generate(range.begin(), range.end(), [n = istart]() mutable { return n++; }); for (auto range_it : range) { channels.push_back(range_it); } } catch (std::exception &e) { throw RuntimeError( "Could not load channels. Invalid channel range: " + it); } } // else convert to int else { int ival = 0; try { ival = StringTo(it); } catch (std::exception &e) { throw RuntimeError( "Could not load channels. Invalid channel number: " + it); } channels.push_back(ival); } } } if (removeDuplicates(channels)) { LOG(logWARNING) << "Removed duplicates from channel file"; } LOG(logDEBUG1) << "list:" << ToString(channels); return channels; } std::vector getChannelsFromFile(const std::string &fname) { // read bad channels file std::ifstream input_file(fname); if (!input_file) { throw RuntimeError("Could not open bad channels file " + fname + " for reading"); } std::vector lines; for (std::string line; std::getline(input_file, line);) { // ignore comments if (line.find('#') != std::string::npos) { line.erase(line.find('#')); } // ignore empty lines if (line.empty()) { continue; } lines.push_back(line); } return getChannelsFromStringList(lines); } std::string getAbsolutePathFromCurrentProcess(const std::string &fname) { if (fname[0] == '/') { return fname; } // in case PATH_MAX defines the longest possible path on linux and macOS // use string instead of char array to avoid overflow std::string path(PATH_MAX, '\0'); #if defined(__APPLE__) uint32_t size = PATH_MAX; if (_NSGetExecutablePath(path.data(), &size) != 0) { throw std::runtime_error("Failed to get executable path"); } // Resolve any symlinks and .. components std::string resolved(PATH_MAX, '\0'); if (!realpath(path.data(), resolved.data())) { throw std::runtime_error("realpath failed for executable"); } path = resolved; #else ssize_t len = readlink("/proc/self/exe", path.data(), PATH_MAX - 1); if (len < 0) { throw RuntimeError("Could not get absolute path for " + fname); } path[len] = '\0'; #endif // get dir path and attach file name std::string absPath = (std::string(dirname(path.data())) + '/' + fname); return absPath; } } // namespace sls