libcore_io_Linux.cpp revision 462bdac45c10f43d88d8f07f6994e272a27c14a2
15fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy/*
25fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy * Copyright (C) 2011 The Android Open Source Project
35fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy *
45fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
55fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy * you may not use this file except in compliance with the License.
65fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy * You may obtain a copy of the License at
75fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy *
85fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
95fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy *
105fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy * Unless required by applicable law or agreed to in writing, software
115fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
125fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy * See the License for the specific language governing permissions and
145fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy * limitations under the License.
155fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy */
165fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy
175fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#define LOG_TAG "Posix"
185fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy
195fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include "JNIHelp.h"
205fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include "JniConstants.h"
215fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include "JniException.h"
225fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include "ScopedPrimitiveArray.h"
235fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include "ScopedUtfChars.h"
245fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include "StaticAssert.h"
255fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include "toStringArray.h"
265fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy
275fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <errno.h>
285fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <fcntl.h>
295fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <stdlib.h>
305fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <sys/ioctl.h>
315fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <sys/mman.h>
325fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <sys/sendfile.h>
335fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <sys/socket.h>
345fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <sys/stat.h>
355fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <sys/types.h>
365fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <sys/uio.h>
375fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <sys/utsname.h>
385fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <sys/vfs.h> // Bionic doesn't have <sys/statvfs.h>
395fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy#include <unistd.h>
405fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy
415fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guystatic void throwErrnoException(JNIEnv* env, const char* name) {
425fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    int errnum = errno;
435fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy
445fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    jthrowable cause = NULL;
455fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    if (env->ExceptionCheck()) {
465fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        cause = env->ExceptionOccurred();
475fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        env->ExceptionClear();
485fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    }
495fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy
505fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    ScopedLocalRef<jstring> javaName(env, env->NewStringUTF(name));
515fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    if (javaName.get() == NULL) {
525fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        // Not really much we can do here. We're probably dead in the water,
535fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        // but let's try to stumble on...
545fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        env->ExceptionClear();
555fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    }
565fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy
575fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    jobject exception;
585fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    if (cause != NULL) {
595fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass, "<init>",
605fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy                "(Ljava/lang/String;ILjava/lang/Throwable;)V");
615fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        exception = env->NewObject(JniConstants::errnoExceptionClass, ctor,
625fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy                javaName.get(), errnum, cause);
635fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    } else {
645fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass, "<init>",
655fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy                "(Ljava/lang/String;I)V");
665fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        exception = env->NewObject(JniConstants::errnoExceptionClass, ctor, javaName.get(), errnum);
675fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    }
685fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    env->Throw(reinterpret_cast<jthrowable>(exception));
695fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy}
705fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy
715fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guytemplate <typename rc_t>
725fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guystatic rc_t throwIfMinusOne(JNIEnv* env, const char* name, rc_t rc) {
735fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    if (rc == rc_t(-1)) {
745fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy        throwErrnoException(env, name);
755fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    }
765fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy    return rc;
775fccb70de94f4270cff1ca35d59a289bdf37a89fRomain Guy}
78
79template <typename T>
80class IoVec {
81public:
82    IoVec(JNIEnv* env, size_t bufferCount) : mEnv(env), mBufferCount(bufferCount) {
83    }
84
85    bool init(jobjectArray javaBuffers, jintArray javaOffsets, jintArray javaByteCounts) {
86        // We can't delete our local references until after the I/O, so make sure we have room.
87        if (mEnv->PushLocalFrame(mBufferCount + 16) < 0) {
88            return false;
89        }
90        ScopedIntArrayRO offsets(mEnv, javaOffsets);
91        if (offsets.get() == NULL) {
92            return false;
93        }
94        ScopedIntArrayRO byteCounts(mEnv, javaByteCounts);
95        if (byteCounts.get() == NULL) {
96            return false;
97        }
98        // TODO: Linux actually has a 1024 buffer limit. glibc works around this, and we should too.
99        for (size_t i = 0; i < mBufferCount; ++i) {
100            jobject buffer = mEnv->GetObjectArrayElement(javaBuffers, i);
101            jbyte* ptr;
102            if (mEnv->IsInstanceOf(buffer, JniConstants::byteArrayClass)) {
103                // We need to pin the array for the duration.
104                jbyteArray byteArray = reinterpret_cast<jbyteArray>(buffer);
105                mScopedByteArrays.push_back(new T(mEnv, byteArray));
106                ptr = const_cast<jbyte*>(mScopedByteArrays.back()->get());
107            } else {
108                // A direct ByteBuffer is easier.
109                ptr = reinterpret_cast<jbyte*>(mEnv->GetDirectBufferAddress(buffer));
110            }
111            if (ptr == NULL) {
112                return false;
113            }
114            struct iovec iov;
115            iov.iov_base = reinterpret_cast<void*>(ptr + offsets[i]);
116            iov.iov_len = byteCounts[i];
117            mIoVec.push_back(iov);
118        }
119        return true;
120    }
121
122    ~IoVec() {
123        for (size_t i = 0; i < mScopedByteArrays.size(); ++i) {
124            delete mScopedByteArrays[i];
125        }
126        mEnv->PopLocalFrame(NULL);
127    }
128
129    iovec* get() {
130        return &mIoVec[0];
131    }
132
133    size_t size() {
134        return mBufferCount;
135    }
136
137private:
138    JNIEnv* mEnv;
139    size_t mBufferCount;
140    std::vector<iovec> mIoVec;
141    std::vector<T*> mScopedByteArrays;
142};
143
144static jobject makeStructStat(JNIEnv* env, const struct stat& sb) {
145    static jmethodID ctor = env->GetMethodID(JniConstants::structStatClass, "<init>",
146            "(JJIJIIJJJJJJJ)V");
147    return env->NewObject(JniConstants::structStatClass, ctor,
148            static_cast<jlong>(sb.st_dev), static_cast<jlong>(sb.st_ino),
149            static_cast<jint>(sb.st_mode), static_cast<jlong>(sb.st_nlink),
150            static_cast<jint>(sb.st_uid), static_cast<jint>(sb.st_gid),
151            static_cast<jlong>(sb.st_rdev), static_cast<jlong>(sb.st_size),
152            static_cast<jlong>(sb.st_atime), static_cast<jlong>(sb.st_mtime),
153            static_cast<jlong>(sb.st_ctime), static_cast<jlong>(sb.st_blksize),
154            static_cast<jlong>(sb.st_blocks));
155}
156
157static jobject makeStructStatFs(JNIEnv* env, const struct statfs& sb) {
158    STATIC_ASSERT(sizeof(sb.f_bavail) == sizeof(jlong), statfs_not_64_bit);
159    STATIC_ASSERT(sizeof(sb.f_bfree) == sizeof(jlong), statfs_not_64_bit);
160    STATIC_ASSERT(sizeof(sb.f_blocks) == sizeof(jlong), statfs_not_64_bit);
161
162    static jmethodID ctor = env->GetMethodID(JniConstants::structStatFsClass, "<init>",
163            "(JJJJJJJJ)V");
164    return env->NewObject(JniConstants::structStatFsClass, ctor, static_cast<jlong>(sb.f_bsize),
165            static_cast<jlong>(sb.f_blocks), static_cast<jlong>(sb.f_bfree),
166            static_cast<jlong>(sb.f_bavail), static_cast<jlong>(sb.f_files),
167            static_cast<jlong>(sb.f_ffree), static_cast<jlong>(sb.f_namelen),
168            static_cast<jlong>(sb.f_frsize));
169}
170
171static jobject makeStructUtsname(JNIEnv* env, const struct utsname& buf) {
172#define TO_JAVA_STRING(NAME) \
173        jstring NAME = env->NewStringUTF(buf. NAME); \
174        if (NAME == NULL) return NULL;
175
176    TO_JAVA_STRING(sysname);
177    TO_JAVA_STRING(nodename);
178    TO_JAVA_STRING(release);
179    TO_JAVA_STRING(version);
180    TO_JAVA_STRING(machine);
181#undef TO_JAVA_STRING
182
183    static jmethodID ctor = env->GetMethodID(JniConstants::structUtsnameClass, "<init>",
184            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
185    return env->NewObject(JniConstants::structUtsnameClass, ctor,
186            sysname, nodename, release, version, machine);
187};
188
189static jobject doStat(JNIEnv* env, jstring javaPath, bool isLstat) {
190    ScopedUtfChars path(env, javaPath);
191    if (path.c_str() == NULL) {
192        return NULL;
193    }
194    struct stat sb;
195    int rc = isLstat ? TEMP_FAILURE_RETRY(lstat(path.c_str(), &sb))
196                     : TEMP_FAILURE_RETRY(stat(path.c_str(), &sb));
197    if (rc == -1) {
198        throwErrnoException(env, isLstat ? "lstat" : "stat");
199        return NULL;
200    }
201    return makeStructStat(env, sb);
202}
203
204static jboolean Posix_access(JNIEnv* env, jobject, jstring javaPath, jint mode) {
205    ScopedUtfChars path(env, javaPath);
206    if (path.c_str() == NULL) {
207        return JNI_FALSE;
208    }
209    int rc = TEMP_FAILURE_RETRY(access(path.c_str(), mode));
210    if (rc == -1) {
211        throwErrnoException(env, "access");
212    }
213    return (rc == 0);
214}
215
216static void Posix_chmod(JNIEnv* env, jobject, jstring javaPath, jint mode) {
217    ScopedUtfChars path(env, javaPath);
218    if (path.c_str() == NULL) {
219        return;
220    }
221    throwIfMinusOne(env, "chmod", TEMP_FAILURE_RETRY(chmod(path.c_str(), mode)));
222}
223
224static void Posix_close(JNIEnv* env, jobject, jobject javaFd) {
225    // Get the FileDescriptor's 'fd' field and clear it.
226    // We need to do this before we can throw an IOException (http://b/3222087).
227    int fd = jniGetFDFromFileDescriptor(env, javaFd);
228    jniSetFileDescriptorOfFD(env, javaFd, -1);
229
230    // Even if close(2) fails with EINTR, the fd will have been closed.
231    // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone else's fd.
232    // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
233    throwIfMinusOne(env, "close", close(fd));
234}
235
236static jobjectArray Posix_environ(JNIEnv* env, jobject) {
237    extern char** environ; // Standard, but not in any header file.
238    return toStringArray(env, environ);
239}
240
241static jint Posix_fcntlVoid(JNIEnv* env, jobject, jobject javaFd, jint cmd) {
242    int fd = jniGetFDFromFileDescriptor(env, javaFd);
243    return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd)));
244}
245
246static jint Posix_fcntlLong(JNIEnv* env, jobject, jobject javaFd, jint cmd, jlong arg) {
247    int fd = jniGetFDFromFileDescriptor(env, javaFd);
248    return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd, arg)));
249}
250
251static jint Posix_fcntlFlock(JNIEnv* env, jobject, jobject javaFd, jint cmd, jobject javaFlock) {
252    static jfieldID typeFid = env->GetFieldID(JniConstants::structFlockClass, "l_type", "S");
253    static jfieldID whenceFid = env->GetFieldID(JniConstants::structFlockClass, "l_whence", "S");
254    static jfieldID startFid = env->GetFieldID(JniConstants::structFlockClass, "l_start", "J");
255    static jfieldID lenFid = env->GetFieldID(JniConstants::structFlockClass, "l_len", "J");
256    static jfieldID pidFid = env->GetFieldID(JniConstants::structFlockClass, "l_pid", "I");
257
258    struct flock64 lock;
259    memset(&lock, 0, sizeof(lock));
260    lock.l_type = env->GetShortField(javaFlock, typeFid);
261    lock.l_whence = env->GetShortField(javaFlock, whenceFid);
262    lock.l_start = env->GetLongField(javaFlock, startFid);
263    lock.l_len = env->GetLongField(javaFlock, lenFid);
264    lock.l_pid = env->GetIntField(javaFlock, pidFid);
265
266    int fd = jniGetFDFromFileDescriptor(env, javaFd);
267    int rc = throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd, &lock)));
268    if (rc != -1) {
269        env->SetShortField(javaFlock, typeFid, lock.l_type);
270        env->SetShortField(javaFlock, whenceFid, lock.l_whence);
271        env->SetLongField(javaFlock, startFid, lock.l_start);
272        env->SetLongField(javaFlock, lenFid, lock.l_len);
273        env->SetIntField(javaFlock, pidFid, lock.l_pid);
274    }
275    return rc;
276}
277
278static void Posix_fdatasync(JNIEnv* env, jobject, jobject javaFd) {
279    int fd = jniGetFDFromFileDescriptor(env, javaFd);
280    throwIfMinusOne(env, "fdatasync", TEMP_FAILURE_RETRY(fdatasync(fd)));
281}
282
283static jobject Posix_fstat(JNIEnv* env, jobject, jobject javaFd) {
284    int fd = jniGetFDFromFileDescriptor(env, javaFd);
285    struct stat sb;
286    int rc = TEMP_FAILURE_RETRY(fstat(fd, &sb));
287    if (rc == -1) {
288        throwErrnoException(env, "fstat");
289        return NULL;
290    }
291    return makeStructStat(env, sb);
292}
293
294static jobject Posix_fstatfs(JNIEnv* env, jobject, jobject javaFd) {
295    int fd = jniGetFDFromFileDescriptor(env, javaFd);
296    struct statfs sb;
297    int rc = TEMP_FAILURE_RETRY(fstatfs(fd, &sb));
298    if (rc == -1) {
299        throwErrnoException(env, "fstatfs");
300        return NULL;
301    }
302    return makeStructStatFs(env, sb);
303}
304
305static void Posix_fsync(JNIEnv* env, jobject, jobject javaFd) {
306    int fd = jniGetFDFromFileDescriptor(env, javaFd);
307    throwIfMinusOne(env, "fsync", TEMP_FAILURE_RETRY(fsync(fd)));
308}
309
310static void Posix_ftruncate(JNIEnv* env, jobject, jobject javaFd, jlong length) {
311    int fd = jniGetFDFromFileDescriptor(env, javaFd);
312    throwIfMinusOne(env, "ftruncate", TEMP_FAILURE_RETRY(ftruncate64(fd, length)));
313}
314
315static jstring Posix_getenv(JNIEnv* env, jobject, jstring javaName) {
316    ScopedUtfChars name(env, javaName);
317    if (name.c_str() == NULL) {
318        return NULL;
319    }
320    return env->NewStringUTF(getenv(name.c_str()));
321}
322
323static jint Posix_ioctlInt(JNIEnv* env, jobject, jobject javaFd, jint cmd, jobject javaArg) {
324    // This is complicated because ioctls may return their result by updating their argument
325    // or via their return value, so we need to support both.
326    int fd = jniGetFDFromFileDescriptor(env, javaFd);
327    static jfieldID valueFid = env->GetFieldID(JniConstants::mutableIntClass, "value", "I");
328    jint arg = env->GetIntField(javaArg, valueFid);
329    int rc = throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, cmd, &arg)));
330    if (!env->ExceptionCheck()) {
331        env->SetIntField(javaArg, valueFid, arg);
332    }
333    return rc;
334}
335
336static jboolean Posix_isatty(JNIEnv* env, jobject, jobject javaFd) {
337    int fd = jniGetFDFromFileDescriptor(env, javaFd);
338    return TEMP_FAILURE_RETRY(isatty(fd)) == 0;
339}
340
341static void Posix_listen(JNIEnv* env, jobject, jobject javaFd, jint backlog) {
342    int fd = jniGetFDFromFileDescriptor(env, javaFd);
343    throwIfMinusOne(env, "listen", TEMP_FAILURE_RETRY(listen(fd, backlog)));
344}
345
346static jlong Posix_lseek(JNIEnv* env, jobject, jobject javaFd, jlong offset, jint whence) {
347    int fd = jniGetFDFromFileDescriptor(env, javaFd);
348    return throwIfMinusOne(env, "lseek", TEMP_FAILURE_RETRY(lseek64(fd, offset, whence)));
349}
350
351static jobject Posix_lstat(JNIEnv* env, jobject, jstring javaPath) {
352    return doStat(env, javaPath, true);
353}
354
355static void Posix_mincore(JNIEnv* env, jobject, jlong address, jlong byteCount, jbyteArray javaVector) {
356    ScopedByteArrayRW vector(env, javaVector);
357    if (vector.get() == NULL) {
358        return;
359    }
360    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
361    unsigned char* vec = reinterpret_cast<unsigned char*>(vector.get());
362    throwIfMinusOne(env, "mincore", TEMP_FAILURE_RETRY(mincore(ptr, byteCount, vec)));
363}
364
365static void Posix_mkdir(JNIEnv* env, jobject, jstring javaPath, jint mode) {
366    ScopedUtfChars path(env, javaPath);
367    if (path.c_str() == NULL) {
368        return;
369    }
370    throwIfMinusOne(env, "mkdir", TEMP_FAILURE_RETRY(mkdir(path.c_str(), mode)));
371}
372
373static void Posix_mlock(JNIEnv* env, jobject, jlong address, jlong byteCount) {
374    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
375    throwIfMinusOne(env, "mlock", TEMP_FAILURE_RETRY(mlock(ptr, byteCount)));
376}
377
378static jlong Posix_mmap(JNIEnv* env, jobject, jlong address, jlong byteCount, jint prot, jint flags, jobject javaFd, jlong offset) {
379    int fd = jniGetFDFromFileDescriptor(env, javaFd);
380    void* suggestedPtr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
381    void* ptr = mmap(suggestedPtr, byteCount, prot, flags, fd, offset);
382    if (ptr == MAP_FAILED) {
383        throwErrnoException(env, "mmap");
384    }
385    return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr));
386}
387
388static void Posix_msync(JNIEnv* env, jobject, jlong address, jlong byteCount, jint flags) {
389    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
390    throwIfMinusOne(env, "msync", TEMP_FAILURE_RETRY(msync(ptr, byteCount, flags)));
391}
392
393static void Posix_munlock(JNIEnv* env, jobject, jlong address, jlong byteCount) {
394    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
395    throwIfMinusOne(env, "munlock", TEMP_FAILURE_RETRY(munlock(ptr, byteCount)));
396}
397
398static void Posix_munmap(JNIEnv* env, jobject, jlong address, jlong byteCount) {
399    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
400    throwIfMinusOne(env, "munmap", TEMP_FAILURE_RETRY(munmap(ptr, byteCount)));
401}
402
403static jobject Posix_open(JNIEnv* env, jobject, jstring javaPath, jint flags, jint mode) {
404    ScopedUtfChars path(env, javaPath);
405    if (path.c_str() == NULL) {
406        return NULL;
407    }
408    int fd = throwIfMinusOne(env, "open", TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)));
409    return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
410}
411
412static jobjectArray Posix_pipe(JNIEnv* env, jobject) {
413    int fds[2];
414    throwIfMinusOne(env, "pipe", TEMP_FAILURE_RETRY(pipe(&fds[0])));
415    jobjectArray result = env->NewObjectArray(2, JniConstants::fileDescriptorClass, NULL);
416    if (result == NULL) {
417        return NULL;
418    }
419    for (int i = 0; i < 2; ++i) {
420        ScopedLocalRef<jobject> fd(env, jniCreateFileDescriptor(env, fds[i]));
421        if (fd.get() == NULL) {
422            return NULL;
423        }
424        env->SetObjectArrayElement(result, i, fd.get());
425        if (env->ExceptionCheck()) {
426            return NULL;
427        }
428    }
429    return result;
430}
431
432static jint Posix_read(JNIEnv* env, jobject, jobject javaFd, jbyteArray javaBytes, jint byteOffset, jint byteCount) {
433    int fd = jniGetFDFromFileDescriptor(env, javaFd);
434    ScopedByteArrayRW bytes(env, javaBytes);
435    if (bytes.get() == NULL) {
436        return -1;
437    }
438    return throwIfMinusOne(env, "read", TEMP_FAILURE_RETRY(read(fd, bytes.get() + byteOffset, byteCount)));
439}
440
441static jint Posix_readDirectBuffer(JNIEnv* env, jobject, jobject javaFd, jobject byteBuffer, jint position, jint remaining) {
442    int fd = jniGetFDFromFileDescriptor(env, javaFd);
443    jbyte* ptr = reinterpret_cast<jbyte*>(env->GetDirectBufferAddress(byteBuffer));
444    return throwIfMinusOne(env, "read", TEMP_FAILURE_RETRY(read(fd, ptr + position, remaining)));
445}
446
447static jint Posix_readv(JNIEnv* env, jobject, jobject javaFd, jobjectArray buffers, jintArray offsets, jintArray byteCounts) {
448    IoVec<ScopedByteArrayRW> ioVec(env, env->GetArrayLength(buffers));
449    if (!ioVec.init(buffers, offsets, byteCounts)) {
450        return -1;
451    }
452    int fd = jniGetFDFromFileDescriptor(env, javaFd);
453    return throwIfMinusOne(env, "readv", TEMP_FAILURE_RETRY(readv(fd, ioVec.get(), ioVec.size())));
454}
455
456static void Posix_remove(JNIEnv* env, jobject, jstring javaPath) {
457    ScopedUtfChars path(env, javaPath);
458    if (path.c_str() == NULL) {
459        return;
460    }
461    throwIfMinusOne(env, "remove", TEMP_FAILURE_RETRY(remove(path.c_str())));
462}
463
464static void Posix_rename(JNIEnv* env, jobject, jstring javaOldPath, jstring javaNewPath) {
465    ScopedUtfChars oldPath(env, javaOldPath);
466    if (oldPath.c_str() == NULL) {
467        return;
468    }
469    ScopedUtfChars newPath(env, javaNewPath);
470    if (newPath.c_str() == NULL) {
471        return;
472    }
473    throwIfMinusOne(env, "rename", TEMP_FAILURE_RETRY(rename(oldPath.c_str(), newPath.c_str())));
474}
475
476static jlong Posix_sendfile(JNIEnv* env, jobject, jobject javaOutFd, jobject javaInFd, jobject javaOffset, jlong byteCount) {
477    int outFd = jniGetFDFromFileDescriptor(env, javaOutFd);
478    int inFd = jniGetFDFromFileDescriptor(env, javaInFd);
479    static jfieldID valueFid = env->GetFieldID(JniConstants::mutableLongClass, "value", "J");
480    off_t offset = 0;
481    off_t* offsetPtr = NULL;
482    if (javaOffset != NULL) {
483        // TODO: fix bionic so we can have a 64-bit off_t!
484        offset = env->GetLongField(javaOffset, valueFid);
485        offsetPtr = &offset;
486    }
487    jlong result = throwIfMinusOne(env, "sendfile", TEMP_FAILURE_RETRY(sendfile(outFd, inFd, offsetPtr, byteCount)));
488    if (javaOffset != NULL) {
489        env->SetLongField(javaOffset, valueFid, offset);
490    }
491    return result;
492}
493
494static void Posix_setsockoptInt(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jint value) {
495    int fd = jniGetFDFromFileDescriptor(env, javaFd);
496    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &value, sizeof(value))));
497}
498
499static void Posix_shutdown(JNIEnv* env, jobject, jobject javaFd, jint how) {
500    int fd = jniGetFDFromFileDescriptor(env, javaFd);
501    throwIfMinusOne(env, "shutdown", TEMP_FAILURE_RETRY(shutdown(fd, how)));
502}
503
504static jobject Posix_socket(JNIEnv* env, jobject, jint domain, jint type, jint protocol) {
505    int fd = throwIfMinusOne(env, "socket", TEMP_FAILURE_RETRY(socket(domain, type, protocol)));
506    return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
507}
508
509static jobject Posix_stat(JNIEnv* env, jobject, jstring javaPath) {
510    return doStat(env, javaPath, false);
511}
512
513static jobject Posix_statfs(JNIEnv* env, jstring javaPath) {
514    ScopedUtfChars path(env, javaPath);
515    if (path.c_str() == NULL) {
516        return NULL;
517    }
518    struct statfs sb;
519    int rc = TEMP_FAILURE_RETRY(statfs(path.c_str(), &sb));
520    if (rc == -1) {
521        throwErrnoException(env, "statfs");
522        return NULL;
523    }
524    return makeStructStatFs(env, sb);
525}
526
527static jstring Posix_strerror(JNIEnv* env, jobject, jint errnum) {
528    char buffer[BUFSIZ];
529    const char* message = jniStrError(errnum, buffer, sizeof(buffer));
530    return env->NewStringUTF(message);
531}
532
533static void Posix_symlink(JNIEnv* env, jobject, jstring javaOldPath, jstring javaNewPath) {
534    ScopedUtfChars oldPath(env, javaOldPath);
535    if (oldPath.c_str() == NULL) {
536        return;
537    }
538    ScopedUtfChars newPath(env, javaNewPath);
539    if (newPath.c_str() == NULL) {
540        return;
541    }
542    throwIfMinusOne(env, "symlink", TEMP_FAILURE_RETRY(symlink(oldPath.c_str(), newPath.c_str())));
543}
544
545static jlong Posix_sysconf(JNIEnv* env, jobject, jint name) {
546    // Since -1 is a valid result from sysconf(3), detecting failure is a little more awkward.
547    errno = 0;
548    long result = sysconf(name);
549    if (result == -1L && errno == EINVAL) {
550        throwErrnoException(env, "sysconf");
551    }
552    return result;
553}
554
555static jobject Posix_uname(JNIEnv* env, jobject) {
556    struct utsname buf;
557    if (throwIfMinusOne(env, "uname", TEMP_FAILURE_RETRY(uname(&buf))) == -1) {
558        return NULL;
559    }
560    return makeStructUtsname(env, buf);
561}
562
563static jint Posix_write(JNIEnv* env, jobject, jobject javaFd, jbyteArray javaBytes, jint byteOffset, jint byteCount) {
564    int fd = jniGetFDFromFileDescriptor(env, javaFd);
565    ScopedByteArrayRO bytes(env, javaBytes);
566    if (bytes.get() == NULL) {
567        return -1;
568    }
569    return throwIfMinusOne(env, "write", TEMP_FAILURE_RETRY(write(fd, bytes.get() + byteOffset, byteCount)));
570}
571
572static jint Posix_writeDirectBuffer(JNIEnv* env, jobject, jobject javaFd, jobject byteBuffer, jint position, jint remaining) {
573    int fd = jniGetFDFromFileDescriptor(env, javaFd);
574    jbyte* ptr = reinterpret_cast<jbyte*>(env->GetDirectBufferAddress(byteBuffer));
575    return throwIfMinusOne(env, "write", TEMP_FAILURE_RETRY(write(fd, ptr + position, remaining)));
576}
577
578static jint Posix_writev(JNIEnv* env, jobject, jobject javaFd, jobjectArray buffers, jintArray offsets, jintArray byteCounts) {
579    IoVec<ScopedByteArrayRO> ioVec(env, env->GetArrayLength(buffers));
580    if (!ioVec.init(buffers, offsets, byteCounts)) {
581        return -1;
582    }
583    int fd = jniGetFDFromFileDescriptor(env, javaFd);
584    return throwIfMinusOne(env, "writev", TEMP_FAILURE_RETRY(writev(fd, ioVec.get(), ioVec.size())));
585}
586
587static JNINativeMethod gMethods[] = {
588    NATIVE_METHOD(Posix, access, "(Ljava/lang/String;I)Z"),
589    NATIVE_METHOD(Posix, chmod, "(Ljava/lang/String;I)V"),
590    NATIVE_METHOD(Posix, close, "(Ljava/io/FileDescriptor;)V"),
591    NATIVE_METHOD(Posix, environ, "()[Ljava/lang/String;"),
592    NATIVE_METHOD(Posix, fcntlVoid, "(Ljava/io/FileDescriptor;I)I"),
593    NATIVE_METHOD(Posix, fcntlLong, "(Ljava/io/FileDescriptor;IJ)I"),
594    NATIVE_METHOD(Posix, fcntlFlock, "(Ljava/io/FileDescriptor;ILlibcore/io/StructFlock;)I"),
595    NATIVE_METHOD(Posix, fdatasync, "(Ljava/io/FileDescriptor;)V"),
596    NATIVE_METHOD(Posix, fstat, "(Ljava/io/FileDescriptor;)Llibcore/io/StructStat;"),
597    NATIVE_METHOD(Posix, fstatfs, "(Ljava/io/FileDescriptor;)Llibcore/io/StructStatFs;"),
598    NATIVE_METHOD(Posix, fsync, "(Ljava/io/FileDescriptor;)V"),
599    NATIVE_METHOD(Posix, ftruncate, "(Ljava/io/FileDescriptor;J)V"),
600    NATIVE_METHOD(Posix, getenv, "(Ljava/lang/String;)Ljava/lang/String;"),
601    NATIVE_METHOD(Posix, ioctlInt, "(Ljava/io/FileDescriptor;ILlibcore/util/MutableInt;)I"),
602    NATIVE_METHOD(Posix, isatty, "(Ljava/io/FileDescriptor;)Z"),
603    NATIVE_METHOD(Posix, listen, "(Ljava/io/FileDescriptor;I)V"),
604    NATIVE_METHOD(Posix, lseek, "(Ljava/io/FileDescriptor;JI)J"),
605    NATIVE_METHOD(Posix, lstat, "(Ljava/lang/String;)Llibcore/io/StructStat;"),
606    NATIVE_METHOD(Posix, mincore, "(JJ[B)V"),
607    NATIVE_METHOD(Posix, mkdir, "(Ljava/lang/String;I)V"),
608    NATIVE_METHOD(Posix, mlock, "(JJ)V"),
609    NATIVE_METHOD(Posix, mmap, "(JJIILjava/io/FileDescriptor;J)J"),
610    NATIVE_METHOD(Posix, msync, "(JJI)V"),
611    NATIVE_METHOD(Posix, munlock, "(JJ)V"),
612    NATIVE_METHOD(Posix, munmap, "(JJ)V"),
613    NATIVE_METHOD(Posix, open, "(Ljava/lang/String;II)Ljava/io/FileDescriptor;"),
614    NATIVE_METHOD(Posix, pipe, "()[Ljava/io/FileDescriptor;"),
615    NATIVE_METHOD(Posix, read, "(Ljava/io/FileDescriptor;[BII)I"),
616    NATIVE_METHOD(Posix, readDirectBuffer, "(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;II)I"),
617    NATIVE_METHOD(Posix, readv, "(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I"),
618    NATIVE_METHOD(Posix, remove, "(Ljava/lang/String;)V"),
619    NATIVE_METHOD(Posix, rename, "(Ljava/lang/String;Ljava/lang/String;)V"),
620    NATIVE_METHOD(Posix, sendfile, "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Llibcore/util/MutableLong;J)J"),
621    NATIVE_METHOD(Posix, setsockoptInt, "(Ljava/io/FileDescriptor;III)V"),
622    NATIVE_METHOD(Posix, shutdown, "(Ljava/io/FileDescriptor;I)V"),
623    NATIVE_METHOD(Posix, socket, "(III)Ljava/io/FileDescriptor;"),
624    NATIVE_METHOD(Posix, stat, "(Ljava/lang/String;)Llibcore/io/StructStat;"),
625    NATIVE_METHOD(Posix, statfs, "(Ljava/lang/String;)Llibcore/io/StructStatFs;"),
626    NATIVE_METHOD(Posix, strerror, "(I)Ljava/lang/String;"),
627    NATIVE_METHOD(Posix, symlink, "(Ljava/lang/String;Ljava/lang/String;)V"),
628    NATIVE_METHOD(Posix, sysconf, "(I)J"),
629    NATIVE_METHOD(Posix, uname, "()Llibcore/io/StructUtsname;"),
630    NATIVE_METHOD(Posix, write, "(Ljava/io/FileDescriptor;[BII)I"),
631    NATIVE_METHOD(Posix, writeDirectBuffer, "(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;II)I"),
632    NATIVE_METHOD(Posix, writev, "(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I"),
633};
634int register_libcore_io_Posix(JNIEnv* env) {
635    return jniRegisterNativeMethods(env, "libcore/io/Posix", gMethods, NELEM(gMethods));
636}
637