No public description
PiperOrigin-RevId: 604846219
diff --git a/centipede/BUILD b/centipede/BUILD
index 2aa9c97..153477c 100644
--- a/centipede/BUILD
+++ b/centipede/BUILD
@@ -616,6 +616,7 @@
":disable_riegeli": ["CENTIPEDE_DISABLE_RIEGELI"],
"//conditions:default": [],
}),
+ visibility = EXTENDED_API_VISIBILITY,
deps = [
":defs",
":logging",
diff --git a/centipede/remote_file.cc b/centipede/remote_file.cc
index 48015a7..e2a7c68 100644
--- a/centipede/remote_file.cc
+++ b/centipede/remote_file.cc
@@ -139,6 +139,10 @@
return std::filesystem::exists(path);
}
+ABSL_ATTRIBUTE_WEAK bool RemotePathIsDirectory(std::string_view path) {
+ return std::filesystem::is_directory(path);
+}
+
ABSL_ATTRIBUTE_WEAK int64_t RemoteFileGetSize(std::string_view path) {
FILE *f = std::fopen(path.data(), "r");
CHECK(f != nullptr) << VV(path);
@@ -171,6 +175,16 @@
::globfree(&glob_ret);
}
+ABSL_ATTRIBUTE_WEAK std::vector<std::string> RemoteListDirectory(
+ std::string_view path) {
+ if (!std::filesystem::is_directory(path)) return {};
+ std::vector<std::string> ret;
+ for (const auto &entry : std::filesystem::directory_iterator(path)) {
+ ret.push_back(entry.path());
+ }
+ return ret;
+}
+
ABSL_ATTRIBUTE_WEAK std::vector<std::string> RemoteListFilesRecursively(
std::string_view path) {
if (!std::filesystem::exists(path)) return {};
diff --git a/centipede/remote_file.h b/centipede/remote_file.h
index 19ca891..3d0ae64 100644
--- a/centipede/remote_file.h
+++ b/centipede/remote_file.h
@@ -76,12 +76,19 @@
// Returns true if `path` exists.
bool RemotePathExists(std::string_view path);
+// Returns true if `path` is a directory.
+bool RemotePathIsDirectory(std::string_view path);
+
// Returns the size of the file at `path` in bytes. The file must exist.
int64_t RemoteFileGetSize(std::string_view path);
// Finds all files matching `glob` and appends them to `matches`.
void RemoteGlobMatch(std::string_view glob, std::vector<std::string> &matches);
+// Returns a list of top-level paths under `path`. If `path` is not a directory,
+// or it's an empty directory, returns an empty list.
+std::vector<std::string> RemoteListDirectory(std::string_view path);
+
// Recursively lists all files within `path`. Does not return any directories.
// Returns an empty vector if `path` is an empty directory, or `path` does not
// exist. Returns `{path}` if `path` is a non-directory.
diff --git a/fuzztest/BUILD b/fuzztest/BUILD
index e21c923..2871676 100644
--- a/fuzztest/BUILD
+++ b/fuzztest/BUILD
@@ -407,6 +407,7 @@
"@com_google_absl//absl/hash",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/strings:string_view",
+ "@com_google_fuzztest//centipede:remote_file",
],
)
diff --git a/fuzztest/internal/io.cc b/fuzztest/internal/io.cc
index 3658908..eedd8df 100644
--- a/fuzztest/internal/io.cc
+++ b/fuzztest/internal/io.cc
@@ -14,11 +14,6 @@
#include "./fuzztest/internal/io.h"
-#include <cerrno>
-#include <cstdio>
-#include <cstring>
-#include <filesystem>
-#include <fstream>
#include <optional>
#include <sstream>
#include <string>
@@ -30,6 +25,7 @@
#include "absl/hash/hash.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
+#include "./centipede/remote_file.h"
#include "./fuzztest/internal/logging.h"
#if defined(__APPLE__)
@@ -39,55 +35,81 @@
__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_13_0)
// std::filesystem requires macOS 10.15+ or iOS 13+.
// Just stub out these functions.
-#define STUB_FILESYSTEM
+#define FUZZTEST_STUB_FILESYSTEM
#endif
#endif
namespace fuzztest::internal {
-#if defined(STUB_FILESYSTEM)
+#if defined(FUZZTEST_STUB_FILESYSTEM)
-bool WriteFile(absl::string_view filename, absl::string_view contents) {
- FUZZTEST_INTERNAL_CHECK(false, "Can't replay in iOS/MacOS");
+bool WriteFile(absl::string_view path, absl::string_view contents) {
+ 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");
+std::optional<std::string> ReadFile(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 IsDirectory(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");
+bool CreateDirectory(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> ListDirectory(absl::string_view path) {
+ FUZZTEST_INTERNAL_CHECK(false, "Filesystem API not supported in iOS/MacOS");
}
-#else // defined(__APPLE__)
+std::vector<std::string> ListDirectoryRecursively(absl::string_view path) {
+ FUZZTEST_INTERNAL_CHECK(false, "Filesystem API not supported in iOS/MacOS");
+}
-bool WriteFile(absl::string_view filename, absl::string_view contents) {
- std::filesystem::path file_path{
- std::string_view{filename.data(), filename.size()}};
+#else // FUZZTEST_STUB_FILESYSTEM
+bool WriteFile(absl::string_view path, absl::string_view contents) {
// Just in case the directory does not currently exist.
- // If it does, this is a noop.
- std::filesystem::create_directories(file_path.parent_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__, filename, errno, strerror(errno));
+ if (!CreateDirectory(Dirname(path))) {
+ absl::FPrintF(GetStderr(), "[!] %s:%d: Couldn't create directory: %s\n",
+ __FILE__, __LINE__, path);
+ return false;
}
- return !file.fail();
+ centipede::RemoteFileSetContents(path, std::string(contents));
+ return true;
}
+std::optional<std::string> ReadFile(absl::string_view path) {
+ std::string contents;
+ if (!centipede::RemotePathExists(path)) {
+ absl::FPrintF(GetStderr(), "[!] %s:%d: File doesn't exist: %s\n", __FILE__,
+ __LINE__, path);
+ return std::nullopt;
+ }
+ centipede::RemoteFileGetContents(path, contents);
+ return contents;
+}
+
+bool IsDirectory(absl::string_view path) {
+ return centipede::RemotePathIsDirectory(path);
+}
+
+bool CreateDirectory(absl::string_view path) {
+ centipede::RemoteMkdir(path);
+ return true;
+}
+
+std::vector<std::string> ListDirectory(absl::string_view path) {
+ return centipede::RemoteListDirectory(path);
+}
+
+std::vector<std::string> ListDirectoryRecursively(absl::string_view path) {
+ return centipede::RemoteListFilesRecursively(path);
+}
+
+#endif // FUZZTEST_STUB_FILESYSTEM
+
std::string WriteDataToDir(absl::string_view data, absl::string_view outdir) {
std::string filename(outdir);
if (filename.back() != '/') filename += '/';
@@ -97,35 +119,21 @@
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> data = ReadFile(path);
- if (data.has_value()) {
- out.push_back(FilePathAndData{std::move(path), *std::move(data)});
+ std::optional<std::string> contents = ReadFile(path);
+ if (contents.has_value()) {
+ out.push_back(FilePathAndData{std::move(path), *std::move(contents)});
}
};
- 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());
+ if (IsDirectory(file_or_dir)) {
+ for (const auto& path : ListDirectoryRecursively(file_or_dir)) {
+ if (!IsDirectory(path)) {
+ try_append_file(path);
+ }
}
} else {
try_append_file(std::string(file_or_dir));
@@ -133,17 +141,13 @@
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;
-}
+absl::string_view Dirname(absl::string_view filename) {
+ auto last_slash_pos = filename.find_last_of("/\\");
-#endif // defined(STUB_FILESYSTEM)
+ return last_slash_pos == absl::string_view::npos
+ ? filename
+ : filename.substr(0, last_slash_pos);
+}
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 b2f4d9e..9ff7394 100644
--- a/fuzztest/internal/io.h
+++ b/fuzztest/internal/io.h
@@ -23,38 +23,53 @@
namespace fuzztest::internal {
-bool WriteFile(absl::string_view filename, absl::string_view contents);
+// 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,
+// or it's an empty 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);
// 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. 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 *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.
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);
-
// Reads files as strings from the directory `dir` and returns a vector usable
// by .WithSeeds().
std::vector<std::tuple<std::string>> ReadFilesFromDirectory(
absl::string_view dir);
+// Returns the dirname of `filename`.
+absl::string_view Dirname(absl::string_view filename);
+
+// Returns the basename of `filename`.
+absl::string_view Basename(absl::string_view filename);
+
} // namespace fuzztest::internal
#endif // FUZZTEST_FUZZTEST_INTERNAL_IO_H_