1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/ext/base/file_utils.h"
18
19 #include <sys/stat.h>
20 #include <sys/types.h>
21
22 #include <algorithm>
23
24 #include "perfetto/base/build_config.h"
25 #include "perfetto/base/logging.h"
26 #include "perfetto/base/platform_handle.h"
27 #include "perfetto/ext/base/scoped_file.h"
28 #include "perfetto/ext/base/utils.h"
29
30 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
31 #include <Windows.h>
32 #include <direct.h>
33 #include <io.h>
34 #else
35 #include <dirent.h>
36 #include <unistd.h>
37 #endif
38
39 namespace perfetto {
40 namespace base {
41 namespace {
42 constexpr size_t kBufSize = 2048;
43 }
44
Read(int fd,void * dst,size_t dst_size)45 ssize_t Read(int fd, void* dst, size_t dst_size) {
46 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
47 return _read(fd, dst, static_cast<unsigned>(dst_size));
48 #else
49 return PERFETTO_EINTR(read(fd, dst, dst_size));
50 #endif
51 }
52
ReadFileDescriptor(int fd,std::string * out)53 bool ReadFileDescriptor(int fd, std::string* out) {
54 // Do not override existing data in string.
55 size_t i = out->size();
56
57 struct stat buf {};
58 if (fstat(fd, &buf) != -1) {
59 if (buf.st_size > 0)
60 out->resize(i + static_cast<size_t>(buf.st_size));
61 }
62
63 ssize_t bytes_read;
64 for (;;) {
65 if (out->size() < i + kBufSize)
66 out->resize(out->size() + kBufSize);
67
68 bytes_read = Read(fd, &((*out)[i]), kBufSize);
69 if (bytes_read > 0) {
70 i += static_cast<size_t>(bytes_read);
71 } else {
72 out->resize(i);
73 return bytes_read == 0;
74 }
75 }
76 }
77
ReadPlatformHandle(PlatformHandle h,std::string * out)78 bool ReadPlatformHandle(PlatformHandle h, std::string* out) {
79 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
80 // Do not override existing data in string.
81 size_t i = out->size();
82
83 for (;;) {
84 if (out->size() < i + kBufSize)
85 out->resize(out->size() + kBufSize);
86 DWORD bytes_read = 0;
87 auto res = ::ReadFile(h, &((*out)[i]), kBufSize, &bytes_read, nullptr);
88 if (res && bytes_read > 0) {
89 i += static_cast<size_t>(bytes_read);
90 } else {
91 out->resize(i);
92 const bool is_eof = res && bytes_read == 0;
93 auto err = res ? 0 : GetLastError();
94 // The "Broken pipe" error on Windows is slighly different than Unix:
95 // On Unix: a "broken pipe" error can happen only on the writer side. On
96 // the reader there is no broken pipe, just a EOF.
97 // On windows: the reader also sees a broken pipe error.
98 // Here we normalize on the Unix behavior, treating broken pipe as EOF.
99 return is_eof || err == ERROR_BROKEN_PIPE;
100 }
101 }
102 #else
103 return ReadFileDescriptor(h, out);
104 #endif
105 }
106
ReadFileStream(FILE * f,std::string * out)107 bool ReadFileStream(FILE* f, std::string* out) {
108 return ReadFileDescriptor(fileno(f), out);
109 }
110
ReadFile(const std::string & path,std::string * out)111 bool ReadFile(const std::string& path, std::string* out) {
112 base::ScopedFile fd = base::OpenFile(path, O_RDONLY);
113 if (!fd)
114 return false;
115
116 return ReadFileDescriptor(*fd, out);
117 }
118
WriteAll(int fd,const void * buf,size_t count)119 ssize_t WriteAll(int fd, const void* buf, size_t count) {
120 size_t written = 0;
121 while (written < count) {
122 // write() on windows takes an unsigned int size.
123 uint32_t bytes_left = static_cast<uint32_t>(
124 std::min(count - written, static_cast<size_t>(UINT32_MAX)));
125 ssize_t wr = PERFETTO_EINTR(
126 write(fd, static_cast<const char*>(buf) + written, bytes_left));
127 if (wr == 0)
128 break;
129 if (wr < 0)
130 return wr;
131 written += static_cast<size_t>(wr);
132 }
133 return static_cast<ssize_t>(written);
134 }
135
WriteAllHandle(PlatformHandle h,const void * buf,size_t count)136 ssize_t WriteAllHandle(PlatformHandle h, const void* buf, size_t count) {
137 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
138 DWORD wsize = 0;
139 if (::WriteFile(h, buf, static_cast<DWORD>(count), &wsize, nullptr)) {
140 return wsize;
141 } else {
142 return -1;
143 }
144 #else
145 return WriteAll(h, buf, count);
146 #endif
147 }
148
FlushFile(int fd)149 bool FlushFile(int fd) {
150 PERFETTO_DCHECK(fd != 0);
151 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
152 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
153 return !PERFETTO_EINTR(fdatasync(fd));
154 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
155 return !PERFETTO_EINTR(_commit(fd));
156 #else
157 return !PERFETTO_EINTR(fsync(fd));
158 #endif
159 }
160
Mkdir(const std::string & path)161 bool Mkdir(const std::string& path) {
162 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
163 return _mkdir(path.c_str()) == 0;
164 #else
165 return mkdir(path.c_str(), 0755) == 0;
166 #endif
167 }
168
Rmdir(const std::string & path)169 bool Rmdir(const std::string& path) {
170 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
171 return _rmdir(path.c_str()) == 0;
172 #else
173 return rmdir(path.c_str()) == 0;
174 #endif
175 }
176
CloseFile(int fd)177 int CloseFile(int fd) {
178 return close(fd);
179 }
180
OpenFile(const std::string & path,int flags,FileOpenMode mode)181 ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode mode) {
182 PERFETTO_DCHECK((flags & O_CREAT) == 0 || mode != kFileModeInvalid);
183 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
184 // Always use O_BINARY on Windows, to avoid silly EOL translations.
185 ScopedFile fd(_open(path.c_str(), flags | O_BINARY, mode));
186 #else
187 // Always open a ScopedFile with O_CLOEXEC so we can safely fork and exec.
188 ScopedFile fd(open(path.c_str(), flags | O_CLOEXEC, mode));
189 #endif
190 return fd;
191 }
192
FileExists(const std::string & path)193 bool FileExists(const std::string& path) {
194 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
195 return _access(path.c_str(), 0) == 0;
196 #else
197 return access(path.c_str(), F_OK) == 0;
198 #endif
199 }
200
201 // Declared in base/platform_handle.h.
ClosePlatformHandle(PlatformHandle handle)202 int ClosePlatformHandle(PlatformHandle handle) {
203 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
204 // Make the return value UNIX-style.
205 return CloseHandle(handle) ? 0 : -1;
206 #else
207 return close(handle);
208 #endif
209 }
210
211 } // namespace base
212 } // namespace perfetto
213