xref: /aosp_15_r20/external/perfetto/src/base/file_utils.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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/file_utils.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include <sys/stat.h>
20*6dbdd20aSAndroid Build Coastguard Worker #include <sys/types.h>
21*6dbdd20aSAndroid Build Coastguard Worker 
22*6dbdd20aSAndroid Build Coastguard Worker #include <algorithm>
23*6dbdd20aSAndroid Build Coastguard Worker #include <deque>
24*6dbdd20aSAndroid Build Coastguard Worker #include <optional>
25*6dbdd20aSAndroid Build Coastguard Worker #include <string>
26*6dbdd20aSAndroid Build Coastguard Worker #include <vector>
27*6dbdd20aSAndroid Build Coastguard Worker 
28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/build_config.h"
29*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/compiler.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/platform_handle.h"
32*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/status.h"
33*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/platform.h"
34*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_file.h"
35*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
36*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h"
37*6dbdd20aSAndroid Build Coastguard Worker 
38*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
39*6dbdd20aSAndroid Build Coastguard Worker #include <Windows.h>
40*6dbdd20aSAndroid Build Coastguard Worker #include <direct.h>
41*6dbdd20aSAndroid Build Coastguard Worker #include <io.h>
42*6dbdd20aSAndroid Build Coastguard Worker #include <stringapiset.h>
43*6dbdd20aSAndroid Build Coastguard Worker #else
44*6dbdd20aSAndroid Build Coastguard Worker #include <dirent.h>
45*6dbdd20aSAndroid Build Coastguard Worker #include <unistd.h>
46*6dbdd20aSAndroid Build Coastguard Worker #endif
47*6dbdd20aSAndroid Build Coastguard Worker 
48*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
49*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
50*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
51*6dbdd20aSAndroid Build Coastguard Worker #define PERFETTO_SET_FILE_PERMISSIONS
52*6dbdd20aSAndroid Build Coastguard Worker #include <fcntl.h>
53*6dbdd20aSAndroid Build Coastguard Worker #include <grp.h>
54*6dbdd20aSAndroid Build Coastguard Worker #include <sys/stat.h>
55*6dbdd20aSAndroid Build Coastguard Worker #include <sys/types.h>
56*6dbdd20aSAndroid Build Coastguard Worker #include <unistd.h>
57*6dbdd20aSAndroid Build Coastguard Worker #endif
58*6dbdd20aSAndroid Build Coastguard Worker 
59*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
60*6dbdd20aSAndroid Build Coastguard Worker namespace base {
61*6dbdd20aSAndroid Build Coastguard Worker namespace {
62*6dbdd20aSAndroid Build Coastguard Worker constexpr size_t kBufSize = 2048;
63*6dbdd20aSAndroid Build Coastguard Worker 
64*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
65*6dbdd20aSAndroid Build Coastguard Worker // Wrap FindClose to: (1) make the return unix-style; (2) deal with stdcall.
CloseFindHandle(HANDLE h)66*6dbdd20aSAndroid Build Coastguard Worker int CloseFindHandle(HANDLE h) {
67*6dbdd20aSAndroid Build Coastguard Worker   return FindClose(h) ? 0 : -1;
68*6dbdd20aSAndroid Build Coastguard Worker }
69*6dbdd20aSAndroid Build Coastguard Worker 
ToUtf16(const std::string str)70*6dbdd20aSAndroid Build Coastguard Worker std::optional<std::wstring> ToUtf16(const std::string str) {
71*6dbdd20aSAndroid Build Coastguard Worker   int len = MultiByteToWideChar(CP_UTF8, 0, str.data(),
72*6dbdd20aSAndroid Build Coastguard Worker                                 static_cast<int>(str.size()), nullptr, 0);
73*6dbdd20aSAndroid Build Coastguard Worker   if (len < 0) {
74*6dbdd20aSAndroid Build Coastguard Worker     return std::nullopt;
75*6dbdd20aSAndroid Build Coastguard Worker   }
76*6dbdd20aSAndroid Build Coastguard Worker   std::vector<wchar_t> tmp;
77*6dbdd20aSAndroid Build Coastguard Worker   tmp.resize(static_cast<std::vector<wchar_t>::size_type>(len));
78*6dbdd20aSAndroid Build Coastguard Worker   len =
79*6dbdd20aSAndroid Build Coastguard Worker       MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()),
80*6dbdd20aSAndroid Build Coastguard Worker                           tmp.data(), static_cast<int>(tmp.size()));
81*6dbdd20aSAndroid Build Coastguard Worker   if (len < 0) {
82*6dbdd20aSAndroid Build Coastguard Worker     return std::nullopt;
83*6dbdd20aSAndroid Build Coastguard Worker   }
84*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(static_cast<std::vector<wchar_t>::size_type>(len) ==
85*6dbdd20aSAndroid Build Coastguard Worker                  tmp.size());
86*6dbdd20aSAndroid Build Coastguard Worker   return std::wstring(tmp.data(), tmp.size());
87*6dbdd20aSAndroid Build Coastguard Worker }
88*6dbdd20aSAndroid Build Coastguard Worker 
89*6dbdd20aSAndroid Build Coastguard Worker #endif
90*6dbdd20aSAndroid Build Coastguard Worker 
91*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
92*6dbdd20aSAndroid Build Coastguard Worker 
Read(int fd,void * dst,size_t dst_size)93*6dbdd20aSAndroid Build Coastguard Worker ssize_t Read(int fd, void* dst, size_t dst_size) {
94*6dbdd20aSAndroid Build Coastguard Worker   ssize_t ret;
95*6dbdd20aSAndroid Build Coastguard Worker   platform::BeforeMaybeBlockingSyscall();
96*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
97*6dbdd20aSAndroid Build Coastguard Worker   ret = _read(fd, dst, static_cast<unsigned>(dst_size));
98*6dbdd20aSAndroid Build Coastguard Worker #else
99*6dbdd20aSAndroid Build Coastguard Worker   ret = PERFETTO_EINTR(read(fd, dst, dst_size));
100*6dbdd20aSAndroid Build Coastguard Worker #endif
101*6dbdd20aSAndroid Build Coastguard Worker   platform::AfterMaybeBlockingSyscall();
102*6dbdd20aSAndroid Build Coastguard Worker   return ret;
103*6dbdd20aSAndroid Build Coastguard Worker }
104*6dbdd20aSAndroid Build Coastguard Worker 
ReadFileDescriptor(int fd,std::string * out)105*6dbdd20aSAndroid Build Coastguard Worker bool ReadFileDescriptor(int fd, std::string* out) {
106*6dbdd20aSAndroid Build Coastguard Worker   // Do not override existing data in string.
107*6dbdd20aSAndroid Build Coastguard Worker   size_t i = out->size();
108*6dbdd20aSAndroid Build Coastguard Worker 
109*6dbdd20aSAndroid Build Coastguard Worker   struct stat buf {};
110*6dbdd20aSAndroid Build Coastguard Worker   if (fstat(fd, &buf) != -1) {
111*6dbdd20aSAndroid Build Coastguard Worker     if (buf.st_size > 0)
112*6dbdd20aSAndroid Build Coastguard Worker       out->resize(i + static_cast<size_t>(buf.st_size));
113*6dbdd20aSAndroid Build Coastguard Worker   }
114*6dbdd20aSAndroid Build Coastguard Worker 
115*6dbdd20aSAndroid Build Coastguard Worker   ssize_t bytes_read;
116*6dbdd20aSAndroid Build Coastguard Worker   for (;;) {
117*6dbdd20aSAndroid Build Coastguard Worker     if (out->size() < i + kBufSize)
118*6dbdd20aSAndroid Build Coastguard Worker       out->resize(out->size() + kBufSize);
119*6dbdd20aSAndroid Build Coastguard Worker 
120*6dbdd20aSAndroid Build Coastguard Worker     bytes_read = Read(fd, &((*out)[i]), kBufSize);
121*6dbdd20aSAndroid Build Coastguard Worker     if (bytes_read > 0) {
122*6dbdd20aSAndroid Build Coastguard Worker       i += static_cast<size_t>(bytes_read);
123*6dbdd20aSAndroid Build Coastguard Worker     } else {
124*6dbdd20aSAndroid Build Coastguard Worker       out->resize(i);
125*6dbdd20aSAndroid Build Coastguard Worker       return bytes_read == 0;
126*6dbdd20aSAndroid Build Coastguard Worker     }
127*6dbdd20aSAndroid Build Coastguard Worker   }
128*6dbdd20aSAndroid Build Coastguard Worker }
129*6dbdd20aSAndroid Build Coastguard Worker 
ReadPlatformHandle(PlatformHandle h,std::string * out)130*6dbdd20aSAndroid Build Coastguard Worker bool ReadPlatformHandle(PlatformHandle h, std::string* out) {
131*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
132*6dbdd20aSAndroid Build Coastguard Worker   // Do not override existing data in string.
133*6dbdd20aSAndroid Build Coastguard Worker   size_t i = out->size();
134*6dbdd20aSAndroid Build Coastguard Worker 
135*6dbdd20aSAndroid Build Coastguard Worker   for (;;) {
136*6dbdd20aSAndroid Build Coastguard Worker     if (out->size() < i + kBufSize)
137*6dbdd20aSAndroid Build Coastguard Worker       out->resize(out->size() + kBufSize);
138*6dbdd20aSAndroid Build Coastguard Worker     DWORD bytes_read = 0;
139*6dbdd20aSAndroid Build Coastguard Worker     auto res = ::ReadFile(h, &((*out)[i]), kBufSize, &bytes_read, nullptr);
140*6dbdd20aSAndroid Build Coastguard Worker     if (res && bytes_read > 0) {
141*6dbdd20aSAndroid Build Coastguard Worker       i += static_cast<size_t>(bytes_read);
142*6dbdd20aSAndroid Build Coastguard Worker     } else {
143*6dbdd20aSAndroid Build Coastguard Worker       out->resize(i);
144*6dbdd20aSAndroid Build Coastguard Worker       const bool is_eof = res && bytes_read == 0;
145*6dbdd20aSAndroid Build Coastguard Worker       auto err = res ? 0 : GetLastError();
146*6dbdd20aSAndroid Build Coastguard Worker       // The "Broken pipe" error on Windows is slighly different than Unix:
147*6dbdd20aSAndroid Build Coastguard Worker       // On Unix: a "broken pipe" error can happen only on the writer side. On
148*6dbdd20aSAndroid Build Coastguard Worker       // the reader there is no broken pipe, just a EOF.
149*6dbdd20aSAndroid Build Coastguard Worker       // On windows: the reader also sees a broken pipe error.
150*6dbdd20aSAndroid Build Coastguard Worker       // Here we normalize on the Unix behavior, treating broken pipe as EOF.
151*6dbdd20aSAndroid Build Coastguard Worker       return is_eof || err == ERROR_BROKEN_PIPE;
152*6dbdd20aSAndroid Build Coastguard Worker     }
153*6dbdd20aSAndroid Build Coastguard Worker   }
154*6dbdd20aSAndroid Build Coastguard Worker #else
155*6dbdd20aSAndroid Build Coastguard Worker   return ReadFileDescriptor(h, out);
156*6dbdd20aSAndroid Build Coastguard Worker #endif
157*6dbdd20aSAndroid Build Coastguard Worker }
158*6dbdd20aSAndroid Build Coastguard Worker 
ReadFileStream(FILE * f,std::string * out)159*6dbdd20aSAndroid Build Coastguard Worker bool ReadFileStream(FILE* f, std::string* out) {
160*6dbdd20aSAndroid Build Coastguard Worker   return ReadFileDescriptor(fileno(f), out);
161*6dbdd20aSAndroid Build Coastguard Worker }
162*6dbdd20aSAndroid Build Coastguard Worker 
ReadFile(const std::string & path,std::string * out)163*6dbdd20aSAndroid Build Coastguard Worker bool ReadFile(const std::string& path, std::string* out) {
164*6dbdd20aSAndroid Build Coastguard Worker   base::ScopedFile fd = base::OpenFile(path, O_RDONLY);
165*6dbdd20aSAndroid Build Coastguard Worker   if (!fd)
166*6dbdd20aSAndroid Build Coastguard Worker     return false;
167*6dbdd20aSAndroid Build Coastguard Worker 
168*6dbdd20aSAndroid Build Coastguard Worker   return ReadFileDescriptor(*fd, out);
169*6dbdd20aSAndroid Build Coastguard Worker }
170*6dbdd20aSAndroid Build Coastguard Worker 
WriteAll(int fd,const void * buf,size_t count)171*6dbdd20aSAndroid Build Coastguard Worker ssize_t WriteAll(int fd, const void* buf, size_t count) {
172*6dbdd20aSAndroid Build Coastguard Worker   size_t written = 0;
173*6dbdd20aSAndroid Build Coastguard Worker   while (written < count) {
174*6dbdd20aSAndroid Build Coastguard Worker     // write() on windows takes an unsigned int size.
175*6dbdd20aSAndroid Build Coastguard Worker     uint32_t bytes_left = static_cast<uint32_t>(
176*6dbdd20aSAndroid Build Coastguard Worker         std::min(count - written, static_cast<size_t>(UINT32_MAX)));
177*6dbdd20aSAndroid Build Coastguard Worker     platform::BeforeMaybeBlockingSyscall();
178*6dbdd20aSAndroid Build Coastguard Worker     ssize_t wr = PERFETTO_EINTR(
179*6dbdd20aSAndroid Build Coastguard Worker         write(fd, static_cast<const char*>(buf) + written, bytes_left));
180*6dbdd20aSAndroid Build Coastguard Worker     platform::AfterMaybeBlockingSyscall();
181*6dbdd20aSAndroid Build Coastguard Worker     if (wr == 0)
182*6dbdd20aSAndroid Build Coastguard Worker       break;
183*6dbdd20aSAndroid Build Coastguard Worker     if (wr < 0)
184*6dbdd20aSAndroid Build Coastguard Worker       return wr;
185*6dbdd20aSAndroid Build Coastguard Worker     written += static_cast<size_t>(wr);
186*6dbdd20aSAndroid Build Coastguard Worker   }
187*6dbdd20aSAndroid Build Coastguard Worker   return static_cast<ssize_t>(written);
188*6dbdd20aSAndroid Build Coastguard Worker }
189*6dbdd20aSAndroid Build Coastguard Worker 
WriteAllHandle(PlatformHandle h,const void * buf,size_t count)190*6dbdd20aSAndroid Build Coastguard Worker ssize_t WriteAllHandle(PlatformHandle h, const void* buf, size_t count) {
191*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
192*6dbdd20aSAndroid Build Coastguard Worker   DWORD wsize = 0;
193*6dbdd20aSAndroid Build Coastguard Worker   if (::WriteFile(h, buf, static_cast<DWORD>(count), &wsize, nullptr)) {
194*6dbdd20aSAndroid Build Coastguard Worker     return wsize;
195*6dbdd20aSAndroid Build Coastguard Worker   } else {
196*6dbdd20aSAndroid Build Coastguard Worker     return -1;
197*6dbdd20aSAndroid Build Coastguard Worker   }
198*6dbdd20aSAndroid Build Coastguard Worker #else
199*6dbdd20aSAndroid Build Coastguard Worker   return WriteAll(h, buf, count);
200*6dbdd20aSAndroid Build Coastguard Worker #endif
201*6dbdd20aSAndroid Build Coastguard Worker }
202*6dbdd20aSAndroid Build Coastguard Worker 
FlushFile(int fd)203*6dbdd20aSAndroid Build Coastguard Worker bool FlushFile(int fd) {
204*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(fd != 0);
205*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
206*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
207*6dbdd20aSAndroid Build Coastguard Worker   return !PERFETTO_EINTR(fdatasync(fd));
208*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
209*6dbdd20aSAndroid Build Coastguard Worker   return !PERFETTO_EINTR(_commit(fd));
210*6dbdd20aSAndroid Build Coastguard Worker #else
211*6dbdd20aSAndroid Build Coastguard Worker   return !PERFETTO_EINTR(fsync(fd));
212*6dbdd20aSAndroid Build Coastguard Worker #endif
213*6dbdd20aSAndroid Build Coastguard Worker }
214*6dbdd20aSAndroid Build Coastguard Worker 
Mkdir(const std::string & path)215*6dbdd20aSAndroid Build Coastguard Worker bool Mkdir(const std::string& path) {
216*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
217*6dbdd20aSAndroid Build Coastguard Worker   return _mkdir(path.c_str()) == 0;
218*6dbdd20aSAndroid Build Coastguard Worker #else
219*6dbdd20aSAndroid Build Coastguard Worker   return mkdir(path.c_str(), 0755) == 0;
220*6dbdd20aSAndroid Build Coastguard Worker #endif
221*6dbdd20aSAndroid Build Coastguard Worker }
222*6dbdd20aSAndroid Build Coastguard Worker 
Rmdir(const std::string & path)223*6dbdd20aSAndroid Build Coastguard Worker bool Rmdir(const std::string& path) {
224*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
225*6dbdd20aSAndroid Build Coastguard Worker   return _rmdir(path.c_str()) == 0;
226*6dbdd20aSAndroid Build Coastguard Worker #else
227*6dbdd20aSAndroid Build Coastguard Worker   return rmdir(path.c_str()) == 0;
228*6dbdd20aSAndroid Build Coastguard Worker #endif
229*6dbdd20aSAndroid Build Coastguard Worker }
230*6dbdd20aSAndroid Build Coastguard Worker 
CloseFile(int fd)231*6dbdd20aSAndroid Build Coastguard Worker int CloseFile(int fd) {
232*6dbdd20aSAndroid Build Coastguard Worker   return close(fd);
233*6dbdd20aSAndroid Build Coastguard Worker }
234*6dbdd20aSAndroid Build Coastguard Worker 
OpenFile(const std::string & path,int flags,FileOpenMode mode)235*6dbdd20aSAndroid Build Coastguard Worker ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode mode) {
236*6dbdd20aSAndroid Build Coastguard Worker   // If a new file might be created, ensure that the permissions for the new
237*6dbdd20aSAndroid Build Coastguard Worker   // file are explicitly specified.
238*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK((flags & O_CREAT) == 0 || mode != kFileModeInvalid);
239*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
240*6dbdd20aSAndroid Build Coastguard Worker   // Always use O_BINARY on Windows, to avoid silly EOL translations.
241*6dbdd20aSAndroid Build Coastguard Worker   ScopedFile fd(_open(path.c_str(), flags | O_BINARY, mode));
242*6dbdd20aSAndroid Build Coastguard Worker #else
243*6dbdd20aSAndroid Build Coastguard Worker   // Always open a ScopedFile with O_CLOEXEC so we can safely fork and exec.
244*6dbdd20aSAndroid Build Coastguard Worker   ScopedFile fd(open(path.c_str(), flags | O_CLOEXEC, mode));
245*6dbdd20aSAndroid Build Coastguard Worker #endif
246*6dbdd20aSAndroid Build Coastguard Worker   return fd;
247*6dbdd20aSAndroid Build Coastguard Worker }
248*6dbdd20aSAndroid Build Coastguard Worker 
OpenFstream(const char * path,const char * mode)249*6dbdd20aSAndroid Build Coastguard Worker ScopedFstream OpenFstream(const char* path, const char* mode) {
250*6dbdd20aSAndroid Build Coastguard Worker   ScopedFstream file;
251*6dbdd20aSAndroid Build Coastguard Worker // On Windows fopen interprets filename using the ANSI or OEM codepage but
252*6dbdd20aSAndroid Build Coastguard Worker // sqlite3_value_text returns a UTF-8 string. To make sure we interpret the
253*6dbdd20aSAndroid Build Coastguard Worker // filename correctly we use _wfopen and a UTF-16 string on windows.
254*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
255*6dbdd20aSAndroid Build Coastguard Worker   auto w_path = ToUtf16(path);
256*6dbdd20aSAndroid Build Coastguard Worker   auto w_mode = ToUtf16(mode);
257*6dbdd20aSAndroid Build Coastguard Worker   if (w_path && w_mode) {
258*6dbdd20aSAndroid Build Coastguard Worker     file.reset(_wfopen(w_path->c_str(), w_mode->c_str()));
259*6dbdd20aSAndroid Build Coastguard Worker   }
260*6dbdd20aSAndroid Build Coastguard Worker #else
261*6dbdd20aSAndroid Build Coastguard Worker   file.reset(fopen(path, mode));
262*6dbdd20aSAndroid Build Coastguard Worker #endif
263*6dbdd20aSAndroid Build Coastguard Worker   return file;
264*6dbdd20aSAndroid Build Coastguard Worker }
265*6dbdd20aSAndroid Build Coastguard Worker 
FileExists(const std::string & path)266*6dbdd20aSAndroid Build Coastguard Worker bool FileExists(const std::string& path) {
267*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
268*6dbdd20aSAndroid Build Coastguard Worker   return _access(path.c_str(), 0) == 0;
269*6dbdd20aSAndroid Build Coastguard Worker #else
270*6dbdd20aSAndroid Build Coastguard Worker   return access(path.c_str(), F_OK) == 0;
271*6dbdd20aSAndroid Build Coastguard Worker #endif
272*6dbdd20aSAndroid Build Coastguard Worker }
273*6dbdd20aSAndroid Build Coastguard Worker 
274*6dbdd20aSAndroid Build Coastguard Worker // Declared in base/platform_handle.h.
ClosePlatformHandle(PlatformHandle handle)275*6dbdd20aSAndroid Build Coastguard Worker int ClosePlatformHandle(PlatformHandle handle) {
276*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
277*6dbdd20aSAndroid Build Coastguard Worker   // Make the return value UNIX-style.
278*6dbdd20aSAndroid Build Coastguard Worker   return CloseHandle(handle) ? 0 : -1;
279*6dbdd20aSAndroid Build Coastguard Worker #else
280*6dbdd20aSAndroid Build Coastguard Worker   return close(handle);
281*6dbdd20aSAndroid Build Coastguard Worker #endif
282*6dbdd20aSAndroid Build Coastguard Worker }
283*6dbdd20aSAndroid Build Coastguard Worker 
ListFilesRecursive(const std::string & dir_path,std::vector<std::string> & output)284*6dbdd20aSAndroid Build Coastguard Worker base::Status ListFilesRecursive(const std::string& dir_path,
285*6dbdd20aSAndroid Build Coastguard Worker                                 std::vector<std::string>& output) {
286*6dbdd20aSAndroid Build Coastguard Worker   std::string root_dir_path = dir_path;
287*6dbdd20aSAndroid Build Coastguard Worker   if (root_dir_path.back() == '\\') {
288*6dbdd20aSAndroid Build Coastguard Worker     root_dir_path.back() = '/';
289*6dbdd20aSAndroid Build Coastguard Worker   } else if (root_dir_path.back() != '/') {
290*6dbdd20aSAndroid Build Coastguard Worker     root_dir_path.push_back('/');
291*6dbdd20aSAndroid Build Coastguard Worker   }
292*6dbdd20aSAndroid Build Coastguard Worker 
293*6dbdd20aSAndroid Build Coastguard Worker   // dir_queue contains full paths to the directories. The paths include the
294*6dbdd20aSAndroid Build Coastguard Worker   // root_dir_path at the beginning and the trailing slash at the end.
295*6dbdd20aSAndroid Build Coastguard Worker   std::deque<std::string> dir_queue;
296*6dbdd20aSAndroid Build Coastguard Worker   dir_queue.push_back(root_dir_path);
297*6dbdd20aSAndroid Build Coastguard Worker 
298*6dbdd20aSAndroid Build Coastguard Worker   while (!dir_queue.empty()) {
299*6dbdd20aSAndroid Build Coastguard Worker     const std::string cur_dir = std::move(dir_queue.front());
300*6dbdd20aSAndroid Build Coastguard Worker     dir_queue.pop_front();
301*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
302*6dbdd20aSAndroid Build Coastguard Worker     return base::ErrStatus("ListFilesRecursive not supported yet");
303*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
304*6dbdd20aSAndroid Build Coastguard Worker     std::string glob_path = cur_dir + "*";
305*6dbdd20aSAndroid Build Coastguard Worker     // + 1 because we also have to count the NULL terminator.
306*6dbdd20aSAndroid Build Coastguard Worker     if (glob_path.length() + 1 > MAX_PATH)
307*6dbdd20aSAndroid Build Coastguard Worker       return base::ErrStatus("Directory path %s is too long", dir_path.c_str());
308*6dbdd20aSAndroid Build Coastguard Worker     WIN32_FIND_DATAA ffd;
309*6dbdd20aSAndroid Build Coastguard Worker 
310*6dbdd20aSAndroid Build Coastguard Worker     base::ScopedResource<HANDLE, CloseFindHandle, nullptr, false,
311*6dbdd20aSAndroid Build Coastguard Worker                          base::PlatformHandleChecker>
312*6dbdd20aSAndroid Build Coastguard Worker         hFind(FindFirstFileA(glob_path.c_str(), &ffd));
313*6dbdd20aSAndroid Build Coastguard Worker     if (!hFind) {
314*6dbdd20aSAndroid Build Coastguard Worker       // For empty directories, there should be at least one entry '.'.
315*6dbdd20aSAndroid Build Coastguard Worker       // If FindFirstFileA returns INVALID_HANDLE_VALUE, this means directory
316*6dbdd20aSAndroid Build Coastguard Worker       // couldn't be accessed.
317*6dbdd20aSAndroid Build Coastguard Worker       return base::ErrStatus("Failed to open directory %s", cur_dir.c_str());
318*6dbdd20aSAndroid Build Coastguard Worker     }
319*6dbdd20aSAndroid Build Coastguard Worker     do {
320*6dbdd20aSAndroid Build Coastguard Worker       if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0)
321*6dbdd20aSAndroid Build Coastguard Worker         continue;
322*6dbdd20aSAndroid Build Coastguard Worker       if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
323*6dbdd20aSAndroid Build Coastguard Worker         std::string subdir_path = cur_dir + ffd.cFileName + '/';
324*6dbdd20aSAndroid Build Coastguard Worker         dir_queue.push_back(subdir_path);
325*6dbdd20aSAndroid Build Coastguard Worker       } else {
326*6dbdd20aSAndroid Build Coastguard Worker         const std::string full_path = cur_dir + ffd.cFileName;
327*6dbdd20aSAndroid Build Coastguard Worker         PERFETTO_CHECK(full_path.length() > root_dir_path.length());
328*6dbdd20aSAndroid Build Coastguard Worker         output.push_back(full_path.substr(root_dir_path.length()));
329*6dbdd20aSAndroid Build Coastguard Worker       }
330*6dbdd20aSAndroid Build Coastguard Worker     } while (FindNextFileA(*hFind, &ffd));
331*6dbdd20aSAndroid Build Coastguard Worker #else
332*6dbdd20aSAndroid Build Coastguard Worker     ScopedDir dir = ScopedDir(opendir(cur_dir.c_str()));
333*6dbdd20aSAndroid Build Coastguard Worker     if (!dir) {
334*6dbdd20aSAndroid Build Coastguard Worker       return base::ErrStatus("Failed to open directory %s", cur_dir.c_str());
335*6dbdd20aSAndroid Build Coastguard Worker     }
336*6dbdd20aSAndroid Build Coastguard Worker     for (auto* dirent = readdir(dir.get()); dirent != nullptr;
337*6dbdd20aSAndroid Build Coastguard Worker          dirent = readdir(dir.get())) {
338*6dbdd20aSAndroid Build Coastguard Worker       if (strcmp(dirent->d_name, ".") == 0 ||
339*6dbdd20aSAndroid Build Coastguard Worker           strcmp(dirent->d_name, "..") == 0) {
340*6dbdd20aSAndroid Build Coastguard Worker         continue;
341*6dbdd20aSAndroid Build Coastguard Worker       }
342*6dbdd20aSAndroid Build Coastguard Worker       if (dirent->d_type == DT_DIR) {
343*6dbdd20aSAndroid Build Coastguard Worker         dir_queue.push_back(cur_dir + dirent->d_name + '/');
344*6dbdd20aSAndroid Build Coastguard Worker       } else if (dirent->d_type == DT_REG) {
345*6dbdd20aSAndroid Build Coastguard Worker         const std::string full_path = cur_dir + dirent->d_name;
346*6dbdd20aSAndroid Build Coastguard Worker         PERFETTO_CHECK(full_path.length() > root_dir_path.length());
347*6dbdd20aSAndroid Build Coastguard Worker         output.push_back(full_path.substr(root_dir_path.length()));
348*6dbdd20aSAndroid Build Coastguard Worker       }
349*6dbdd20aSAndroid Build Coastguard Worker     }
350*6dbdd20aSAndroid Build Coastguard Worker #endif
351*6dbdd20aSAndroid Build Coastguard Worker   }
352*6dbdd20aSAndroid Build Coastguard Worker   return base::OkStatus();
353*6dbdd20aSAndroid Build Coastguard Worker }
354*6dbdd20aSAndroid Build Coastguard Worker 
GetFileExtension(const std::string & filename)355*6dbdd20aSAndroid Build Coastguard Worker std::string GetFileExtension(const std::string& filename) {
356*6dbdd20aSAndroid Build Coastguard Worker   auto ext_idx = filename.rfind('.');
357*6dbdd20aSAndroid Build Coastguard Worker   if (ext_idx == std::string::npos)
358*6dbdd20aSAndroid Build Coastguard Worker     return std::string();
359*6dbdd20aSAndroid Build Coastguard Worker   return filename.substr(ext_idx);
360*6dbdd20aSAndroid Build Coastguard Worker }
361*6dbdd20aSAndroid Build Coastguard Worker 
SetFilePermissions(const std::string & file_path,const std::string & group_name_or_id,const std::string & mode_bits)362*6dbdd20aSAndroid Build Coastguard Worker base::Status SetFilePermissions(const std::string& file_path,
363*6dbdd20aSAndroid Build Coastguard Worker                                 const std::string& group_name_or_id,
364*6dbdd20aSAndroid Build Coastguard Worker                                 const std::string& mode_bits) {
365*6dbdd20aSAndroid Build Coastguard Worker #ifdef PERFETTO_SET_FILE_PERMISSIONS
366*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(!file_path.empty());
367*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(!group_name_or_id.empty());
368*6dbdd20aSAndroid Build Coastguard Worker 
369*6dbdd20aSAndroid Build Coastguard Worker   // Default |group_id| to -1 for not changing the group ownership.
370*6dbdd20aSAndroid Build Coastguard Worker   gid_t group_id = static_cast<gid_t>(-1);
371*6dbdd20aSAndroid Build Coastguard Worker   auto maybe_group_id = base::StringToUInt32(group_name_or_id);
372*6dbdd20aSAndroid Build Coastguard Worker   if (maybe_group_id) {  // A numerical group ID.
373*6dbdd20aSAndroid Build Coastguard Worker     group_id = *maybe_group_id;
374*6dbdd20aSAndroid Build Coastguard Worker   } else {  // A group name.
375*6dbdd20aSAndroid Build Coastguard Worker     struct group* file_group = nullptr;
376*6dbdd20aSAndroid Build Coastguard Worker     // Query the group ID of |group|.
377*6dbdd20aSAndroid Build Coastguard Worker     do {
378*6dbdd20aSAndroid Build Coastguard Worker       file_group = getgrnam(group_name_or_id.c_str());
379*6dbdd20aSAndroid Build Coastguard Worker     } while (file_group == nullptr && errno == EINTR);
380*6dbdd20aSAndroid Build Coastguard Worker     if (file_group == nullptr) {
381*6dbdd20aSAndroid Build Coastguard Worker       return base::ErrStatus("Failed to get group information of %s ",
382*6dbdd20aSAndroid Build Coastguard Worker                              group_name_or_id.c_str());
383*6dbdd20aSAndroid Build Coastguard Worker     }
384*6dbdd20aSAndroid Build Coastguard Worker     group_id = file_group->gr_gid;
385*6dbdd20aSAndroid Build Coastguard Worker   }
386*6dbdd20aSAndroid Build Coastguard Worker 
387*6dbdd20aSAndroid Build Coastguard Worker   if (PERFETTO_EINTR(chown(file_path.c_str(), geteuid(), group_id))) {
388*6dbdd20aSAndroid Build Coastguard Worker     return base::ErrStatus("Failed to chown %s ", file_path.c_str());
389*6dbdd20aSAndroid Build Coastguard Worker   }
390*6dbdd20aSAndroid Build Coastguard Worker 
391*6dbdd20aSAndroid Build Coastguard Worker   // |mode| accepts values like "0660" as "rw-rw----" mode bits.
392*6dbdd20aSAndroid Build Coastguard Worker   auto mode_value = base::StringToInt32(mode_bits, 8);
393*6dbdd20aSAndroid Build Coastguard Worker   if (!(mode_bits.size() == 4 && mode_value.has_value())) {
394*6dbdd20aSAndroid Build Coastguard Worker     return base::ErrStatus(
395*6dbdd20aSAndroid Build Coastguard Worker         "The chmod mode bits must be a 4-digit octal number, e.g. 0660");
396*6dbdd20aSAndroid Build Coastguard Worker   }
397*6dbdd20aSAndroid Build Coastguard Worker   if (PERFETTO_EINTR(
398*6dbdd20aSAndroid Build Coastguard Worker           chmod(file_path.c_str(), static_cast<mode_t>(mode_value.value())))) {
399*6dbdd20aSAndroid Build Coastguard Worker     return base::ErrStatus("Failed to chmod %s", file_path.c_str());
400*6dbdd20aSAndroid Build Coastguard Worker   }
401*6dbdd20aSAndroid Build Coastguard Worker   return base::OkStatus();
402*6dbdd20aSAndroid Build Coastguard Worker #else
403*6dbdd20aSAndroid Build Coastguard Worker   base::ignore_result(file_path);
404*6dbdd20aSAndroid Build Coastguard Worker   base::ignore_result(group_name_or_id);
405*6dbdd20aSAndroid Build Coastguard Worker   base::ignore_result(mode_bits);
406*6dbdd20aSAndroid Build Coastguard Worker   return base::ErrStatus(
407*6dbdd20aSAndroid Build Coastguard Worker       "Setting file permissions is not supported on this platform");
408*6dbdd20aSAndroid Build Coastguard Worker #endif
409*6dbdd20aSAndroid Build Coastguard Worker }
410*6dbdd20aSAndroid Build Coastguard Worker 
GetFileSize(const std::string & file_path)411*6dbdd20aSAndroid Build Coastguard Worker std::optional<uint64_t> GetFileSize(const std::string& file_path) {
412*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
413*6dbdd20aSAndroid Build Coastguard Worker   // This does not use base::OpenFile to avoid getting an exclusive lock.
414*6dbdd20aSAndroid Build Coastguard Worker   base::ScopedPlatformHandle fd(
415*6dbdd20aSAndroid Build Coastguard Worker       CreateFileA(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
416*6dbdd20aSAndroid Build Coastguard Worker                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
417*6dbdd20aSAndroid Build Coastguard Worker #else
418*6dbdd20aSAndroid Build Coastguard Worker   base::ScopedFile fd(base::OpenFile(file_path, O_RDONLY | O_CLOEXEC));
419*6dbdd20aSAndroid Build Coastguard Worker #endif
420*6dbdd20aSAndroid Build Coastguard Worker   if (!fd) {
421*6dbdd20aSAndroid Build Coastguard Worker     return std::nullopt;
422*6dbdd20aSAndroid Build Coastguard Worker   }
423*6dbdd20aSAndroid Build Coastguard Worker   return GetFileSize(*fd);
424*6dbdd20aSAndroid Build Coastguard Worker }
425*6dbdd20aSAndroid Build Coastguard Worker 
GetFileSize(PlatformHandle fd)426*6dbdd20aSAndroid Build Coastguard Worker std::optional<uint64_t> GetFileSize(PlatformHandle fd) {
427*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
428*6dbdd20aSAndroid Build Coastguard Worker   LARGE_INTEGER file_size;
429*6dbdd20aSAndroid Build Coastguard Worker   file_size.QuadPart = 0;
430*6dbdd20aSAndroid Build Coastguard Worker   if (!GetFileSizeEx(fd, &file_size)) {
431*6dbdd20aSAndroid Build Coastguard Worker     return std::nullopt;
432*6dbdd20aSAndroid Build Coastguard Worker   }
433*6dbdd20aSAndroid Build Coastguard Worker   static_assert(sizeof(decltype(file_size.QuadPart)) <= sizeof(uint64_t));
434*6dbdd20aSAndroid Build Coastguard Worker   return static_cast<uint64_t>(file_size.QuadPart);
435*6dbdd20aSAndroid Build Coastguard Worker #else
436*6dbdd20aSAndroid Build Coastguard Worker   struct stat buf {};
437*6dbdd20aSAndroid Build Coastguard Worker   if (fstat(fd, &buf) == -1) {
438*6dbdd20aSAndroid Build Coastguard Worker     return std::nullopt;
439*6dbdd20aSAndroid Build Coastguard Worker   }
440*6dbdd20aSAndroid Build Coastguard Worker   static_assert(sizeof(decltype(buf.st_size)) <= sizeof(uint64_t));
441*6dbdd20aSAndroid Build Coastguard Worker   return static_cast<uint64_t>(buf.st_size);
442*6dbdd20aSAndroid Build Coastguard Worker #endif
443*6dbdd20aSAndroid Build Coastguard Worker }
444*6dbdd20aSAndroid Build Coastguard Worker 
445*6dbdd20aSAndroid Build Coastguard Worker }  // namespace base
446*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
447