Path: blob/master/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c
41133 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <sys/types.h>26#include <sys/socket.h>27#include <fcntl.h>28#include <sys/uio.h>29#include <unistd.h>30#ifdef MACOSX31#include <sys/mount.h>32#include <sys/param.h>33#endif34#include <sys/stat.h>35#include <sys/statvfs.h>3637#if defined(__linux__)38#include <linux/fs.h>39#include <sys/ioctl.h>40#endif4142#if defined(_ALLBSD_SOURCE)43#define lseek64 lseek44#define stat64 stat45#define flock64 flock46#define off64_t off_t47#define F_SETLKW64 F_SETLKW48#define F_SETLK64 F_SETLK49#define pread64 pread50#define pwrite64 pwrite51#define ftruncate64 ftruncate52#define fstat64 fstat53#define fdatasync fsync54#endif5556#include "jni.h"57#include "jni_util.h"58#include "jvm.h"59#include "jlong.h"60#include "nio.h"61#include "nio_util.h"62#include "sun_nio_ch_FileDispatcherImpl.h"63#include "java_lang_Long.h"6465static int preCloseFD = -1; /* File descriptor to which we dup other fd's66before closing them for real */676869JNIEXPORT void JNICALL70Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl)71{72int sp[2];73if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {74JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");75return;76}77preCloseFD = sp[0];78close(sp[1]);79}8081JNIEXPORT jint JNICALL82Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz,83jobject fdo, jlong address, jint len)84{85jint fd = fdval(env, fdo);86void *buf = (void *)jlong_to_ptr(address);8788return convertReturnVal(env, read(fd, buf, len), JNI_TRUE);89}9091JNIEXPORT jint JNICALL92Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo,93jlong address, jint len, jlong offset)94{95jint fd = fdval(env, fdo);96void *buf = (void *)jlong_to_ptr(address);9798return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE);99}100101JNIEXPORT jlong JNICALL102Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz,103jobject fdo, jlong address, jint len)104{105jint fd = fdval(env, fdo);106struct iovec *iov = (struct iovec *)jlong_to_ptr(address);107return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE);108}109110JNIEXPORT jint JNICALL111Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz,112jobject fdo, jlong address, jint len)113{114jint fd = fdval(env, fdo);115void *buf = (void *)jlong_to_ptr(address);116117return convertReturnVal(env, write(fd, buf, len), JNI_FALSE);118}119120JNIEXPORT jint JNICALL121Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo,122jlong address, jint len, jlong offset)123{124jint fd = fdval(env, fdo);125void *buf = (void *)jlong_to_ptr(address);126127return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE);128}129130JNIEXPORT jlong JNICALL131Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz,132jobject fdo, jlong address, jint len)133{134jint fd = fdval(env, fdo);135struct iovec *iov = (struct iovec *)jlong_to_ptr(address);136return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE);137}138139static jlong140handle(JNIEnv *env, jlong rv, char *msg)141{142if (rv >= 0)143return rv;144if (errno == EINTR)145return IOS_INTERRUPTED;146JNU_ThrowIOExceptionWithLastError(env, msg);147return IOS_THROWN;148}149150JNIEXPORT jlong JNICALL151Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv *env, jclass clazz,152jobject fdo, jlong offset)153{154jint fd = fdval(env, fdo);155off64_t result;156if (offset < 0) {157result = lseek64(fd, 0, SEEK_CUR);158} else {159result = lseek64(fd, offset, SEEK_SET);160}161return handle(env, (jlong)result, "lseek64 failed");162}163164JNIEXPORT jint JNICALL165Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,166jobject fdo, jboolean md)167{168jint fd = fdval(env, fdo);169int result = 0;170171#ifdef MACOSX172result = fcntl(fd, F_FULLFSYNC);173if (result == -1) {174struct statfs fbuf;175int errno_fcntl = errno;176if (fstatfs(fd, &fbuf) == 0) {177if ((fbuf.f_flags & MNT_LOCAL) == 0) {178/* Try fsync() in case file is not local. */179result = fsync(fd);180}181} else {182/* fstatfs() failed so restore errno from fcntl(). */183errno = errno_fcntl;184}185}186#else /* end MACOSX, begin not-MACOSX */187if (md == JNI_FALSE) {188result = fdatasync(fd);189} else {190#ifdef _AIX191/* On AIX, calling fsync on a file descriptor that is opened only for192* reading results in an error ("EBADF: The FileDescriptor parameter is193* not a valid file descriptor open for writing.").194* However, at this point it is not possibly anymore to read the195* 'writable' attribute of the corresponding file channel so we have to196* use 'fcntl'.197*/198int getfl = fcntl(fd, F_GETFL);199if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) {200return 0;201}202#endif /* _AIX */203result = fsync(fd);204}205#endif /* not-MACOSX */206return handle(env, result, "Force failed");207}208209JNIEXPORT jint JNICALL210Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,211jobject fdo, jlong size)212{213return handle(env,214ftruncate64(fdval(env, fdo), size),215"Truncation failed");216}217218JNIEXPORT jlong JNICALL219Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)220{221jint fd = fdval(env, fdo);222struct stat64 fbuf;223224if (fstat64(fd, &fbuf) < 0)225return handle(env, -1, "Size failed");226227#ifdef BLKGETSIZE64228if (S_ISBLK(fbuf.st_mode)) {229uint64_t size;230if (ioctl(fd, BLKGETSIZE64, &size) < 0)231return handle(env, -1, "Size failed");232return (jlong)size;233}234#endif235236return fbuf.st_size;237}238239JNIEXPORT jint JNICALL240Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,241jboolean block, jlong pos, jlong size,242jboolean shared)243{244jint fd = fdval(env, fdo);245jint lockResult = 0;246int cmd = 0;247struct flock64 fl;248249fl.l_whence = SEEK_SET;250if (size == (jlong)java_lang_Long_MAX_VALUE) {251fl.l_len = (off64_t)0;252} else {253fl.l_len = (off64_t)size;254}255fl.l_start = (off64_t)pos;256if (shared == JNI_TRUE) {257fl.l_type = F_RDLCK;258} else {259fl.l_type = F_WRLCK;260}261if (block == JNI_TRUE) {262cmd = F_SETLKW64;263} else {264cmd = F_SETLK64;265}266lockResult = fcntl(fd, cmd, &fl);267if (lockResult < 0) {268if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES))269return sun_nio_ch_FileDispatcherImpl_NO_LOCK;270if (errno == EINTR)271return sun_nio_ch_FileDispatcherImpl_INTERRUPTED;272JNU_ThrowIOExceptionWithLastError(env, "Lock failed");273}274return 0;275}276277JNIEXPORT void JNICALL278Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this,279jobject fdo, jlong pos, jlong size)280{281jint fd = fdval(env, fdo);282jint lockResult = 0;283struct flock64 fl;284int cmd = F_SETLK64;285286fl.l_whence = SEEK_SET;287if (size == (jlong)java_lang_Long_MAX_VALUE) {288fl.l_len = (off64_t)0;289} else {290fl.l_len = (off64_t)size;291}292fl.l_start = (off64_t)pos;293fl.l_type = F_UNLCK;294lockResult = fcntl(fd, cmd, &fl);295if (lockResult < 0) {296JNU_ThrowIOExceptionWithLastError(env, "Release failed");297}298}299300301static void closeFileDescriptor(JNIEnv *env, int fd) {302if (fd != -1) {303int result = close(fd);304if (result < 0)305JNU_ThrowIOExceptionWithLastError(env, "Close failed");306}307}308309JNIEXPORT void JNICALL310Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo)311{312jint fd = fdval(env, fdo);313closeFileDescriptor(env, fd);314}315316JNIEXPORT void JNICALL317Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo)318{319jint fd = fdval(env, fdo);320if (preCloseFD >= 0) {321if (dup2(preCloseFD, fd) < 0)322JNU_ThrowIOExceptionWithLastError(env, "dup2 failed");323}324}325326JNIEXPORT void JNICALL327Java_sun_nio_ch_FileDispatcherImpl_dup0(JNIEnv *env, jobject this, jobject fdo1, jobject fdo2)328{329if (dup2(fdval(env, fdo1), fdval(env, fdo2)) < 0) {330JNU_ThrowIOExceptionWithLastError(env, "dup2 failed");331}332}333334JNIEXPORT void JNICALL335Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd)336{337closeFileDescriptor(env, fd);338}339340JNIEXPORT jint JNICALL341Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass clazz,342jobject fdo)343{344jint fd = fdval(env, fdo);345jint result;346#ifdef MACOSX347struct statvfs file_stat;348#else349struct statvfs64 file_stat;350#endif351352#if defined(O_DIRECT) || defined(F_NOCACHE) || defined(DIRECTIO_ON)353#ifdef O_DIRECT354jint orig_flag;355orig_flag = fcntl(fd, F_GETFL);356if (orig_flag == -1) {357JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");358return -1;359}360result = fcntl(fd, F_SETFL, orig_flag | O_DIRECT);361if (result == -1) {362JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");363return result;364}365#elif defined(F_NOCACHE)366result = fcntl(fd, F_NOCACHE, 1);367if (result == -1) {368JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");369return result;370}371#elif defined(DIRECTIO_ON)372result = directio(fd, DIRECTIO_ON);373if (result == -1) {374JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");375return result;376}377#endif378#ifdef MACOSX379result = fstatvfs(fd, &file_stat);380#else381result = fstatvfs64(fd, &file_stat);382#endif383if(result == -1) {384JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");385return result;386} else {387result = (int)file_stat.f_frsize;388}389#else390result = -1;391#endif392return result;393}394395396