Skip to content

Commit

Permalink
Add safe Util::dataToDecimal<T> and FileUtil::readDecimal to read…
Browse files Browse the repository at this point in the history
… single decimals from files like `/proc/sys/net/ipv4/tcp_max_orphans`

Implementation is value- and thread-safe, utilizing `std::strtoll`.

Signed-off-by: Sven Göthel <[email protected]>
Change-Id: Iad74f253bdac5636757b130b299b5deacda658db
  • Loading branch information
Sven Göthel committed Nov 1, 2024
1 parent b5cd651 commit 80c6478
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
34 changes: 34 additions & 0 deletions common/FileUtil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <Poco/Path.h>

#include "Log.hpp"
#include "Util.hpp"

namespace FileUtil
{
Expand Down Expand Up @@ -183,6 +184,39 @@ namespace FileUtil
/// Reads the whole file to memory. Only for small files.
std::unique_ptr<std::vector<char>> 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<typename T,
std::enable_if_t< std::is_integral_v<T>, 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<size_t>(n);
}
::close(fd);
return consumed > 0 ? Util::dataToDecimal(data, consumed+1 /* re-add EOS */, defaultValue) : defaultValue;
}


/// File/Directory stat helper.
class Stat
{
Expand Down
20 changes: 20 additions & 0 deletions common/Util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <sstream>
#include <string>
#include <map>
#include <type_traits>
#include <utility>
#include <inttypes.h>
#include <cctype>
Expand Down Expand Up @@ -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<typename T,
std::enable_if_t< std::is_integral_v<T>, 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<char*>(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<T> && num < 0 ) ) // unsigned target type
{
return defaultValue;
}
return static_cast<T>(num);
}

/// Exception safe scope count/guard
struct ReferenceHolder
{
Expand Down

0 comments on commit 80c6478

Please sign in to comment.