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 <sys/mman.h>
      8 #include <sys/stat.h>
      9 #include <unistd.h>
     10 
     11 #include "base/logging.h"
     12 #include "base/threading/thread_restrictions.h"
     13 
     14 namespace base {
     15 
     16 MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) {
     17 }
     18 
     19 bool MemoryMappedFile::MapFileRegionToMemory(
     20     const MemoryMappedFile::Region& region) {
     21   ThreadRestrictions::AssertIOAllowed();
     22 
     23   off_t map_start = 0;
     24   size_t map_size = 0;
     25   int32 data_offset = 0;
     26 
     27   if (region == MemoryMappedFile::Region::kWholeFile) {
     28     int64 file_len = file_.GetLength();
     29     if (file_len == -1) {
     30       DPLOG(ERROR) << "fstat " << file_.GetPlatformFile();
     31       return false;
     32     }
     33     map_size = static_cast<size_t>(file_len);
     34     length_ = map_size;
     35   } else {
     36     // The region can be arbitrarily aligned. mmap, instead, requires both the
     37     // start and size to be page-aligned. Hence, we map here the page-aligned
     38     // outer region [|aligned_start|, |aligned_start| + |size|] which contains
     39     // |region| and then add up the |data_offset| displacement.
     40     int64 aligned_start = 0;
     41     int64 aligned_size = 0;
     42     CalculateVMAlignedBoundaries(region.offset,
     43                                  region.size,
     44                                  &aligned_start,
     45                                  &aligned_size,
     46                                  &data_offset);
     47 
     48     // Ensure that the casts in the mmap call below are sane.
     49     if (aligned_start < 0 || aligned_size < 0 ||
     50         aligned_start > std::numeric_limits<off_t>::max() ||
     51         static_cast<uint64>(aligned_size) >
     52             std::numeric_limits<size_t>::max() ||
     53         static_cast<uint64>(region.size) > std::numeric_limits<size_t>::max()) {
     54       DLOG(ERROR) << "Region bounds are not valid for mmap";
     55       return false;
     56     }
     57 
     58     map_start = static_cast<off_t>(aligned_start);
     59     map_size = static_cast<size_t>(aligned_size);
     60     length_ = static_cast<size_t>(region.size);
     61   }
     62 
     63   data_ = static_cast<uint8*>(mmap(NULL,
     64                                    map_size,
     65                                    PROT_READ,
     66                                    MAP_SHARED,
     67                                    file_.GetPlatformFile(),
     68                                    map_start));
     69   if (data_ == MAP_FAILED) {
     70     DPLOG(ERROR) << "mmap " << file_.GetPlatformFile();
     71     return false;
     72   }
     73 
     74   data_ += data_offset;
     75   return true;
     76 }
     77 
     78 void MemoryMappedFile::CloseHandles() {
     79   ThreadRestrictions::AssertIOAllowed();
     80 
     81   if (data_ != NULL)
     82     munmap(data_, length_);
     83   file_.Close();
     84 
     85   data_ = NULL;
     86   length_ = 0;
     87 }
     88 
     89 }  // namespace base
     90