diff --git a/common/FileUtil.hpp b/common/FileUtil.hpp index 144768061d67a..4c84f36806067 100644 --- a/common/FileUtil.hpp +++ b/common/FileUtil.hpp @@ -20,6 +20,7 @@ #include #include "Log.hpp" +#include "Util.hpp" namespace FileUtil { @@ -183,6 +184,39 @@ namespace FileUtil /// Reads the whole file to memory. Only for small files. std::unique_ptr> readFile(const std::string& path, int maxSize = 256 * 1024); + /// Returns the decimal value of given file content being cached in the given data segment if parsed correctly by `std::strtoll`, + /// otherwise returns `defaultValue`. + template, bool> = true> + T readDecimal(const std::string& path, char* data, const size_t dataLen, const T defaultValue) + { + if (dataLen <= 1) // no space for data + EOS + return defaultValue; + errno = 0; // Flush previous error indicator. Reminder: errno is thread-local + const int fd = ::open(path.c_str(), O_RDONLY); + if (fd < 0) + return defaultValue; + + ::memset(data, 0, dataLen); + size_t consumed = 0; + while ( dataLen-consumed-1 /* ex-EOS */ > 0 ) + { + ssize_t n; + while ((n = ::read(fd, data+consumed, dataLen-consumed-1 /* ex-EOS */)) < 0 && errno == EINTR) {} + if (n < 0) // Error + { + consumed = 0; + break; + } + else if (n == 0) // EOF + break; + consumed += static_cast(n); + } + ::close(fd); + return consumed > 0 ? Util::dataToDecimal(data, consumed+1 /* re-add EOS */, defaultValue) : defaultValue; + } + + /// File/Directory stat helper. class Stat { diff --git a/common/Util.hpp b/common/Util.hpp index a1efb0d68feab..eadbea1e8137e 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -230,6 +231,25 @@ namespace Util return true; } + /// Returns the decimal value of given data segment if parsed correctly by `std::strtoll`, + /// otherwise returns `defaultValue`. + template, bool> = true> + T dataToDecimal(const char* data, const size_t dataLen, const T defaultValue) + { + if( dataLen <= 1 ) // no space for data + EOS + return defaultValue; + char* endptr = const_cast(data) + dataLen; + errno = 0; // Flush previous error indicator. Reminder: errno is thread-local + const long long num = std::strtoll(data, &endptr, 10); + if( 0 != errno || nullptr == endptr || endptr == data || // parsing error + ( std::is_unsigned_v && num < 0 ) ) // unsigned target type + { + return defaultValue; + } + return static_cast(num); + } + /// Exception safe scope count/guard struct ReferenceHolder {