Flutter Engine
The Flutter Engine
file_fuchsia.cc
Go to the documentation of this file.
1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(DART_HOST_OS_FUCHSIA)
7
8#include "bin/file.h"
9
10#include <errno.h> // NOLINT
11#include <fcntl.h> // NOLINT
12#include <lib/fdio/fdio.h> // NOLINT
13#include <lib/fdio/namespace.h> // NOLINT
14#include <libgen.h> // NOLINT
15#include <sys/mman.h> // NOLINT
16#include <sys/stat.h> // NOLINT
17#include <sys/types.h> // NOLINT
18#include <unistd.h> // NOLINT
19#include <utime.h> // NOLINT
20
21#include "bin/builtin.h"
22#include "bin/fdutils.h"
23#include "bin/namespace.h"
25#include "platform/syslog.h"
26#include "platform/utils.h"
27
28namespace dart {
29namespace bin {
30
31class FileHandle {
32 public:
33 explicit FileHandle(int fd) : fd_(fd) {}
34 ~FileHandle() {}
35 int fd() const { return fd_; }
36 void set_fd(int fd) { fd_ = fd; }
37
38 private:
39 int fd_;
40
41 DISALLOW_COPY_AND_ASSIGN(FileHandle);
42};
43
44File::~File() {
45 if (!IsClosed() && (handle_->fd() != STDOUT_FILENO) &&
46 (handle_->fd() != STDERR_FILENO)) {
47 Close();
48 }
49 delete handle_;
50}
51
52void File::Close() {
53 ASSERT(handle_->fd() >= 0);
54 if (handle_->fd() == STDOUT_FILENO) {
55 // If stdout, redirect fd to Fuchsia's equivalent of /dev/null.
56 auto* null_fdio = fdio_null_create();
57 ASSERT(null_fdio != nullptr);
58 int null_fd = NO_RETRY_EXPECTED(fdio_bind_to_fd(null_fdio, -1, 0));
59 ASSERT(null_fd >= 0);
60 VOID_NO_RETRY_EXPECTED(dup2(null_fd, handle_->fd()));
61 VOID_NO_RETRY_EXPECTED(close(null_fd));
62 } else {
63 int err = NO_RETRY_EXPECTED(close(handle_->fd()));
64 if (err != 0) {
65 const int kBufferSize = 1024;
66 char error_buf[kBufferSize];
67 Syslog::PrintErr("%s\n", Utils::StrError(errno, error_buf, kBufferSize));
68 }
69 }
70 handle_->set_fd(kClosedFd);
71}
72
73intptr_t File::GetFD() {
74 return handle_->fd();
75}
76
77bool File::IsClosed() {
78 return handle_->fd() == kClosedFd;
79}
80
81MappedMemory* File::Map(MapType type,
82 int64_t position,
83 int64_t length,
84 void* start) {
85 ASSERT(handle_->fd() >= 0);
86 ASSERT(length > 0);
87 void* hint = nullptr;
88 int prot = PROT_NONE;
89 int flags = MAP_PRIVATE;
90 switch (type) {
91 case kReadOnly:
92 prot = PROT_READ;
93 break;
94 case kReadExecute:
95 // Try to allocate near the VM's binary.
96 hint = reinterpret_cast<void*>(&Dart_Initialize);
97 prot = PROT_READ | PROT_EXEC;
98 break;
99 case kReadWrite:
100 prot = PROT_READ | PROT_WRITE;
101 break;
102 }
103 if (start != nullptr) {
104 hint = start;
105 flags |= MAP_FIXED;
106 }
107 void* addr = mmap(hint, length, prot, flags, handle_->fd(), position);
108 if (addr == MAP_FAILED) {
109 return nullptr;
110 }
111 return new MappedMemory(addr, length, /*should_unmap=*/start == nullptr);
112}
113
114void MappedMemory::Unmap() {
115 int result = munmap(address_, size_);
116 ASSERT(result == 0);
117 address_ = nullptr;
118 size_ = 0;
119}
120
121int64_t File::Read(void* buffer, int64_t num_bytes) {
122 ASSERT(handle_->fd() >= 0);
123 return NO_RETRY_EXPECTED(read(handle_->fd(), buffer, num_bytes));
124}
125
126int64_t File::Write(const void* buffer, int64_t num_bytes) {
127 ASSERT(handle_->fd() >= 0);
128 return NO_RETRY_EXPECTED(write(handle_->fd(), buffer, num_bytes));
129}
130
131bool File::VPrint(const char* format, va_list args) {
132 // Measure.
133 va_list measure_args;
134 va_copy(measure_args, args);
135 intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
136 va_end(measure_args);
137
138 char* buffer = reinterpret_cast<char*>(malloc(len + 1));
139
140 // Print.
141 va_list print_args;
142 va_copy(print_args, args);
143 Utils::VSNPrint(buffer, len + 1, format, print_args);
144 va_end(print_args);
145
146 bool result = WriteFully(buffer, len);
147 free(buffer);
148 return result;
149}
150
151int64_t File::Position() {
152 ASSERT(handle_->fd() >= 0);
153 return NO_RETRY_EXPECTED(lseek(handle_->fd(), 0, SEEK_CUR));
154}
155
156bool File::SetPosition(int64_t position) {
157 ASSERT(handle_->fd() >= 0);
158 return NO_RETRY_EXPECTED(lseek(handle_->fd(), position, SEEK_SET)) >= 0;
159}
160
161bool File::Truncate(int64_t length) {
162 ASSERT(handle_->fd() >= 0);
163 return NO_RETRY_EXPECTED(ftruncate(handle_->fd(), length) != -1);
164}
165
166bool File::Flush() {
167 ASSERT(handle_->fd() >= 0);
168 return NO_RETRY_EXPECTED(fsync(handle_->fd())) != -1;
169}
170
171bool File::Lock(File::LockType lock, int64_t start, int64_t end) {
172 ASSERT(handle_->fd() >= 0);
173 ASSERT((end == -1) || (end > start));
174 struct flock fl;
175 switch (lock) {
177 fl.l_type = F_UNLCK;
178 break;
181 fl.l_type = F_RDLCK;
182 break;
185 fl.l_type = F_WRLCK;
186 break;
187 default:
188 return false;
189 }
190 fl.l_whence = SEEK_SET;
191 fl.l_start = start;
192 fl.l_len = end == -1 ? 0 : end - start;
193 int cmd = F_SETLK;
194 if ((lock == File::kLockBlockingShared) ||
196 cmd = F_SETLKW;
197 }
198 return NO_RETRY_EXPECTED(fcntl(handle_->fd(), cmd, &fl)) != -1;
199}
200
201int64_t File::Length() {
202 ASSERT(handle_->fd() >= 0);
203 struct stat st;
204 if (NO_RETRY_EXPECTED(fstat(handle_->fd(), &st)) == 0) {
205 return st.st_size;
206 }
207 return -1;
208}
209
210File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) {
211 UNREACHABLE();
212 return nullptr;
213}
214
215File* File::OpenFD(int fd) {
216 return new File(new FileHandle(fd));
217}
218
219File* File::Open(Namespace* namespc, const char* name, FileOpenMode mode) {
220 NamespaceScope ns(namespc, name);
221 // Report errors for non-regular files.
222 struct stat st;
223 if (NO_RETRY_EXPECTED(fstatat(ns.fd(), ns.path(), &st, 0)) == 0) {
224 if (S_ISDIR(st.st_mode)) {
225 errno = EISDIR;
226 return nullptr;
227 }
228 }
229 int flags = O_RDONLY;
230 if ((mode & kWrite) != 0) {
231 ASSERT((mode & kWriteOnly) == 0);
232 flags = (O_RDWR | O_CREAT);
233 }
234 if ((mode & kWriteOnly) != 0) {
235 ASSERT((mode & kWrite) == 0);
236 flags = (O_WRONLY | O_CREAT);
237 }
238 if ((mode & kTruncate) != 0) {
239 flags = flags | O_TRUNC;
240 }
241 flags |= O_CLOEXEC;
242 int fd = NO_RETRY_EXPECTED(openat(ns.fd(), ns.path(), flags, 0666));
243 if (fd < 0) {
244 return nullptr;
245 }
246 if ((((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) ||
247 (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) {
248 int64_t position = lseek(fd, 0, SEEK_END);
249 if (position < 0) {
250 return nullptr;
251 }
252 }
253 return OpenFD(fd);
254}
255
256CStringUniquePtr File::UriToPath(const char* uri) {
257 const char* path =
258 (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0) ? uri + 7 : uri;
259 UriDecoder uri_decoder(path);
260 if (uri_decoder.decoded() == nullptr) {
261 errno = EINVAL;
262 return CStringUniquePtr(nullptr);
263 }
264 return CStringUniquePtr(strdup(uri_decoder.decoded()));
265}
266
267File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
268 auto path = UriToPath(uri);
269 if (path == nullptr) {
270 return nullptr;
271 }
272 return File::Open(namespc, path.get(), mode);
273}
274
275File* File::OpenStdio(int fd) {
276 return new File(new FileHandle(fd));
277}
278
279bool File::Exists(Namespace* namespc, const char* name) {
280 NamespaceScope ns(namespc, name);
281 struct stat st;
282 if (NO_RETRY_EXPECTED(fstatat(ns.fd(), ns.path(), &st, 0)) == 0) {
283 // Everything but a directory and a link is a file to Dart.
284 return !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode);
285 }
286 return false;
287}
288
289bool File::ExistsUri(Namespace* namespc, const char* uri) {
290 auto path = UriToPath(uri);
291 if (path == nullptr) {
292 return false;
293 }
294 return File::Exists(namespc, path.get());
295}
296
297bool File::Create(Namespace* namespc, const char* name, bool exclusive) {
298 NamespaceScope ns(namespc, name);
299 int flags = O_RDONLY | O_CREAT | O_CLOEXEC;
300 if (exclusive) {
301 flags |= O_EXCL;
302 }
303 const int fd = NO_RETRY_EXPECTED(openat(ns.fd(), ns.path(), flags, 0666));
304 if (fd < 0) {
305 Syslog::PrintErr("File::Create() openat(%ld, %s) failed: %s\n", ns.fd(),
306 ns.path(), strerror(errno));
307 return false;
308 }
309 // File.create returns a File, so we shouldn't be giving the illusion that the
310 // call has created a file or that a file already exists if there is already
311 // an entity at the same path that is a directory or a link.
312 bool is_file = false;
313 struct stat st;
314 if (NO_RETRY_EXPECTED(fstat(fd, &st)) == 0) {
315 is_file = true;
316 if (S_ISDIR(st.st_mode)) {
317 errno = EISDIR;
318 is_file = false;
319 } else if (S_ISLNK(st.st_mode)) {
320 errno = ENOENT;
321 is_file = false;
322 }
323 }
325 return is_file;
326}
327
328bool File::CreateLink(Namespace* namespc,
329 const char* name,
330 const char* target) {
331 NamespaceScope ns(namespc, name);
332 return NO_RETRY_EXPECTED(symlinkat(target, ns.fd(), ns.path())) == 0;
333}
334
335bool File::CreatePipe(Namespace* namespc, File** readPipe, File** writePipe) {
336 int pipe_fds[2];
337 int status = NO_RETRY_EXPECTED(pipe(pipe_fds));
338 if (status != 0) {
339 return false;
340 }
341 *readPipe = OpenFD(pipe_fds[0]);
342 *writePipe = OpenFD(pipe_fds[1]);
343 return true;
344}
345
346File::Type File::GetType(Namespace* namespc,
347 const char* name,
348 bool follow_links) {
349 NamespaceScope ns(namespc, name);
350 struct stat entry_info;
351 int stat_success;
352 if (follow_links) {
353 stat_success =
354 TEMP_FAILURE_RETRY(fstatat(ns.fd(), ns.path(), &entry_info, 0));
355 } else {
356 stat_success = TEMP_FAILURE_RETRY(
357 fstatat(ns.fd(), ns.path(), &entry_info, AT_SYMLINK_NOFOLLOW));
358 }
359 if (stat_success == -1) {
360 return File::kDoesNotExist;
361 }
362 if (S_ISDIR(entry_info.st_mode)) {
363 return File::kIsDirectory;
364 }
365 if (S_ISREG(entry_info.st_mode)) {
366 return File::kIsFile;
367 }
368 if (S_ISLNK(entry_info.st_mode)) {
369 return File::kIsLink;
370 }
371 if (S_ISSOCK(entry_info.st_mode)) {
372 return File::kIsSock;
373 }
374 if (S_ISFIFO(entry_info.st_mode)) {
375 return File::kIsPipe;
376 }
377 return File::kDoesNotExist;
378}
379
380static void SetErrno(File::Type type) {
381 switch (type) {
383 errno = EISDIR;
384 break;
386 errno = ENOENT;
387 break;
388 default:
389 errno = EINVAL;
390 break;
391 }
392}
393
394static bool CheckTypeAndSetErrno(Namespace* namespc,
395 const char* name,
396 File::Type expected,
397 bool follow_links) {
398 File::Type actual = File::GetType(namespc, name, follow_links);
399 if (actual == expected) {
400 return true;
401 }
402 SetErrno(actual);
403 return false;
404}
405
406bool File::Delete(Namespace* namespc, const char* name) {
407 File::Type type = File::GetType(namespc, name, true);
408 if (type == kIsFile || type == kIsSock || type == kIsPipe) {
409 NamespaceScope ns(namespc, name);
410 return (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0);
411 }
412 SetErrno(type);
413 return false;
414}
415
416bool File::DeleteLink(Namespace* namespc, const char* name) {
417 NamespaceScope ns(namespc, name);
418 return CheckTypeAndSetErrno(namespc, name, kIsLink, false) &&
419 (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0);
420}
421
422bool File::Rename(Namespace* namespc,
423 const char* old_path,
424 const char* new_path) {
425 File::Type type = File::GetType(namespc, old_path, true);
426 if (type == kIsFile || type == kIsSock || type == kIsPipe) {
427 NamespaceScope oldns(namespc, old_path);
428 NamespaceScope newns(namespc, new_path);
429 return (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
430 newns.path())) == 0);
431 }
432 SetErrno(type);
433 return false;
434}
435
436bool File::RenameLink(Namespace* namespc,
437 const char* old_path,
438 const char* new_path) {
439 NamespaceScope oldns(namespc, old_path);
440 NamespaceScope newns(namespc, new_path);
441 return CheckTypeAndSetErrno(namespc, old_path, kIsLink, false) &&
442 (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
443 newns.path())) == 0);
444}
445
446bool File::Copy(Namespace* namespc,
447 const char* old_path,
448 const char* new_path) {
449 File::Type type = File::GetType(namespc, old_path, true);
450 if (type != kIsFile && type != kIsSock && type != kIsPipe) {
451 SetErrno(type);
452 return false;
453 }
454 NamespaceScope oldns(namespc, old_path);
455 struct stat st;
456 if (NO_RETRY_EXPECTED(fstatat(oldns.fd(), oldns.path(), &st, 0)) != 0) {
457 return false;
458 }
459 const int old_fd =
460 NO_RETRY_EXPECTED(openat(oldns.fd(), oldns.path(), O_RDONLY | O_CLOEXEC));
461 if (old_fd < 0) {
462 return false;
463 }
464 NamespaceScope newns(namespc, new_path);
465 const int new_fd = NO_RETRY_EXPECTED(
466 openat(newns.fd(), newns.path(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC,
467 st.st_mode));
468 if (new_fd < 0) {
469 close(old_fd);
470 return false;
471 }
472 // TODO(ZX-429): Use sendfile/copyfile or equivalent when there is one.
473 intptr_t result;
474 const intptr_t kBufferSize = 8 * KB;
475 uint8_t* buffer = reinterpret_cast<uint8_t*>(malloc(kBufferSize));
476 while ((result = NO_RETRY_EXPECTED(read(old_fd, buffer, kBufferSize))) > 0) {
477 int wrote = NO_RETRY_EXPECTED(write(new_fd, buffer, result));
478 if (wrote != result) {
479 result = -1;
480 break;
481 }
482 }
483 free(buffer);
486 if (result < 0) {
487 int e = errno;
488 VOID_NO_RETRY_EXPECTED(unlinkat(newns.fd(), newns.path(), 0));
489 errno = e;
490 return false;
491 }
492 return true;
493}
494
495static bool StatHelper(Namespace* namespc, const char* name, struct stat* st) {
496 NamespaceScope ns(namespc, name);
497 if (NO_RETRY_EXPECTED(fstatat(ns.fd(), ns.path(), st, 0)) != 0) {
498 return false;
499 }
500 // Signal an error if it's a directory.
501 if (S_ISDIR(st->st_mode)) {
502 errno = EISDIR;
503 return false;
504 }
505 // Otherwise assume the caller knows what it's doing.
506 return true;
507}
508
509int64_t File::LengthFromPath(Namespace* namespc, const char* name) {
510 struct stat st;
511 if (!StatHelper(namespc, name, &st)) {
512 return -1;
513 }
514 return st.st_size;
515}
516
517static int64_t TimespecToMilliseconds(const struct timespec& t) {
518 return static_cast<int64_t>(t.tv_sec) * 1000L +
519 static_cast<int64_t>(t.tv_nsec) / 1000000L;
520}
521
522static void MillisecondsToTimespec(int64_t millis, struct timespec* t) {
523 ASSERT(t != nullptr);
524 t->tv_sec = millis / kMillisecondsPerSecond;
525 t->tv_nsec = (millis % kMillisecondsPerSecond) * 1000L;
526}
527
528void File::Stat(Namespace* namespc, const char* name, int64_t* data) {
529 NamespaceScope ns(namespc, name);
530 struct stat st;
531 if (TEMP_FAILURE_RETRY(fstatat(ns.fd(), ns.path(), &st, 0)) == 0) {
532 if (S_ISREG(st.st_mode)) {
533 data[kType] = kIsFile;
534 } else if (S_ISDIR(st.st_mode)) {
536 } else if (S_ISLNK(st.st_mode)) {
537 data[kType] = kIsLink;
538 } else if (S_ISSOCK(st.st_mode)) {
539 data[kType] = kIsSock;
540 } else if (S_ISFIFO(st.st_mode)) {
541 data[kType] = kIsPipe;
542 } else {
544 }
545 data[kCreatedTime] = TimespecToMilliseconds(st.st_ctim);
546 data[kModifiedTime] = TimespecToMilliseconds(st.st_mtim);
547 data[kAccessedTime] = TimespecToMilliseconds(st.st_atim);
548 data[kMode] = st.st_mode;
549 data[kSize] = st.st_size;
550 } else {
552 }
553}
554
555time_t File::LastModified(Namespace* namespc, const char* name) {
556 struct stat st;
557 if (!StatHelper(namespc, name, &st)) {
558 return -1;
559 }
560 return st.st_mtime;
561}
562
563time_t File::LastAccessed(Namespace* namespc, const char* name) {
564 struct stat st;
565 if (!StatHelper(namespc, name, &st)) {
566 return -1;
567 }
568 return st.st_atime;
569}
570
571bool File::SetLastAccessed(Namespace* namespc,
572 const char* name,
573 int64_t millis) {
574 // First get the current times.
575 struct stat st;
576 if (!StatHelper(namespc, name, &st)) {
577 return false;
578 }
579
580 // Set the new time:
581 NamespaceScope ns(namespc, name);
582 struct timespec times[2];
583 MillisecondsToTimespec(millis, &times[0]);
584 times[1] = st.st_mtim;
585 return utimensat(ns.fd(), ns.path(), times, 0) == 0;
586}
587
588bool File::SetLastModified(Namespace* namespc,
589 const char* name,
590 int64_t millis) {
591 // First get the current times.
592 struct stat st;
593 if (!StatHelper(namespc, name, &st)) {
594 return false;
595 }
596
597 // Set the new time:
598 NamespaceScope ns(namespc, name);
599 struct timespec times[2];
600 times[0] = st.st_atim;
601 MillisecondsToTimespec(millis, &times[1]);
602 return utimensat(ns.fd(), ns.path(), times, 0) == 0;
603}
604
605const char* File::LinkTarget(Namespace* namespc,
606 const char* name,
607 char* dest,
608 int dest_size) {
609 NamespaceScope ns(namespc, name);
610 struct stat link_stats;
611 const int status = TEMP_FAILURE_RETRY(
612 fstatat(ns.fd(), ns.path(), &link_stats, AT_SYMLINK_NOFOLLOW));
613 if (status != 0) {
614 return nullptr;
615 }
616 if (!S_ISLNK(link_stats.st_mode)) {
617 errno = ENOENT;
618 return nullptr;
619 }
620 // Don't rely on the link_stats.st_size for the size of the link
621 // target. For some filesystems, e.g. procfs, this value is always
622 // 0. Also the link might have changed before the readlink call.
623 const int kBufferSize = PATH_MAX + 1;
624 char target[kBufferSize];
625 const int target_size =
626 TEMP_FAILURE_RETRY(readlinkat(ns.fd(), ns.path(), target, kBufferSize));
627 if (target_size <= 0) {
628 return nullptr;
629 }
630 if (dest == nullptr) {
631 dest = DartUtils::ScopedCString(target_size + 1);
632 } else {
633 ASSERT(dest_size > 0);
634 if (dest_size <= target_size) {
635 return nullptr;
636 }
637 }
638 memmove(dest, target, target_size);
639 dest[target_size] = '\0';
640 return dest;
641}
642
643bool File::IsAbsolutePath(const char* pathname) {
644 return ((pathname != nullptr) && (pathname[0] == '/'));
645}
646
647const char* File::GetCanonicalPath(Namespace* namespc,
648 const char* name,
649 char* dest,
650 int dest_size) {
651 if (name == nullptr) {
652 return nullptr;
653 }
654 if (!Namespace::IsDefault(namespc)) {
655 // TODO(zra): There is no realpathat(). Also chasing a symlink might result
656 // in a path to something outside of the namespace, so canonicalizing paths
657 // would have to be done carefully. For now, don't do anything.
658 return name;
659 }
660 char* abs_path;
661 if (dest == nullptr) {
663 } else {
664 ASSERT(dest_size >= PATH_MAX);
665 }
666 ASSERT(dest != nullptr);
667 do {
668 abs_path = realpath(name, dest);
669 } while ((abs_path == nullptr) && (errno == EINTR));
670 ASSERT(abs_path == nullptr || IsAbsolutePath(abs_path));
671 ASSERT(abs_path == nullptr || (abs_path == dest));
672 return abs_path;
673}
674
675const char* File::PathSeparator() {
676 return "/";
677}
678
680 return "/";
681}
682
683static int fd_is_valid(int fd) {
684 return NO_RETRY_EXPECTED(fcntl(fd, F_GETFD)) != -1 || errno != EBADF;
685}
686
688 struct stat buf;
689 int result = TEMP_FAILURE_RETRY(fstat(fd, &buf));
690 if (result == -1) {
691 // fstat() on fds 0, 1, 2 on Fuchsia return -1 with errno ENOTSUP,
692 // but if they are opened, then we can read/write them, so pretend they
693 // are kPipe.
694 return ((errno == ENOTSUP) && fd_is_valid(fd)) ? kPipe : kTypeError;
695 }
696 if (S_ISCHR(buf.st_mode)) {
697 return kTerminal;
698 }
699 if (S_ISFIFO(buf.st_mode)) {
700 return kPipe;
701 }
702 if (S_ISSOCK(buf.st_mode)) {
703 return kSocket;
704 }
705 if (S_ISREG(buf.st_mode)) {
706 return kFile;
707 }
708 return kOther;
709}
710
711File::Identical File::AreIdentical(Namespace* namespc_1,
712 const char* file_1,
713 Namespace* namespc_2,
714 const char* file_2) {
715 struct stat file_1_info;
716 struct stat file_2_info;
717 int status;
718 {
719 NamespaceScope ns1(namespc_1, file_1);
720 status = TEMP_FAILURE_RETRY(
721 fstatat(ns1.fd(), ns1.path(), &file_1_info, AT_SYMLINK_NOFOLLOW));
722 if (status == -1) {
723 return File::kError;
724 }
725 }
726 {
727 NamespaceScope ns2(namespc_2, file_2);
728 status = TEMP_FAILURE_RETRY(
729 fstatat(ns2.fd(), ns2.path(), &file_2_info, AT_SYMLINK_NOFOLLOW));
730 if (status == -1) {
731 return File::kError;
732 }
733 }
734 return ((file_1_info.st_ino == file_2_info.st_ino) &&
735 (file_1_info.st_dev == file_2_info.st_dev))
738}
739
740} // namespace bin
741} // namespace dart
742
743#endif // defined(DART_HOST_OS_FUCHSIA)
static SkISize times(const SkISize &size, float factor)
static bool read(SkStream *stream, void *buffer, size_t amount)
static const size_t kBufferSize
Definition: SkString.cpp:27
#define UNREACHABLE()
Definition: assert.h:248
GLenum type
static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
static char * StrError(int err, char *buffer, size_t bufsize)
Definition: utils_android.h:40
static char * ScopedCString(intptr_t length)
Definition: dartutils.h:224
static void SaveErrorAndClose(intptr_t fd)
FileHandle(HANDLE handle)
static bool CreatePipe(Namespace *namespc, File **readPipe, File **writePipe)
static bool DeleteLink(Namespace *namespc, const char *path)
static bool IsAbsolutePath(const char *path)
MappedMemory * Map(MapType type, int64_t position, int64_t length, void *start=nullptr)
static const char * GetCanonicalPath(Namespace *namespc, const char *path, char *dest=nullptr, int dest_size=0)
static CStringUniquePtr UriToPath(const char *uri)
@ kModifiedTime
Definition: file.h:100
@ kCreatedTime
Definition: file.h:99
@ kAccessedTime
Definition: file.h:101
int64_t Position()
int64_t Read(void *buffer, int64_t num_bytes)
static bool SetLastAccessed(Namespace *namespc, const char *path, int64_t millis)
static File * OpenUri(Namespace *namespc, const char *uri, FileOpenMode mode)
@ kIsDirectory
Definition: file.h:77
@ kDoesNotExist
Definition: file.h:81
static bool SetLastModified(Namespace *namespc, const char *path, int64_t millis)
static time_t LastModified(Namespace *namespc, const char *path)
static void Stat(Namespace *namespc, const char *path, int64_t *data)
static const char * PathSeparator()
static bool Create(Namespace *namespc, const char *path, bool exclusive)
bool VPrint(const char *format, va_list args)
static bool Rename(Namespace *namespc, const char *old_path, const char *new_path)
static bool Delete(Namespace *namespc, const char *path)
static const char * StringEscapedPathSeparator()
@ kDifferent
Definition: file.h:84
@ kIdentical
Definition: file.h:84
bool WriteFully(const void *buffer, int64_t num_bytes)
Definition: file_support.cc:55
static int64_t LengthFromPath(Namespace *namespc, const char *path)
@ kReadExecute
Definition: file.h:122
static bool Copy(Namespace *namespc, const char *old_path, const char *new_path)
static time_t LastAccessed(Namespace *namespc, const char *path)
intptr_t GetFD()
bool result
Definition: file.h:170
int64_t Write(const void *buffer, int64_t num_bytes)
static bool Exists(Namespace *namespc, const char *path)
static File * Open(Namespace *namespc, const char *path, FileOpenMode mode)
bool Lock(LockType lock, int64_t start, int64_t end)
@ kTypeError
Definition: file.h:93
bool SetPosition(int64_t position)
static Identical AreIdentical(Namespace *namespc_1, const char *file_1, Namespace *namespc_2, const char *file_2)
int64_t Length()
static File * OpenFD(int fd)
static const char * LinkTarget(Namespace *namespc, const char *pathname, char *dest=nullptr, int dest_size=0)
@ kLockBlockingShared
Definition: file.h:113
@ kLockBlockingExclusive
Definition: file.h:114
@ kLockExclusive
Definition: file.h:112
static bool CreateLink(Namespace *namespc, const char *path, const char *target)
static bool ExistsUri(Namespace *namespc, const char *uri)
@ kWriteOnly
Definition: file.h:59
static File * OpenStdio(int fd)
static StdioHandleType GetStdioHandleType(int fd)
static Type GetType(Namespace *namespc, const char *path, bool follow_links)
bool Truncate(int64_t length)
static bool RenameLink(Namespace *namespc, const char *old_path, const char *new_path)
static bool IsDefault(Namespace *namespc)
Definition: namespace.cc:111
#define ASSERT(E)
FlutterSemanticsFlag flags
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
uint32_t uint32_t * format
uint32_t * target
size_t length
Definition: dart_vm.cc:33
const char *const name
CAllocUniquePtr< char > CStringUniquePtr
Definition: utils.h:31
void * malloc(size_t size)
Definition: allocation.cc:19
DART_EXPORT char * Dart_Initialize(Dart_InitializeParams *params)
constexpr intptr_t KB
Definition: globals.h:528
constexpr intptr_t kMillisecondsPerSecond
Definition: globals.h:560
static int8_t data[kExtLength]
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 buffer
Definition: switches.h:126
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
char * strdup(const char *str1)
dest
Definition: zip.py:79
#define PATH_MAX
Definition: globals.h:708
fuchsia::ui::composition::ParentViewportWatcherHandle handle_
#define NO_RETRY_EXPECTED(expression)
#define VOID_NO_RETRY_EXPECTED(expression)
#define TEMP_FAILURE_RETRY(expression)
void write(SkWStream *wStream, const T &text)
Definition: skqp.cpp:188