#include <unistd.h>
#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread_restrictions.h"
namespace base {
-MemoryMappedFile::MemoryMappedFile()
- : file_(kInvalidPlatformFileValue),
- data_(NULL),
- length_(0) {
+MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) {
}
-bool MemoryMappedFile::MapFileToMemoryInternal() {
+bool MemoryMappedFile::MapFileRegionToMemory(
+ const MemoryMappedFile::Region& region) {
ThreadRestrictions::AssertIOAllowed();
- struct stat file_stat;
- if (fstat(file_, &file_stat) == kInvalidPlatformFileValue) {
- DPLOG(ERROR) << "fstat " << file_;
- 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_, 0));
- if (data_ == MAP_FAILED)
- DPLOG(ERROR) << "mmap " << file_;
+ 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() {
if (data_ != NULL)
munmap(data_, length_);
- if (file_ != kInvalidPlatformFileValue)
- ignore_result(HANDLE_EINTR(close(file_)));
+ file_.Close();
data_ = NULL;
length_ = 0;
- file_ = kInvalidPlatformFileValue;
}
} // namespace base