libcore_io_Linux.cpp revision f5333fd2094bdac4d6506177b1964b79afa64d77
1ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes/* 2ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * Copyright (C) 2011 The Android Open Source Project 3ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * 4ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 5ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * you may not use this file except in compliance with the License. 6ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * You may obtain a copy of the License at 7ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * 8ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 9ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * 10ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * Unless required by applicable law or agreed to in writing, software 11ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 12ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * See the License for the specific language governing permissions and 14ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * limitations under the License. 15ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes */ 16ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes 17ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes#define LOG_TAG "Posix" 18ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes 19ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes#include "JNIHelp.h" 20ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes#include "JniConstants.h" 21ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes#include "JniException.h" 22ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes#include "ScopedUtfChars.h" 23ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes#include "toStringArray.h" 24ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes 25ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes#include <errno.h> 26ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes#include <stdlib.h> 2752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes#include <unistd.h> 2847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes#include <sys/stat.h> 29ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes 30f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughesstatic jboolean maybeThrow(JNIEnv* env, const char* name, int rc, int errnum) { 31ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes if (rc != -1) { 3247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return false; 33ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes } 34ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes 35ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes jthrowable cause = NULL; 36ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes if (env->ExceptionCheck()) { 37ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes cause = env->ExceptionOccurred(); 38ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes env->ExceptionClear(); 39ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes } 40ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes 41f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes ScopedLocalRef<jstring> javaName(env, env->NewStringUTF(name)); 42f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes if (javaName.get() == NULL) { 43f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes // Not really much we can do here. We're probably dead in the water, 44f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes // but let's try to stumble on... 45f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes env->ExceptionClear(); 46f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes } 47f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes 48ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes jobject exception; 49ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes if (cause != NULL) { 50f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass, "<init>", 51f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes "(Ljava/lang/String;ILjava/lang/Throwable;)V"); 52f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes exception = env->NewObject(JniConstants::errnoExceptionClass, ctor, 53f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes javaName.get(), errnum, cause); 54ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes } else { 55f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass, "<init>", 56f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes "(Ljava/lang/String;I)V"); 57f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes exception = env->NewObject(JniConstants::errnoExceptionClass, ctor, javaName.get(), errnum); 58ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes } 59ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes env->Throw(reinterpret_cast<jthrowable>(exception)); 6047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return true; 6147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes} 6247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes 6347cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughesstatic jobject makeStructStat(JNIEnv* env, const struct stat& sb) { 6447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes static jmethodID ctor = env->GetMethodID(JniConstants::structStatClass, "<init>", 6547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes "(JJIJIIJJJJJJJ)V"); 6647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return env->NewObject(JniConstants::structStatClass, ctor, 6747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes jlong(sb.st_dev), jlong(sb.st_ino), jint(sb.st_mode), jlong(sb.st_nlink), 6847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes jint(sb.st_uid), jint(sb.st_gid), jlong(sb.st_rdev), jlong(sb.st_size), 6947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes jlong(sb.st_atime), jlong(sb.st_mtime), jlong(sb.st_ctime), 7047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes jlong(sb.st_blksize), jlong(sb.st_blocks)); 7147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes} 7247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes 7347cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughesstatic jobject doStat(JNIEnv* env, jstring javaPath, bool isLstat) { 7447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes ScopedUtfChars path(env, javaPath); 7547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes if (path.c_str() == NULL) { 7647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return NULL; 7747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes } 7847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes struct stat sb; 7947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes int rc = isLstat ? TEMP_FAILURE_RETRY(lstat(path.c_str(), &sb)) 8047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes : TEMP_FAILURE_RETRY(stat(path.c_str(), &sb)); 81f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes if (maybeThrow(env, isLstat ? "lstat" : "stat", rc, errno)) { 8247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return NULL; 8347cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes } 8447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return makeStructStat(env, sb); 85ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes} 86ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes 87ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughesstatic jboolean Posix_access(JNIEnv* env, jobject, jstring javaPath, jint mode) { 88ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes ScopedUtfChars path(env, javaPath); 89ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes if (path.c_str() == NULL) { 90ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes return JNI_FALSE; 91ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes } 9247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes int rc = TEMP_FAILURE_RETRY(access(path.c_str(), mode)); 93f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes maybeThrow(env, "access", rc, errno); 94ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes return (rc == 0); 95ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes} 96ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes 97ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughesstatic jobjectArray Posix_environ(JNIEnv* env, jobject) { 98ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes extern char** environ; // Standard, but not in any header file. 99ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes return toStringArray(env, environ); 100ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes} 101ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes 10252724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughesstatic void Posix_fdatasync(JNIEnv* env, jobject, jobject javaFd) { 10352724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes int fd = jniGetFDFromFileDescriptor(env, javaFd); 10447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes int rc = TEMP_FAILURE_RETRY(fdatasync(fd)); 105f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes maybeThrow(env, "fdatasync", rc, errno); 10652724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes} 10752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes 10847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughesstatic jobject Posix_fstat(JNIEnv* env, jobject, jobject javaFd) { 10947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes int fd = jniGetFDFromFileDescriptor(env, javaFd); 11047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes struct stat sb; 11147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes int rc = TEMP_FAILURE_RETRY(fstat(fd, &sb)); 112f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes if (maybeThrow(env, "fstat", rc, errno)) { 11347cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return NULL; 11447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes } 11547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return makeStructStat(env, sb); 11647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes} 11747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes 11852724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughesstatic void Posix_fsync(JNIEnv* env, jobject, jobject javaFd) { 11952724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes int fd = jniGetFDFromFileDescriptor(env, javaFd); 12047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes int rc = TEMP_FAILURE_RETRY(fsync(fd)); 121f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes maybeThrow(env, "fsync", rc, errno); 122f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes} 123f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes 124f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughesstatic void Posix_ftruncate(JNIEnv* env, jobject, jobject javaFd, jlong length) { 125f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes int fd = jniGetFDFromFileDescriptor(env, javaFd); 126f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes int rc = TEMP_FAILURE_RETRY(ftruncate64(fd, length)); 127f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes maybeThrow(env, "ftruncate", rc, errno); 12852724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes} 12952724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes 130ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughesstatic jstring Posix_getenv(JNIEnv* env, jobject, jstring javaName) { 131ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes ScopedUtfChars name(env, javaName); 132ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes if (name.c_str() == NULL) { 133ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes return NULL; 134ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes } 135ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes return env->NewStringUTF(getenv(name.c_str())); 136ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes} 137ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes 13847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughesstatic jobject Posix_lstat(JNIEnv* env, jobject, jstring javaPath) { 13947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return doStat(env, javaPath, true); 14047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes} 14147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes 14247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughesstatic jobject Posix_stat(JNIEnv* env, jobject, jstring javaPath) { 14347cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return doStat(env, javaPath, false); 14447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes} 14547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes 146ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughesstatic jstring Posix_strerror(JNIEnv* env, jobject, jint errnum) { 14752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes char buffer[BUFSIZ]; 148ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes const char* message = jniStrError(errnum, buffer, sizeof(buffer)); 149ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes return env->NewStringUTF(message); 150ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes} 151ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes 1526fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughesstatic jlong Posix_sysconf(JNIEnv* env, jobject, jint name) { 1536fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes // Since -1 is a valid result from sysconf(3), detecting failure is a little more awkward. 1546fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes errno = 0; 1556fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes long result = sysconf(name); 1566fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes if (result == -1L && errno == EINVAL) { 157f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes maybeThrow(env, "sysconf", -1, errno); 1586fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes } 1596fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes return result; 1606fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes} 1616fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes 162ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughesstatic JNINativeMethod gMethods[] = { 163ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes NATIVE_METHOD(Posix, access, "(Ljava/lang/String;I)Z"), 164ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes NATIVE_METHOD(Posix, environ, "()[Ljava/lang/String;"), 16552724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes NATIVE_METHOD(Posix, fdatasync, "(Ljava/io/FileDescriptor;)V"), 16647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes NATIVE_METHOD(Posix, fstat, "(Ljava/io/FileDescriptor;)Llibcore/io/StructStat;"), 16752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes NATIVE_METHOD(Posix, fsync, "(Ljava/io/FileDescriptor;)V"), 168f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes NATIVE_METHOD(Posix, ftruncate, "(Ljava/io/FileDescriptor;J)V"), 169ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes NATIVE_METHOD(Posix, getenv, "(Ljava/lang/String;)Ljava/lang/String;"), 17047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes NATIVE_METHOD(Posix, lstat, "(Ljava/lang/String;)Llibcore/io/StructStat;"), 17147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes NATIVE_METHOD(Posix, stat, "(Ljava/lang/String;)Llibcore/io/StructStat;"), 172ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes NATIVE_METHOD(Posix, strerror, "(I)Ljava/lang/String;"), 1736fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes NATIVE_METHOD(Posix, sysconf, "(I)J"), 174ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes}; 175ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughesint register_libcore_io_Posix(JNIEnv* env) { 176ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes return jniRegisterNativeMethods(env, "libcore/io/Posix", gMethods, NELEM(gMethods)); 177ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes} 178