• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "lang_id/common/file/mmap.h"
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <sys/mman.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 
27 #include "lang_id/common/lite_base/logging.h"
28 #include "lang_id/common/lite_base/macros.h"
29 
30 namespace libtextclassifier3 {
31 namespace mobile {
32 
33 namespace {
GetLastSystemError()34 inline string GetLastSystemError() {
35   return string(strerror(errno));
36 }
37 
GetErrorMmapHandle()38 inline MmapHandle GetErrorMmapHandle() {
39   return MmapHandle(nullptr, 0);
40 }
41 
42 class FileCloser {
43  public:
FileCloser(int fd)44   explicit FileCloser(int fd) : fd_(fd) {}
~FileCloser()45   ~FileCloser() {
46     int result = close(fd_);
47     if (result != 0) {
48       const string last_error = GetLastSystemError();
49       SAFTM_LOG(ERROR) << "Error closing file descriptor: " << last_error;
50     }
51   }
52  private:
53   const int fd_;
54 
55   SAFTM_DISALLOW_COPY_AND_ASSIGN(FileCloser);
56 };
57 }  // namespace
58 
MmapFile(const string & filename)59 MmapHandle MmapFile(const string &filename) {
60   int fd = open(filename.c_str(), O_RDONLY);
61 
62   if (fd < 0) {
63     const string last_error = GetLastSystemError();
64     SAFTM_LOG(ERROR) << "Error opening " << filename << ": " << last_error;
65     return GetErrorMmapHandle();
66   }
67 
68   // Make sure we close fd no matter how we exit this function.  As the man page
69   // for mmap clearly states: "closing the file descriptor does not unmap the
70   // region."  Hence, we can close fd as soon as we return from here.
71   FileCloser file_closer(fd);
72 
73   return MmapFile(fd);
74 }
75 
MmapFile(int fd)76 MmapHandle MmapFile(int fd) {
77   // Get file stats to obtain file size.
78   struct stat sb;
79   if (fstat(fd, &sb) != 0) {
80     const string last_error = GetLastSystemError();
81     SAFTM_LOG(ERROR) << "Unable to stat fd: " << last_error;
82     return GetErrorMmapHandle();
83   }
84   size_t file_size_in_bytes = static_cast<size_t>(sb.st_size);
85 
86   // Perform actual mmap.
87   void *mmap_addr = mmap(
88 
89       // Let system pick address for mmapp-ed data.
90       nullptr,
91 
92       // Mmap all bytes from the file.
93       file_size_in_bytes,
94 
95       // One can read / write the mapped data (but see MAP_PRIVATE below).
96       // Normally, we expect only to read it, but in the future, we may want to
97       // write it, to fix e.g., endianness differences.
98       PROT_READ | PROT_WRITE,
99 
100       // Updates to mmaped data are *not* propagated to actual file.
101       // AFAIK(salcianu) that's anyway not possible on Android.
102       MAP_PRIVATE,
103 
104       // Descriptor of file to mmap.
105       fd,
106 
107       // Map bytes right from the beginning of the file.  This, and
108       // file_size_in_bytes (2nd argument) means we map all bytes from the file.
109       0);
110   if (mmap_addr == MAP_FAILED) {
111     const string last_error = GetLastSystemError();
112     SAFTM_LOG(ERROR) << "Error while mmapping: " << last_error;
113     return GetErrorMmapHandle();
114   }
115 
116   return MmapHandle(mmap_addr, file_size_in_bytes);
117 }
118 
Unmap(MmapHandle mmap_handle)119 bool Unmap(MmapHandle mmap_handle) {
120   if (!mmap_handle.ok()) {
121     // Unmapping something that hasn't been mapped is trivially successful.
122     return true;
123   }
124   if (munmap(mmap_handle.start(), mmap_handle.num_bytes()) != 0) {
125     const string last_error = GetLastSystemError();
126     SAFTM_LOG(ERROR) << "Error during Unmap / munmap: " << last_error;
127     return false;
128   }
129   return true;
130 }
131 
132 }  // namespace mobile
133 }  // namespace nlp_saft
134