1 /* 2 * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <sys/mman.h> 27 #include <sys/stat.h> 28 #include <fcntl.h> 29 #include <sys/types.h> 30 #include <unistd.h> 31 32 #if defined(__linux__) || defined(__solaris__) 33 #include <sys/sendfile.h> 34 #elif defined(_AIX) 35 #include <sys/socket.h> 36 #elif defined(_ALLBSD_SOURCE) 37 #include <sys/socket.h> 38 #include <sys/uio.h> 39 #define lseek64 lseek 40 #define mmap64 mmap 41 #endif 42 43 #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 51 static jfieldID chan_fd; /* jobject 'fd' in sun.nio.ch.FileChannelImpl */ 52 53 JNIEXPORT jlong JNICALL 54 Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz) 55 { 56 jlong pageSize = sysconf(_SC_PAGESIZE); 57 chan_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;"); 58 return pageSize; 59 } 60 61 static jlong 62 handle(JNIEnv *env, jlong rv, char *msg) 63 { 64 if (rv >= 0) 65 return rv; 66 if (errno == EINTR) 67 return IOS_INTERRUPTED; 68 JNU_ThrowIOExceptionWithLastError(env, msg); 69 return IOS_THROWN; 70 } 71 72 73 JNIEXPORT jlong JNICALL 74 Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this, 75 jint prot, jlong off, jlong len) 76 { 77 void *mapAddress = 0; 78 jobject fdo = (*env)->GetObjectField(env, this, chan_fd); 79 jint fd = fdval(env, fdo); 80 int protections = 0; 81 int flags = 0; 82 83 if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) { 84 protections = PROT_READ; 85 flags = MAP_SHARED; 86 } else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) { 87 protections = PROT_WRITE | PROT_READ; 88 flags = MAP_SHARED; 89 } else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) { 90 protections = PROT_WRITE | PROT_READ; 91 flags = MAP_PRIVATE; 92 } 93 94 mapAddress = mmap64( 95 0, /* Let OS decide location */ 96 len, /* Number of bytes to map */ 97 protections, /* File permissions */ 98 flags, /* Changes are shared */ 99 fd, /* File descriptor of mapped file */ 100 off); /* Offset into file */ 101 102 if (mapAddress == MAP_FAILED) { 103 if (errno == ENOMEM) { 104 JNU_ThrowOutOfMemoryError(env, "Map failed"); 105 return IOS_THROWN; 106 } 107 return handle(env, -1, "Map failed"); 108 } 109 110 return ((jlong) (unsigned long) mapAddress); 111 } 112 113 114 JNIEXPORT jint JNICALL 115 Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this, 116 jlong address, jlong len) 117 { 118 void *a = (void *)jlong_to_ptr(address); 119 return handle(env, 120 munmap(a, (size_t)len), 121 "Unmap failed"); 122 } 123 124 JNIEXPORT jlong JNICALL 125 Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, 126 jobject srcFDO, 127 jlong position, jlong count, 128 jobject dstFDO) 129 { 130 jint srcFD = fdval(env, srcFDO); 131 jint dstFD = fdval(env, dstFDO); 132 133 #if defined(__linux__) 134 off64_t offset = (off64_t)position; 135 jlong n = sendfile64(dstFD, srcFD, &offset, (size_t)count); 136 if (n < 0) { 137 if (errno == EAGAIN) 138 return IOS_UNAVAILABLE; 139 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 140 return IOS_UNSUPPORTED_CASE; 141 if (errno == EINTR) { 142 return IOS_INTERRUPTED; 143 } 144 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 145 return IOS_THROWN; 146 } 147 return n; 148 #elif defined (__solaris__) 149 sendfilevec64_t sfv; 150 size_t numBytes = 0; 151 jlong result; 152 153 sfv.sfv_fd = srcFD; 154 sfv.sfv_flag = 0; 155 sfv.sfv_off = (off64_t)position; 156 sfv.sfv_len = count; 157 158 result = sendfilev64(dstFD, &sfv, 1, &numBytes); 159 160 /* Solaris sendfilev() will return -1 even if some bytes have been 161 * transferred, so we check numBytes first. 162 */ 163 if (numBytes > 0) 164 return numBytes; 165 if (result < 0) { 166 if (errno == EAGAIN) 167 return IOS_UNAVAILABLE; 168 if (errno == EOPNOTSUPP) 169 return IOS_UNSUPPORTED_CASE; 170 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 171 return IOS_UNSUPPORTED_CASE; 172 if (errno == EINTR) 173 return IOS_INTERRUPTED; 174 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 175 return IOS_THROWN; 176 } 177 return result; 178 #elif defined(__APPLE__) 179 off_t numBytes; 180 int result; 181 182 numBytes = count; 183 184 result = sendfile(srcFD, dstFD, position, &numBytes, NULL, 0); 185 186 if (numBytes > 0) 187 return numBytes; 188 189 if (result == -1) { 190 if (errno == EAGAIN) 191 return IOS_UNAVAILABLE; 192 if (errno == EOPNOTSUPP || errno == ENOTSOCK || errno == ENOTCONN) 193 return IOS_UNSUPPORTED_CASE; 194 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 195 return IOS_UNSUPPORTED_CASE; 196 if (errno == EINTR) 197 return IOS_INTERRUPTED; 198 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 199 return IOS_THROWN; 200 } 201 202 return result; 203 204 #elif defined(_AIX) 205 jlong max = (jlong)java_lang_Integer_MAX_VALUE; 206 struct sf_parms sf_iobuf; 207 jlong result; 208 209 if (position > max) 210 return IOS_UNSUPPORTED_CASE; 211 212 if (count > max) 213 count = max; 214 215 memset(&sf_iobuf, 0, sizeof(sf_iobuf)); 216 sf_iobuf.file_descriptor = srcFD; 217 sf_iobuf.file_offset = (off_t)position; 218 sf_iobuf.file_bytes = count; 219 220 result = send_file(&dstFD, &sf_iobuf, SF_SYNC_CACHE); 221 222 /* AIX send_file() will return 0 when this operation complete successfully, 223 * return 1 when partial bytes transfered and return -1 when an error has 224 * Occured. 225 */ 226 if (result == -1) { 227 if (errno == EWOULDBLOCK) 228 return IOS_UNAVAILABLE; 229 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 230 return IOS_UNSUPPORTED_CASE; 231 if (errno == EINTR) 232 return IOS_INTERRUPTED; 233 if (errno == ENOTSOCK) 234 return IOS_UNSUPPORTED; 235 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 236 return IOS_THROWN; 237 } 238 239 if (sf_iobuf.bytes_sent > 0) 240 return (jlong)sf_iobuf.bytes_sent; 241 242 return IOS_UNSUPPORTED_CASE; 243 #else 244 return IOS_UNSUPPORTED_CASE; 245 #endif 246 } 247