1 // Copyright 2013 The Chromium Authors
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 "base/files/memory_mapped_file.h"
6
7 #include <fcntl.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <sys/mman.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13
14 #include "base/files/file_util.h"
15 #include "base/logging.h"
16 #include "base/numerics/safe_conversions.h"
17 #include "base/threading/scoped_blocking_call.h"
18 #include "build/build_config.h"
19
20 namespace base {
21
22 MemoryMappedFile::MemoryMappedFile() = default;
23
24 #if !BUILDFLAG(IS_NACL)
MapFileRegionToMemory(const MemoryMappedFile::Region & region,Access access)25 bool MemoryMappedFile::MapFileRegionToMemory(
26 const MemoryMappedFile::Region& region,
27 Access access) {
28 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
29
30 off_t map_start = 0;
31 size_t map_size = 0;
32 int32_t data_offset = 0;
33
34 if (region == MemoryMappedFile::Region::kWholeFile) {
35 int64_t file_len = file_.GetLength();
36 if (file_len < 0) {
37 DPLOG(ERROR) << "fstat " << file_.GetPlatformFile();
38 return false;
39 }
40 if (!IsValueInRangeForNumericType<size_t>(file_len))
41 return false;
42 map_size = static_cast<size_t>(file_len);
43 length_ = map_size;
44 } else {
45 // The region can be arbitrarily aligned. mmap, instead, requires both the
46 // start and size to be page-aligned. Hence, we map here the page-aligned
47 // outer region [|aligned_start|, |aligned_start| + |size|] which contains
48 // |region| and then add up the |data_offset| displacement.
49 int64_t aligned_start = 0;
50 size_t aligned_size = 0;
51 CalculateVMAlignedBoundaries(region.offset,
52 region.size,
53 &aligned_start,
54 &aligned_size,
55 &data_offset);
56
57 // Ensure that the casts in the mmap call below are sane.
58 if (aligned_start < 0 ||
59 !IsValueInRangeForNumericType<off_t>(aligned_start)) {
60 DLOG(ERROR) << "Region bounds are not valid for mmap";
61 return false;
62 }
63
64 map_start = static_cast<off_t>(aligned_start);
65 map_size = aligned_size;
66 length_ = region.size;
67 }
68
69 int prot = 0;
70 int flags = MAP_SHARED;
71 switch (access) {
72 case READ_ONLY:
73 prot |= PROT_READ;
74 break;
75
76 case READ_WRITE:
77 prot |= PROT_READ | PROT_WRITE;
78 break;
79
80 case READ_WRITE_COPY:
81 prot |= PROT_READ | PROT_WRITE;
82 flags = MAP_PRIVATE;
83 break;
84
85 case READ_WRITE_EXTEND:
86 prot |= PROT_READ | PROT_WRITE;
87
88 if (!AllocateFileRegion(&file_, region.offset, region.size))
89 return false;
90
91 break;
92 }
93
94 data_ = static_cast<uint8_t*>(
95 mmap(nullptr, map_size, prot, flags, file_.GetPlatformFile(), map_start));
96 if (data_ == MAP_FAILED) {
97 DPLOG(ERROR) << "mmap " << file_.GetPlatformFile();
98 return false;
99 }
100
101 data_ += data_offset;
102 return true;
103 }
104 #endif
105
CloseHandles()106 void MemoryMappedFile::CloseHandles() {
107 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
108
109 if (data_ != nullptr) {
110 munmap(data_, length_);
111 }
112 file_.Close();
113 length_ = 0;
114 }
115
116 } // namespace base
117