/* Copyright (c) 2023, Google Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef OPENSSL_HEADER_CRYPTO_TEST_FILE_UTIL_H #define OPENSSL_HEADER_CRYPTO_TEST_FILE_UTIL_H #include #include #include #include #include #include #if defined(OPENSSL_WINDOWS) #include #else #include #endif BSSL_NAMESPACE_BEGIN struct FileDeleter { void operator()(FILE *f) const { if (f != nullptr) { fclose(f); } } }; using ScopedFILE = std::unique_ptr; class ScopedFD { public: ScopedFD() = default; explicit ScopedFD(int fd) : fd_(fd) {} ~ScopedFD() { reset(); } ScopedFD(ScopedFD &&other) { *this = std::move(other); } ScopedFD &operator=(ScopedFD other) { reset(other.release()); return *this; } bool is_valid() const { return fd_ >= 0; } int get() const { return fd_; } int release() { return std::exchange(fd_, -1); } void reset(int fd = -1) { if (is_valid()) { #if defined(OPENSSL_WINDOWS) _close(fd_); #else close(fd_); #endif } fd_ = fd; } private: int fd_ = -1; }; // SkipTempFileTests returns true and prints a warning if tests involving // temporary files should be skipped because of platform issues. bool SkipTempFileTests(); // TemporaryFile manages a temporary file for testing. class TemporaryFile { public: TemporaryFile() = default; ~TemporaryFile(); TemporaryFile(TemporaryFile &other) { *this = std::move(other); } TemporaryFile& operator=(TemporaryFile&&other) { // Ensure |path_| is empty so it doesn't try to delete the File. path_ = std::exchange(other.path_, {}); return *this; } // Init initializes the temporary file with the specified content. It returns // true on success and false on error. On error, callers should call // |IgnoreTempFileErrors| to determine whether to ignore the error. bool Init(bssl::Span content = {}); bool Init(const std::string &content) { return Init(bssl::MakeConstSpan( reinterpret_cast(content.data()), content.size())); } // Open opens the file as a |FILE| with the specified mode. ScopedFILE Open(const char *mode) const; // Open opens the file as a file descriptor with the specified flags. ScopedFD OpenFD(int flags) const; // path returns the path to the temporary file. const std::string &path() const { return path_; } private: std::string path_; }; // TemporaryDirectory manages a temporary directory for testing. class TemporaryDirectory { public: TemporaryDirectory() = default; ~TemporaryDirectory(); TemporaryDirectory(TemporaryDirectory &other) { *this = std::move(other); } TemporaryDirectory& operator=(TemporaryDirectory&&other) { // Ensure |other_| is empty so it doesn't try to delete the directory. path_ = std::exchange(other.path_, {}); files_ = std::exchange(other.files_, {}); return *this; } // Init initializes the temporary directory. It returns true on success and // false on error. On error, callers should call |IgnoreTempFileErrors| to // determine whether to ignore the error. bool Init(); // path returns the path to the temporary directory. const std::string &path() const { return path_; } // AddFile adds a file to the temporary directory with the specified content. // It returns true on success and false on error. Subdirectories in the // temporary directory are not currently supported. bool AddFile(const std::string &filename, bssl::Span content); bool AddFile(const std::string &filename, const std::string &content) { return AddFile( filename, bssl::MakeConstSpan(reinterpret_cast(content.data()), content.size())); } // GetFilePath returns the path to the speciifed file within the temporary // directory. std::string GetFilePath(const std::string &filename) { #if defined(OPENSSL_WINDOWS) return path_ + '\\' + filename; #else return path_ + '/' + filename; #endif } private: std::string path_; std::set files_; }; BSSL_NAMESPACE_END #endif // OPENSSL_HEADER_CRYPTO_TEST_FILE_UTIL_H