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 "base/files/file_path.h"
      8 #include "base/strings/string16.h"
      9 #include "base/threading/thread_restrictions.h"
     10 
     11 namespace base {
     12 
     13 MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0), image_(false) {
     14 }
     15 
     16 bool MemoryMappedFile::InitializeAsImageSection(const FilePath& file_name) {
     17   image_ = true;
     18   return Initialize(file_name);
     19 }
     20 
     21 bool MemoryMappedFile::MapFileRegionToMemory(
     22     const MemoryMappedFile::Region& region) {
     23   ThreadRestrictions::AssertIOAllowed();
     24 
     25   if (!file_.IsValid())
     26     return false;
     27 
     28   int flags = image_ ? SEC_IMAGE | PAGE_READONLY : PAGE_READONLY;
     29 
     30   file_mapping_.Set(::CreateFileMapping(file_.GetPlatformFile(), NULL,
     31                                         flags, 0, 0, NULL));
     32   if (!file_mapping_.IsValid())
     33     return false;
     34 
     35   LARGE_INTEGER map_start = {0};
     36   SIZE_T map_size = 0;
     37   int32 data_offset = 0;
     38 
     39   if (region == MemoryMappedFile::Region::kWholeFile) {
     40     int64 file_len = file_.GetLength();
     41     if (file_len <= 0 || file_len > kint32max)
     42       return false;
     43     length_ = static_cast<size_t>(file_len);
     44   } else {
     45     // The region can be arbitrarily aligned. MapViewOfFile, instead, requires
     46     // that the start address is aligned to the VM granularity (which is
     47     // typically larger than a page size, for instance 32k).
     48     // Also, conversely to POSIX's mmap, the |map_size| doesn't have to be
     49     // aligned and must be less than or equal the mapped file size.
     50     // We map here the outer region [|aligned_start|, |aligned_start+size|]
     51     // which contains |region| and then add up the |data_offset| displacement.
     52     int64 aligned_start = 0;
     53     int64 ignored = 0;
     54     CalculateVMAlignedBoundaries(
     55         region.offset, region.size, &aligned_start, &ignored, &data_offset);
     56     int64 size = region.size + data_offset;
     57 
     58     // Ensure that the casts below in the MapViewOfFile call are sane.
     59     if (aligned_start < 0 || size < 0 ||
     60         static_cast<uint64>(size) > std::numeric_limits<SIZE_T>::max()) {
     61       DLOG(ERROR) << "Region bounds are not valid for MapViewOfFile";
     62       return false;
     63     }
     64     map_start.QuadPart = aligned_start;
     65     map_size = static_cast<SIZE_T>(size);
     66     length_ = static_cast<size_t>(region.size);
     67   }
     68 
     69   data_ = static_cast<uint8*>(::MapViewOfFile(file_mapping_.Get(),
     70                                               FILE_MAP_READ,
     71                                               map_start.HighPart,
     72                                               map_start.LowPart,
     73                                               map_size));
     74   if (data_ == NULL)
     75     return false;
     76   data_ += data_offset;
     77   return true;
     78 }
     79 
     80 void MemoryMappedFile::CloseHandles() {
     81   if (data_)
     82     ::UnmapViewOfFile(data_);
     83   if (file_mapping_.IsValid())
     84     file_mapping_.Close();
     85   if (file_.IsValid())
     86     file_.Close();
     87 
     88   data_ = NULL;
     89   length_ = 0;
     90 }
     91 
     92 }  // namespace base
     93