Flutter Engine
The Flutter Engine
file_win.cc
Go to the documentation of this file.
1// Copyright (c) 2012, 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_WINDOWS)
7
8#include <functional>
9#include <memory>
10#include <utility>
11
12// clang-format off
13#include <Shlwapi.h> // NOLINT
14#include <fcntl.h> // NOLINT
15#include <io.h> // NOLINT
16#include <pathcch.h> // NOLINT
17#include <winioctl.h> // NOLINT
18#undef StrDup // defined in Shlwapi.h as StrDupW
19#include <stdio.h> // NOLINT
20#include <string.h> // NOLINT
21#include <sys/stat.h> // NOLINT
22#include <sys/utime.h> // NOLINT
23// clang-format on
24
25#include "bin/builtin.h"
26#include "bin/crypto.h"
27#include "bin/directory.h"
28#include "bin/file.h"
29#include "bin/file_win.h"
30#include "bin/namespace.h"
31#include "bin/utils.h"
32#include "bin/utils_win.h"
33#include "platform/syslog.h"
34#include "platform/utils.h"
35
36namespace dart {
37namespace bin {
38
39class FileHandle {
40 public:
41 explicit FileHandle(int fd) : fd_(fd) {}
42 ~FileHandle() {}
43 int fd() const { return fd_; }
44 void set_fd(int fd) { fd_ = fd; }
45
46 private:
47 int fd_;
48
49 DISALLOW_COPY_AND_ASSIGN(FileHandle);
50};
51
52File::~File() {
53 if (!IsClosed() && handle_->fd() != _fileno(stdout) &&
54 handle_->fd() != _fileno(stderr)) {
55 Close();
56 }
57 delete handle_;
58}
59
60void File::Close() {
61 ASSERT(handle_->fd() >= 0);
62 int closing_fd = handle_->fd();
63 if ((closing_fd == _fileno(stdout)) || (closing_fd == _fileno(stderr))) {
64 int fd = _open("NUL", _O_WRONLY);
65 ASSERT(fd >= 0);
66 _dup2(fd, closing_fd);
67 Utils::Close(fd);
68 } else {
69 int err = Utils::Close(closing_fd);
70 if (err != 0) {
71 Syslog::PrintErr("%s\n", strerror(errno));
72 }
73 }
74 handle_->set_fd(kClosedFd);
75}
76
77intptr_t File::GetFD() {
78 return handle_->fd();
79}
80
81bool File::IsClosed() {
82 return handle_->fd() == kClosedFd;
83}
84
85MappedMemory* File::Map(File::MapType type,
86 int64_t position,
87 int64_t length,
88 void* start) {
89 DWORD prot_alloc;
90 DWORD prot_final;
91 switch (type) {
92 case File::kReadOnly:
93 prot_alloc = PAGE_READWRITE;
94 prot_final = PAGE_READONLY;
95 break;
97 prot_alloc = PAGE_EXECUTE_READWRITE;
98 prot_final = PAGE_EXECUTE_READ;
99 break;
100 case File::kReadWrite:
101 prot_alloc = PAGE_READWRITE;
102 prot_final = PAGE_READWRITE;
103 break;
104 }
105
106 void* addr = start;
107 if (addr == nullptr) {
108 addr = VirtualAlloc(nullptr, length, MEM_COMMIT | MEM_RESERVE, prot_alloc);
109 if (addr == nullptr) {
110 Syslog::PrintErr("VirtualAlloc failed %d\n", GetLastError());
111 return nullptr;
112 }
113 }
114
115 const int64_t remaining_length = Length() - position;
116 SetPosition(position);
117 if (!ReadFully(addr, Utils::Minimum(length, remaining_length))) {
118 Syslog::PrintErr("ReadFully failed %d\n", GetLastError());
119 if (start == nullptr) {
120 VirtualFree(addr, 0, MEM_RELEASE);
121 }
122 return nullptr;
123 }
124
125 // If the requested mapping is larger than the file size, we should fill the
126 // extra memory with zeros.
127 if (length > remaining_length) {
128 memset(reinterpret_cast<uint8_t*>(addr) + remaining_length, 0,
129 length - remaining_length);
130 }
131
132 DWORD old_prot;
133 bool result = VirtualProtect(addr, length, prot_final, &old_prot);
134 if (!result) {
135 Syslog::PrintErr("VirtualProtect failed %d\n", GetLastError());
136 if (start == nullptr) {
137 VirtualFree(addr, 0, MEM_RELEASE);
138 }
139 return nullptr;
140 }
141 return new MappedMemory(addr, length, /*should_unmap=*/start == nullptr);
142}
143
144void MappedMemory::Unmap() {
145 BOOL result = VirtualFree(address_, 0, MEM_RELEASE);
146 ASSERT(result);
147 address_ = nullptr;
148 size_ = 0;
149}
150
151int64_t File::Read(void* buffer, int64_t num_bytes) {
152 ASSERT(handle_->fd() >= 0);
153 return Utils::Read(handle_->fd(), buffer, num_bytes);
154}
155
156int64_t File::Write(const void* buffer, int64_t num_bytes) {
157 int fd = handle_->fd();
158 // Avoid narrowing conversion
159 ASSERT(fd >= 0 && num_bytes <= MAXDWORD && num_bytes >= 0);
160 HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
161 DWORD written = 0;
162 BOOL result = WriteFile(handle, buffer, num_bytes, &written, nullptr);
163 if (!result) {
164 return -1;
165 }
166 DWORD mode;
167 int64_t bytes_written = written;
168 if (GetConsoleMode(handle, &mode)) {
169 // If `handle` is for a console, then `written` may refer to the number of
170 // characters printed to the screen rather than the number of bytes of the
171 // buffer that were actually consumed. To compute the number of bytes that
172 // were actually consumed, we convert the buffer to a wchar_t using the
173 // console's current code page, filling as many characters as were
174 // printed, and then convert that many characters back to the encoding for
175 // the code page, which gives the number of bytes of `buffer` used to
176 // generate the characters that were printed.
177 wchar_t* wide = new wchar_t[written];
178 int cp = GetConsoleOutputCP();
179 MultiByteToWideChar(cp, 0, reinterpret_cast<const char*>(buffer), -1, wide,
180 written);
181 int buffer_len =
182 WideCharToMultiByte(cp, 0, wide, written, nullptr, 0, nullptr, nullptr);
183 delete[] wide;
184 bytes_written = buffer_len;
185 }
186 return bytes_written;
187}
188
189bool File::VPrint(const char* format, va_list args) {
190 // Measure.
191 va_list measure_args;
192 va_copy(measure_args, args);
193 intptr_t len = _vscprintf(format, measure_args);
194 va_end(measure_args);
195
196 char* buffer = reinterpret_cast<char*>(malloc(len + 1));
197
198 // Print.
199 va_list print_args;
200 va_copy(print_args, args);
201 _vsnprintf(buffer, len + 1, format, print_args);
202 va_end(print_args);
203
204 bool result = WriteFully(buffer, len);
205 free(buffer);
206 return result;
207}
208
209int64_t File::Position() {
210 ASSERT(handle_->fd() >= 0);
211 HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(handle_->fd()));
212 LARGE_INTEGER zero_offset;
213 zero_offset.QuadPart = 0;
214 LARGE_INTEGER position;
215 if (!SetFilePointerEx(handle, zero_offset, &position, FILE_CURRENT)) {
216 return -1L;
217 }
218 return position.QuadPart;
219}
220
221bool File::SetPosition(int64_t position) {
222 ASSERT(handle_->fd() >= 0);
223 HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(handle_->fd()));
224 LARGE_INTEGER requested_position;
225 requested_position.QuadPart = position;
226 return SetFilePointerEx(handle, requested_position,
227 /*lpNewFilePointer=*/nullptr, FILE_BEGIN);
228}
229
230bool File::Truncate(int64_t length) {
231 if (!SetPosition(length)) {
232 return false;
233 }
234 HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(handle_->fd()));
235 return SetEndOfFile(handle);
236}
237
238bool File::Flush() {
239 ASSERT(handle_->fd());
240 HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(handle_->fd()));
241 return FlushFileBuffers(handle);
242}
243
244bool File::Lock(File::LockType lock, int64_t start, int64_t end) {
245 ASSERT(handle_->fd() >= 0);
246 ASSERT((end == -1) || (end > start));
247 HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(handle_->fd()));
248 OVERLAPPED overlapped;
249 ZeroMemory(&overlapped, sizeof(OVERLAPPED));
250
251 overlapped.Offset = Utils::Low32Bits(start);
252 overlapped.OffsetHigh = Utils::High32Bits(start);
253
254 int64_t length = end == -1 ? 0 : end - start;
255 if (length == 0) {
257 }
258 int32_t length_low = Utils::Low32Bits(length);
259 int32_t length_high = Utils::High32Bits(length);
260
261 BOOL rc;
262 switch (lock) {
264 rc = UnlockFileEx(handle, 0, length_low, length_high, &overlapped);
265 break;
270 DWORD flags = 0;
271 if ((lock == File::kLockShared) || (lock == File::kLockExclusive)) {
272 flags |= LOCKFILE_FAIL_IMMEDIATELY;
273 }
274 if ((lock == File::kLockExclusive) ||
276 flags |= LOCKFILE_EXCLUSIVE_LOCK;
277 }
278 rc = LockFileEx(handle, flags, 0, length_low, length_high, &overlapped);
279 break;
280 }
281 default:
282 UNREACHABLE();
283 }
284 return rc;
285}
286
287int64_t File::Length() {
288 ASSERT(handle_->fd() >= 0);
289 struct __stat64 st;
290 if (_fstat64(handle_->fd(), &st) == 0) {
291 return st.st_size;
292 }
293 return -1;
294}
295
296File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) {
297 int flags = O_RDONLY | O_BINARY | O_NOINHERIT;
298 if ((mode & kWrite) != 0) {
299 ASSERT((mode & kWriteOnly) == 0);
300 flags = (O_RDWR | O_CREAT | O_BINARY | O_NOINHERIT);
301 }
302 if ((mode & kWriteOnly) != 0) {
303 ASSERT((mode & kWrite) == 0);
304 flags = (O_WRONLY | O_CREAT | O_BINARY | O_NOINHERIT);
305 }
306 if ((mode & kTruncate) != 0) {
307 flags = flags | O_TRUNC;
308 }
309 int fd = _wopen(system_name, flags, 0666);
310 if (fd < 0) {
311 return nullptr;
312 }
313 if ((((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) ||
314 (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) {
315 int64_t position = _lseeki64(fd, 0, SEEK_END);
316 if (position < 0) {
317 return nullptr;
318 }
319 }
320 return OpenFD(fd);
321}
322
323File* File::OpenFD(int fd) {
324 return new File(new FileHandle(fd));
325}
326
327static std::unique_ptr<wchar_t[]> ConvertToAbsolutePath(
328 const std::unique_ptr<wchar_t[]>& path) {
329 // Initial buffer size is selected to avoid overallocating too much
330 // memory.
331 int buffer_size = 1024;
332 do {
333 auto buffer = std::make_unique<wchar_t[]>(buffer_size);
334 int full_path_length =
335 GetFullPathNameW(path.get(), buffer_size, buffer.get(),
336 /*lpFilePart=*/nullptr);
337 if (full_path_length == 0) {
338 return nullptr;
339 }
340
341 // Note: when sucessful full_path_length does *not* include terminating
342 // NUL character, but on failure it *does* include it when returning
343 // the size of buffer which we need. Hence comparison here is `<`, rather
344 // than `<=`.
345 if (full_path_length < buffer_size) {
346 return buffer;
347 }
348
349 buffer_size = full_path_length;
350 } while (true);
351}
352
353static bool IsAbsolutePath(const wchar_t* pathname) {
354 if (pathname == nullptr) return false;
355 char first = pathname[0];
356 char second = pathname[1];
357 if (first == L'\\' && second == L'\\') return true;
358 if (second != L':') return false;
359 first |= 0x20;
360 char third = pathname[2];
361 return (first >= L'a') && (first <= L'z') &&
362 (third == L'\\' || third == L'/');
363}
364
365const wchar_t* kLongPathPrefix = L"\\\\?\\";
366const int kLongPathPrefixLength = 4;
367
368// `\\.\` is a device namespace prefix somewhat similar to `\\?\`.
369// We should preserve it at the start of the file names.
370const wchar_t* kDeviceNamespacePrefix = L"\\\\.\\";
371const int kDeviceNamespacePrefixLength = 4;
372
373static bool IsLongPathPrefixed(const std::unique_ptr<wchar_t[]>& path) {
374 return wcsncmp(path.get(), kLongPathPrefix, kLongPathPrefixLength) == 0;
375}
376
377static bool IsDeviceNamespacePrefixed(const std::unique_ptr<wchar_t[]>& path) {
378 return wcsncmp(path.get(), kDeviceNamespacePrefix,
379 kDeviceNamespacePrefixLength) == 0;
380}
381
382// Converts the given UTF8 path to wide char. If resulting path does not
383// fit into MAX_PATH / MAX_DIRECTORY_PATH (or if |force_long_prefix| is true)
384// then converts the path to the absolute `\\?\`-prefixed form.
385//
386// This function does not change paths which are already prefixed with `\\.\`
387// prefix.
388//
389// UNC paths (`\\server\share\...`) are converted to `\\?\UNC\server\share\...`
390// if necessary.
391//
392// Note:
393// 1. Some WinAPI functions (like SetCurrentDirectoryW) are always limited
394// to MAX_PATH long paths and converting to `\\?\`-prefixed form does not
395// remove this limitation. Always check Win API documentation.
396// 2. This function might change relative path to an absolute path.
397static std::unique_ptr<wchar_t[]> ToWinAPIPath(const char* utf8_path,
398 bool is_file,
399 bool force_long_prefix) {
400 auto path = Utf8ToWideChar(utf8_path);
401
402 // File name and Directory name have different size limit.
403 // Reference: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation
404 const int path_short_limit = is_file ? MAX_PATH : MAX_DIRECTORY_PATH;
405
406 std::unique_ptr<wchar_t[]> absolute_path;
407 if (!IsAbsolutePath(path.get())) {
408 absolute_path = ConvertToAbsolutePath(path);
409 if (absolute_path == nullptr) {
410 return path;
411 }
412 } else {
413 absolute_path = std::move(path);
414 }
415
416 int path_length = wcslen(absolute_path.get());
417
418 if (!force_long_prefix && path_length < path_short_limit) {
419 if (path == nullptr) {
420 return absolute_path;
421 } else {
422 return path;
423 }
424 }
425
426 if (IsLongPathPrefixed(absolute_path) ||
427 IsDeviceNamespacePrefixed(absolute_path)) {
428 return absolute_path;
429 }
430
431 // If the path already starts with `\\` but not with `\\?\` or `\\.\`
432 // then we need to replace `\\` with `\\?\UNC\`.
433 const bool is_unc = (wcsncmp(absolute_path.get(), L"\\\\", 2) == 0);
434 const wchar_t* kUNCLongPathPrefix = L"\\\\?\\UNC\\";
435 const int kUNCLongPathPrefixLength = 8;
436
437 // Add prefix and replace forward slashes with backward slashes.
438 //
439 // If the path is UNC we skip the first two characters of the path `\\`
440 // hence -2.
441 const intptr_t result_length =
442 (is_unc ? kUNCLongPathPrefixLength : kLongPathPrefixLength) +
443 path_length + (is_unc ? -2 : 0) + 1;
444 auto result = std::make_unique<wchar_t[]>(result_length);
445 intptr_t result_pos;
446 intptr_t path_pos;
447 if (is_unc) {
448 wcsncpy(result.get(), kUNCLongPathPrefix, kUNCLongPathPrefixLength);
449 result_pos = kUNCLongPathPrefixLength;
450 path_pos = 2;
451 } else {
452 wcsncpy(result.get(), kLongPathPrefix, kLongPathPrefixLength);
453 result_pos = kLongPathPrefixLength;
454 path_pos = 0;
455 }
456 while (path_pos < path_length) {
457 wchar_t ch = absolute_path[path_pos++];
458 result.get()[result_pos++] = ch == L'/' ? L'\\' : ch;
459 }
460 result.get()[result_pos++] = L'\0';
461 ASSERT(result_pos == result_length);
462 return result;
463}
464
465// Converts the given UTF8 path to wide char. If resulting path does not
466// fit into MAX_DIRECTORY_PATH (or if |force_long_prefix| is true) then
467// converts the path to the absolute `\\?\`-prefixed form.
468//
469// Note:
470// 1. Some WinAPI functions (like SetCurrentDirectoryW) are always limited
471// to MAX_PATH long paths and converting to `\\?\`-prefixed form does not
472// remove this limitation. Always check Win API documentation.
473// 2. This function might change relative path to an absolute path.
474static std::unique_ptr<wchar_t[]> ToWinAPIFilePath(
475 const char* path,
476 bool force_long_prefix = false) {
477 return ToWinAPIPath(path, /*is_file=*/true, force_long_prefix);
478}
479
480std::unique_ptr<wchar_t[]> ToWinAPIDirectoryPath(
481 const char* path,
482 bool force_long_prefix /* = false */) {
483 return ToWinAPIPath(path, /*is_file=*/false, force_long_prefix);
484}
485
486File* File::Open(Namespace* namespc, const char* name, FileOpenMode mode) {
487 const auto path = ToWinAPIFilePath(name);
488 File* file = FileOpenW(path.get(), mode);
489 return file;
490}
491
492CStringUniquePtr File::UriToPath(const char* uri) {
493 UriDecoder uri_decoder(uri);
494 if (uri_decoder.decoded() == nullptr) {
495 SetLastError(ERROR_INVALID_NAME);
496 return CStringUniquePtr(nullptr);
497 }
498
499 const auto uri_w = Utf8ToWideChar(uri_decoder.decoded());
500 if (!UrlIsFileUrlW(uri_w.get())) {
501 return CStringUniquePtr(Utils::StrDup(uri_decoder.decoded()));
502 }
503 wchar_t filename_w[MAX_PATH];
504 DWORD filename_len = MAX_PATH;
505 HRESULT result = PathCreateFromUrlW(uri_w.get(), filename_w, &filename_len,
506 /* dwFlags= */ 0);
507 if (result != S_OK) {
508 return CStringUniquePtr(nullptr);
509 }
510
511 WideToUtf8Scope utf8_path(filename_w);
512 return utf8_path.release();
513}
514
515File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
516 auto path = UriToPath(uri);
517 if (path == nullptr) {
518 return nullptr;
519 }
520 return Open(namespc, path.get(), mode);
521}
522
523File* File::OpenStdio(int fd) {
524 int stdio_fd = -1;
525 switch (fd) {
526 case 1:
527 stdio_fd = _fileno(stdout);
528 break;
529 case 2:
530 stdio_fd = _fileno(stderr);
531 break;
532 default:
533 UNREACHABLE();
534 }
535 _setmode(stdio_fd, _O_BINARY);
536 return new File(new FileHandle(stdio_fd));
537}
538
539static bool StatHelper(const wchar_t* path, struct __stat64* st) {
540 int stat_status = _wstat64(path, st);
541 if (stat_status != 0) {
542 return false;
543 }
544 if ((st->st_mode & S_IFMT) != S_IFREG) {
545 SetLastError(ERROR_NOT_SUPPORTED);
546 return false;
547 }
548 return true;
549}
550
551static bool FileExists(const wchar_t* path) {
552 struct __stat64 st;
553 return StatHelper(path, &st);
554}
555
556bool File::Exists(Namespace* namespc, const char* name) {
557 const auto path = ToWinAPIFilePath(name);
558 return FileExists(path.get());
559}
560
561bool File::ExistsUri(Namespace* namespc, const char* uri) {
562 UriDecoder uri_decoder(uri);
563 if (uri_decoder.decoded() == nullptr) {
564 SetLastError(ERROR_INVALID_NAME);
565 return false;
566 }
567 return File::Exists(namespc, uri_decoder.decoded());
568}
569
570bool File::Create(Namespace* namespc, const char* name, bool exclusive) {
571 const auto path = ToWinAPIFilePath(name);
572 int flags = O_RDONLY | O_CREAT;
573 if (exclusive) {
574 flags |= O_EXCL;
575 }
576 int fd = _wopen(path.get(), flags, 0666);
577 if (fd < 0) {
578 return false;
579 }
580 return (Utils::Close(fd) == 0);
581}
582
583// This structure is needed for creating and reading Junctions.
584typedef struct _REPARSE_DATA_BUFFER {
585 ULONG ReparseTag;
586 USHORT ReparseDataLength;
587 USHORT Reserved;
588
589 union {
590 struct {
591 USHORT SubstituteNameOffset;
592 USHORT SubstituteNameLength;
593 USHORT PrintNameOffset;
594 USHORT PrintNameLength;
595 ULONG Flags;
596 WCHAR PathBuffer[1];
597 } SymbolicLinkReparseBuffer;
598
599 struct {
600 USHORT SubstituteNameOffset;
601 USHORT SubstituteNameLength;
602 USHORT PrintNameOffset;
603 USHORT PrintNameLength;
604 WCHAR PathBuffer[1];
605 } MountPointReparseBuffer;
606
607 struct {
608 UCHAR DataBuffer[1];
609 } GenericReparseBuffer;
610 };
611} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
612
613bool File::CreateLink(Namespace* namespc,
614 const char* utf8_name,
615 const char* utf8_target) {
616 const auto name = ToWinAPIFilePath(utf8_name);
617
618 std::unique_ptr<wchar_t[]> target;
619 bool target_is_directory;
620 if (File::IsAbsolutePath(utf8_target)) {
621 target = ToWinAPIFilePath(utf8_target);
622 target_is_directory =
623 File::GetType(target.get(), /*follow_links=*/true) == kIsDirectory;
624 } else {
625 // The path of `target` is relative to `name`.
626 //
627 // To determine if `target` is a file or directory, we need to calculate
628 // either its absolute path or its path relative to the current working
629 // directory.
630 //
631 // For example:
632 //
633 // name= C:\A\B\Link ..\..\Link ..\..\Link
634 // target= MyFile MyFile ..\Dir\MyFile
635 // --------------------------------------------------------------------
636 // target_path= C:\A\B\MyFile ..\..\MyFile ..\..\..\Dir\MyFile
637 //
638 // The transformation steps are:
639 // 1. target_path := name ..\..\Link
640 // 2. target_path := remove_file(target_path) ..\..\
641 // 3. target_path := combine(target_path, target) ..\..\..\Dir\MyFile
642 target = Utf8ToWideChar(utf8_target);
643
644 // 1. target_path := name
645 intptr_t target_path_max_length =
646 wcslen(name.get()) + wcslen(target.get()) + 2;
647 auto target_path = std::make_unique<wchar_t[]>(target_path_max_length);
648 wcscpy_s(target_path.get(), target_path_max_length, name.get());
649
650 // 2. target_path := remove_file(target_path)
651 HRESULT remove_result =
652 PathCchRemoveFileSpec(target_path.get(), target_path_max_length);
653 if (remove_result == S_FALSE) {
654 // If the file component could not be removed, then `name` is
655 // top-level, like "C:\" or "/". Attempts to create files at those paths
656 // will fail with ERROR_ACCESS_DENIED.
658 return false;
659 } else if (remove_result != S_OK) {
660 SetLastError(remove_result);
661 return false;
662 }
663
664 // 3. target_path := combine(target_path, target)
665 HRESULT combine_result = PathCchCombineEx(
666 target_path.get(), target_path_max_length, target_path.get(),
667 target.get(), PATHCCH_ALLOW_LONG_PATHS);
668 if (combine_result != S_OK) {
669 SetLastError(combine_result);
670 return false;
671 }
672
673 target_is_directory =
674 File::GetType(target_path.get(), /*follow_links=*/true) == kIsDirectory;
675 }
676
677 DWORD flags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
678 if (target_is_directory) {
679 flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
680 }
681 int create_status = CreateSymbolicLinkW(name.get(), target.get(), flags);
682
683 // If running on a Windows 10 build older than 14972, an invalid parameter
684 // error will be returned when trying to use the
685 // SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE flag. Retry without the flag.
686 if ((create_status == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)) {
687 flags &= ~SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
688 create_status = CreateSymbolicLinkW(name.get(), target.get(), flags);
689 }
690
691 return (create_status != 0);
692}
693
694bool File::CreatePipe(Namespace* namespc, File** readPipe, File** writePipe) {
695 int pipe_fds[2];
696 int status = _pipe(pipe_fds, 4096, _O_BINARY);
697 if (status != 0) {
698 return false;
699 }
700 *readPipe = OpenFD(pipe_fds[0]);
701 *writePipe = OpenFD(pipe_fds[1]);
702 return true;
703}
704
705bool File::Delete(Namespace* namespc, const char* name) {
706 const auto path = ToWinAPIFilePath(name);
707 int status = _wremove(path.get());
708 return status != -1;
709}
710
711static bool DeleteLinkHelper(const wchar_t* path) {
712 bool result = false;
713 DWORD attributes = GetFileAttributesW(path);
714 if ((attributes == INVALID_FILE_ATTRIBUTES) ||
715 ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0)) {
716 SetLastError(ERROR_NOT_A_REPARSE_POINT);
717 return false;
718 }
719 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
720 // It's a junction, which is a special type of directory, or a symbolic
721 // link to a directory. Remove the directory.
722 result = (RemoveDirectoryW(path) != 0);
723 } else {
724 // Symbolic link to a file. Remove the file.
725 result = (DeleteFileW(path) != 0);
726 }
727 return result;
728}
729
730bool File::DeleteLink(Namespace* namespc, const char* name) {
731 const auto path = ToWinAPIFilePath(name);
732 return DeleteLinkHelper(path.get());
733}
734
735static bool RenameHelper(File::Type expected,
736 const char* old_name,
737 const char* new_name) {
738 const auto old_path = ToWinAPIFilePath(old_name);
739 File::Type type = File::GetType(old_path.get(), /*follow_links=*/false);
740 if (type != expected) {
742 return false;
743 }
744 const auto new_path = ToWinAPIFilePath(new_name);
745 DWORD flags = MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING;
746
747 // Symbolic links (e.g. produced by Link.create) to directories on Windows
748 // appear as special directories. MoveFileExW's MOVEFILE_REPLACE_EXISTING
749 // does not allow for replacement of directories, so we need to remove it
750 // before renaming.
751 if ((Directory::Exists(new_path.get()) == Directory::EXISTS) &&
752 (File::GetType(new_path.get(), /*follow_links=*/false) ==
753 File::kIsLink)) {
754 // Bail out if the DeleteLink call fails.
755 if (!DeleteLinkHelper(new_path.get())) {
756 return false;
757 }
758 }
759 int move_status = MoveFileExW(old_path.get(), new_path.get(), flags);
760 return (move_status != 0);
761}
762
763bool File::Rename(Namespace* namespc,
764 const char* old_name,
765 const char* new_name) {
766 return RenameHelper(File::kIsFile, old_name, new_name);
767}
768
769bool File::RenameLink(Namespace* namespc,
770 const char* old_name,
771 const char* new_name) {
772 return RenameHelper(File::kIsLink, old_name, new_name);
773}
774
775static std::unique_ptr<wchar_t[]> GetDirectoryPath(
776 const std::unique_ptr<wchar_t[]>& path) {
777 for (intptr_t i = wcslen(path.get()) - 1; i >= 0; --i) {
778 if (path.get()[i] == '\\' || path.get()[i] == '/') {
779 // Note: we need to copy the trailing directory separator so we need to
780 // copy i + 1 characters (plus trailing '\0').
781 auto result = std::make_unique<wchar_t[]>(i + 2);
782 wcsncpy(result.get(), path.get(), i + 1);
783 return result;
784 }
785 }
786 return nullptr;
787}
788
789static void FreeUUID(wchar_t* ptr) {
790 RpcStringFreeW(&ptr);
791}
792
793static std::unique_ptr<wchar_t, decltype(FreeUUID)*> GenerateUUIDString() {
794 UUID uuid;
795 RPC_STATUS status = UuidCreateSequential(&uuid);
796 if ((status != RPC_S_OK) && (status != RPC_S_UUID_LOCAL_ONLY)) {
797 return {nullptr, nullptr};
798 }
799 wchar_t* uuid_string;
800 status = UuidToStringW(&uuid, &uuid_string);
801 if (status != RPC_S_OK) {
802 return {nullptr, nullptr};
803 }
804
805 return {uuid_string, &FreeUUID};
806}
807
808// This function will copy the |src| file to a temporary file in the
809// directory where |dest| resides and returns the path of temp file.
810static std::unique_ptr<wchar_t[]> CopyIntoTempFile(
811 const std::unique_ptr<wchar_t[]>& src,
812 const std::unique_ptr<wchar_t[]>& dest) {
813 const auto dir = GetDirectoryPath(dest);
814 if (dir == nullptr) {
815 return nullptr;
816 }
817
818 uint32_t suffix_bytes = 0;
819 const int kSuffixSize = sizeof(suffix_bytes);
820 if (Crypto::GetRandomBytes(kSuffixSize,
821 reinterpret_cast<uint8_t*>(&suffix_bytes))) {
822 const size_t file_path_buf_size = wcslen(dir.get()) + 8 + 1;
823 auto file_path = std::make_unique<wchar_t[]>(file_path_buf_size);
824 swprintf(file_path.get(), file_path_buf_size, L"%s%x", dir.get(),
825 suffix_bytes);
826
827 if (CopyFileExW(src.get(), file_path.get(), nullptr, nullptr, nullptr, 0) !=
828 0) {
829 return file_path;
830 }
831
832 // If CopyFileExW() fails to copy to a temp file with random hex, fall
833 // back to copy to a uuid temp file.
834 }
835
836 const auto uuid_str = GenerateUUIDString();
837 if (uuid_str == nullptr) {
838 return nullptr;
839 }
840
841 const size_t file_path_buf_size =
842 wcslen(dir.get()) + wcslen(uuid_str.get()) + 1;
843 auto file_path = std::make_unique<wchar_t[]>(file_path_buf_size);
844 swprintf(file_path.get(), file_path_buf_size, L"%s%s", dir.get(),
845 uuid_str.get());
846
847 if (CopyFileExW(src.get(), file_path.get(), nullptr, nullptr, nullptr, 0) !=
848 0) {
849 return file_path;
850 }
851
852 return nullptr;
853}
854
855bool File::Copy(Namespace* namespc,
856 const char* old_name,
857 const char* new_name) {
858 // We are going to concatenate new path with temporary file names in
859 // CopyIntoTempFile so we force long prefix no matter what.
860 const auto old_path = ToWinAPIFilePath(old_name);
861 const auto new_path = ToWinAPIFilePath(new_name, /*force_long_prefix=*/true);
862
863 File::Type type = GetType(old_path.get(), /*follow_links=*/false);
864 if (type != kIsFile) {
866 return false;
867 }
868
869 const auto temp_file = CopyIntoTempFile(old_path, new_path);
870 if (temp_file == nullptr) {
871 // If temp file creation fails, fall back on doing a direct copy.
872 return CopyFileExW(old_path.get(), new_path.get(), nullptr, nullptr,
873 nullptr, 0) != 0;
874 }
875
876 // Remove the existing file. Otherwise, renaming will fail.
877 if (FileExists(new_path.get())) {
878 DeleteFileW(new_path.get());
879 }
880
881 if (!MoveFileW(temp_file.get(), new_path.get())) {
883 DeleteFileW(temp_file.get());
885 return false;
886 }
887
888 return true;
889}
890
891int64_t File::LengthFromPath(Namespace* namespc, const char* name) {
892 struct __stat64 st;
893 const auto path = ToWinAPIFilePath(name);
894 if (!StatHelper(path.get(), &st)) {
895 return -1;
896 }
897 return st.st_size;
898}
899
900const char* File::LinkTarget(Namespace* namespc,
901 const char* pathname,
902 char* dest,
903 int dest_size) {
904 const auto path = ToWinAPIFilePath(pathname);
905 HANDLE dir_handle = CreateFileW(
906 path.get(), GENERIC_READ,
907 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
908 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
909 nullptr);
910 if (dir_handle == INVALID_HANDLE_VALUE) {
911 return nullptr;
912 }
913
914 // Allocate a buffer for regular paths (smaller than MAX_PATH). If buffer is
915 // too small for a long path, allocate a bigger buffer and try again.
916 int buffer_size =
917 sizeof(REPARSE_DATA_BUFFER) + (MAX_PATH + 1) * sizeof(WCHAR);
918 REPARSE_DATA_BUFFER* buffer =
919 reinterpret_cast<REPARSE_DATA_BUFFER*>(Dart_ScopeAllocate(buffer_size));
920 DWORD received_bytes; // Value is not used.
921 int result = DeviceIoControl(dir_handle, FSCTL_GET_REPARSE_POINT, nullptr, 0,
922 buffer, buffer_size, &received_bytes, nullptr);
923 if (result == 0) {
925 // If ERROR_MORE_DATA is thrown, the target path exceeds the size limit. A
926 // bigger buffer will be required.
927 if (error == ERROR_MORE_DATA) {
928 // Allocate a bigger buffer with MAX_LONG_PATH
930 sizeof(REPARSE_DATA_BUFFER) + (MAX_LONG_PATH + 1) * sizeof(WCHAR);
931 buffer = reinterpret_cast<REPARSE_DATA_BUFFER*>(
933 result = DeviceIoControl(dir_handle, FSCTL_GET_REPARSE_POINT, nullptr, 0,
934 buffer, buffer_size, &received_bytes, nullptr);
935 if (result == 0) {
936 // Overwrite the ERROR_MORE_DATA.
938 }
939 }
940 if (result == 0) {
941 CloseHandle(dir_handle);
943 return nullptr;
944 }
945 }
946 if (CloseHandle(dir_handle) == 0) {
947 return nullptr;
948 }
949
950 wchar_t* target;
951 size_t target_offset;
952 size_t target_length;
953 if (buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
954 target = buffer->MountPointReparseBuffer.PathBuffer;
955 target_offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
956 target_length = buffer->MountPointReparseBuffer.SubstituteNameLength;
957 } else if (buffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
958 target = buffer->SymbolicLinkReparseBuffer.PathBuffer;
959 target_offset = buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset;
960 target_length = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
961 } else { // Not a junction or a symbolic link.
962 SetLastError(ERROR_NOT_A_REPARSE_POINT);
963 return nullptr;
964 }
965
966 target_offset /= sizeof(wchar_t); // Offset and length are in bytes.
967 target_length /= sizeof(wchar_t);
968 target += target_offset;
969 // Remove "\??\" from beginning of target.
970 if ((target_length > 4) && (wcsncmp(L"\\??\\", target, 4) == 0)) {
971 target += 4;
972 target_length -= 4;
973 }
974 int utf8_length = WideCharToMultiByte(CP_UTF8, 0, target, target_length,
975 nullptr, 0, nullptr, nullptr);
976 if (dest_size > 0 && dest_size <= utf8_length) {
977 return nullptr;
978 }
979 if (dest == nullptr) {
980 dest = DartUtils::ScopedCString(utf8_length + 1);
981 }
982 if (0 == WideCharToMultiByte(CP_UTF8, 0, target, target_length, dest,
983 utf8_length, nullptr, nullptr)) {
984 return nullptr;
985 }
986 dest[utf8_length] = '\0';
987 return dest;
988}
989
990void File::Stat(Namespace* namespc, const char* name, int64_t* data) {
991 const auto path = ToWinAPIFilePath(name);
992 File::Type type = GetType(path.get(), /*follow_links=*/true);
993 data[kType] = type;
994 if (type != kDoesNotExist) {
995 struct _stat64 st;
996 int stat_status = _wstat64(path.get(), &st);
997 if (stat_status == 0) {
998 data[kCreatedTime] = st.st_ctime * 1000;
999 data[kModifiedTime] = st.st_mtime * 1000;
1000 data[kAccessedTime] = st.st_atime * 1000;
1001 data[kMode] = st.st_mode;
1002 data[kSize] = st.st_size;
1003 } else {
1005 }
1006 }
1007}
1008
1009time_t File::LastAccessed(Namespace* namespc, const char* name) {
1010 struct __stat64 st;
1011 const auto path = ToWinAPIFilePath(name);
1012 if (!StatHelper(path.get(), &st)) {
1013 return -1;
1014 }
1015 return st.st_atime;
1016}
1017
1018time_t File::LastModified(Namespace* namespc, const char* name) {
1019 struct __stat64 st;
1020 const auto path = ToWinAPIFilePath(name);
1021 if (!StatHelper(path.get(), &st)) {
1022 return -1;
1023 }
1024 return st.st_mtime;
1025}
1026
1027bool File::SetLastAccessed(Namespace* namespc,
1028 const char* name,
1029 int64_t millis) {
1030 struct __stat64 st;
1031 const auto path = ToWinAPIFilePath(name);
1032 if (!StatHelper(path.get(), &st)) { // Checks that it is a file.
1033 return false;
1034 }
1035
1036 // _utime and related functions set the access and modification times of the
1037 // affected file. Even if the specified modification time is not changed
1038 // from the current value, _utime will trigger a file modification event
1039 // (e.g. ReadDirectoryChangesW will report the file as modified).
1040 //
1041 // So set the file access time directly using SetFileTime.
1042 FILETIME at = GetFiletimeFromMillis(millis);
1043 HANDLE file_handle =
1044 CreateFileW(path.get(), FILE_WRITE_ATTRIBUTES,
1045 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1046 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
1047 if (file_handle == INVALID_HANDLE_VALUE) {
1048 return false;
1049 }
1050 bool result = SetFileTime(file_handle, nullptr, &at, nullptr);
1051 CloseHandle(file_handle);
1052 return result;
1053}
1054
1055bool File::SetLastModified(Namespace* namespc,
1056 const char* name,
1057 int64_t millis) {
1058 // First get the current times.
1059 struct __stat64 st;
1060 const auto path = ToWinAPIFilePath(name);
1061 if (!StatHelper(path.get(), &st)) {
1062 return false;
1063 }
1064
1065 // Set the new time:
1066 struct __utimbuf64 times;
1067 times.actime = st.st_atime;
1068 times.modtime = millis / kMillisecondsPerSecond;
1069 return _wutime64(path.get(), &times) == 0;
1070}
1071
1072// Keep this function synchronized with the behavior
1073// of `FileSystemEntity.isAbsolute` in file_system_entity.dart.
1074bool File::IsAbsolutePath(const char* pathname) {
1075 if (pathname == nullptr) return false;
1076 char first = pathname[0];
1077 char second = pathname[1];
1078 if (first == '\\' && second == '\\') return true;
1079 if (second != ':') return false;
1080 first |= 0x20;
1081 char third = pathname[2];
1082 return (first >= 'a') && (first <= 'z') && (third == '\\' || third == '/');
1083}
1084
1085const char* File::GetCanonicalPath(Namespace* namespc,
1086 const char* pathname,
1087 char* dest,
1088 int dest_size) {
1089 const auto path = ToWinAPIFilePath(pathname);
1090 HANDLE file_handle =
1091 CreateFileW(path.get(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
1092 FILE_FLAG_BACKUP_SEMANTICS, nullptr);
1093 if (file_handle == INVALID_HANDLE_VALUE) {
1094 return nullptr;
1095 }
1096 wchar_t dummy_buffer[1];
1097 int required_size =
1098 GetFinalPathNameByHandle(file_handle, dummy_buffer, 0, VOLUME_NAME_DOS);
1099 if (required_size == 0) {
1101 CloseHandle(file_handle);
1103 return nullptr;
1104 }
1105
1106 const auto canonical_path = std::make_unique<wchar_t[]>(required_size);
1107 int result_size = GetFinalPathNameByHandle(file_handle, canonical_path.get(),
1108 required_size, VOLUME_NAME_DOS);
1109 ASSERT(result_size <= required_size - 1);
1110 CloseHandle(file_handle);
1111
1112 // Remove leading \\?\ since it is only to overcome MAX_PATH limitation.
1113 // Leave it if input used it though.
1114 int offset = 0;
1115 if ((result_size > 4) &&
1116 (wcsncmp(canonical_path.get(), L"\\\\?\\", 4) == 0) &&
1117 (strncmp(pathname, "\\\\?\\", 4) != 0)) {
1118 if ((result_size > 8) &&
1119 (wcsncmp(canonical_path.get(), L"\\\\?\\UNC\\", 8) == 0)) {
1120 // Leave '\\?\UNC\' prefix intact - stripping it makes invalid UNC name.
1121 } else {
1122 offset = 4;
1123 }
1124 }
1125 int utf8_size = WideCharToMultiByte(CP_UTF8, 0, canonical_path.get() + offset,
1126 -1, nullptr, 0, nullptr, nullptr);
1127 if (dest == nullptr) {
1128 dest = DartUtils::ScopedCString(utf8_size);
1129 dest_size = utf8_size;
1130 }
1131 if (dest_size != 0) {
1132 ASSERT(utf8_size <= dest_size);
1133 }
1134 if (0 == WideCharToMultiByte(CP_UTF8, 0, canonical_path.get() + offset, -1,
1135 dest, dest_size, nullptr, nullptr)) {
1136 return nullptr;
1137 }
1138 return dest;
1139}
1140
1141const char* File::PathSeparator() {
1142 // This is already UTF-8 encoded.
1143 return "\\";
1144}
1145
1147 // This is already UTF-8 encoded.
1148 return "\\\\";
1149}
1150
1152 // Treat all stdio handles as pipes. The Windows event handler and
1153 // socket code will handle the different handle types.
1154 return kPipe;
1155}
1156
1157File::Type File::GetType(const wchar_t* path, bool follow_links) {
1158 DWORD attributes = GetFileAttributesW(path);
1159 if (attributes == INVALID_FILE_ATTRIBUTES) {
1160 return File::kDoesNotExist;
1161 } else if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
1162 if (follow_links) {
1163 HANDLE target_handle = CreateFileW(
1164 path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1165 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
1166 if (target_handle == INVALID_HANDLE_VALUE) {
1167 return File::kDoesNotExist;
1168 } else {
1169 BY_HANDLE_FILE_INFORMATION info;
1170 if (!GetFileInformationByHandle(target_handle, &info)) {
1171 CloseHandle(target_handle);
1172 return File::kDoesNotExist;
1173 }
1174 CloseHandle(target_handle);
1175 return ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
1177 : File::kIsFile;
1178 }
1179 } else {
1180 return File::kIsLink;
1181 }
1182 } else if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1183 return File::kIsDirectory;
1184 }
1185 return File::kIsFile;
1186}
1187
1188File::Type File::GetType(Namespace* namespc,
1189 const char* name,
1190 bool follow_links) {
1191 const auto path = ToWinAPIFilePath(name);
1192 return GetType(path.get(), follow_links);
1193}
1194
1195File::Identical File::AreIdentical(Namespace* namespc_1,
1196 const char* file_1,
1197 Namespace* namespc_2,
1198 const char* file_2) {
1199 USE(namespc_1);
1200 USE(namespc_2);
1201 BY_HANDLE_FILE_INFORMATION file_info[2];
1202 const std::unique_ptr<wchar_t[]> file_names[2] = {ToWinAPIFilePath(file_1),
1203 ToWinAPIFilePath(file_2)};
1204 for (int i = 0; i < 2; ++i) {
1205 HANDLE file_handle = CreateFileW(
1206 file_names[i].get(), 0,
1207 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
1208 OPEN_EXISTING,
1209 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
1210 if (file_handle == INVALID_HANDLE_VALUE) {
1211 return File::kError;
1212 }
1213 int result = GetFileInformationByHandle(file_handle, &file_info[i]);
1214 if (result == 0) {
1216 CloseHandle(file_handle);
1218 return File::kError;
1219 }
1220 if (CloseHandle(file_handle) == 0) {
1221 return File::kError;
1222 }
1223 }
1224 if ((file_info[0].dwVolumeSerialNumber ==
1225 file_info[1].dwVolumeSerialNumber) &&
1226 (file_info[0].nFileIndexHigh == file_info[1].nFileIndexHigh) &&
1227 (file_info[0].nFileIndexLow == file_info[1].nFileIndexLow)) {
1228 return kIdentical;
1229 } else {
1230 return kDifferent;
1231 }
1232}
1233
1234} // namespace bin
1235} // namespace dart
1236
1237#endif // defined(DART_HOST_OS_WINDOWS)
static SkISize times(const SkISize &size, float factor)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
static uint32_t buffer_size(uint32_t offset, uint32_t maxAlignment)
#define UNREACHABLE()
Definition: assert.h:248
#define MAX_LONG_PATH
Definition: utils_win.h:15
GLenum type
static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static int32_t Low32Bits(int64_t value)
Definition: utils.h:369
static char * StrDup(const char *s)
static int32_t High32Bits(int64_t value)
Definition: utils.h:373
static T Minimum(T x, T y)
Definition: utils.h:36
static size_t Read(int filedes, void *buf, size_t nbyte)
static int Close(int fildes)
static bool GetRandomBytes(intptr_t count, uint8_t *buffer)
static char * ScopedCString(intptr_t length)
Definition: dartutils.h:224
static ExistsResult Exists(Namespace *namespc, const char *path)
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)
bool ReadFully(void *buffer, int64_t num_bytes)
Definition: file_support.cc:41
@ 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)
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)
#define ASSERT(E)
#define MAX_DIRECTORY_PATH
Definition: file_win.h:14
FlutterSemanticsFlag flags
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
uint32_t uint32_t * format
uint32_t * target
size_t length
void WriteFile(const void *buffer, intptr_t num_bytes, void *stream)
std::unique_ptr< wchar_t[]> Utf8ToWideChar(const char *path)
FILETIME GetFiletimeFromMillis(int64_t millis)
std::unique_ptr< wchar_t[]> ToWinAPIDirectoryPath(const char *path, bool force_long_prefix=false)
Definition: dart_vm.cc:33
constexpr int64_t kMaxInt64
Definition: globals.h:486
const char *const name
CAllocUniquePtr< char > CStringUniquePtr
Definition: utils.h:31
void * malloc(size_t size)
Definition: allocation.cc:19
DART_EXPORT uint8_t * Dart_ScopeAllocate(intptr_t size)
constexpr intptr_t kMillisecondsPerSecond
Definition: globals.h:560
static void USE(T &&)
Definition: globals.h:618
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 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
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
static bool IsAbsolutePath(const char *path)
Definition: file_win.cc:37
bool FileExists(const fml::UniqueFD &base_directory, const char *path)
Definition: file_posix.cc:183
const myers::Point & get(const myers::Segment &)
dest
Definition: zip.py:79
fuchsia::ui::composition::ParentViewportWatcherHandle handle_
SeparatedVector2 offset
int BOOL
Definition: windows_types.h:37
#define INVALID_HANDLE_VALUE
WINBASEAPI VOID WINAPI SetLastError(_In_ DWORD dwErrCode)
struct _FILETIME FILETIME
WINBASEAPI _Check_return_ _Post_equals_last_error_ DWORD WINAPI GetLastError(VOID)
void * HANDLE
Definition: windows_types.h:36
struct _OVERLAPPED OVERLAPPED
DWORD ULONG
Definition: windows_types.h:40
#define MAX_PATH
unsigned long DWORD
Definition: windows_types.h:22
#define ERROR_FILE_NOT_FOUND
#define ERROR_ACCESS_DENIED