Refactor IO library.

PiperOrigin-RevId: 604782351
diff --git a/fuzztest/BUILD b/fuzztest/BUILD
index 3b99066..e21c923 100644
--- a/fuzztest/BUILD
+++ b/fuzztest/BUILD
@@ -407,9 +407,7 @@
         "@com_google_absl//absl/hash",
         "@com_google_absl//absl/strings:str_format",
         "@com_google_absl//absl/strings:string_view",
-    ] + select({
-        "//conditions:default": [],
-    }),
+    ],
 )
 
 cc_test(
diff --git a/fuzztest/internal/io.cc b/fuzztest/internal/io.cc
index fba867b..3658908 100644
--- a/fuzztest/internal/io.cc
+++ b/fuzztest/internal/io.cc
@@ -39,115 +39,55 @@
      __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_13_0)
 // std::filesystem requires macOS 10.15+ or iOS 13+.
 // Just stub out these functions.
-#define FUZZTEST_STUB_FILESYSTEM
+#define STUB_FILESYSTEM
 #endif
 #endif
 
 namespace fuzztest::internal {
 
-#if defined(FUZZTEST_STUB_FILESYSTEM)
+#if defined(STUB_FILESYSTEM)
 
-// TODO(lszekeres): Return absl::Status instead of bool for these.
-
-bool WriteFile(absl::string_view path, absl::string_view contents) {
-  FUZZTEST_INTERNAL_CHECK(false, "Filesystem API not supported in iOS/MacOS");
+bool WriteFile(absl::string_view filename, absl::string_view contents) {
+  FUZZTEST_INTERNAL_CHECK(false, "Can't replay in iOS/MacOS");
 }
 
-std::optional<std::string> ReadFile(absl::string_view path) {
-  FUZZTEST_INTERNAL_CHECK(false, "Filesystem API not supported in iOS/MacOS");
+std::string WriteDataToDir(absl::string_view data, absl::string_view dir) {
+  FUZZTEST_INTERNAL_CHECK(false, "Can't replay in iOS/MacOS");
 }
 
-bool IsDirectory(absl::string_view path) {
-  FUZZTEST_INTERNAL_CHECK(false, "Filesystem API not supported in iOS/MacOS");
+std::vector<FilePathAndData> ReadFileOrDirectory(
+    absl::string_view file_or_dir) {
+  FUZZTEST_INTERNAL_CHECK(false, "Can't replay in iOS/MacOS");
 }
 
-bool CreateDirectory(absl::string_view path) {
-  FUZZTEST_INTERNAL_CHECK(false, "Filesystem API not supported in iOS/MacOS");
+std::optional<std::string> ReadFile(absl::string_view file) {
+  FUZZTEST_INTERNAL_CHECK(false, "Can't replay in iOS/MacOS");
 }
 
-std::vector<std::string> ListDirectory(absl::string_view path) {
-  FUZZTEST_INTERNAL_CHECK(false, "Filesystem API not supported in iOS/MacOS");
+std::vector<std::string> ListDirectory(absl::string_view dir) {
+  FUZZTEST_INTERNAL_CHECK(false, "Can't replay in iOS/MacOS");
 }
 
-std::vector<std::string> ListDirectoryRecursively(absl::string_view path) {
-  FUZZTEST_INTERNAL_CHECK(false, "Filesystem API not supported in iOS/MacOS");
-}
+#else  // defined(__APPLE__)
 
-#else
-
-bool WriteFile(absl::string_view path, absl::string_view contents) {
-  const std::filesystem::path fs_path{
-      std::string_view{path.data(), path.size()}};
+bool WriteFile(absl::string_view filename, absl::string_view contents) {
+  std::filesystem::path file_path{
+      std::string_view{filename.data(), filename.size()}};
 
   // Just in case the directory does not currently exist.
   // If it does, this is a noop.
-  CreateDirectory(fs_path.parent_path().string());
+  std::filesystem::create_directories(file_path.parent_path());
 
-  std::ofstream file(fs_path);
+  std::ofstream file(file_path);
   file << contents;
   file.close();
   if (!file.good()) {
-    absl::FPrintF(GetStderr(), "[!] %s:%d: Error writing %s: (%d) %s\n",
-                  __FILE__, __LINE__, path, errno, strerror(errno));
+    absl::FPrintF(GetStderr(), "%s:%d: Error writing %s: (%d) %s\n", __FILE__,
+                  __LINE__, filename, errno, strerror(errno));
   }
   return !file.fail();
 }
 
-std::optional<std::string> ReadFile(absl::string_view path) {
-  const std::filesystem::path fs_path{
-      std::string_view{path.data(), path.size()}};
-
-  std::ifstream stream(fs_path);
-  if (!stream.good()) {
-    absl::FPrintF(GetStderr(), "[!] %s:%d: Error reading %s: (%d) %s\n",
-                  __FILE__, __LINE__, path, errno, strerror(errno));
-    return std::nullopt;
-  }
-  std::stringstream buffer;
-  buffer << stream.rdbuf();
-  return buffer.str();
-}
-
-bool IsDirectory(absl::string_view path) {
-  const std::filesystem::path fs_path{
-      std::string_view{path.data(), path.size()}};
-
-  return std::filesystem::is_directory(fs_path);
-}
-
-bool CreateDirectory(absl::string_view path) {
-  const std::filesystem::path fs_path{
-      std::string_view{path.data(), path.size()}};
-
-  return std::filesystem::create_directories(fs_path);
-}
-
-std::vector<std::string> ListDirectory(absl::string_view path) {
-  std::vector<std::string> output_paths;
-
-  const std::filesystem::path fs_path{
-      std::string_view{path.data(), path.size()}};
-  if (!std::filesystem::is_directory(fs_path)) return output_paths;
-  for (const auto& entry : std::filesystem::directory_iterator(fs_path)) {
-    output_paths.push_back(entry.path().string());
-  }
-  return output_paths;
-}
-
-std::vector<std::string> ListDirectoryRecursively(absl::string_view path) {
-  std::vector<std::string> output_paths;
-
-  const std::filesystem::path fs_path{
-      std::string_view{path.data(), path.size()}};
-  for (const auto& entry :
-       std::filesystem::recursive_directory_iterator(fs_path)) {
-    output_paths.push_back(entry.path().string());
-  }
-  return output_paths;
-}
-
-#endif  // FUZZTEST_STUB_FILESYSTEM
-
 std::string WriteDataToDir(absl::string_view data, absl::string_view outdir) {
   std::string filename(outdir);
   if (filename.back() != '/') filename += '/';
@@ -157,21 +97,35 @@
   return filename;
 }
 
+std::optional<std::string> ReadFile(absl::string_view file) {
+  std::filesystem::path file_path{std::string_view{file.data(), file.size()}};
+  if (!std::filesystem::is_regular_file(file_path)) return std::nullopt;
+  std::ifstream stream(file_path);
+  if (!stream.good()) {
+    absl::FPrintF(stderr, "%s:%d: Error reading %s: (%d) %s\n", __FILE__,
+                  __LINE__, file, errno, strerror(errno));
+    return std::nullopt;
+  }
+  std::stringstream buffer;
+  buffer << stream.rdbuf();
+  return buffer.str();
+}
+
 std::vector<FilePathAndData> ReadFileOrDirectory(
     absl::string_view file_or_dir) {
   std::vector<FilePathAndData> out;
-
   const auto try_append_file = [&](std::string path) {
-    std::optional<std::string> contents = ReadFile(path);
-    if (contents.has_value()) {
-      out.push_back(FilePathAndData{std::move(path), *std::move(contents)});
+    std::optional<std::string> data = ReadFile(path);
+    if (data.has_value()) {
+      out.push_back(FilePathAndData{std::move(path), *std::move(data)});
     }
   };
-  if (IsDirectory(file_or_dir)) {
-    for (const auto& path : ListDirectoryRecursively(file_or_dir)) {
-      if (!IsDirectory(path)) {
-        try_append_file(path);
-      }
+  std::filesystem::path file_or_dir_path{
+      std::string_view{file_or_dir.data(), file_or_dir.size()}};
+  if (std::filesystem::is_directory(file_or_dir_path)) {
+    for (const auto& entry :
+         std::filesystem::recursive_directory_iterator(file_or_dir_path)) {
+      try_append_file(entry.path().string());
     }
   } else {
     try_append_file(std::string(file_or_dir));
@@ -179,6 +133,18 @@
   return out;
 }
 
+std::vector<std::string> ListDirectory(absl::string_view dir) {
+  std::vector<std::string> out;
+  std::filesystem::path dir_path{std::string_view{dir.data(), dir.size()}};
+  if (!std::filesystem::is_directory(dir_path)) return out;
+  for (const auto& entry : std::filesystem::directory_iterator(dir_path)) {
+    out.push_back(entry.path().string());
+  }
+  return out;
+}
+
+#endif  // defined(STUB_FILESYSTEM)
+
 absl::string_view Basename(absl::string_view filename) {
   auto last_slash_pos = filename.find_last_of("/\\");
 
diff --git a/fuzztest/internal/io.h b/fuzztest/internal/io.h
index 3481224..b2f4d9e 100644
--- a/fuzztest/internal/io.h
+++ b/fuzztest/internal/io.h
@@ -23,42 +23,30 @@
 
 namespace fuzztest::internal {
 
-// Writes `contents` to the file at `path`.  Returns true on success, false
-// otherwise.
-bool WriteFile(absl::string_view path, absl::string_view contents);
-
-// Returns the contents of the file at `path` or std::nullopt on failure.
-std::optional<std::string> ReadFile(absl::string_view path);
-
-// Returns true if `path` is a directory, false otherwise.
-bool IsDirectory(absl::string_view path);
-
-// Creates directory at `path`, *recursively* creating parent directories if
-// necessary. Returns true on success, false otherwise.
-bool CreateDirectory(absl::string_view path);
-
-// Returns a list of top-level paths under `path`. If `path` is not a directory,
-// returns an empty list.
-std::vector<std::string> ListDirectory(absl::string_view path);
-
-// Returns all paths under `path` *recursively*. If `path` is not a directory,
-// returns an empty list.
-std::vector<std::string> ListDirectoryRecursively(absl::string_view path);
+bool WriteFile(absl::string_view filename, absl::string_view contents);
 
 // Write `data` to its hash-based filename in `dir`. Returns the `dir`-appended
 // path to the file.
 std::string WriteDataToDir(absl::string_view data, absl::string_view dir);
 
+// Reads `file` and returns its content. If `file` is not a regular file or
+// reading it fails, returns `std::nullopt`.
+std::optional<std::string> ReadFile(absl::string_view file);
+
 struct FilePathAndData {
   std::string path;
   std::string data;
 };
 
 // If `file_or_dir` is a directory, returns a list of its files' paths and
-// contents *recursively*. If `file_or_dir` is a file, returns a singleton list
-// with its path and content. In all other cases, returns an empty list.
+// contents. If `file_or_dir` is a file, returns a singleton list with its path
+// and content. In all other cases, returns an empty list.
 std::vector<FilePathAndData> ReadFileOrDirectory(absl::string_view file_or_dir);
 
+// Returns a list of top-level paths in `dir`. If `dir` is not a directory,
+// returns an empty list.
+std::vector<std::string> ListDirectory(absl::string_view dir);
+
 // Returns the basename of `filename`.
 absl::string_view Basename(absl::string_view filename);