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/mapping.h"
6
7 #include <fcntl.h>
8 #include <io.h>
9 #include <windows.h>
10
11 #include <type_traits>
12
13 #include "flutter/fml/file.h"
14 #include "flutter/fml/platform/win/errors_win.h"
15 #include "flutter/fml/platform/win/wstring_conversion.h"
16
17 namespace fml {
18
19 Mapping::Mapping() = default;
20
21 Mapping::~Mapping() = default;
22
IsWritable(std::initializer_list<FileMapping::Protection> protection_flags)23 static bool IsWritable(
24 std::initializer_list<FileMapping::Protection> protection_flags) {
25 for (auto protection : protection_flags) {
26 if (protection == FileMapping::Protection::kWrite) {
27 return true;
28 }
29 }
30 return false;
31 }
32
IsExecutable(std::initializer_list<FileMapping::Protection> protection_flags)33 static bool IsExecutable(
34 std::initializer_list<FileMapping::Protection> protection_flags) {
35 for (auto protection : protection_flags) {
36 if (protection == FileMapping::Protection::kExecute) {
37 return true;
38 }
39 }
40 return false;
41 }
42
FileMapping(const fml::UniqueFD & fd,std::initializer_list<Protection> protections)43 FileMapping::FileMapping(const fml::UniqueFD& fd,
44 std::initializer_list<Protection> protections)
45 : size_(0), mapping_(nullptr) {
46 if (!fd.is_valid()) {
47 return;
48 }
49
50 const auto mapping_size = ::GetFileSize(fd.get(), nullptr);
51
52 if (mapping_size == INVALID_FILE_SIZE) {
53 FML_DLOG(ERROR) << "Invalid file size. " << GetLastErrorMessage();
54 return;
55 }
56
57 if (mapping_size == 0) {
58 valid_ = true;
59 return;
60 }
61
62 DWORD protect_flags = 0;
63 bool read_only = !IsWritable(protections);
64
65 if (IsExecutable(protections)) {
66 protect_flags = PAGE_EXECUTE_READ;
67 } else if (read_only) {
68 protect_flags = PAGE_READONLY;
69 } else {
70 protect_flags = PAGE_READWRITE;
71 }
72
73 mapping_handle_.reset(::CreateFileMapping(fd.get(), // hFile
74 nullptr, // lpAttributes
75 protect_flags, // flProtect
76 0, // dwMaximumSizeHigh
77 0, // dwMaximumSizeLow
78 nullptr // lpName
79 ));
80
81 if (!mapping_handle_.is_valid()) {
82 return;
83 }
84
85 const DWORD desired_access = read_only ? FILE_MAP_READ : FILE_MAP_WRITE;
86
87 auto mapping = reinterpret_cast<uint8_t*>(
88 MapViewOfFile(mapping_handle_.get(), desired_access, 0, 0, mapping_size));
89
90 if (mapping == nullptr) {
91 FML_DLOG(ERROR) << "Could not setup file mapping. "
92 << GetLastErrorMessage();
93 return;
94 }
95
96 mapping_ = mapping;
97 size_ = mapping_size;
98 valid_ = true;
99 if (IsWritable(protections)) {
100 mutable_mapping_ = mapping_;
101 }
102 }
103
~FileMapping()104 FileMapping::~FileMapping() {
105 if (mapping_ != nullptr) {
106 UnmapViewOfFile(mapping_);
107 }
108 }
109
GetSize() const110 size_t FileMapping::GetSize() const {
111 return size_;
112 }
113
GetMapping() const114 const uint8_t* FileMapping::GetMapping() const {
115 return mapping_;
116 }
117
IsValid() const118 bool FileMapping::IsValid() const {
119 return valid_;
120 }
121
122 } // namespace fml
123