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