Flutter Engine
The Flutter Engine
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
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) {
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
Definition: unique_object.h:89
const T & get() const
Definition: unique_object.h:87
FlutterSemanticsFlag flags
GAsyncResult * result
#define FML_HANDLE_EINTR(x)
Definition: eintr_wrapper.h:20
#define FML_DLOG(severity)
Definition: logging.h:102
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
Definition: ascii_trie.cc:9
fml::UniqueFD OpenFileReadOnly(const fml::UniqueFD &base_directory, const char *path)
Definition: file.cc:92
bool VisitFiles(const fml::UniqueFD &directory, const FileVisitor &visitor)
Definition: file_posix.cc:236
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)
Definition: file_posix.cc:191
fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor)
Definition: file_posix.cc:123
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
Definition: file_posix.cc:97
bool IsFile(const std::string &path)
Definition: file_posix.cc:146
static int ToPosixAccessFlags(FilePermission permission)
Definition: file_posix.cc:34
std::string CreateTemporaryDirectory()
Definition: file_posix.cc:25
bool UnlinkDirectory(const char *path)
Definition: file_posix.cc:163
bool TruncateFile(const fml::UniqueFD &file, size_t size)
Definition: file_posix.cc:155
bool FileExists(const fml::UniqueFD &base_directory, const char *path)
Definition: file_posix.cc:183
bool UnlinkFile(const char *path)
Definition: file_posix.cc:171
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)
Definition: file_posix.cc:127
void write(SkWStream *wStream, const T &text)
Definition: skqp.cpp:188
SeparatedVector2 offset
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define ERROR(message)
Definition: elf_loader.cc:260
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131