Home | History | Annotate | Download | only in files
      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