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);