memory_mapped_file_posix.cc 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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. #include "base/files/memory_mapped_file.h"
  5. #include <fcntl.h>
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <sys/mman.h>
  9. #include <sys/stat.h>
  10. #include <unistd.h>
  11. #include "base/files/file_util.h"
  12. #include "base/logging.h"
  13. #include "base/numerics/safe_conversions.h"
  14. #include "base/threading/scoped_blocking_call.h"
  15. #include "build/build_config.h"
  16. namespace base {
  17. MemoryMappedFile::MemoryMappedFile() : data_(nullptr), length_(0) {}
  18. #if !BUILDFLAG(IS_NACL)
  19. bool MemoryMappedFile::MapFileRegionToMemory(
  20. const MemoryMappedFile::Region& region,
  21. Access access) {
  22. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  23. off_t map_start = 0;
  24. size_t map_size = 0;
  25. int32_t data_offset = 0;
  26. if (region == MemoryMappedFile::Region::kWholeFile) {
  27. int64_t file_len = file_.GetLength();
  28. if (file_len < 0) {
  29. DPLOG(ERROR) << "fstat " << file_.GetPlatformFile();
  30. return false;
  31. }
  32. if (!IsValueInRangeForNumericType<size_t>(file_len))
  33. return false;
  34. map_size = static_cast<size_t>(file_len);
  35. length_ = map_size;
  36. } else {
  37. // The region can be arbitrarily aligned. mmap, instead, requires both the
  38. // start and size to be page-aligned. Hence, we map here the page-aligned
  39. // outer region [|aligned_start|, |aligned_start| + |size|] which contains
  40. // |region| and then add up the |data_offset| displacement.
  41. int64_t aligned_start = 0;
  42. size_t aligned_size = 0;
  43. CalculateVMAlignedBoundaries(region.offset,
  44. region.size,
  45. &aligned_start,
  46. &aligned_size,
  47. &data_offset);
  48. // Ensure that the casts in the mmap call below are sane.
  49. if (aligned_start < 0 ||
  50. !IsValueInRangeForNumericType<off_t>(aligned_start)) {
  51. DLOG(ERROR) << "Region bounds are not valid for mmap";
  52. return false;
  53. }
  54. map_start = static_cast<off_t>(aligned_start);
  55. map_size = aligned_size;
  56. length_ = region.size;
  57. }
  58. int flags = 0;
  59. switch (access) {
  60. case READ_ONLY:
  61. flags |= PROT_READ;
  62. break;
  63. case READ_WRITE:
  64. flags |= PROT_READ | PROT_WRITE;
  65. break;
  66. case READ_WRITE_EXTEND:
  67. flags |= PROT_READ | PROT_WRITE;
  68. if (!AllocateFileRegion(&file_, region.offset, region.size))
  69. return false;
  70. break;
  71. }
  72. data_ = static_cast<uint8_t*>(mmap(nullptr, map_size, flags, MAP_SHARED,
  73. file_.GetPlatformFile(), map_start));
  74. if (data_ == MAP_FAILED) {
  75. DPLOG(ERROR) << "mmap " << file_.GetPlatformFile();
  76. return false;
  77. }
  78. data_ += data_offset;
  79. return true;
  80. }
  81. #endif
  82. void MemoryMappedFile::CloseHandles() {
  83. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  84. if (data_ != nullptr)
  85. munmap(data_, length_);
  86. file_.Close();
  87. data_ = nullptr;
  88. length_ = 0;
  89. }
  90. } // namespace base