// -------------------------------------------------------------------------- // // File // Name: Utils.cpp // Purpose: Utility function // Created: 2003/07/31 // // -------------------------------------------------------------------------- #include "Box.h" #include #include #include #include #ifdef HAVE_EXECINFO_H #include #include #endif #ifdef HAVE_CXXABI_H #include #endif #ifdef HAVE_DLFCN_H #include #endif #ifdef NEED_BOX_VERSION_H # include "BoxVersion.h" #endif #include "CommonException.h" #include "Logging.h" #include "Utils.h" #include "MemLeakFindOn.h" std::string GetBoxBackupVersion() { return BOX_VERSION; } // -------------------------------------------------------------------------- // // Function // Name: SplitString(const std::string &, char, std::vector &) // Purpose: Splits a string at a given character // Created: 2003/07/31 // // -------------------------------------------------------------------------- void SplitString(std::string String, char SplitOn, std::vector &rOutput) { // Split it up. std::string::size_type begin = 0, end = 0, pos = 0; while(end = String.find_first_of(SplitOn, pos), end != String.npos) { // Is it preceded by the escape character? if(end > 0 && String[end - 1] == '\\') { // Ignore this one, don't change begin, let the next // match/fallback consume it instead. But remove the // backslash from the string, and set pos to the // current position, which no longer contains a // separator character. String.erase(end - 1, 1); pos = end; } else { // Extract the substring and move past it. unsigned int len = end - begin; if(len >= 1) { rOutput.push_back(String.substr(begin, len)); } begin = end + 1; pos = begin; } } // Last string if(begin < String.size()) { rOutput.push_back(String.substr(begin)); } /*#ifndef BOX_RELEASE_BUILD BOX_TRACE("Splitting string '" << String << " on " << (char)SplitOn); for(unsigned int l = 0; l < rOutput.size(); ++l) { BOX_TRACE(l << " = '" << rOutput[l] << "'"); } #endif*/ } bool StartsWith(const std::string& prefix, const std::string& haystack) { return haystack.size() >= prefix.size() && haystack.substr(0, prefix.size()) == prefix; } bool EndsWith(const std::string& suffix, const std::string& haystack) { return haystack.size() >= suffix.size() && haystack.substr(haystack.size() - suffix.size()) == suffix; } std::string RemovePrefix(const std::string& prefix, const std::string& haystack) { if(StartsWith(prefix, haystack)) { return haystack.substr(prefix.size()); } else { return ""; } } std::string RemoveSuffix(const std::string& suffix, const std::string& haystack) { if(EndsWith(suffix, haystack)) { return haystack.substr(0, haystack.size() - suffix.size()); } else { return ""; } } static std::string demangle(const std::string& mangled_name) { std::string demangled_name = mangled_name; #ifdef HAVE_CXXABI_H char buffer[1024]; int status; size_t length = sizeof(buffer); char* result = abi::__cxa_demangle(mangled_name.c_str(), buffer, &length, &status); if (status == 0) { demangled_name = result; } else if (status == -1) { BOX_WARNING("Demangle failed with " "memory allocation error: " << mangled_name); } else if (status == -2) { // Probably non-C++ name, don't demangle /* BOX_WARNING("Demangle failed with " "with invalid name: " << mangled_name); */ } else if (status == -3) { BOX_WARNING("Demangle failed with " "with invalid argument: " << mangled_name); } else { BOX_WARNING("Demangle failed with " "with unknown error " << status << ": " << mangled_name); } #endif // HAVE_CXXABI_H return demangled_name; } void DumpStackBacktrace() { #ifdef HAVE_EXECINFO_H void *array[20]; size_t size = backtrace(array, 20); BOX_TRACE("Obtained " << size << " stack frames."); for(size_t i = 0; i < size; i++) { std::ostringstream output; output << "Stack frame " << i << ": "; #ifdef HAVE_DLADDR Dl_info info; int result = dladdr(array[i], &info); if(result == 0) { BOX_LOG_SYS_WARNING("Failed to resolve " "backtrace address " << array[i]); output << "unresolved address " << array[i]; } else if(info.dli_sname == NULL) { output << "unknown address " << array[i]; } else { uint64_t diff = (uint64_t) array[i]; diff -= (uint64_t) info.dli_saddr; output << demangle(info.dli_sname) << "+" << (void *)diff; } #else output << "address " << array[i]; #endif // HAVE_DLADDR BOX_TRACE(output.str()); } #else // !HAVE_EXECINFO_H BOX_TRACE("Backtrace support was not compiled in"); #endif // HAVE_EXECINFO_H } // -------------------------------------------------------------------------- // // Function // Name: FileExists(const std::string& rFilename) // Purpose: Does a file exist? // Created: 20/11/03 // // -------------------------------------------------------------------------- bool FileExists(const std::string& rFilename, int64_t *pFileSize, bool TreatLinksAsNotExisting) { EMU_STRUCT_STAT st; if(EMU_LSTAT(rFilename.c_str(), &st) != 0) { if(errno == ENOENT) { return false; } else { THROW_EXCEPTION(CommonException, OSFileError); } } // is it a file? if((st.st_mode & S_IFDIR) == 0) { if(TreatLinksAsNotExisting && ((st.st_mode & S_IFLNK) != 0)) { return false; } // Yes. Tell caller the size? if(pFileSize != 0) { *pFileSize = st.st_size; } return true; } else { return false; } } // -------------------------------------------------------------------------- // // Function // Name: ObjectExists(const std::string& rFilename) // Purpose: Does a object exist, and if so, is it a file or a directory? // Created: 23/11/03 // // -------------------------------------------------------------------------- int ObjectExists(const std::string& rFilename) { EMU_STRUCT_STAT st; if(EMU_STAT(rFilename.c_str(), &st) != 0) { if(errno == ENOENT) { return ObjectExists_NoObject; } else { THROW_EXCEPTION(CommonException, OSFileError); } } // is it a file or a dir? return ((st.st_mode & S_IFDIR) == 0)?ObjectExists_File:ObjectExists_Dir; } std::string HumanReadableSize(int64_t Bytes) { double readableValue = Bytes; std::string units = " B"; if (readableValue > 1024) { readableValue /= 1024; units = "kB"; } if (readableValue > 1024) { readableValue /= 1024; units = "MB"; } if (readableValue > 1024) { readableValue /= 1024; units = "GB"; } std::ostringstream result; result << std::fixed << std::setprecision(2) << readableValue << " " << units; return result.str(); } std::string FormatUsageBar(int64_t Blocks, int64_t Bytes, int64_t Max, bool MachineReadable) { std::ostringstream result; if (MachineReadable) { result << (Bytes >> 10) << " kB, " << std::setprecision(0) << ((Bytes*100)/Max) << "%"; } else { // Bar graph char bar[17]; unsigned int b = (int)((Bytes * (sizeof(bar)-1)) / Max); if(b > sizeof(bar)-1) {b = sizeof(bar)-1;} for(unsigned int l = 0; l < b; l++) { bar[l] = '*'; } for(unsigned int l = b; l < sizeof(bar) - 1; l++) { bar[l] = ' '; } bar[sizeof(bar)-1] = '\0'; result << std::fixed << std::setw(10) << Blocks << " blocks, " << std::setw(10) << HumanReadableSize(Bytes) << ", " << std::setw(3) << std::setprecision(0) << ((Bytes*100)/Max) << "% |" << bar << "|"; } return result.str(); } std::string FormatUsageLineStart(const std::string& rName, bool MachineReadable) { std::ostringstream result; if (MachineReadable) { result << rName << ": "; } else { result << std::setw(20) << std::right << rName << ": "; } return result.str(); }