Added the non-fatal MaybeReadFileToString() function
Applications which read files to string typically had to previously
die upon encountering an error, which could sometimes be unideal in
the larger scope of the program. A MaybeReadFileToString() function
was added for cases where a program must read from a file, but shouldn't
ever die.
Change-Id: I1877d41276674c12b1f8443a1d0162dc46261a6b
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/util/file.cc b/aos/util/file.cc
index 4e2d1cd..591539c 100644
--- a/aos/util/file.cc
+++ b/aos/util/file.cc
@@ -7,6 +7,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <optional>
#include <string_view>
#if __has_feature(memory_sanitizer)
#include <sanitizer/msan_interface.h>
@@ -17,14 +18,27 @@
namespace aos {
namespace util {
-::std::string ReadFileToStringOrDie(const std::string_view filename) {
- ::std::string r;
+std::string ReadFileToStringOrDie(const std::string_view filename) {
+ std::optional<std::string> r = MaybeReadFileToString(filename);
+ PCHECK(r.has_value()) << "Failed to read " << filename << " to string";
+ return r.value();
+}
+
+std::optional<std::string> MaybeReadFileToString(
+ const std::string_view filename) {
+ std::string r;
ScopedFD fd(open(::std::string(filename).c_str(), O_RDONLY));
- PCHECK(fd.get() != -1) << ": opening " << filename;
+ if (fd.get() == -1) {
+ PLOG(ERROR) << "Failed to open " << filename;
+ return std::nullopt;
+ }
while (true) {
char buffer[1024];
const ssize_t result = read(fd.get(), buffer, sizeof(buffer));
- PCHECK(result >= 0) << ": reading from " << filename;
+ if (result < 0) {
+ PLOG(ERROR) << "Failed to read from " << filename;
+ return std::nullopt;
+ }
if (result == 0) {
break;
}
diff --git a/aos/util/file.h b/aos/util/file.h
index 3b2231a..0cba867 100644
--- a/aos/util/file.h
+++ b/aos/util/file.h
@@ -22,7 +22,12 @@
// Returns the complete contents of filename. LOG(FATAL)s if any errors are
// encountered.
-::std::string ReadFileToStringOrDie(const std::string_view filename);
+std::string ReadFileToStringOrDie(const std::string_view filename);
+
+// Returns the complete contents of filename. Returns nullopt, but never dies
+// if any errors are encountered.
+std::optional<std::string> MaybeReadFileToString(
+ const std::string_view filename);
// Creates filename if it doesn't exist and sets the contents to contents.
void WriteStringToFileOrDie(const std::string_view filename,
diff --git a/aos/util/file_test.cc b/aos/util/file_test.cc
index 712447e..df16d58 100644
--- a/aos/util/file_test.cc
+++ b/aos/util/file_test.cc
@@ -1,6 +1,7 @@
#include "aos/util/file.h"
#include <cstdlib>
+#include <optional>
#include <string>
#include "gtest/gtest.h"
@@ -14,20 +15,44 @@
// Basic test of reading a normal file.
TEST(FileTest, ReadNormalFile) {
- const ::std::string tmpdir(aos::testing::TestTmpDir());
- const ::std::string test_file = tmpdir + "/test_file";
+ const std::string tmpdir(aos::testing::TestTmpDir());
+ const std::string test_file = tmpdir + "/test_file";
ASSERT_EQ(0, system(("echo contents > " + test_file).c_str()));
EXPECT_EQ("contents\n", ReadFileToStringOrDie(test_file));
}
// Tests reading a file with 0 size, among other weird things.
TEST(FileTest, ReadSpecialFile) {
- const ::std::string stat = ReadFileToStringOrDie("/proc/self/stat");
+ const std::string stat = ReadFileToStringOrDie("/proc/self/stat");
EXPECT_EQ('\n', stat[stat.size() - 1]);
- const ::std::string my_pid = ::std::to_string(getpid());
+ const std::string my_pid = ::std::to_string(getpid());
EXPECT_EQ(my_pid, stat.substr(0, my_pid.size()));
}
+// Basic test of maybe reading a normal file.
+TEST(FileTest, MaybeReadNormalFile) {
+ const std::string tmpdir(aos::testing::TestTmpDir());
+ const std::string test_file = tmpdir + "/test_file";
+ ASSERT_EQ(0, system(("echo contents > " + test_file).c_str()));
+ EXPECT_EQ("contents\n", MaybeReadFileToString(test_file).value());
+}
+
+// Tests maybe reading a file with 0 size, among other weird things.
+TEST(FileTest, MaybeReadSpecialFile) {
+ const std::optional<std::string> stat =
+ MaybeReadFileToString("/proc/self/stat");
+ ASSERT_TRUE(stat.has_value());
+ EXPECT_EQ('\n', (*stat)[stat->size() - 1]);
+ const std::string my_pid = std::to_string(getpid());
+ EXPECT_EQ(my_pid, stat->substr(0, my_pid.size()));
+}
+
+// Tests maybe reading a non-existent file, and not fatally erroring.
+TEST(FileTest, MaybeReadNonexistentFile) {
+ const std::optional<std::string> contents = MaybeReadFileToString("/dne");
+ ASSERT_FALSE(contents.has_value());
+}
+
// Tests that the PathExists function works under normal conditions.
TEST(FileTest, PathExistsTest) {
const std::string tmpdir(aos::testing::TestTmpDir());