1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * System utilities.
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "DexFile.h"
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "SysUtil.h"
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdlib.h>
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdio.h>
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <unistd.h>
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <string.h>
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP
2864896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden# include <sys/mman.h>
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <limits.h>
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <errno.h>
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3364896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden#include <JNIHelp.h>        // TEMP_FAILURE_RETRY may or may not be in unistd
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create an anonymous shared memory segment large enough to hold "length"
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * bytes.  The actual segment may be larger because mmap() operates on
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * page boundaries (usually 4K).
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void* sysCreateAnonShmem(size_t length)
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* ptr;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ptr = mmap(NULL, length, PROT_READ | PROT_WRITE,
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            MAP_SHARED | MAP_ANON, -1, 0);
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (ptr == MAP_FAILED) {
49e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("mmap(%d, RW, SHARED|ANON) failed: %s", (int) length,
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            strerror(errno));
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return NULL;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return ptr;
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else
56c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block    ALOGE("sysCreateAnonShmem not implemented.");
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return NULL;
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
6199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
6299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Create a private anonymous storage area.
6399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
6499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectint sysCreatePrivateMap(size_t length, MemMapping* pMap)
6599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
6699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    void* memPtr;
6799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
6899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    memPtr = sysCreateAnonShmem(length);
6999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (memPtr == NULL)
7099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return -1;
7199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
7299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pMap->addr = pMap->baseAddr = memPtr;
7399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pMap->length = pMap->baseLength = length;
7499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return 0;
7599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
7699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
7799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
7899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Determine the current offset and remaining length of the open file.
7999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    off_t start, end;
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    size_t length;
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(start_ != NULL);
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(length_ != NULL);
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    start = lseek(fd, 0L, SEEK_CUR);
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    end = lseek(fd, 0L, SEEK_END);
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    (void) lseek(fd, start, SEEK_SET);
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (start == (off_t) -1 || end == (off_t) -1) {
93c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("could not determine length of file");
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    length = end - start;
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (length == 0) {
99c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("file is empty");
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *start_ = start;
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *length_ = length;
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return 0;
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Pull the contents of a file into an new shared memory segment.  We grab
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * everything from fd's current offset on.
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need to know the length ahead of time so we can allocate a segment
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of sufficient size.
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint sysLoadFileInShmem(int fd, MemMapping* pMap)
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    off_t start;
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    size_t length, actual;
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* memPtr;
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(pMap != NULL);
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (getFileStartAndLength(fd, &start, &length) < 0)
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    memPtr = sysCreateAnonShmem(length);
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (memPtr == NULL)
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    actual = read(fd, memPtr, length);
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (actual != length) {
134c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("only read %d of %d bytes", (int) actual, (int) length);
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sysReleaseShmem(pMap);
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseAddr = pMap->addr = memPtr;
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseLength = pMap->length = length;
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return 0;
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else
144c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block    ALOGE("sysLoadFileInShmem not implemented.");
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return -1;
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
149518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#ifndef HAVE_POSIX_FILEMAP
150518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFaddenint sysFakeMapFile(int fd, MemMapping* pMap)
151518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden{
152518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    /* No MMAP, just fake it by copying the bits.
153518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden       For Win32 we could use MapViewOfFile if really necessary
154518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden       (see libs/utils/FileMap.cpp).
155518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    */
156518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    off_t start;
157518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    size_t length;
158518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    void* memPtr;
159518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden
160518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    assert(pMap != NULL);
161518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden
162518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    if (getFileStartAndLength(fd, &start, &length) < 0)
163518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden        return -1;
164518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden
165518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    memPtr = malloc(length);
166518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    if (read(fd, memPtr, length) < 0) {
167e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("read(fd=%d, start=%d, length=%d) failed: %s", (int) length,
168518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden            fd, (int) start, strerror(errno));
169518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden        return -1;
170518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    }
171518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden
172518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    pMap->baseAddr = pMap->addr = memPtr;
173518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    pMap->baseLength = pMap->length = length;
174518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden
175518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    return 0;
176518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden}
177518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#endif
178518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Map a file (from fd's current offset) into a shared, read-only memory
18196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * segment.  The file offset must be a multiple of the system page size.
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * value and does not disturb "pMap".
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
186b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFaddenint sysMapFileInShmemReadOnly(int fd, MemMapping* pMap)
187b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden{
188b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden#ifdef HAVE_POSIX_FILEMAP
189b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    off_t start;
190b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    size_t length;
191b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    void* memPtr;
192b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden
193b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    assert(pMap != NULL);
194b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden
195b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    if (getFileStartAndLength(fd, &start, &length) < 0)
196b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden        return -1;
197b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden
198b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start);
199b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    if (memPtr == MAP_FAILED) {
200e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("mmap(%d, RO, FILE|SHARED, %d, %d) failed: %s", (int) length,
201b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden            fd, (int) start, strerror(errno));
202b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden        return -1;
203b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    }
204b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden
205b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    pMap->baseAddr = pMap->addr = memPtr;
206b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    pMap->baseLength = pMap->length = length;
207b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden
208b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    return 0;
209b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden#else
210518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    return sysFakeMapFile(fd, pMap);
211b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden#endif
212b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden}
213b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden
214b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden/*
215b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * Map a file (from fd's current offset) into a private, read-write memory
216b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * segment that will be marked read-only (a/k/a "writable read-only").  The
217b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * file offset must be a multiple of the system page size.
218b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden *
219b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * In some cases the mapping will be fully writable (e.g. for files on
220b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * FAT filesystems).
221b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden *
222b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
223b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * value and does not disturb "pMap".
224b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden */
225b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFaddenint sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap)
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    off_t start;
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    size_t length;
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* memPtr;
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(pMap != NULL);
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (getFileStartAndLength(fd, &start, &length) < 0)
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
23796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    memPtr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,
23896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            fd, start);
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (memPtr == MAP_FAILED) {
240e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("mmap(%d, R/W, FILE|PRIVATE, %d, %d) failed: %s", (int) length,
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            fd, (int) start, strerror(errno));
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
24496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (mprotect(memPtr, length, PROT_READ) < 0) {
245b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden        /* this fails with EACCESS on FAT filesystems, e.g. /sdcard */
246b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden        int err = errno;
24792c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("mprotect(%p, %d, PROT_READ) failed: %s",
248b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden            memPtr, length, strerror(err));
249062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("mprotect(RO) failed (%d), file will remain read-write", err);
25096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseAddr = pMap->addr = memPtr;
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseLength = pMap->length = length;
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return 0;
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else
257518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    return sysFakeMapFile(fd, pMap);
258b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden#endif
259b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden}
260b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2628911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Map part of a file into a shared, read-only memory segment.  The "start"
2638911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * offset is absolute, not relative.
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * value and does not disturb "pMap".
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2688911f7a2222124ba724a4a9281555b74d0e098e2Andy McFaddenint sysMapFileSegmentInShmem(int fd, off_t start, size_t length,
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    MemMapping* pMap)
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP
2728911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden    size_t actualLength;
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    off_t actualStart;
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int adjust;
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* memPtr;
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(pMap != NULL);
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* adjust to be page-aligned */
28064896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    adjust = start % SYSTEM_PAGE_SIZE;
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    actualStart = start - adjust;
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    actualLength = length + adjust;
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED,
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                fd, actualStart);
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (memPtr == MAP_FAILED) {
287e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s",
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            (int) actualLength, fd, (int) actualStart, strerror(errno));
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseAddr = memPtr;
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseLength = actualLength;
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->addr = (char*)memPtr + adjust;
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->length = length;
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
297614dca3bb487f17ef8ea37a82a22dd6c4abc027eDan Bornstein    LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d",
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        (int) start, (int) length,
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pMap->baseAddr, (int) pMap->baseLength,
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pMap->addr, (int) pMap->length);
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return 0;
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else
304c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block    ALOGE("sysMapFileSegmentInShmem not implemented.");
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return -1;
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
31096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Change the access rights on one or more pages to read-only or read-write.
31196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
31296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns 0 on success.
31396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
31496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenint sysChangeMapAccess(void* addr, size_t length, int wantReadWrite,
31596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    MemMapping* pMap)
31696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
317518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#ifdef HAVE_POSIX_FILEMAP
31896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /*
31996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     * Verify that "addr" is part of this mapping file.
32096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     */
32196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (addr < pMap->baseAddr ||
32296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        (u1*)addr >= (u1*)pMap->baseAddr + pMap->baseLength)
32396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    {
324c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Attempted to change %p; map is %p - %p",
32596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            addr, pMap->baseAddr, (u1*)pMap->baseAddr + pMap->baseLength);
32696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return -1;
32796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
32896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
32996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /*
33096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     * Align "addr" to a page boundary and adjust "length" appropriately.
33196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     * (The address must be page-aligned, the length doesn't need to be,
33296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     * but we do need to ensure we cover the same range.)
33396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     */
334b210a9f9c7ae17e2028a86d9a4e9a3b35472862aSangWook Han    u1* alignAddr = (u1*) ((uintptr_t) addr & ~(SYSTEM_PAGE_SIZE-1));
33596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    size_t alignLength = length + ((u1*) addr - alignAddr);
33696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
3374308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    //ALOGI("%p/%zd --> %p/%zd", addr, length, alignAddr, alignLength);
33896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int prot = wantReadWrite ? (PROT_READ|PROT_WRITE) : (PROT_READ);
33996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (mprotect(alignAddr, alignLength, prot) != 0) {
34096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        int err = errno;
34192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("mprotect (%p,%zd,%d) failed: %s",
34296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            alignAddr, alignLength, prot, strerror(errno));
34396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return (errno != 0) ? errno : -1;
34496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
345518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#endif
34696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
347518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    /* for "fake" mapping, no need to do anything */
34896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return 0;
34996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
35096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
35196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release a memory mapping.
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid sysReleaseShmem(MemMapping* pMap)
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pMap->baseAddr == NULL && pMap->baseLength == 0)
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (munmap(pMap->baseAddr, pMap->baseLength) < 0) {
361e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("munmap(%p, %d) failed: %s",
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            pMap->baseAddr, (int)pMap->baseLength, strerror(errno));
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
36492c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("munmap(%p, %d) succeeded", pMap->baseAddr, pMap->baseLength);
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pMap->baseAddr = NULL;
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pMap->baseLength = 0;
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Free the bits allocated by sysMapFileInShmem. */
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pMap->baseAddr != NULL) {
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      free(pMap->baseAddr);
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      pMap->baseAddr = NULL;
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseLength = 0;
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Make a copy of a MemMapping.
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid sysCopyMap(MemMapping* dst, const MemMapping* src)
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    memcpy(dst, src, sizeof(MemMapping));
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
38664896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden/*
38764896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden * Write until all bytes have been written.
38864896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden *
38964896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden * Returns 0 on success, or an errno value on failure.
39064896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden */
39164896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFaddenint sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg)
39264896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden{
39364896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    while (count != 0) {
39464896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden        ssize_t actual = TEMP_FAILURE_RETRY(write(fd, buf, count));
39564896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden        if (actual < 0) {
39664896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden            int err = errno;
397c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("%s: write failed: %s", logMsg, strerror(err));
39864896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden            return err;
39964896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden        } else if (actual != (ssize_t) count) {
400062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("%s: partial write (will retry): (%d of %zd)",
40164896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden                logMsg, (int) actual, count);
40264896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden            buf = (const void*) (((const u1*) buf) + actual);
40364896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden        }
40464896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden        count -= actual;
40564896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    }
40664896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden
40764896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    return 0;
40864896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden}
409650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein
410650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein/* See documentation comment in header file. */
411650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornsteinint sysCopyFileToFile(int outFd, int inFd, size_t count)
412650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein{
413650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein    const size_t kBufSize = 32768;
414650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein    unsigned char buf[kBufSize];
415650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein
416650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein    while (count != 0) {
417650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein        size_t getSize = (count > kBufSize) ? kBufSize : count;
418650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein
419650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein        ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, buf, getSize));
420650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein        if (actual != (ssize_t) getSize) {
421e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("sysCopyFileToFile: copy read failed (%d vs %zd)",
422650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein                (int) actual, getSize);
423650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein            return -1;
424650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein        }
425650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein
426650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein        if (sysWriteFully(outFd, buf, getSize, "sysCopyFileToFile") != 0)
427650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein            return -1;
428650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein
429650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein        count -= getSize;
430650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein    }
431650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein
432650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein    return 0;
433650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein}
434