Path: blob/master/src/java.base/unix/native/libnio/ch/FileChannelImpl.c
41133 views
/*1* Copyright (c) 2000, 2020, 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/mman.h>26#include <sys/stat.h>27#include <fcntl.h>28#include <sys/types.h>29#include <unistd.h>3031#if defined(__linux__)32#include <sys/sendfile.h>33#elif defined(_AIX)34#include <string.h>35#include <sys/socket.h>36#elif defined(_ALLBSD_SOURCE)37#include <sys/socket.h>38#include <sys/uio.h>39#define lseek64 lseek40#define mmap64 mmap41#endif4243#include "jni.h"44#include "jni_util.h"45#include "jlong.h"46#include "nio.h"47#include "nio_util.h"48#include "sun_nio_ch_FileChannelImpl.h"49#include "java_lang_Integer.h"50#include <assert.h>5152static jfieldID chan_fd; /* jobject 'fd' in sun.nio.ch.FileChannelImpl */5354JNIEXPORT jlong JNICALL55Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz)56{57jlong pageSize = sysconf(_SC_PAGESIZE);58chan_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;");59return pageSize;60}6162static jlong63handle(JNIEnv *env, jlong rv, char *msg)64{65if (rv >= 0)66return rv;67if (errno == EINTR)68return IOS_INTERRUPTED;69JNU_ThrowIOExceptionWithLastError(env, msg);70return IOS_THROWN;71}727374JNIEXPORT jlong JNICALL75Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this,76jint prot, jlong off, jlong len, jboolean map_sync)77{78void *mapAddress = 0;79jobject fdo = (*env)->GetObjectField(env, this, chan_fd);80jint fd = fdval(env, fdo);81int protections = 0;82int flags = 0;8384// should never be called with map_sync and prot == PRIVATE85assert((prot != sun_nio_ch_FileChannelImpl_MAP_PV) || !map_sync);8687if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) {88protections = PROT_READ;89flags = MAP_SHARED;90} else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) {91protections = PROT_WRITE | PROT_READ;92flags = MAP_SHARED;93} else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) {94protections = PROT_WRITE | PROT_READ;95flags = MAP_PRIVATE;96}9798// if MAP_SYNC and MAP_SHARED_VALIDATE are not defined then it is99// best to define them here. This ensures the code compiles on old100// OS releases which do not provide the relevant headers. If run101// on the same machine then it will work if the kernel contains102// the necessary support otherwise mmap should fail with an103// invalid argument error104105#ifndef MAP_SYNC106#define MAP_SYNC 0x80000107#endif108#ifndef MAP_SHARED_VALIDATE109#define MAP_SHARED_VALIDATE 0x03110#endif111112if (map_sync) {113// ensure114// 1) this is Linux on AArch64, x86_64, or PPC64 LE115// 2) the mmap APIs are available at compile time116#if !defined(LINUX) || ! (defined(aarch64) || (defined(amd64) && defined(_LP64)) || defined(ppc64le))117// TODO - implement for solaris/AIX/BSD/WINDOWS and for 32 bit118JNU_ThrowInternalError(env, "should never call map on platform where MAP_SYNC is unimplemented");119return IOS_THROWN;120#else121flags |= MAP_SYNC | MAP_SHARED_VALIDATE;122#endif123}124125mapAddress = mmap64(1260, /* Let OS decide location */127len, /* Number of bytes to map */128protections, /* File permissions */129flags, /* Changes are shared */130fd, /* File descriptor of mapped file */131off); /* Offset into file */132133if (mapAddress == MAP_FAILED) {134if (map_sync && errno == ENOTSUP) {135JNU_ThrowIOExceptionWithLastError(env, "map with mode MAP_SYNC unsupported");136return IOS_THROWN;137}138139if (errno == ENOMEM) {140JNU_ThrowOutOfMemoryError(env, "Map failed");141return IOS_THROWN;142}143return handle(env, -1, "Map failed");144}145146return ((jlong) (unsigned long) mapAddress);147}148149150JNIEXPORT jint JNICALL151Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this,152jlong address, jlong len)153{154void *a = (void *)jlong_to_ptr(address);155return handle(env,156munmap(a, (size_t)len),157"Unmap failed");158}159160JNIEXPORT jlong JNICALL161Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this,162jobject srcFDO,163jlong position, jlong count,164jobject dstFDO)165{166jint srcFD = fdval(env, srcFDO);167jint dstFD = fdval(env, dstFDO);168169#if defined(__linux__)170off64_t offset = (off64_t)position;171jlong n = sendfile64(dstFD, srcFD, &offset, (size_t)count);172if (n < 0) {173if (errno == EAGAIN)174return IOS_UNAVAILABLE;175if ((errno == EINVAL) && ((ssize_t)count >= 0))176return IOS_UNSUPPORTED_CASE;177if (errno == EINTR) {178return IOS_INTERRUPTED;179}180JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");181return IOS_THROWN;182}183return n;184#elif defined(__APPLE__)185off_t numBytes;186int result;187188numBytes = count;189190result = sendfile(srcFD, dstFD, position, &numBytes, NULL, 0);191192if (numBytes > 0)193return numBytes;194195if (result == -1) {196if (errno == EAGAIN)197return IOS_UNAVAILABLE;198if (errno == EOPNOTSUPP || errno == ENOTSOCK || errno == ENOTCONN)199return IOS_UNSUPPORTED_CASE;200if ((errno == EINVAL) && ((ssize_t)count >= 0))201return IOS_UNSUPPORTED_CASE;202if (errno == EINTR)203return IOS_INTERRUPTED;204JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");205return IOS_THROWN;206}207208return result;209210#elif defined(_AIX)211jlong max = (jlong)java_lang_Integer_MAX_VALUE;212struct sf_parms sf_iobuf;213jlong result;214215if (position > max)216return IOS_UNSUPPORTED_CASE;217218if (count > max)219count = max;220221memset(&sf_iobuf, 0, sizeof(sf_iobuf));222sf_iobuf.file_descriptor = srcFD;223sf_iobuf.file_offset = (off_t)position;224sf_iobuf.file_bytes = count;225226result = send_file(&dstFD, &sf_iobuf, SF_SYNC_CACHE);227228/* AIX send_file() will return 0 when this operation complete successfully,229* return 1 when partial bytes transfered and return -1 when an error has230* Occured.231*/232if (result == -1) {233if (errno == EWOULDBLOCK)234return IOS_UNAVAILABLE;235if ((errno == EINVAL) && ((ssize_t)count >= 0))236return IOS_UNSUPPORTED_CASE;237if (errno == EINTR)238return IOS_INTERRUPTED;239if (errno == ENOTSOCK)240return IOS_UNSUPPORTED;241JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");242return IOS_THROWN;243}244245if (sf_iobuf.bytes_sent > 0)246return (jlong)sf_iobuf.bytes_sent;247248return IOS_UNSUPPORTED_CASE;249#else250return IOS_UNSUPPORTED_CASE;251#endif252}253254255256