Fixes to utility / unit test related code.
* Eliminated bugs related to reading content from pipes/files, including
general cleanup/refactoring of these code pieces and API.
* Eliminated bugs related binding/unbinding of loopback devices, which
are used in unit testing.
BUG=chromium-os:31082
TEST=Builds and runs unit tests
CQ-DEPEND=Ib7b3552e98ca40b6141688e2dea5a1407db12b2a
Change-Id: Ifaab8697602a35ce7d7fb9384fdcb1ca64b72515
Reviewed-on: https://gerrit.chromium.org/gerrit/27911
Reviewed-by: Don Garrett <dgarrett@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
Commit-Ready: Gilad Arnold <garnold@chromium.org>
diff --git a/utils.cc b/utils.cc
index 9cb8053..e0d9244 100644
--- a/utils.cc
+++ b/utils.cc
@@ -141,33 +141,70 @@
}
-bool ReadFile(const std::string& path, std::vector<char>* out) {
- CHECK(out);
+// Append |nbytes| of content from |buf| to the vector pointed to by either
+// |vec_p| or |str_p|.
+static void AppendBytes(const char* buf, size_t nbytes,
+ std::vector<char>* vec_p) {
+ CHECK(buf);
+ CHECK(vec_p);
+ vec_p->insert(vec_p->end(), buf, buf + nbytes);
+}
+static void AppendBytes(const char* buf, size_t nbytes,
+ std::string* str_p) {
+ CHECK(buf);
+ CHECK(str_p);
+ str_p->append(buf, nbytes);
+}
+
+// Reads from an open file |fp|, appending the read content to the container
+// pointer to by |out_p|. Returns true upon successful reading all of the
+// file's content, false otherwise.
+template <class T>
+static bool Read(FILE* fp, T* out_p) {
+ CHECK(fp);
+ char buf[1024];
+ while (size_t nbytes = fread(buf, 1, sizeof(buf), fp))
+ AppendBytes(buf, nbytes, out_p);
+ return feof(fp) && !ferror(fp);
+}
+
+// Opens a file |path| for reading, then uses |append_func| to append its
+// content to a container |out_p|.
+template <class T>
+static bool ReadFileAndAppend(const std::string& path, T* out_p) {
FILE* fp = fopen(path.c_str(), "r");
if (!fp)
return false;
- const size_t kChunkSize = 1024;
- size_t read_size;
- do {
- char buf[kChunkSize];
- read_size = fread(buf, 1, kChunkSize, fp);
- if (read_size == 0)
- break;
- out->insert(out->end(), buf, buf + read_size);
- } while (read_size == kChunkSize);
- bool success = !ferror(fp);
- TEST_AND_RETURN_FALSE_ERRNO(fclose(fp) == 0);
- return success;
+ bool success = Read(fp, out_p);
+ return (success && !fclose(fp));
}
-bool ReadFileToString(const std::string& path, std::string* out) {
- vector<char> data;
- bool success = ReadFile(path, &data);
- if (!success) {
+// Invokes a pipe |cmd|, then uses |append_func| to append its stdout to a
+// container |out_p|.
+template <class T>
+static bool ReadPipeAndAppend(const std::string& cmd, T* out_p) {
+ FILE* fp = popen(cmd.c_str(), "r");
+ if (!fp)
return false;
- }
- (*out) = string(&data[0], data.size());
- return true;
+ bool success = Read(fp, out_p);
+ return (success && pclose(fp) >= 0);
+}
+
+
+bool ReadFile(const std::string& path, std::vector<char>* out_p) {
+ return ReadFileAndAppend(path, out_p);
+}
+
+bool ReadFile(const std::string& path, std::string* out_p) {
+ return ReadFileAndAppend(path, out_p);
+}
+
+bool ReadPipe(const std::string& cmd, std::vector<char>* out_p) {
+ return ReadPipeAndAppend(cmd, out_p);
+}
+
+bool ReadPipe(const std::string& cmd, std::string* out_p) {
+ return ReadPipeAndAppend(cmd, out_p);
}
off_t FileSize(const string& path) {