#include #include #include #if !defined(_WIN32) #include #include #else // defined(_WIN32) #include #include #include #include #endif // defined(_WIN32) // Creates the filename pattern passed to and completed by `mkstemp`. #if !defined(_WIN32) static std::string make_filename(std::string_view name_prefix) { // The filename argument to `mkstemp` needs "XXXXXX" at the end according to // http://pubs.opengroup.org/onlinepubs/009695399/functions/mkstemp.html constexpr const char* kRandomPattern = "XXXXXX"; // We see if any of these environment variables is set and use their value, or // else default the temporary directory to `/tmp`. const char* tmp_directory = "/tmp"; for (const char* variable : {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}) { if (const char* path = getenv(variable)) { tmp_directory = path; break; } } return fmt::format("{}/{}{}", tmp_directory, name_prefix, kRandomPattern); } #else static std::string make_filename() { char name[L_tmpnam_s]{}; auto res = tmpnam_s(name, L_tmpnam_s); if (res != 0) { TORCH_WARN("Error generating temporary file"); return ""; } return name; } #endif // !defined(_WIN32) namespace c10 { /// Attempts to return a temporary file or returns `nullopt` if an error /// occurred. std::optional try_make_tempfile(std::string_view name_prefix) { #if defined(_WIN32) auto filename = make_filename(); #else auto filename = make_filename(name_prefix); #endif if (filename.empty()) { return std::nullopt; } #if defined(_WIN32) return TempFile(std::move(filename)); #else const int fd = mkstemp(filename.data()); if (fd == -1) { return std::nullopt; } return TempFile(std::move(filename), fd); #endif // defined(_WIN32) } /// Like `try_make_tempfile`, but throws an exception if a temporary file could /// not be returned. TempFile make_tempfile(std::string_view name_prefix) { if (auto tempfile = try_make_tempfile(name_prefix)) { return std::move(*tempfile); } TORCH_CHECK(false, "Error generating temporary file: ", std::strerror(errno)); } /// Attempts to return a temporary directory or returns `nullopt` if an error /// occurred. std::optional try_make_tempdir(std::string_view name_prefix) { #if defined(_WIN32) for (int i = 0; i < 10; i++) { auto dirname = make_filename(); if (dirname.empty()) { return std::nullopt; } if (CreateDirectoryA(dirname.c_str(), nullptr)) { return TempDir(dirname); } if (GetLastError() == ERROR_SUCCESS) { return std::nullopt; } } return std::nullopt; #else auto filename = make_filename(name_prefix); const char* dirname = mkdtemp(filename.data()); if (!dirname) { return std::nullopt; } return TempDir(dirname); #endif // defined(_WIN32) } #if defined(_WIN32) bool TempFile::open() { if (fd != -1) { return false; } auto err = _sopen_s( &fd, name.c_str(), _O_CREAT | _O_TEMPORARY | _O_EXCL | _O_BINARY | _O_RDWR, _SH_DENYNO, _S_IREAD | _S_IWRITE); if (err != 0) { fd = -1; return false; } return true; } #endif TempFile::~TempFile() { if (!name.empty()) { #if !defined(_WIN32) if (fd >= 0) { unlink(name.c_str()); close(fd); } #else if (fd >= 0) { _close(fd); } #endif } } TempDir::~TempDir() { if (!name.empty()) { #if !defined(_WIN32) rmdir(name.c_str()); #else // defined(_WIN32) RemoveDirectoryA(name.c_str()); #endif // defined(_WIN32) } } /// Like `try_make_tempdir`, but throws an exception if a temporary directory /// could not be returned. TempDir make_tempdir(std::string_view name_prefix) { if (auto tempdir = try_make_tempdir(name_prefix)) { return std::move(*tempdir); } #if !defined(_WIN32) TORCH_CHECK( false, "Error generating temporary directory: ", std::strerror(errno)); #else // defined(_WIN32) TORCH_CHECK(false, "Error generating temporary directory"); #endif // defined(_WIN32) } } // namespace c10