libcore_io_Linux.cpp revision dedaccdfa07c370a58cba08b096133ad9eec0ec3
1/* 2 * Copyright (C) 2011 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#define LOG_TAG "Posix" 18 19#include "JNIHelp.h" 20#include "JniConstants.h" 21#include "JniException.h" 22#include "ScopedUtfChars.h" 23#include "toStringArray.h" 24 25#include <errno.h> 26#include <stdlib.h> 27#include <unistd.h> 28#include <sys/stat.h> 29 30static void throwErrnoException(JNIEnv* env, const char* name, int errnum) { 31 jthrowable cause = NULL; 32 if (env->ExceptionCheck()) { 33 cause = env->ExceptionOccurred(); 34 env->ExceptionClear(); 35 } 36 37 ScopedLocalRef<jstring> javaName(env, env->NewStringUTF(name)); 38 if (javaName.get() == NULL) { 39 // Not really much we can do here. We're probably dead in the water, 40 // but let's try to stumble on... 41 env->ExceptionClear(); 42 } 43 44 jobject exception; 45 if (cause != NULL) { 46 static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass, "<init>", 47 "(Ljava/lang/String;ILjava/lang/Throwable;)V"); 48 exception = env->NewObject(JniConstants::errnoExceptionClass, ctor, 49 javaName.get(), errnum, cause); 50 } else { 51 static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass, "<init>", 52 "(Ljava/lang/String;I)V"); 53 exception = env->NewObject(JniConstants::errnoExceptionClass, ctor, javaName.get(), errnum); 54 } 55 env->Throw(reinterpret_cast<jthrowable>(exception)); 56} 57 58template <typename rc_t> 59static rc_t throwIfMinusOne(JNIEnv* env, const char* name, int errnum, rc_t rc) { 60 if (rc == rc_t(-1)) { 61 throwErrnoException(env, name, errnum); 62 } 63 return rc; 64} 65 66static jobject makeStructStat(JNIEnv* env, const struct stat& sb) { 67 static jmethodID ctor = env->GetMethodID(JniConstants::structStatClass, "<init>", 68 "(JJIJIIJJJJJJJ)V"); 69 return env->NewObject(JniConstants::structStatClass, ctor, 70 jlong(sb.st_dev), jlong(sb.st_ino), jint(sb.st_mode), jlong(sb.st_nlink), 71 jint(sb.st_uid), jint(sb.st_gid), jlong(sb.st_rdev), jlong(sb.st_size), 72 jlong(sb.st_atime), jlong(sb.st_mtime), jlong(sb.st_ctime), 73 jlong(sb.st_blksize), jlong(sb.st_blocks)); 74} 75 76static jobject doStat(JNIEnv* env, jstring javaPath, bool isLstat) { 77 ScopedUtfChars path(env, javaPath); 78 if (path.c_str() == NULL) { 79 return NULL; 80 } 81 struct stat sb; 82 int rc = isLstat ? TEMP_FAILURE_RETRY(lstat(path.c_str(), &sb)) 83 : TEMP_FAILURE_RETRY(stat(path.c_str(), &sb)); 84 if (rc == -1) { 85 throwErrnoException(env, isLstat ? "lstat" : "stat", errno); 86 return NULL; 87 } 88 return makeStructStat(env, sb); 89} 90 91static jboolean Posix_access(JNIEnv* env, jobject, jstring javaPath, jint mode) { 92 ScopedUtfChars path(env, javaPath); 93 if (path.c_str() == NULL) { 94 return JNI_FALSE; 95 } 96 int rc = TEMP_FAILURE_RETRY(access(path.c_str(), mode)); 97 if (rc == -1) { 98 throwErrnoException(env, "access", errno); 99 } 100 return (rc == 0); 101} 102 103static jobjectArray Posix_environ(JNIEnv* env, jobject) { 104 extern char** environ; // Standard, but not in any header file. 105 return toStringArray(env, environ); 106} 107 108static void Posix_fdatasync(JNIEnv* env, jobject, jobject javaFd) { 109 int fd = jniGetFDFromFileDescriptor(env, javaFd); 110 throwIfMinusOne(env, "fdatasync", errno, TEMP_FAILURE_RETRY(fdatasync(fd))); 111} 112 113static jobject Posix_fstat(JNIEnv* env, jobject, jobject javaFd) { 114 int fd = jniGetFDFromFileDescriptor(env, javaFd); 115 struct stat sb; 116 int rc = TEMP_FAILURE_RETRY(fstat(fd, &sb)); 117 if (rc == -1) { 118 throwErrnoException(env, "fstat", errno); 119 return NULL; 120 } 121 return makeStructStat(env, sb); 122} 123 124static void Posix_fsync(JNIEnv* env, jobject, jobject javaFd) { 125 int fd = jniGetFDFromFileDescriptor(env, javaFd); 126 throwIfMinusOne(env, "fsync", errno, TEMP_FAILURE_RETRY(fsync(fd))); 127} 128 129static void Posix_ftruncate(JNIEnv* env, jobject, jobject javaFd, jlong length) { 130 int fd = jniGetFDFromFileDescriptor(env, javaFd); 131 throwIfMinusOne(env, "ftruncate", errno, TEMP_FAILURE_RETRY(ftruncate64(fd, length))); 132} 133 134static jstring Posix_getenv(JNIEnv* env, jobject, jstring javaName) { 135 ScopedUtfChars name(env, javaName); 136 if (name.c_str() == NULL) { 137 return NULL; 138 } 139 return env->NewStringUTF(getenv(name.c_str())); 140} 141 142static jlong Posix_lseek(JNIEnv* env, jobject, jobject javaFd, jlong offset, jint whence) { 143 int fd = jniGetFDFromFileDescriptor(env, javaFd); 144 return throwIfMinusOne(env, "lseek", errno, TEMP_FAILURE_RETRY(lseek64(fd, offset, whence))); 145} 146 147static jobject Posix_lstat(JNIEnv* env, jobject, jstring javaPath) { 148 return doStat(env, javaPath, true); 149} 150 151static jobject Posix_stat(JNIEnv* env, jobject, jstring javaPath) { 152 return doStat(env, javaPath, false); 153} 154 155static jstring Posix_strerror(JNIEnv* env, jobject, jint errnum) { 156 char buffer[BUFSIZ]; 157 const char* message = jniStrError(errnum, buffer, sizeof(buffer)); 158 return env->NewStringUTF(message); 159} 160 161static jlong Posix_sysconf(JNIEnv* env, jobject, jint name) { 162 // Since -1 is a valid result from sysconf(3), detecting failure is a little more awkward. 163 errno = 0; 164 long result = sysconf(name); 165 if (result == -1L && errno == EINVAL) { 166 throwErrnoException(env, "sysconf", errno); 167 } 168 return result; 169} 170 171static JNINativeMethod gMethods[] = { 172 NATIVE_METHOD(Posix, access, "(Ljava/lang/String;I)Z"), 173 NATIVE_METHOD(Posix, environ, "()[Ljava/lang/String;"), 174 NATIVE_METHOD(Posix, fdatasync, "(Ljava/io/FileDescriptor;)V"), 175 NATIVE_METHOD(Posix, fstat, "(Ljava/io/FileDescriptor;)Llibcore/io/StructStat;"), 176 NATIVE_METHOD(Posix, fsync, "(Ljava/io/FileDescriptor;)V"), 177 NATIVE_METHOD(Posix, ftruncate, "(Ljava/io/FileDescriptor;J)V"), 178 NATIVE_METHOD(Posix, getenv, "(Ljava/lang/String;)Ljava/lang/String;"), 179 NATIVE_METHOD(Posix, lseek, "(Ljava/io/FileDescriptor;JI)J"), 180 NATIVE_METHOD(Posix, lstat, "(Ljava/lang/String;)Llibcore/io/StructStat;"), 181 NATIVE_METHOD(Posix, stat, "(Ljava/lang/String;)Llibcore/io/StructStat;"), 182 NATIVE_METHOD(Posix, strerror, "(I)Ljava/lang/String;"), 183 NATIVE_METHOD(Posix, sysconf, "(I)J"), 184}; 185int register_libcore_io_Posix(JNIEnv* env) { 186 return jniRegisterNativeMethods(env, "libcore/io/Posix", gMethods, NELEM(gMethods)); 187} 188