Index: base/files/memory_mapped_file_posix.cc |
diff --git a/base/files/memory_mapped_file_posix.cc b/base/files/memory_mapped_file_posix.cc |
index 5d7e0079992d835d32aad565d4836600257cb4b5..ebf38779f039708835242eb19ed7223927a28f40 100644 |
--- a/base/files/memory_mapped_file_posix.cc |
+++ b/base/files/memory_mapped_file_posix.cc |
@@ -16,22 +16,63 @@ namespace base { |
MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) { |
} |
-bool MemoryMappedFile::MapFileToMemory() { |
+bool MemoryMappedFile::MapFileRegionToMemory( |
+ const MemoryMappedFile::Region& region) { |
ThreadRestrictions::AssertIOAllowed(); |
- struct stat file_stat; |
- if (fstat(file_.GetPlatformFile(), &file_stat) == -1 ) { |
- DPLOG(ERROR) << "fstat " << file_.GetPlatformFile(); |
- return false; |
+ off_t map_start = 0; |
+ size_t map_size = 0; |
+ int32 data_offset = 0; |
+ |
+ if (region == MemoryMappedFile::Region::kWholeFile) { |
+ int64 file_len = file_.GetLength(); |
+ if (file_len == -1) { |
+ DPLOG(ERROR) << "fstat " << file_.GetPlatformFile(); |
+ return false; |
+ } |
+ map_size = static_cast<size_t>(file_len); |
+ length_ = map_size; |
+ } else { |
+ // The region can be arbitrarily aligned. mmap, instead, requires both the |
+ // start and size to be page-aligned. Hence, we map here the page-aligned |
+ // outer region [|aligned_start|, |aligned_start| + |size|] which contains |
+ // |region| and then add up the |data_offset| displacement. |
+ int64 aligned_start = 0; |
+ int64 aligned_size = 0; |
+ CalculateVMAlignedBoundaries(region.offset, |
+ region.size, |
+ &aligned_start, |
+ &aligned_size, |
+ &data_offset); |
+ |
+ // Ensure that the casts in the mmap call below are sane. |
+ if (aligned_start < 0 || aligned_size < 0 || |
+ aligned_start > std::numeric_limits<off_t>::max() || |
+ static_cast<uint64>(aligned_size) > |
+ std::numeric_limits<size_t>::max() || |
+ static_cast<uint64>(region.size) > std::numeric_limits<size_t>::max()) { |
+ DLOG(ERROR) << "Region bounds are not valid for mmap"; |
+ return false; |
+ } |
+ |
+ map_start = static_cast<off_t>(aligned_start); |
+ map_size = static_cast<size_t>(aligned_size); |
+ length_ = static_cast<size_t>(region.size); |
} |
- length_ = file_stat.st_size; |
- data_ = static_cast<uint8*>( |
- mmap(NULL, length_, PROT_READ, MAP_SHARED, file_.GetPlatformFile(), 0)); |
- if (data_ == MAP_FAILED) |
+ data_ = static_cast<uint8*>(mmap(NULL, |
+ map_size, |
+ PROT_READ, |
+ MAP_SHARED, |
+ file_.GetPlatformFile(), |
+ map_start)); |
+ if (data_ == MAP_FAILED) { |
DPLOG(ERROR) << "mmap " << file_.GetPlatformFile(); |
+ return false; |
+ } |
- return data_ != MAP_FAILED; |
+ data_ += data_offset; |
+ return true; |
} |
void MemoryMappedFile::CloseHandles() { |