base: move TemporaryFile and TemporaryDir to android-base/file.h

Allow a wider legitimate audience to use TemporaryFile and
TemporaryDir by moving them from android-base/test_utils.h to
android-base/file.h.

Test: compile
Bug: 119313545
Change-Id: Ie558c5873ce5b3937914918b6bfb427e5b61d0da
diff --git a/file.cpp b/file.cpp
index 3834ed4..e4407d0 100644
--- a/file.cpp
+++ b/file.cpp
@@ -19,6 +19,8 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -37,10 +39,105 @@
 #include <mach-o/dyld.h>
 #endif
 #if defined(_WIN32)
+#include <direct.h>
 #include <windows.h>
 #define O_NOFOLLOW 0
+#define OS_PATH_SEPARATOR '\\'
+#else
+#define OS_PATH_SEPARATOR '/'
 #endif
 
+#ifdef _WIN32
+int mkstemp(char* template_name) {
+  if (_mktemp(template_name) == nullptr) {
+    return -1;
+  }
+  // Use open() to match the close() that TemporaryFile's destructor does.
+  // Use O_BINARY to match base file APIs.
+  return open(template_name, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
+}
+
+char* mkdtemp(char* template_name) {
+  if (_mktemp(template_name) == nullptr) {
+    return nullptr;
+  }
+  if (_mkdir(template_name) == -1) {
+    return nullptr;
+  }
+  return template_name;
+}
+#endif
+
+namespace {
+
+std::string GetSystemTempDir() {
+#if defined(__ANDROID__)
+  const char* tmpdir = "/data/local/tmp";
+  if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
+    return tmpdir;
+  }
+  // Tests running in app context can't access /data/local/tmp,
+  // so try current directory if /data/local/tmp is not accessible.
+  return ".";
+#elif defined(_WIN32)
+  char tmp_dir[MAX_PATH];
+  DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
+  CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
+  CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
+
+  // GetTempPath() returns a path with a trailing slash, but init()
+  // does not expect that, so remove it.
+  CHECK_EQ(tmp_dir[result - 1], '\\');
+  tmp_dir[result - 1] = '\0';
+  return tmp_dir;
+#else
+  return "/tmp";
+#endif
+}
+
+}  // namespace
+
+TemporaryFile::TemporaryFile() {
+  init(GetSystemTempDir());
+}
+
+TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
+  init(tmp_dir);
+}
+
+TemporaryFile::~TemporaryFile() {
+  if (fd != -1) {
+    close(fd);
+  }
+  if (remove_file_) {
+    unlink(path);
+  }
+}
+
+int TemporaryFile::release() {
+  int result = fd;
+  fd = -1;
+  return result;
+}
+
+void TemporaryFile::init(const std::string& tmp_dir) {
+  snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
+  fd = mkstemp(path);
+}
+
+TemporaryDir::TemporaryDir() {
+  init(GetSystemTempDir());
+}
+
+TemporaryDir::~TemporaryDir() {
+  rmdir(path);
+}
+
+bool TemporaryDir::init(const std::string& tmp_dir) {
+  snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
+  return (mkdtemp(path) != nullptr);
+}
+
 namespace android {
 namespace base {