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