1 /* 2 * Copyright (c) 2000, 2019, 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 <string.h> 36 #include <sys/socket.h> 37 #elif defined(_ALLBSD_SOURCE) 38 #include <sys/socket.h> 39 #include <sys/uio.h> 40 #define lseek64 lseek 41 #define mmap64 mmap 42 #endif 43 44 #include "jni.h" 45 #include "jni_util.h" 46 #include "jlong.h" 47 #include "nio.h" 48 #include "nio_util.h" 49 #include "sun_nio_ch_FileChannelImpl.h" 50 #include "java_lang_Integer.h" 51 #include <assert.h> 52 53 static jfieldID chan_fd; /* jobject 'fd' in sun.nio.ch.FileChannelImpl */ 54 55 JNIEXPORT jlong JNICALL 56 Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz) 57 { 58 jlong pageSize = sysconf(_SC_PAGESIZE); 59 chan_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;"); 60 return pageSize; 61 } 62 63 static jlong 64 handle(JNIEnv *env, jlong rv, char *msg) 65 { 66 if (rv >= 0) 67 return rv; 68 if (errno == EINTR) 69 return IOS_INTERRUPTED; 70 JNU_ThrowIOExceptionWithLastError(env, msg); 71 return IOS_THROWN; 72 } 73 74 75 JNIEXPORT jlong JNICALL 76 Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this, 77 jint prot, jlong off, jlong len, jboolean map_sync) 78 { 79 void *mapAddress = 0; 80 jobject fdo = (*env)->GetObjectField(env, this, chan_fd); 81 jint fd = fdval(env, fdo); 82 int protections = 0; 83 int flags = 0; 84 85 // should never be called with map_sync and prot == PRIVATE 86 assert((prot != sun_nio_ch_FileChannelImpl_MAP_PV) || !map_sync); 87 88 if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) { 89 protections = PROT_READ; 90 flags = MAP_SHARED; 91 } else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) { 92 protections = PROT_WRITE | PROT_READ; 93 flags = MAP_SHARED; 94 } else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) { 95 protections = PROT_WRITE | PROT_READ; 96 flags = MAP_PRIVATE; 97 } 98 99 // if MAP_SYNC and MAP_SHARED_VALIDATE are not defined then it is 100 // best to define them here. This ensures the code compiles on old 101 // OS releases which do not provide the relevant headers. If run 102 // on the same machine then it will work if the kernel contains 103 // the necessary support otherwise mmap should fail with an 104 // invalid argument error 105 106 #ifndef MAP_SYNC 107 #define MAP_SYNC 0x80000 108 #endif 109 #ifndef MAP_SHARED_VALIDATE 110 #define MAP_SHARED_VALIDATE 0x03 111 #endif 112 113 if (map_sync) { 114 // ensure 115 // 1) this is Linux on AArch64, x86_64, or PPC64 LE 116 // 2) the mmap APIs are available at compile time 117 #if !defined(LINUX) || ! (defined(aarch64) || (defined(amd64) && defined(_LP64)) || defined(ppc64le)) 118 // TODO - implement for solaris/AIX/BSD/WINDOWS and for 32 bit 119 JNU_ThrowInternalError(env, "should never call map on platform where MAP_SYNC is unimplemented"); 120 return IOS_THROWN; 121 #else 122 flags |= MAP_SYNC | MAP_SHARED_VALIDATE; 123 #endif 124 } 125 126 mapAddress = mmap64( 127 0, /* Let OS decide location */ 128 len, /* Number of bytes to map */ 129 protections, /* File permissions */ 130 flags, /* Changes are shared */ 131 fd, /* File descriptor of mapped file */ 132 off); /* Offset into file */ 133 134 if (mapAddress == MAP_FAILED) { 135 if (map_sync && errno == ENOTSUP) { 136 JNU_ThrowIOExceptionWithLastError(env, "map with mode MAP_SYNC unsupported"); 137 return IOS_THROWN; 138 } 139 140 if (errno == ENOMEM) { 141 JNU_ThrowOutOfMemoryError(env, "Map failed"); 142 return IOS_THROWN; 143 } 144 return handle(env, -1, "Map failed"); 145 } 146 147 return ((jlong) (unsigned long) mapAddress); 148 } 149 150 151 JNIEXPORT jint JNICALL 152 Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this, 153 jlong address, jlong len) 154 { 155 void *a = (void *)jlong_to_ptr(address); 156 return handle(env, 157 munmap(a, (size_t)len), 158 "Unmap failed"); 159 } 160 161 JNIEXPORT jlong JNICALL 162 Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, 163 jobject srcFDO, 164 jlong position, jlong count, 165 jobject dstFDO) 166 { 167 jint srcFD = fdval(env, srcFDO); 168 jint dstFD = fdval(env, dstFDO); 169 170 #if defined(__linux__) 171 off64_t offset = (off64_t)position; 172 jlong n = sendfile64(dstFD, srcFD, &offset, (size_t)count); 173 if (n < 0) { 174 if (errno == EAGAIN) 175 return IOS_UNAVAILABLE; 176 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 177 return IOS_UNSUPPORTED_CASE; 178 if (errno == EINTR) { 179 return IOS_INTERRUPTED; 180 } 181 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 182 return IOS_THROWN; 183 } 184 return n; 185 #elif defined (__solaris__) 186 sendfilevec64_t sfv; 187 size_t numBytes = 0; 188 jlong result; 189 190 sfv.sfv_fd = srcFD; 191 sfv.sfv_flag = 0; 192 sfv.sfv_off = (off64_t)position; 193 sfv.sfv_len = count; 194 195 result = sendfilev64(dstFD, &sfv, 1, &numBytes); 196 197 /* Solaris sendfilev() will return -1 even if some bytes have been 198 * transferred, so we check numBytes first. 199 */ 200 if (numBytes > 0) 201 return numBytes; 202 if (result < 0) { 203 if (errno == EAGAIN) 204 return IOS_UNAVAILABLE; 205 if (errno == EOPNOTSUPP) 206 return IOS_UNSUPPORTED_CASE; 207 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 208 return IOS_UNSUPPORTED_CASE; 209 if (errno == EINTR) 210 return IOS_INTERRUPTED; 211 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 212 return IOS_THROWN; 213 } 214 return result; 215 #elif defined(__APPLE__) 216 off_t numBytes; 217 int result; 218 219 numBytes = count; 220 221 result = sendfile(srcFD, dstFD, position, &numBytes, NULL, 0); 222 223 if (numBytes > 0) 224 return numBytes; 225 226 if (result == -1) { 227 if (errno == EAGAIN) 228 return IOS_UNAVAILABLE; 229 if (errno == EOPNOTSUPP || errno == ENOTSOCK || errno == ENOTCONN) 230 return IOS_UNSUPPORTED_CASE; 231 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 232 return IOS_UNSUPPORTED_CASE; 233 if (errno == EINTR) 234 return IOS_INTERRUPTED; 235 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 236 return IOS_THROWN; 237 } 238 239 return result; 240 241 #elif defined(_AIX) 242 jlong max = (jlong)java_lang_Integer_MAX_VALUE; 243 struct sf_parms sf_iobuf; 244 jlong result; 245 246 if (position > max) 247 return IOS_UNSUPPORTED_CASE; 248 249 if (count > max) 250 count = max; 251 252 memset(&sf_iobuf, 0, sizeof(sf_iobuf)); 253 sf_iobuf.file_descriptor = srcFD; 254 sf_iobuf.file_offset = (off_t)position; 255 sf_iobuf.file_bytes = count; 256 257 result = send_file(&dstFD, &sf_iobuf, SF_SYNC_CACHE); 258 259 /* AIX send_file() will return 0 when this operation complete successfully, 260 * return 1 when partial bytes transfered and return -1 when an error has 261 * Occured. 262 */ 263 if (result == -1) { 264 if (errno == EWOULDBLOCK) 265 return IOS_UNAVAILABLE; 266 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 267 return IOS_UNSUPPORTED_CASE; 268 if (errno == EINTR) 269 return IOS_INTERRUPTED; 270 if (errno == ENOTSOCK) 271 return IOS_UNSUPPORTED; 272 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 273 return IOS_THROWN; 274 } 275 276 if (sf_iobuf.bytes_sent > 0) 277 return (jlong)sf_iobuf.bytes_sent; 278 279 return IOS_UNSUPPORTED_CASE; 280 #else 281 return IOS_UNSUPPORTED_CASE; 282 #endif 283 } 284