1 // Copyright 2013 The Chromium 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 "base/files/memory_mapped_file.h"
6
7 #include <utility>
8
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/numerics/safe_math.h"
12 #include "base/sys_info.h"
13 #include "build/build_config.h"
14
15 namespace base {
16
17 const MemoryMappedFile::Region MemoryMappedFile::Region::kWholeFile = {0, 0};
18
operator ==(const MemoryMappedFile::Region & other) const19 bool MemoryMappedFile::Region::operator==(
20 const MemoryMappedFile::Region& other) const {
21 return other.offset == offset && other.size == size;
22 }
23
operator !=(const MemoryMappedFile::Region & other) const24 bool MemoryMappedFile::Region::operator!=(
25 const MemoryMappedFile::Region& other) const {
26 return other.offset != offset || other.size != size;
27 }
28
~MemoryMappedFile()29 MemoryMappedFile::~MemoryMappedFile() {
30 CloseHandles();
31 }
32
33 #if !defined(OS_NACL)
Initialize(const FilePath & file_name,Access access)34 bool MemoryMappedFile::Initialize(const FilePath& file_name, Access access) {
35 if (IsValid())
36 return false;
37
38 uint32_t flags = 0;
39 switch (access) {
40 case READ_ONLY:
41 flags = File::FLAG_OPEN | File::FLAG_READ;
42 break;
43 case READ_WRITE:
44 flags = File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE;
45 break;
46 case READ_WRITE_EXTEND:
47 // Can't open with "extend" because no maximum size is known.
48 NOTREACHED();
49 }
50 file_.Initialize(file_name, flags);
51
52 if (!file_.IsValid()) {
53 DLOG(ERROR) << "Couldn't open " << file_name.AsUTF8Unsafe();
54 return false;
55 }
56
57 if (!MapFileRegionToMemory(Region::kWholeFile, access)) {
58 CloseHandles();
59 return false;
60 }
61
62 return true;
63 }
64
Initialize(File file,Access access)65 bool MemoryMappedFile::Initialize(File file, Access access) {
66 DCHECK_NE(READ_WRITE_EXTEND, access);
67 return Initialize(std::move(file), Region::kWholeFile, access);
68 }
69
Initialize(File file,const Region & region,Access access)70 bool MemoryMappedFile::Initialize(File file,
71 const Region& region,
72 Access access) {
73 switch (access) {
74 case READ_WRITE_EXTEND:
75 DCHECK(Region::kWholeFile != region);
76 {
77 CheckedNumeric<int64_t> region_end(region.offset);
78 region_end += region.size;
79 if (!region_end.IsValid()) {
80 DLOG(ERROR) << "Region bounds exceed maximum for base::File.";
81 return false;
82 }
83 }
84 FALLTHROUGH;
85 case READ_ONLY:
86 case READ_WRITE:
87 // Ensure that the region values are valid.
88 if (region.offset < 0) {
89 DLOG(ERROR) << "Region bounds are not valid.";
90 return false;
91 }
92 break;
93 }
94
95 if (IsValid())
96 return false;
97
98 if (region != Region::kWholeFile)
99 DCHECK_GE(region.offset, 0);
100
101 file_ = std::move(file);
102
103 if (!MapFileRegionToMemory(region, access)) {
104 CloseHandles();
105 return false;
106 }
107
108 return true;
109 }
110
IsValid() const111 bool MemoryMappedFile::IsValid() const {
112 return data_ != nullptr;
113 }
114
115 // static
CalculateVMAlignedBoundaries(int64_t start,size_t size,int64_t * aligned_start,size_t * aligned_size,int32_t * offset)116 void MemoryMappedFile::CalculateVMAlignedBoundaries(int64_t start,
117 size_t size,
118 int64_t* aligned_start,
119 size_t* aligned_size,
120 int32_t* offset) {
121 // Sadly, on Windows, the mmap alignment is not just equal to the page size.
122 auto mask = SysInfo::VMAllocationGranularity() - 1;
123 DCHECK(IsValueInRangeForNumericType<int32_t>(mask));
124 *offset = start & mask;
125 *aligned_start = start & ~mask;
126 *aligned_size = (size + *offset + mask) & ~mask;
127 }
128 #endif // !defined(OS_NACL)
129
130 } // namespace base
131