Add a file reading utility function

Going to use this for parsing config protobufs.

Change-Id: I471030b31dcf0450d40566560b3ce7338e7a7d21
diff --git a/aos/common/util/BUILD b/aos/common/util/BUILD
index 4437ef6..b62e93c 100644
--- a/aos/common/util/BUILD
+++ b/aos/common/util/BUILD
@@ -220,3 +220,29 @@
     '//aos/testing:test_logging',
   ],
 )
+
+cc_library(
+  name = 'file',
+  hdrs = [
+    'file.h',
+  ],
+  srcs = [
+    'file.cc',
+  ],
+  deps = [
+    '//aos/common:scoped_fd',
+  ],
+)
+
+cc_test(
+  name = 'file_test',
+  srcs = [
+    'file_test.cc',
+  ],
+  deps = [
+    ':file',
+    '//aos/testing:googletest',
+    '//aos/testing:test_logging',
+  ],
+  size = 'small',
+)
diff --git a/aos/common/util/file.cc b/aos/common/util/file.cc
new file mode 100644
index 0000000..4c859cf
--- /dev/null
+++ b/aos/common/util/file.cc
@@ -0,0 +1,28 @@
+#include "aos/common/util/file.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "aos/common/scoped_fd.h"
+
+namespace aos {
+namespace util {
+
+::std::string ReadFileToStringOrDie(const ::std::string &filename) {
+  ::std::string r;
+  ScopedFD fd(PCHECK(open(filename.c_str(), O_RDONLY)));
+  while (true) {
+    char buffer[1024];
+    const ssize_t result = read(fd.get(), buffer, sizeof(buffer));
+    if (result < 0) {
+      PLOG(FATAL, "reading from %s", filename.c_str());
+    } else if (result == 0) {
+      break;
+    }
+    r.append(buffer, result);
+  }
+  return r;
+}
+
+}  // namespace util
+}  // namespace aos
diff --git a/aos/common/util/file.h b/aos/common/util/file.h
new file mode 100644
index 0000000..a32d0a7
--- /dev/null
+++ b/aos/common/util/file.h
@@ -0,0 +1,16 @@
+#ifndef AOS_COMMON_UTIL_FILE_H_
+#define AOS_COMMON_UTIL_FILE_H_
+
+#include <string>
+
+namespace aos {
+namespace util {
+
+// Returns the complete contents of filename. LOG(FATAL)s if any errors are
+// encountered.
+::std::string ReadFileToStringOrDie(const ::std::string &filename);
+
+}  // namespace util
+}  // namespace aos
+
+#endif  // AOS_COMMON_UTIL_FILE_H_
diff --git a/aos/common/util/file_test.cc b/aos/common/util/file_test.cc
new file mode 100644
index 0000000..12a4976
--- /dev/null
+++ b/aos/common/util/file_test.cc
@@ -0,0 +1,40 @@
+#include "aos/common/util/file.h"
+
+#include <stdlib.h>
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "aos/testing/test_logging.h"
+
+namespace aos {
+namespace util {
+namespace testing {
+
+class FileTest : public ::testing::Test {
+ protected:
+  FileTest() {
+    ::aos::testing::EnableTestLogging();
+  }
+};
+
+// Basic test of reading a normal file.
+TEST_F(FileTest, ReadNormalFile) {
+  const ::std::string tmpdir(getenv("TEST_TMPDIR"));
+  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_F(FileTest, ReadSpecialFile) {
+  const ::std::string stat = ReadFileToStringOrDie("/proc/self/stat");
+  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()));
+}
+
+}  // namespace testing
+}  // namespace util
+}  // namespace aos