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