1 /* 2 * Copyright (c) 2000, 2012, 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 "jni.h" 27 #include "jni_util.h" 28 #include "jvm.h" 29 #include "jvm_md.h" 30 #include "jlong.h" 31 #include <sys/mman.h> 32 #include <sys/stat.h> 33 #include <fcntl.h> 34 #include "sun_nio_ch_FileChannelImpl.h" 35 #include "java_lang_Integer.h" 36 #include "nio.h" 37 #include "nio_util.h" 38 #include <dlfcn.h> 39 40 #if defined(__linux__) || defined(__solaris__) 41 #include <sys/sendfile.h> 42 #elif defined(_AIX) 43 #include <sys/socket.h> 44 #elif defined(_ALLBSD_SOURCE) 45 #include <sys/types.h> 46 #include <sys/socket.h> 47 #include <sys/uio.h> 48 49 #define lseek64 lseek 50 #define mmap64 mmap 51 #endif 52 53 static jfieldID chan_fd; /* jobject 'fd' in sun.io.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) 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 if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) { 86 protections = PROT_READ; 87 flags = MAP_SHARED; 88 } else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) { 89 protections = PROT_WRITE | PROT_READ; 90 flags = MAP_SHARED; 91 } else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) { 92 protections = PROT_WRITE | PROT_READ; 93 flags = MAP_PRIVATE; 94 } 95 96 mapAddress = mmap64( 97 0, /* Let OS decide location */ 98 len, /* Number of bytes to map */ 99 protections, /* File permissions */ 100 flags, /* Changes are shared */ 101 fd, /* File descriptor of mapped file */ 102 off); /* Offset into file */ 103 104 if (mapAddress == MAP_FAILED) { 105 if (errno == ENOMEM) { 106 JNU_ThrowOutOfMemoryError(env, "Map failed"); 107 return IOS_THROWN; 108 } 109 return handle(env, -1, "Map failed"); 110 } 111 112 return ((jlong) (unsigned long) mapAddress); 113 } 114 115 116 JNIEXPORT jint JNICALL 117 Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this, 118 jlong address, jlong len) 119 { 120 void *a = (void *)jlong_to_ptr(address); 121 return handle(env, 122 munmap(a, (size_t)len), 123 "Unmap failed"); 124 } 125 126 127 JNIEXPORT jlong JNICALL 128 Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this, 129 jobject fdo, jlong offset) 130 { 131 jint fd = fdval(env, fdo); 132 jlong result = 0; 133 134 if (offset < 0) { 135 result = lseek64(fd, 0, SEEK_CUR); 136 } else { 137 result = lseek64(fd, offset, SEEK_SET); 138 } 139 return handle(env, result, "Position failed"); 140 } 141 142 143 JNIEXPORT void JNICALL 144 Java_sun_nio_ch_FileChannelImpl_close0(JNIEnv *env, jobject this, jobject fdo) 145 { 146 jint fd = fdval(env, fdo); 147 if (fd != -1) { 148 jlong result = close(fd); 149 if (result < 0) { 150 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 151 } 152 } 153 } 154 155 JNIEXPORT jlong JNICALL 156 Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, 157 jobject srcFDO, 158 jlong position, jlong count, 159 jobject dstFDO) 160 { 161 jint srcFD = fdval(env, srcFDO); 162 jint dstFD = fdval(env, dstFDO); 163 164 #if defined(__linux__) 165 off64_t offset = (off64_t)position; 166 jlong n = sendfile64(dstFD, srcFD, &offset, (size_t)count); 167 if (n < 0) { 168 if (errno == EAGAIN) 169 return IOS_UNAVAILABLE; 170 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 171 return IOS_UNSUPPORTED_CASE; 172 if (errno == EINTR) { 173 return IOS_INTERRUPTED; 174 } 175 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 176 return IOS_THROWN; 177 } 178 return n; 179 #elif defined (__solaris__) 180 sendfilevec64_t sfv; 181 size_t numBytes = 0; 182 jlong result; 183 184 sfv.sfv_fd = srcFD; 185 sfv.sfv_flag = 0; 186 sfv.sfv_off = (off64_t)position; 187 sfv.sfv_len = count; 188 189 result = sendfilev64(dstFD, &sfv, 1, &numBytes); 190 191 /* Solaris sendfilev() will return -1 even if some bytes have been 192 * transferred, so we check numBytes first. 193 */ 194 if (numBytes > 0) 195 return numBytes; 196 if (result < 0) { 197 if (errno == EAGAIN) 198 return IOS_UNAVAILABLE; 199 if (errno == EOPNOTSUPP) 200 return IOS_UNSUPPORTED_CASE; 201 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 202 return IOS_UNSUPPORTED_CASE; 203 if (errno == EINTR) 204 return IOS_INTERRUPTED; 205 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 206 return IOS_THROWN; 207 } 208 return result; 209 #elif defined(__APPLE__) 210 off_t numBytes; 211 int result; 212 213 numBytes = count; 214 215 result = sendfile(srcFD, dstFD, position, &numBytes, NULL, 0); 216 217 if (numBytes > 0) 218 return numBytes; 219 220 if (result == -1) { 221 if (errno == EAGAIN) 222 return IOS_UNAVAILABLE; 223 if (errno == EOPNOTSUPP || errno == ENOTSOCK || errno == ENOTCONN) 224 return IOS_UNSUPPORTED_CASE; 225 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 226 return IOS_UNSUPPORTED_CASE; 227 if (errno == EINTR) 228 return IOS_INTERRUPTED; 229 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 230 return IOS_THROWN; 231 } 232 233 return result; 234 235 #elif defined(_AIX) 236 jlong max = (jlong)java_lang_Integer_MAX_VALUE; 237 struct sf_parms sf_iobuf; 238 jlong result; 239 240 if (position > max) 241 return IOS_UNSUPPORTED_CASE; 242 243 if (count > max) 244 count = max; 245 246 memset(&sf_iobuf, 0, sizeof(sf_iobuf)); 247 sf_iobuf.file_descriptor = srcFD; 248 sf_iobuf.file_offset = (off_t)position; 249 sf_iobuf.file_bytes = count; 250 251 result = send_file(&dstFD, &sf_iobuf, SF_SYNC_CACHE); 252 253 /* AIX send_file() will return 0 when this operation complete successfully, 254 * return 1 when partial bytes transfered and return -1 when an error has 255 * Occured. 256 */ 257 if (result == -1) { 258 if (errno == EWOULDBLOCK) 259 return IOS_UNAVAILABLE; 260 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 261 return IOS_UNSUPPORTED_CASE; 262 if (errno == EINTR) 263 return IOS_INTERRUPTED; 264 if (errno == ENOTSOCK) 265 return IOS_UNSUPPORTED; 266 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 267 return IOS_THROWN; 268 } 269 270 if (sf_iobuf.bytes_sent > 0) 271 return (jlong)sf_iobuf.bytes_sent; 272 273 return IOS_UNSUPPORTED_CASE; 274 #else 275 return IOS_UNSUPPORTED_CASE; 276 #endif 277 } 278