Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
file_posix.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/fml/file.h"
6
7#include <dirent.h>
8#include <fcntl.h>
9#include <sys/mman.h>
10#include <sys/stat.h>
11#include <unistd.h>
12
13#include <cstring>
14#include <memory>
15#include <sstream>
16
17#include "flutter/fml/eintr_wrapper.h"
18#include "flutter/fml/logging.h"
19#include "flutter/fml/mapping.h"
20#include "flutter/fml/trace_event.h"
21#include "flutter/fml/unique_fd.h"
22
23namespace fml {
24
26 char directory_name[] = "/tmp/flutter_XXXXXXXX";
27 auto* result = ::mkdtemp(directory_name);
28 if (result == nullptr) {
29 return "";
30 }
31 return {result};
32}
33
34static int ToPosixAccessFlags(FilePermission permission) {
35 int flags = 0;
36 switch (permission) {
38 flags |= O_RDONLY; // read only
39 break;
41 flags |= O_WRONLY; // write only
42 break;
44 flags |= O_RDWR; // read-write
45 break;
46 }
47 return flags;
48}
49
50static int ToPosixCreateModeFlags(FilePermission permission) {
51 int mode = 0;
52 switch (permission) {
54 mode |= S_IRUSR;
55 break;
57 mode |= S_IWUSR;
58 break;
60 mode |= S_IRUSR | S_IWUSR;
61 break;
62 }
63 return mode;
64}
65
66fml::UniqueFD OpenFile(const char* path,
67 bool create_if_necessary,
68 FilePermission permission) {
69 return OpenFile(fml::UniqueFD{AT_FDCWD}, path, create_if_necessary,
70 permission);
71}
72
73fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory,
74 const char* path,
75 bool create_if_necessary,
76 FilePermission permission) {
77 TRACE_EVENT0("flutter", "fml::OpenFile");
78 if (path == nullptr) {
79 return {};
80 }
81
82 int flags = 0;
83 int mode = 0;
84
85 if (create_if_necessary && !FileExists(base_directory, path)) {
86 flags = ToPosixAccessFlags(permission) | O_CREAT | O_TRUNC;
87 mode = ToPosixCreateModeFlags(permission);
88 } else {
89 flags = ToPosixAccessFlags(permission);
90 mode = 0; // Not creating since it already exists.
91 }
92
93 return fml::UniqueFD{
94 FML_HANDLE_EINTR(::openat(base_directory.get(), path, flags, mode))};
95}
96
98 bool create_if_necessary,
99 FilePermission permission) {
100 return OpenDirectory(fml::UniqueFD{AT_FDCWD}, path, create_if_necessary,
101 permission);
102}
103
105 const char* path,
106 bool create_if_necessary,
107 FilePermission permission) {
108 if (path == nullptr) {
109 return {};
110 }
111
112 if (create_if_necessary && !FileExists(base_directory, path)) {
113 if (::mkdirat(base_directory.get(), path,
114 ToPosixCreateModeFlags(permission) | S_IXUSR) != 0) {
115 return {};
116 }
117 }
118
120 ::openat(base_directory.get(), path, O_RDONLY | O_DIRECTORY))};
121}
122
124 return fml::UniqueFD{FML_HANDLE_EINTR(::dup(descriptor))};
125}
126
127bool IsDirectory(const fml::UniqueFD& directory) {
128 if (!directory.is_valid()) {
129 return false;
130 }
131
132 struct stat stat_result = {};
133
134 if (::fstat(directory.get(), &stat_result) != 0) {
135 return false;
136 }
137
138 return S_ISDIR(stat_result.st_mode);
139}
140
141bool IsDirectory(const fml::UniqueFD& base_directory, const char* path) {
142 UniqueFD file = OpenFileReadOnly(base_directory, path);
143 return (file.is_valid() && IsDirectory(file));
144}
145
146bool IsFile(const std::string& path) {
147 struct stat buf;
148 if (stat(path.c_str(), &buf) != 0) {
149 return false;
150 }
151
152 return S_ISREG(buf.st_mode);
153}
154
155bool TruncateFile(const fml::UniqueFD& file, size_t size) {
156 if (!file.is_valid()) {
157 return false;
158 }
159
160 return ::ftruncate(file.get(), size) == 0;
161}
162
163bool UnlinkDirectory(const char* path) {
164 return UnlinkDirectory(fml::UniqueFD{AT_FDCWD}, path);
165}
166
167bool UnlinkDirectory(const fml::UniqueFD& base_directory, const char* path) {
168 return ::unlinkat(base_directory.get(), path, AT_REMOVEDIR) == 0;
169}
170
171bool UnlinkFile(const char* path) {
172 return UnlinkFile(fml::UniqueFD{AT_FDCWD}, path);
173}
174
175bool UnlinkFile(const fml::UniqueFD& base_directory, const char* path) {
176 int code = ::unlinkat(base_directory.get(), path, 0);
177 if (code != 0) {
178 FML_DLOG(ERROR) << strerror(errno);
179 }
180 return code == 0;
181}
182
183bool FileExists(const fml::UniqueFD& base_directory, const char* path) {
184 if (!base_directory.is_valid()) {
185 return false;
186 }
187
188 return ::faccessat(base_directory.get(), path, F_OK, 0) == 0;
189}
190
191bool WriteAtomically(const fml::UniqueFD& base_directory,
192 const char* file_name,
193 const Mapping& data) {
194 if (file_name == nullptr || data.GetMapping() == nullptr) {
195 return false;
196 }
197
198 std::stringstream stream;
199 stream << file_name << ".temp";
200 const auto temp_file_name = stream.str();
201
202 auto temp_file = OpenFile(base_directory, temp_file_name.c_str(), true,
204 if (!temp_file.is_valid()) {
205 return false;
206 }
207
208 if (!TruncateFile(temp_file, data.GetSize())) {
209 return false;
210 }
211
212 ssize_t remaining = data.GetSize();
213 ssize_t written = 0;
214 ssize_t offset = 0;
215
216 while (remaining > 0) {
217 written = FML_HANDLE_EINTR(
218 ::write(temp_file.get(), data.GetMapping() + offset, remaining));
219
220 if (written == -1) {
221 return false;
222 }
223
224 remaining -= written;
225 offset += written;
226 }
227
228 if (::fsync(temp_file.get()) != 0) {
229 return false;
230 }
231
232 return ::renameat(base_directory.get(), temp_file_name.c_str(),
233 base_directory.get(), file_name) == 0;
234}
235
236bool VisitFiles(const fml::UniqueFD& directory, const FileVisitor& visitor) {
237 fml::UniqueFD dup_fd(dup(directory.get()));
238 if (!dup_fd.is_valid()) {
239 FML_DLOG(ERROR) << "Can't dup the directory fd. Error: " << strerror(errno);
240 return true; // continue to visit other files
241 }
242
243 fml::UniqueDir dir(::fdopendir(dup_fd.get()));
244 if (!dir.is_valid()) {
245 FML_DLOG(ERROR) << "Can't open the directory. Error: " << strerror(errno);
246 return true; // continue to visit other files
247 }
248
249 // The directory fd will be closed by `closedir`.
250 (void)dup_fd.release();
251
252 // Without `rewinddir`, `readir` will directly return NULL (end of dir is
253 // reached) after a previuos `VisitFiles` call for the same `const
254 // fml::UniqueFd& directory`.
255 rewinddir(dir.get());
256 while (dirent* ent = readdir(dir.get())) {
257 std::string filename = ent->d_name;
258 if (filename != "." && filename != "..") {
259 if (!visitor(directory, filename)) {
260 return false;
261 }
262 }
263 }
264
265 return true;
266}
267
268} // namespace fml
bool is_valid() const
const T & get() const
FlutterSemanticsFlag flags
GAsyncResult * result
#define FML_HANDLE_EINTR(x)
#define FML_DLOG(severity)
Definition logging.h:102
fml::UniqueFD OpenFileReadOnly(const fml::UniqueFD &base_directory, const char *path)
Definition file.cc:92
bool VisitFiles(const fml::UniqueFD &directory, const FileVisitor &visitor)
static int ToPosixCreateModeFlags(FilePermission permission)
Definition file_posix.cc:50
constexpr std::size_t size(T(&array)[N])
Definition size.h:13
bool WriteAtomically(const fml::UniqueFD &base_directory, const char *file_name, const Mapping &mapping)
fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor)
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
Definition file_posix.cc:97
bool IsFile(const std::string &path)
static int ToPosixAccessFlags(FilePermission permission)
Definition file_posix.cc:34
std::string CreateTemporaryDirectory()
Definition file_posix.cc:25
bool UnlinkDirectory(const char *path)
bool TruncateFile(const fml::UniqueFD &file, size_t size)
bool FileExists(const fml::UniqueFD &base_directory, const char *path)
bool UnlinkFile(const char *path)
fml::UniqueFD OpenFile(const char *path, bool create_if_necessary, FilePermission permission)
This can open a directory on POSIX, but not on Windows.
Definition file_posix.cc:66
FilePermission
Definition file.h:24
std::function< bool(const fml::UniqueFD &directory, const std::string &filename)> FileVisitor
Definition file.h:98
bool IsDirectory(const fml::UniqueFD &directory)
void write(SkWStream *wStream, const T &text)
Definition skqp.cpp:188
Point offset
#define ERROR(message)
#define TRACE_EVENT0(category_group, name)