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 <stddef.h> 8 #include <stdint.h> 9 #include <sys/mman.h> 10 #include <sys/stat.h> 11 #include <unistd.h> 12 13 #include "base/logging.h" 14 #include "base/threading/thread_restrictions.h" 15 #include "build/build_config.h" 16 17 namespace base { 18 19 MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) { 20 } 21 22 #if !defined(OS_NACL) 23 bool MemoryMappedFile::MapFileRegionToMemory( 24 const MemoryMappedFile::Region& region, 25 Access access) { 26 ThreadRestrictions::AssertIOAllowed(); 27 28 off_t map_start = 0; 29 size_t map_size = 0; 30 int32_t data_offset = 0; 31 32 if (region == MemoryMappedFile::Region::kWholeFile) { 33 int64_t file_len = file_.GetLength(); 34 if (file_len == -1) { 35 DPLOG(ERROR) << "fstat " << file_.GetPlatformFile(); 36 return false; 37 } 38 map_size = static_cast<size_t>(file_len); 39 length_ = map_size; 40 } else { 41 // The region can be arbitrarily aligned. mmap, instead, requires both the 42 // start and size to be page-aligned. Hence, we map here the page-aligned 43 // outer region [|aligned_start|, |aligned_start| + |size|] which contains 44 // |region| and then add up the |data_offset| displacement. 45 int64_t aligned_start = 0; 46 int64_t aligned_size = 0; 47 CalculateVMAlignedBoundaries(region.offset, 48 region.size, 49 &aligned_start, 50 &aligned_size, 51 &data_offset); 52 53 // Ensure that the casts in the mmap call below are sane. 54 if (aligned_start < 0 || aligned_size < 0 || 55 aligned_start > std::numeric_limits<off_t>::max() || 56 static_cast<uint64_t>(aligned_size) > 57 std::numeric_limits<size_t>::max() || 58 static_cast<uint64_t>(region.size) > 59 std::numeric_limits<size_t>::max()) { 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 = static_cast<size_t>(aligned_size); 66 length_ = static_cast<size_t>(region.size); 67 } 68 69 int flags = 0; 70 switch (access) { 71 case READ_ONLY: 72 flags |= PROT_READ; 73 break; 74 case READ_WRITE: 75 flags |= PROT_READ | PROT_WRITE; 76 break; 77 case READ_WRITE_EXTEND: 78 // POSIX won't auto-extend the file when it is written so it must first 79 // be explicitly extended to the maximum size. Zeros will fill the new 80 // space. 81 file_.SetLength(std::max(file_.GetLength(), region.offset + region.size)); 82 flags |= PROT_READ | PROT_WRITE; 83 break; 84 } 85 data_ = static_cast<uint8_t*>(mmap(NULL, map_size, flags, MAP_SHARED, 86 file_.GetPlatformFile(), map_start)); 87 if (data_ == MAP_FAILED) { 88 DPLOG(ERROR) << "mmap " << file_.GetPlatformFile(); 89 return false; 90 } 91 92 data_ += data_offset; 93 return true; 94 } 95 #endif 96 97 void MemoryMappedFile::CloseHandles() { 98 ThreadRestrictions::AssertIOAllowed(); 99 100 if (data_ != NULL) 101 munmap(data_, length_); 102 file_.Close(); 103 104 data_ = NULL; 105 length_ = 0; 106 } 107 108 } // namespace base 109