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 <sys/mman.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11
12 #include <type_traits>
13
14 #include "flutter/fml/build_config.h"
15 #include "flutter/fml/eintr_wrapper.h"
16 #include "flutter/fml/unique_fd.h"
17
18 namespace fml {
19
ToPosixProtectionFlags(std::initializer_list<FileMapping::Protection> protection_flags)20 static int ToPosixProtectionFlags(
21 std::initializer_list<FileMapping::Protection> protection_flags) {
22 int flags = 0;
23 for (auto protection : protection_flags) {
24 switch (protection) {
25 case FileMapping::Protection::kRead:
26 flags |= PROT_READ;
27 break;
28 case FileMapping::Protection::kWrite:
29 flags |= PROT_WRITE;
30 break;
31 case FileMapping::Protection::kExecute:
32 flags |= PROT_READ | PROT_EXEC;
33 break;
34 }
35 }
36 return flags;
37 }
38
IsWritable(std::initializer_list<FileMapping::Protection> protection_flags)39 static bool IsWritable(
40 std::initializer_list<FileMapping::Protection> protection_flags) {
41 for (auto protection : protection_flags) {
42 if (protection == FileMapping::Protection::kWrite) {
43 return true;
44 }
45 }
46 return false;
47 }
48
49 Mapping::Mapping() = default;
50
51 Mapping::~Mapping() = default;
52
FileMapping(const fml::UniqueFD & handle,std::initializer_list<Protection> protection)53 FileMapping::FileMapping(const fml::UniqueFD& handle,
54 std::initializer_list<Protection> protection)
55 : size_(0), mapping_(nullptr) {
56 if (!handle.is_valid()) {
57 return;
58 }
59
60 struct stat stat_buffer = {};
61
62 if (::fstat(handle.get(), &stat_buffer) != 0) {
63 return;
64 }
65
66 if (stat_buffer.st_size == 0) {
67 valid_ = true;
68 return;
69 }
70
71 const auto is_writable = IsWritable(protection);
72
73 auto* mapping =
74 ::mmap(nullptr, stat_buffer.st_size, ToPosixProtectionFlags(protection),
75 is_writable ? MAP_SHARED : MAP_PRIVATE, handle.get(), 0);
76
77 if (mapping == MAP_FAILED) {
78 return;
79 }
80
81 mapping_ = static_cast<uint8_t*>(mapping);
82 size_ = stat_buffer.st_size;
83 valid_ = true;
84 if (is_writable) {
85 mutable_mapping_ = mapping_;
86 }
87 }
88
~FileMapping()89 FileMapping::~FileMapping() {
90 if (mapping_ != nullptr) {
91 ::munmap(mapping_, size_);
92 }
93 }
94
GetSize() const95 size_t FileMapping::GetSize() const {
96 return size_;
97 }
98
GetMapping() const99 const uint8_t* FileMapping::GetMapping() const {
100 return mapping_;
101 }
102
IsValid() const103 bool FileMapping::IsValid() const {
104 return valid_;
105 }
106
107 } // namespace fml
108