1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker *
8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker *
10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker */
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/temp_file.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/build_config.h"
20*6dbdd20aSAndroid Build Coastguard Worker
21*6dbdd20aSAndroid Build Coastguard Worker #include <stdio.h>
22*6dbdd20aSAndroid Build Coastguard Worker #include <stdlib.h>
23*6dbdd20aSAndroid Build Coastguard Worker #include <string.h>
24*6dbdd20aSAndroid Build Coastguard Worker
25*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
26*6dbdd20aSAndroid Build Coastguard Worker #include <Windows.h>
27*6dbdd20aSAndroid Build Coastguard Worker #include <direct.h>
28*6dbdd20aSAndroid Build Coastguard Worker #include <fileapi.h>
29*6dbdd20aSAndroid Build Coastguard Worker #include <io.h>
30*6dbdd20aSAndroid Build Coastguard Worker #else
31*6dbdd20aSAndroid Build Coastguard Worker #include <unistd.h>
32*6dbdd20aSAndroid Build Coastguard Worker #endif
33*6dbdd20aSAndroid Build Coastguard Worker
34*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
35*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/file_utils.h"
36*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
37*6dbdd20aSAndroid Build Coastguard Worker
38*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
39*6dbdd20aSAndroid Build Coastguard Worker namespace base {
40*6dbdd20aSAndroid Build Coastguard Worker
41*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
42*6dbdd20aSAndroid Build Coastguard Worker namespace {
GetTempFilePathWin()43*6dbdd20aSAndroid Build Coastguard Worker std::string GetTempFilePathWin() {
44*6dbdd20aSAndroid Build Coastguard Worker std::string tmplt = GetSysTempDir() + "\\perfetto-XXXXXX";
45*6dbdd20aSAndroid Build Coastguard Worker StackString<255> name("%s\\perfetto-XXXXXX", GetSysTempDir().c_str());
46*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(_mktemp_s(name.mutable_data(), name.len() + 1) == 0);
47*6dbdd20aSAndroid Build Coastguard Worker return name.ToStdString();
48*6dbdd20aSAndroid Build Coastguard Worker }
49*6dbdd20aSAndroid Build Coastguard Worker } // namespace
50*6dbdd20aSAndroid Build Coastguard Worker #endif
51*6dbdd20aSAndroid Build Coastguard Worker
GetSysTempDir()52*6dbdd20aSAndroid Build Coastguard Worker std::string GetSysTempDir() {
53*6dbdd20aSAndroid Build Coastguard Worker const char* tmpdir = nullptr;
54*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
55*6dbdd20aSAndroid Build Coastguard Worker if ((tmpdir = getenv("TMP")))
56*6dbdd20aSAndroid Build Coastguard Worker return tmpdir;
57*6dbdd20aSAndroid Build Coastguard Worker if ((tmpdir = getenv("TEMP")))
58*6dbdd20aSAndroid Build Coastguard Worker return tmpdir;
59*6dbdd20aSAndroid Build Coastguard Worker return "C:\\TEMP";
60*6dbdd20aSAndroid Build Coastguard Worker #else
61*6dbdd20aSAndroid Build Coastguard Worker if ((tmpdir = getenv("TMPDIR")))
62*6dbdd20aSAndroid Build Coastguard Worker return base::StripSuffix(tmpdir, "/");
63*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
64*6dbdd20aSAndroid Build Coastguard Worker return "/data/local/tmp";
65*6dbdd20aSAndroid Build Coastguard Worker #else
66*6dbdd20aSAndroid Build Coastguard Worker return "/tmp";
67*6dbdd20aSAndroid Build Coastguard Worker #endif // !OS_ANDROID
68*6dbdd20aSAndroid Build Coastguard Worker #endif // !OS_WIN
69*6dbdd20aSAndroid Build Coastguard Worker }
70*6dbdd20aSAndroid Build Coastguard Worker
71*6dbdd20aSAndroid Build Coastguard Worker // static
Create()72*6dbdd20aSAndroid Build Coastguard Worker TempFile TempFile::Create() {
73*6dbdd20aSAndroid Build Coastguard Worker TempFile temp_file;
74*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
75*6dbdd20aSAndroid Build Coastguard Worker temp_file.path_ = GetTempFilePathWin();
76*6dbdd20aSAndroid Build Coastguard Worker // Several tests want to read-back the temp file while still open. On Windows,
77*6dbdd20aSAndroid Build Coastguard Worker // that requires FILE_SHARE_READ. FILE_SHARE_READ is NOT settable when using
78*6dbdd20aSAndroid Build Coastguard Worker // the POSIX-compat equivalent function _open(). Hence the CreateFileA +
79*6dbdd20aSAndroid Build Coastguard Worker // _open_osfhandle dance here.
80*6dbdd20aSAndroid Build Coastguard Worker HANDLE h =
81*6dbdd20aSAndroid Build Coastguard Worker ::CreateFileA(temp_file.path_.c_str(), GENERIC_READ | GENERIC_WRITE,
82*6dbdd20aSAndroid Build Coastguard Worker FILE_SHARE_DELETE | FILE_SHARE_READ, nullptr, CREATE_ALWAYS,
83*6dbdd20aSAndroid Build Coastguard Worker FILE_ATTRIBUTE_TEMPORARY, nullptr);
84*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(PlatformHandleChecker::IsValid(h));
85*6dbdd20aSAndroid Build Coastguard Worker // According to MSDN, when using _open_osfhandle the caller must not call
86*6dbdd20aSAndroid Build Coastguard Worker // CloseHandle(). Ownership is moved to the file descriptor, which then needs
87*6dbdd20aSAndroid Build Coastguard Worker // to be closed with just with _close().
88*6dbdd20aSAndroid Build Coastguard Worker temp_file.fd_.reset(_open_osfhandle(reinterpret_cast<intptr_t>(h), 0));
89*6dbdd20aSAndroid Build Coastguard Worker #else
90*6dbdd20aSAndroid Build Coastguard Worker temp_file.path_ = GetSysTempDir() + "/perfetto-XXXXXXXX";
91*6dbdd20aSAndroid Build Coastguard Worker temp_file.fd_.reset(mkstemp(&temp_file.path_[0]));
92*6dbdd20aSAndroid Build Coastguard Worker #endif
93*6dbdd20aSAndroid Build Coastguard Worker if (PERFETTO_UNLIKELY(!temp_file.fd_)) {
94*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_FATAL("Could not create temp file %s", temp_file.path_.c_str());
95*6dbdd20aSAndroid Build Coastguard Worker }
96*6dbdd20aSAndroid Build Coastguard Worker return temp_file;
97*6dbdd20aSAndroid Build Coastguard Worker }
98*6dbdd20aSAndroid Build Coastguard Worker
99*6dbdd20aSAndroid Build Coastguard Worker // static
CreateUnlinked()100*6dbdd20aSAndroid Build Coastguard Worker TempFile TempFile::CreateUnlinked() {
101*6dbdd20aSAndroid Build Coastguard Worker TempFile temp_file = TempFile::Create();
102*6dbdd20aSAndroid Build Coastguard Worker temp_file.Unlink();
103*6dbdd20aSAndroid Build Coastguard Worker return temp_file;
104*6dbdd20aSAndroid Build Coastguard Worker }
105*6dbdd20aSAndroid Build Coastguard Worker
106*6dbdd20aSAndroid Build Coastguard Worker TempFile::TempFile() = default;
107*6dbdd20aSAndroid Build Coastguard Worker
~TempFile()108*6dbdd20aSAndroid Build Coastguard Worker TempFile::~TempFile() {
109*6dbdd20aSAndroid Build Coastguard Worker Unlink();
110*6dbdd20aSAndroid Build Coastguard Worker }
111*6dbdd20aSAndroid Build Coastguard Worker
ReleaseFD()112*6dbdd20aSAndroid Build Coastguard Worker ScopedFile TempFile::ReleaseFD() {
113*6dbdd20aSAndroid Build Coastguard Worker Unlink();
114*6dbdd20aSAndroid Build Coastguard Worker return std::move(fd_);
115*6dbdd20aSAndroid Build Coastguard Worker }
116*6dbdd20aSAndroid Build Coastguard Worker
Unlink()117*6dbdd20aSAndroid Build Coastguard Worker void TempFile::Unlink() {
118*6dbdd20aSAndroid Build Coastguard Worker if (path_.empty())
119*6dbdd20aSAndroid Build Coastguard Worker return;
120*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
121*6dbdd20aSAndroid Build Coastguard Worker // If the FD is still open DeleteFile will mark the file as pending deletion
122*6dbdd20aSAndroid Build Coastguard Worker // and delete it only when the process exists.
123*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(DeleteFileA(path_.c_str()));
124*6dbdd20aSAndroid Build Coastguard Worker #else
125*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(unlink(path_.c_str()) == 0);
126*6dbdd20aSAndroid Build Coastguard Worker #endif
127*6dbdd20aSAndroid Build Coastguard Worker path_.clear();
128*6dbdd20aSAndroid Build Coastguard Worker }
129*6dbdd20aSAndroid Build Coastguard Worker
130*6dbdd20aSAndroid Build Coastguard Worker TempFile::TempFile(TempFile&&) noexcept = default;
131*6dbdd20aSAndroid Build Coastguard Worker TempFile& TempFile::operator=(TempFile&&) = default;
132*6dbdd20aSAndroid Build Coastguard Worker
133*6dbdd20aSAndroid Build Coastguard Worker // static
Create()134*6dbdd20aSAndroid Build Coastguard Worker TempDir TempDir::Create() {
135*6dbdd20aSAndroid Build Coastguard Worker TempDir temp_dir;
136*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
137*6dbdd20aSAndroid Build Coastguard Worker temp_dir.path_ = GetTempFilePathWin();
138*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(_mkdir(temp_dir.path_.c_str()) == 0);
139*6dbdd20aSAndroid Build Coastguard Worker #else
140*6dbdd20aSAndroid Build Coastguard Worker temp_dir.path_ = GetSysTempDir() + "/perfetto-XXXXXXXX";
141*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(mkdtemp(&temp_dir.path_[0]));
142*6dbdd20aSAndroid Build Coastguard Worker #endif
143*6dbdd20aSAndroid Build Coastguard Worker return temp_dir;
144*6dbdd20aSAndroid Build Coastguard Worker }
145*6dbdd20aSAndroid Build Coastguard Worker
146*6dbdd20aSAndroid Build Coastguard Worker TempDir::TempDir() = default;
147*6dbdd20aSAndroid Build Coastguard Worker TempDir::TempDir(TempDir&&) noexcept = default;
148*6dbdd20aSAndroid Build Coastguard Worker TempDir& TempDir::operator=(TempDir&&) = default;
149*6dbdd20aSAndroid Build Coastguard Worker
~TempDir()150*6dbdd20aSAndroid Build Coastguard Worker TempDir::~TempDir() {
151*6dbdd20aSAndroid Build Coastguard Worker if (path_.empty())
152*6dbdd20aSAndroid Build Coastguard Worker return; // For objects that get std::move()d.
153*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(Rmdir(path_));
154*6dbdd20aSAndroid Build Coastguard Worker }
155*6dbdd20aSAndroid Build Coastguard Worker
156*6dbdd20aSAndroid Build Coastguard Worker } // namespace base
157*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
158