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 <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 < 0) {
     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       auto file_len = file_.GetLength();
     82       if (file_len < 0) {
     83         DPLOG(ERROR) << "fstat " << file_.GetPlatformFile();
     84         return false;
     85       }
     86       file_.SetLength(std::max(file_len, region.offset + region.size));
     87       flags |= PROT_READ | PROT_WRITE;
     88       break;
     89   }
     90   data_ = static_cast<uint8_t*>(mmap(NULL, map_size, flags, MAP_SHARED,
     91                                      file_.GetPlatformFile(), map_start));
     92   if (data_ == MAP_FAILED) {
     93     DPLOG(ERROR) << "mmap " << file_.GetPlatformFile();
     94     return false;
     95   }
     96 
     97   data_ += data_offset;
     98   return true;
     99 }
    100 #endif
    101 
    102 void MemoryMappedFile::CloseHandles() {
    103   ThreadRestrictions::AssertIOAllowed();
    104 
    105   if (data_ != NULL)
    106     munmap(data_, length_);
    107   file_.Close();
    108 
    109   data_ = NULL;
    110   length_ = 0;
    111 }
    112 
    113 }  // namespace base
    114