• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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