// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/files/memory_mapped_file.h" #include #include #include #include #include #include #include "base/files/file_util.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/threading/scoped_blocking_call.h" #include "build/build_config.h" namespace base { MemoryMappedFile::MemoryMappedFile() : data_(nullptr), length_(0) {} #if !BUILDFLAG(IS_NACL) bool MemoryMappedFile::MapFileRegionToMemory( const MemoryMappedFile::Region& region, Access access) { ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK); off_t map_start = 0; size_t map_size = 0; int32_t data_offset = 0; if (region == MemoryMappedFile::Region::kWholeFile) { int64_t file_len = file_.GetLength(); if (file_len < 0) { DPLOG(ERROR) << "fstat " << file_.GetPlatformFile(); return false; } if (!IsValueInRangeForNumericType(file_len)) return false; map_size = static_cast(file_len); length_ = map_size; } else { // The region can be arbitrarily aligned. mmap, instead, requires both the // start and size to be page-aligned. Hence, we map here the page-aligned // outer region [|aligned_start|, |aligned_start| + |size|] which contains // |region| and then add up the |data_offset| displacement. int64_t aligned_start = 0; size_t aligned_size = 0; CalculateVMAlignedBoundaries(region.offset, region.size, &aligned_start, &aligned_size, &data_offset); // Ensure that the casts in the mmap call below are sane. if (aligned_start < 0 || !IsValueInRangeForNumericType(aligned_start)) { DLOG(ERROR) << "Region bounds are not valid for mmap"; return false; } map_start = static_cast(aligned_start); map_size = aligned_size; length_ = region.size; } int flags = 0; switch (access) { case READ_ONLY: flags |= PROT_READ; break; case READ_WRITE: flags |= PROT_READ | PROT_WRITE; break; case READ_WRITE_EXTEND: flags |= PROT_READ | PROT_WRITE; if (!AllocateFileRegion(&file_, region.offset, region.size)) return false; break; } data_ = static_cast(mmap(nullptr, map_size, flags, MAP_SHARED, file_.GetPlatformFile(), map_start)); if (data_ == MAP_FAILED) { DPLOG(ERROR) << "mmap " << file_.GetPlatformFile(); return false; } data_ += data_offset; return true; } #endif void MemoryMappedFile::CloseHandles() { ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK); if (data_ != nullptr) munmap(data_, length_); file_.Close(); data_ = nullptr; length_ = 0; } } // namespace base