/* unittest_util.h * Copyright 2022 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Utility functions for unit tests. */ #include #include #include #include #include #include "util.h" namespace { constexpr bool is_android_constexpr() { #if defined(__ANDROID__) return true; #else return false; #endif } // Returns a template path that can be used as an argument to mkstemp / mkdtemp. constexpr const char* temp_path_pattern() { if (is_android_constexpr()) return "/data/local/tmp/minijail.tests.XXXXXX"; else return "minijail.tests.XXXXXX"; } // Recursively deletes the subtree rooted at |path|. bool rmdir_recursive(const std::string& path) { auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int { if (file_type == FTW_DP) { if (rmdir(child) == -1) { fprintf(stderr, "rmdir(%s): %s\n", child, strerror(errno)); return -1; } } else if (file_type == FTW_F) { if (unlink(child) == -1) { fprintf(stderr, "unlink(%s): %s\n", child, strerror(errno)); return -1; } } return 0; }; return nftw(path.c_str(), callback, 128, FTW_DEPTH) == 0; } } // namespace // Creates a temporary directory that will be cleaned up upon leaving scope. class TemporaryDir { public: TemporaryDir() : path(temp_path_pattern()) { if (mkdtemp(const_cast(path.c_str())) == nullptr) path.clear(); } ~TemporaryDir() { if (!is_valid()) return; rmdir_recursive(path.c_str()); } bool is_valid() const { return !path.empty(); } std::string path; private: TemporaryDir(const TemporaryDir&) = delete; TemporaryDir& operator=(const TemporaryDir&) = delete; }; // Creates a named temporary file that will be cleaned up upon leaving scope. class TemporaryFile { public: TemporaryFile() : path(temp_path_pattern()) { int fd = mkstemp(const_cast(path.c_str())); if (fd == -1) { path.clear(); return; } close(fd); } ~TemporaryFile() { if (!is_valid()) return; unlink(path.c_str()); } bool is_valid() const { return !path.empty(); } std::string path; private: TemporaryFile(const TemporaryFile&) = delete; TemporaryFile& operator=(const TemporaryFile&) = delete; };