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