• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * System utilities.
5  */
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <sys/mman.h>
11 #include <limits.h>
12 #include <errno.h>
13 #include <assert.h>
14 
15 #define LOG_TAG "minzip"
16 #include "Log.h"
17 #include "SysUtil.h"
18 
19 /*
20  * Having trouble finding a portable way to get this.  sysconf(_SC_PAGE_SIZE)
21  * seems appropriate, but we don't have that on the device.  Some systems
22  * have getpagesize(2), though the linux man page has some odd cautions.
23  */
24 #define DEFAULT_PAGE_SIZE   4096
25 
26 
27 /*
28  * Create an anonymous shared memory segment large enough to hold "length"
29  * bytes.  The actual segment may be larger because mmap() operates on
30  * page boundaries (usually 4K).
31  */
sysCreateAnonShmem(size_t length)32 static void* sysCreateAnonShmem(size_t length)
33 {
34     void* ptr;
35 
36     ptr = mmap(NULL, length, PROT_READ | PROT_WRITE,
37             MAP_SHARED | MAP_ANON, -1, 0);
38     if (ptr == MAP_FAILED) {
39         LOGW("mmap(%d, RW, SHARED|ANON) failed: %s\n", (int) length,
40             strerror(errno));
41         return NULL;
42     }
43 
44     return ptr;
45 }
46 
getFileStartAndLength(int fd,off_t * start_,size_t * length_)47 static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
48 {
49     off_t start, end;
50     size_t length;
51 
52     assert(start_ != NULL);
53     assert(length_ != NULL);
54 
55     start = lseek(fd, 0L, SEEK_CUR);
56     end = lseek(fd, 0L, SEEK_END);
57     (void) lseek(fd, start, SEEK_SET);
58 
59     if (start == (off_t) -1 || end == (off_t) -1) {
60         LOGE("could not determine length of file\n");
61         return -1;
62     }
63 
64     length = end - start;
65     if (length == 0) {
66         LOGE("file is empty\n");
67         return -1;
68     }
69 
70     *start_ = start;
71     *length_ = length;
72 
73     return 0;
74 }
75 
76 /*
77  * Pull the contents of a file into an new shared memory segment.  We grab
78  * everything from fd's current offset on.
79  *
80  * We need to know the length ahead of time so we can allocate a segment
81  * of sufficient size.
82  */
sysLoadFileInShmem(int fd,MemMapping * pMap)83 int sysLoadFileInShmem(int fd, MemMapping* pMap)
84 {
85     off_t start;
86     size_t length, actual;
87     void* memPtr;
88 
89     assert(pMap != NULL);
90 
91     if (getFileStartAndLength(fd, &start, &length) < 0)
92         return -1;
93 
94     memPtr = sysCreateAnonShmem(length);
95     if (memPtr == NULL)
96         return -1;
97 
98     pMap->baseAddr = pMap->addr = memPtr;
99     pMap->baseLength = pMap->length = length;
100 
101     actual = TEMP_FAILURE_RETRY(read(fd, memPtr, length));
102     if (actual != length) {
103         LOGE("only read %d of %d bytes\n", (int) actual, (int) length);
104         sysReleaseShmem(pMap);
105         return -1;
106     }
107 
108     return 0;
109 }
110 
111 /*
112  * Map a file (from fd's current offset) into a shared, read-only memory
113  * segment.  The file offset must be a multiple of the page size.
114  *
115  * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
116  * value and does not disturb "pMap".
117  */
sysMapFileInShmem(int fd,MemMapping * pMap)118 int sysMapFileInShmem(int fd, MemMapping* pMap)
119 {
120     off_t start;
121     size_t length;
122     void* memPtr;
123 
124     assert(pMap != NULL);
125 
126     if (getFileStartAndLength(fd, &start, &length) < 0)
127         return -1;
128 
129     memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start);
130     if (memPtr == MAP_FAILED) {
131         LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n", (int) length,
132             fd, (int) start, strerror(errno));
133         return -1;
134     }
135 
136     pMap->baseAddr = pMap->addr = memPtr;
137     pMap->baseLength = pMap->length = length;
138 
139     return 0;
140 }
141 
142 /*
143  * Map part of a file (from fd's current offset) into a shared, read-only
144  * memory segment.
145  *
146  * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
147  * value and does not disturb "pMap".
148  */
sysMapFileSegmentInShmem(int fd,off_t start,long length,MemMapping * pMap)149 int sysMapFileSegmentInShmem(int fd, off_t start, long length,
150     MemMapping* pMap)
151 {
152     off_t dummy;
153     size_t fileLength, actualLength;
154     off_t actualStart;
155     int adjust;
156     void* memPtr;
157 
158     assert(pMap != NULL);
159 
160     if (getFileStartAndLength(fd, &dummy, &fileLength) < 0)
161         return -1;
162 
163     if (start + length > (long)fileLength) {
164         LOGW("bad segment: st=%d len=%ld flen=%d\n",
165             (int) start, length, (int) fileLength);
166         return -1;
167     }
168 
169     /* adjust to be page-aligned */
170     adjust = start % DEFAULT_PAGE_SIZE;
171     actualStart = start - adjust;
172     actualLength = length + adjust;
173 
174     memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED,
175                 fd, actualStart);
176     if (memPtr == MAP_FAILED) {
177         LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n",
178             (int) actualLength, fd, (int) actualStart, strerror(errno));
179         return -1;
180     }
181 
182     pMap->baseAddr = memPtr;
183     pMap->baseLength = actualLength;
184     pMap->addr = (char*)memPtr + adjust;
185     pMap->length = length;
186 
187     LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d\n",
188         (int) start, (int) length,
189         pMap->baseAddr, (int) pMap->baseLength,
190         pMap->addr, (int) pMap->length);
191 
192     return 0;
193 }
194 
195 /*
196  * Release a memory mapping.
197  */
sysReleaseShmem(MemMapping * pMap)198 void sysReleaseShmem(MemMapping* pMap)
199 {
200     if (pMap->baseAddr == NULL && pMap->baseLength == 0)
201         return;
202 
203     if (munmap(pMap->baseAddr, pMap->baseLength) < 0) {
204         LOGW("munmap(%p, %d) failed: %s\n",
205             pMap->baseAddr, (int)pMap->baseLength, strerror(errno));
206     } else {
207         LOGV("munmap(%p, %d) succeeded\n", pMap->baseAddr, pMap->baseLength);
208         pMap->baseAddr = NULL;
209         pMap->baseLength = 0;
210     }
211 }
212 
213