Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / base / files / memory_mapped_file_posix.cc
index ba00946..ebf3877 100644 (file)
@@ -9,33 +9,70 @@
 #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() {
@@ -43,12 +80,10 @@ 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