xref: /aosp_15_r20/external/pytorch/c10/util/tempfile.cpp (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker #include <c10/util/Exception.h>
2*da0073e9SAndroid Build Coastguard Worker #include <c10/util/tempfile.h>
3*da0073e9SAndroid Build Coastguard Worker #include <fmt/format.h>
4*da0073e9SAndroid Build Coastguard Worker 
5*da0073e9SAndroid Build Coastguard Worker #if !defined(_WIN32)
6*da0073e9SAndroid Build Coastguard Worker #include <unistd.h>
7*da0073e9SAndroid Build Coastguard Worker #include <cerrno>
8*da0073e9SAndroid Build Coastguard Worker #else // defined(_WIN32)
9*da0073e9SAndroid Build Coastguard Worker #include <Windows.h>
10*da0073e9SAndroid Build Coastguard Worker #include <fcntl.h>
11*da0073e9SAndroid Build Coastguard Worker #include <fileapi.h>
12*da0073e9SAndroid Build Coastguard Worker #include <io.h>
13*da0073e9SAndroid Build Coastguard Worker #endif // defined(_WIN32)
14*da0073e9SAndroid Build Coastguard Worker 
15*da0073e9SAndroid Build Coastguard Worker // Creates the filename pattern passed to and completed by `mkstemp`.
16*da0073e9SAndroid Build Coastguard Worker #if !defined(_WIN32)
make_filename(std::string_view name_prefix)17*da0073e9SAndroid Build Coastguard Worker static std::string make_filename(std::string_view name_prefix) {
18*da0073e9SAndroid Build Coastguard Worker   // The filename argument to `mkstemp` needs "XXXXXX" at the end according to
19*da0073e9SAndroid Build Coastguard Worker   // http://pubs.opengroup.org/onlinepubs/009695399/functions/mkstemp.html
20*da0073e9SAndroid Build Coastguard Worker   constexpr const char* kRandomPattern = "XXXXXX";
21*da0073e9SAndroid Build Coastguard Worker 
22*da0073e9SAndroid Build Coastguard Worker   // We see if any of these environment variables is set and use their value, or
23*da0073e9SAndroid Build Coastguard Worker   // else default the temporary directory to `/tmp`.
24*da0073e9SAndroid Build Coastguard Worker 
25*da0073e9SAndroid Build Coastguard Worker   const char* tmp_directory = "/tmp";
26*da0073e9SAndroid Build Coastguard Worker   for (const char* variable : {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}) {
27*da0073e9SAndroid Build Coastguard Worker     if (const char* path = getenv(variable)) {
28*da0073e9SAndroid Build Coastguard Worker       tmp_directory = path;
29*da0073e9SAndroid Build Coastguard Worker       break;
30*da0073e9SAndroid Build Coastguard Worker     }
31*da0073e9SAndroid Build Coastguard Worker   }
32*da0073e9SAndroid Build Coastguard Worker   return fmt::format("{}/{}{}", tmp_directory, name_prefix, kRandomPattern);
33*da0073e9SAndroid Build Coastguard Worker }
34*da0073e9SAndroid Build Coastguard Worker #else
make_filename()35*da0073e9SAndroid Build Coastguard Worker static std::string make_filename() {
36*da0073e9SAndroid Build Coastguard Worker   char name[L_tmpnam_s]{};
37*da0073e9SAndroid Build Coastguard Worker   auto res = tmpnam_s(name, L_tmpnam_s);
38*da0073e9SAndroid Build Coastguard Worker   if (res != 0) {
39*da0073e9SAndroid Build Coastguard Worker     TORCH_WARN("Error generating temporary file");
40*da0073e9SAndroid Build Coastguard Worker     return "";
41*da0073e9SAndroid Build Coastguard Worker   }
42*da0073e9SAndroid Build Coastguard Worker   return name;
43*da0073e9SAndroid Build Coastguard Worker }
44*da0073e9SAndroid Build Coastguard Worker #endif // !defined(_WIN32)
45*da0073e9SAndroid Build Coastguard Worker 
46*da0073e9SAndroid Build Coastguard Worker namespace c10 {
47*da0073e9SAndroid Build Coastguard Worker /// Attempts to return a temporary file or returns `nullopt` if an error
48*da0073e9SAndroid Build Coastguard Worker /// occurred.
try_make_tempfile(std::string_view name_prefix)49*da0073e9SAndroid Build Coastguard Worker std::optional<TempFile> try_make_tempfile(std::string_view name_prefix) {
50*da0073e9SAndroid Build Coastguard Worker #if defined(_WIN32)
51*da0073e9SAndroid Build Coastguard Worker   auto filename = make_filename();
52*da0073e9SAndroid Build Coastguard Worker #else
53*da0073e9SAndroid Build Coastguard Worker   auto filename = make_filename(name_prefix);
54*da0073e9SAndroid Build Coastguard Worker #endif
55*da0073e9SAndroid Build Coastguard Worker   if (filename.empty()) {
56*da0073e9SAndroid Build Coastguard Worker     return std::nullopt;
57*da0073e9SAndroid Build Coastguard Worker   }
58*da0073e9SAndroid Build Coastguard Worker #if defined(_WIN32)
59*da0073e9SAndroid Build Coastguard Worker   return TempFile(std::move(filename));
60*da0073e9SAndroid Build Coastguard Worker #else
61*da0073e9SAndroid Build Coastguard Worker   const int fd = mkstemp(filename.data());
62*da0073e9SAndroid Build Coastguard Worker   if (fd == -1) {
63*da0073e9SAndroid Build Coastguard Worker     return std::nullopt;
64*da0073e9SAndroid Build Coastguard Worker   }
65*da0073e9SAndroid Build Coastguard Worker   return TempFile(std::move(filename), fd);
66*da0073e9SAndroid Build Coastguard Worker #endif // defined(_WIN32)
67*da0073e9SAndroid Build Coastguard Worker }
68*da0073e9SAndroid Build Coastguard Worker 
69*da0073e9SAndroid Build Coastguard Worker /// Like `try_make_tempfile`, but throws an exception if a temporary file could
70*da0073e9SAndroid Build Coastguard Worker /// not be returned.
make_tempfile(std::string_view name_prefix)71*da0073e9SAndroid Build Coastguard Worker TempFile make_tempfile(std::string_view name_prefix) {
72*da0073e9SAndroid Build Coastguard Worker   if (auto tempfile = try_make_tempfile(name_prefix)) {
73*da0073e9SAndroid Build Coastguard Worker     return std::move(*tempfile);
74*da0073e9SAndroid Build Coastguard Worker   }
75*da0073e9SAndroid Build Coastguard Worker   TORCH_CHECK(false, "Error generating temporary file: ", std::strerror(errno));
76*da0073e9SAndroid Build Coastguard Worker }
77*da0073e9SAndroid Build Coastguard Worker 
78*da0073e9SAndroid Build Coastguard Worker /// Attempts to return a temporary directory or returns `nullopt` if an error
79*da0073e9SAndroid Build Coastguard Worker /// occurred.
try_make_tempdir(std::string_view name_prefix)80*da0073e9SAndroid Build Coastguard Worker std::optional<TempDir> try_make_tempdir(std::string_view name_prefix) {
81*da0073e9SAndroid Build Coastguard Worker #if defined(_WIN32)
82*da0073e9SAndroid Build Coastguard Worker   for (int i = 0; i < 10; i++) {
83*da0073e9SAndroid Build Coastguard Worker     auto dirname = make_filename();
84*da0073e9SAndroid Build Coastguard Worker     if (dirname.empty()) {
85*da0073e9SAndroid Build Coastguard Worker       return std::nullopt;
86*da0073e9SAndroid Build Coastguard Worker     }
87*da0073e9SAndroid Build Coastguard Worker     if (CreateDirectoryA(dirname.c_str(), nullptr)) {
88*da0073e9SAndroid Build Coastguard Worker       return TempDir(dirname);
89*da0073e9SAndroid Build Coastguard Worker     }
90*da0073e9SAndroid Build Coastguard Worker     if (GetLastError() == ERROR_SUCCESS) {
91*da0073e9SAndroid Build Coastguard Worker       return std::nullopt;
92*da0073e9SAndroid Build Coastguard Worker     }
93*da0073e9SAndroid Build Coastguard Worker   }
94*da0073e9SAndroid Build Coastguard Worker   return std::nullopt;
95*da0073e9SAndroid Build Coastguard Worker #else
96*da0073e9SAndroid Build Coastguard Worker   auto filename = make_filename(name_prefix);
97*da0073e9SAndroid Build Coastguard Worker   const char* dirname = mkdtemp(filename.data());
98*da0073e9SAndroid Build Coastguard Worker   if (!dirname) {
99*da0073e9SAndroid Build Coastguard Worker     return std::nullopt;
100*da0073e9SAndroid Build Coastguard Worker   }
101*da0073e9SAndroid Build Coastguard Worker   return TempDir(dirname);
102*da0073e9SAndroid Build Coastguard Worker #endif // defined(_WIN32)
103*da0073e9SAndroid Build Coastguard Worker }
104*da0073e9SAndroid Build Coastguard Worker 
105*da0073e9SAndroid Build Coastguard Worker #if defined(_WIN32)
open()106*da0073e9SAndroid Build Coastguard Worker bool TempFile::open() {
107*da0073e9SAndroid Build Coastguard Worker   if (fd != -1) {
108*da0073e9SAndroid Build Coastguard Worker     return false;
109*da0073e9SAndroid Build Coastguard Worker   }
110*da0073e9SAndroid Build Coastguard Worker   auto err = _sopen_s(
111*da0073e9SAndroid Build Coastguard Worker       &fd,
112*da0073e9SAndroid Build Coastguard Worker       name.c_str(),
113*da0073e9SAndroid Build Coastguard Worker       _O_CREAT | _O_TEMPORARY | _O_EXCL | _O_BINARY | _O_RDWR,
114*da0073e9SAndroid Build Coastguard Worker       _SH_DENYNO,
115*da0073e9SAndroid Build Coastguard Worker       _S_IREAD | _S_IWRITE);
116*da0073e9SAndroid Build Coastguard Worker   if (err != 0) {
117*da0073e9SAndroid Build Coastguard Worker     fd = -1;
118*da0073e9SAndroid Build Coastguard Worker     return false;
119*da0073e9SAndroid Build Coastguard Worker   }
120*da0073e9SAndroid Build Coastguard Worker   return true;
121*da0073e9SAndroid Build Coastguard Worker }
122*da0073e9SAndroid Build Coastguard Worker #endif
123*da0073e9SAndroid Build Coastguard Worker 
~TempFile()124*da0073e9SAndroid Build Coastguard Worker TempFile::~TempFile() {
125*da0073e9SAndroid Build Coastguard Worker   if (!name.empty()) {
126*da0073e9SAndroid Build Coastguard Worker #if !defined(_WIN32)
127*da0073e9SAndroid Build Coastguard Worker     if (fd >= 0) {
128*da0073e9SAndroid Build Coastguard Worker       unlink(name.c_str());
129*da0073e9SAndroid Build Coastguard Worker       close(fd);
130*da0073e9SAndroid Build Coastguard Worker     }
131*da0073e9SAndroid Build Coastguard Worker #else
132*da0073e9SAndroid Build Coastguard Worker     if (fd >= 0) {
133*da0073e9SAndroid Build Coastguard Worker       _close(fd);
134*da0073e9SAndroid Build Coastguard Worker     }
135*da0073e9SAndroid Build Coastguard Worker #endif
136*da0073e9SAndroid Build Coastguard Worker   }
137*da0073e9SAndroid Build Coastguard Worker }
138*da0073e9SAndroid Build Coastguard Worker 
~TempDir()139*da0073e9SAndroid Build Coastguard Worker TempDir::~TempDir() {
140*da0073e9SAndroid Build Coastguard Worker   if (!name.empty()) {
141*da0073e9SAndroid Build Coastguard Worker #if !defined(_WIN32)
142*da0073e9SAndroid Build Coastguard Worker     rmdir(name.c_str());
143*da0073e9SAndroid Build Coastguard Worker #else // defined(_WIN32)
144*da0073e9SAndroid Build Coastguard Worker     RemoveDirectoryA(name.c_str());
145*da0073e9SAndroid Build Coastguard Worker #endif // defined(_WIN32)
146*da0073e9SAndroid Build Coastguard Worker   }
147*da0073e9SAndroid Build Coastguard Worker }
148*da0073e9SAndroid Build Coastguard Worker 
149*da0073e9SAndroid Build Coastguard Worker /// Like `try_make_tempdir`, but throws an exception if a temporary directory
150*da0073e9SAndroid Build Coastguard Worker /// could not be returned.
make_tempdir(std::string_view name_prefix)151*da0073e9SAndroid Build Coastguard Worker TempDir make_tempdir(std::string_view name_prefix) {
152*da0073e9SAndroid Build Coastguard Worker   if (auto tempdir = try_make_tempdir(name_prefix)) {
153*da0073e9SAndroid Build Coastguard Worker     return std::move(*tempdir);
154*da0073e9SAndroid Build Coastguard Worker   }
155*da0073e9SAndroid Build Coastguard Worker #if !defined(_WIN32)
156*da0073e9SAndroid Build Coastguard Worker   TORCH_CHECK(
157*da0073e9SAndroid Build Coastguard Worker       false, "Error generating temporary directory: ", std::strerror(errno));
158*da0073e9SAndroid Build Coastguard Worker #else // defined(_WIN32)
159*da0073e9SAndroid Build Coastguard Worker   TORCH_CHECK(false, "Error generating temporary directory");
160*da0073e9SAndroid Build Coastguard Worker #endif // defined(_WIN32)
161*da0073e9SAndroid Build Coastguard Worker }
162*da0073e9SAndroid Build Coastguard Worker } // namespace c10
163