1 /*
2  * Copyright (C) 2006 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 //
18 // Shared file mapping class.
19 //
20 
21 #define LOG_TAG "filemap"
22 
23 #include <utils/FileMap.h>
24 #include <utils/Log.h>
25 
26 #if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO)
27 # define PRId32 "I32d"
28 # define PRIx32 "I32x"
29 # define PRId64 "I64d"
30 #else
31 #include <inttypes.h>
32 #endif
33 #include <stdio.h>
34 #include <stdlib.h>
35 
36 #if !defined(__MINGW32__)
37 #include <sys/mman.h>
38 #endif
39 
40 #include <string.h>
41 #include <memory.h>
42 #include <errno.h>
43 #include <assert.h>
44 
45 using namespace android;
46 
47 /*static*/ long FileMap::mPageSize = -1;
48 
49 // Constructor.  Create an empty object.
FileMap(void)50 FileMap::FileMap(void)
51     : mFileName(nullptr),
52       mBasePtr(nullptr),
53       mBaseLength(0),
54       mDataPtr(nullptr),
55       mDataLength(0)
56 #if defined(__MINGW32__)
57       ,
58       mFileHandle(INVALID_HANDLE_VALUE),
59       mFileMapping(NULL)
60 #endif
61 {
62 }
63 
64 // Move Constructor.
FileMap(FileMap && other)65 FileMap::FileMap(FileMap&& other) noexcept
66     : mFileName(other.mFileName),
67       mBasePtr(other.mBasePtr),
68       mBaseLength(other.mBaseLength),
69       mDataOffset(other.mDataOffset),
70       mDataPtr(other.mDataPtr),
71       mDataLength(other.mDataLength)
72 #if defined(__MINGW32__)
73       ,
74       mFileHandle(other.mFileHandle),
75       mFileMapping(other.mFileMapping)
76 #endif
77 {
78     other.mFileName = nullptr;
79     other.mBasePtr = nullptr;
80     other.mDataPtr = nullptr;
81 #if defined(__MINGW32__)
82     other.mFileHandle = INVALID_HANDLE_VALUE;
83     other.mFileMapping = NULL;
84 #endif
85 }
86 
87 // Move assign operator.
operator =(FileMap && other)88 FileMap& FileMap::operator=(FileMap&& other) noexcept {
89     mFileName = other.mFileName;
90     mBasePtr = other.mBasePtr;
91     mBaseLength = other.mBaseLength;
92     mDataOffset = other.mDataOffset;
93     mDataPtr = other.mDataPtr;
94     mDataLength = other.mDataLength;
95     other.mFileName = nullptr;
96     other.mBasePtr = nullptr;
97     other.mDataPtr = nullptr;
98 #if defined(__MINGW32__)
99     mFileHandle = other.mFileHandle;
100     mFileMapping = other.mFileMapping;
101     other.mFileHandle = INVALID_HANDLE_VALUE;
102     other.mFileMapping = NULL;
103 #endif
104     return *this;
105 }
106 
107 // Destructor.
~FileMap(void)108 FileMap::~FileMap(void)
109 {
110     if (mFileName != nullptr) {
111         free(mFileName);
112     }
113 #if defined(__MINGW32__)
114     if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
115         ALOGD("UnmapViewOfFile(%p) failed, error = %lu\n", mBasePtr,
116               GetLastError() );
117     }
118     if (mFileMapping != NULL) {
119         CloseHandle(mFileMapping);
120     }
121 #else
122     if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
123         ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength);
124     }
125 #endif
126 }
127 
128 
129 // Create a new mapping on an open file.
130 //
131 // Closing the file descriptor does not unmap the pages, so we don't
132 // claim ownership of the fd.
133 //
134 // Returns "false" on failure.
create(const char * origFileName,int fd,off64_t offset,size_t length,bool readOnly)135 bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length,
136         bool readOnly)
137 {
138 #if defined(__MINGW32__)
139     int     adjust;
140     off64_t adjOffset;
141     size_t  adjLength;
142 
143     if (mPageSize == -1) {
144         SYSTEM_INFO  si;
145 
146         GetSystemInfo( &si );
147         mPageSize = si.dwAllocationGranularity;
148     }
149 
150     DWORD  protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
151 
152     mFileHandle  = (HANDLE) _get_osfhandle(fd);
153     mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
154     if (mFileMapping == NULL) {
155         ALOGE("CreateFileMapping(%p, %lx) failed with error %lu\n",
156               mFileHandle, protect, GetLastError() );
157         return false;
158     }
159 
160     adjust    = offset % mPageSize;
161     adjOffset = offset - adjust;
162     adjLength = length + adjust;
163 
164     mBasePtr = MapViewOfFile( mFileMapping,
165                               readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
166                               0,
167                               (DWORD)(adjOffset),
168                               adjLength );
169     if (mBasePtr == NULL) {
170         ALOGE("MapViewOfFile(%" PRId64 ", %zu) failed with error %lu\n",
171               adjOffset, adjLength, GetLastError() );
172         CloseHandle(mFileMapping);
173         mFileMapping = NULL;
174         return false;
175     }
176 #else // !defined(__MINGW32__)
177     assert(fd >= 0);
178     assert(offset >= 0);
179     assert(length > 0);
180 
181     // init on first use
182     if (mPageSize == -1) {
183         mPageSize = sysconf(_SC_PAGESIZE);
184         if (mPageSize == -1) {
185             ALOGE("could not get _SC_PAGESIZE\n");
186             return false;
187         }
188     }
189 
190     int adjust = offset % mPageSize;
191     off64_t adjOffset = offset - adjust;
192     size_t adjLength;
193     if (__builtin_add_overflow(length, adjust, &adjLength)) {
194         ALOGE("adjusted length overflow: length %zu adjust %d", length, adjust);
195         return false;
196     }
197 
198     int flags = MAP_SHARED;
199     int prot = PROT_READ;
200     if (!readOnly) prot |= PROT_WRITE;
201 
202     void* ptr = mmap64(nullptr, adjLength, prot, flags, fd, adjOffset);
203     if (ptr == MAP_FAILED) {
204         if (errno == EINVAL && length == 0) {
205             ptr = nullptr;
206             adjust = 0;
207         } else {
208             ALOGE("mmap(%lld,%zu) failed: %s\n", (long long)adjOffset, adjLength, strerror(errno));
209             return false;
210         }
211     }
212     mBasePtr = ptr;
213 #endif // !defined(__MINGW32__)
214 
215     mFileName = origFileName != nullptr ? strdup(origFileName) : nullptr;
216     mBaseLength = adjLength;
217     mDataOffset = offset;
218     mDataPtr = (char*) mBasePtr + adjust;
219     mDataLength = length;
220 
221     ALOGV("MAP: base %p/%zu data %p/%zu\n",
222         mBasePtr, mBaseLength, mDataPtr, mDataLength);
223 
224     return true;
225 }
226 
227 // Provide guidance to the system.
228 #if !defined(_WIN32)
advise(MapAdvice advice)229 int FileMap::advise(MapAdvice advice)
230 {
231     int cc, sysAdvice;
232 
233     switch (advice) {
234         case NORMAL:        sysAdvice = MADV_NORMAL;        break;
235         case RANDOM:        sysAdvice = MADV_RANDOM;        break;
236         case SEQUENTIAL:    sysAdvice = MADV_SEQUENTIAL;    break;
237         case WILLNEED:      sysAdvice = MADV_WILLNEED;      break;
238         case DONTNEED:      sysAdvice = MADV_DONTNEED;      break;
239         default:
240                             assert(false);
241                             return -1;
242     }
243 
244     cc = madvise(mBasePtr, mBaseLength, sysAdvice);
245     if (cc != 0)
246         ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
247     return cc;
248 }
249 
250 #else
advise(MapAdvice)251 int FileMap::advise(MapAdvice /* advice */)
252 {
253     return -1;
254 }
255 #endif
256