1 /* 2 * Copyright (c) 2000, 2009, 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 "jlong.h" 30 #include <sys/mman.h> 31 #include <sys/stat.h> 32 #include "sun_nio_ch_FileChannelImpl.h" 33 #include "java_lang_Integer.h" 34 #include "nio.h" 35 #include "nio_util.h" 36 #include <dlfcn.h> 37 38 #if defined(__linux__) || defined(__solaris__) 39 #include <sys/sendfile.h> 40 #endif 41 42 static jfieldID chan_fd; /* jobject 'fd' in sun.io.FileChannelImpl */ 43 44 JNIEXPORT jlong JNICALL 45 Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz) 46 { 47 jlong pageSize = sysconf(_SC_PAGESIZE); 48 chan_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;"); 49 return pageSize; 50 } 51 52 static jlong 53 handle(JNIEnv *env, jlong rv, char *msg) 54 { 55 if (rv >= 0) 56 return rv; 57 if (errno == EINTR) 58 return IOS_INTERRUPTED; 59 JNU_ThrowIOExceptionWithLastError(env, msg); 60 return IOS_THROWN; 61 } 62 63 64 JNIEXPORT jlong JNICALL 65 Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this, 66 jint prot, jlong off, jlong len) 67 { 68 void *mapAddress = 0; 69 jobject fdo = (*env)->GetObjectField(env, this, chan_fd); 70 jint fd = fdval(env, fdo); 71 int protections = 0; 72 int flags = 0; 73 74 if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) { 75 protections = PROT_READ; 76 flags = MAP_SHARED; 77 } else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) { 78 protections = PROT_WRITE | PROT_READ; 79 flags = MAP_SHARED; 80 } else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) { 81 protections = PROT_WRITE | PROT_READ; 82 flags = MAP_PRIVATE; 83 } 84 85 mapAddress = mmap64( 86 0, /* Let OS decide location */ 87 len, /* Number of bytes to map */ 88 protections, /* File permissions */ 89 flags, /* Changes are shared */ 90 fd, /* File descriptor of mapped file */ 91 off); /* Offset into file */ 92 93 if (mapAddress == MAP_FAILED) { 94 if (errno == ENOMEM) { 95 JNU_ThrowOutOfMemoryError(env, "Map failed"); 96 return IOS_THROWN; 97 } 98 return handle(env, -1, "Map failed"); 99 } 100 101 return ((jlong) (unsigned long) mapAddress); 102 } 103 104 105 JNIEXPORT jint JNICALL 106 Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this, 107 jlong address, jlong len) 108 { 109 void *a = (void *)jlong_to_ptr(address); 110 return handle(env, 111 munmap(a, (size_t)len), 112 "Unmap failed"); 113 } 114 115 116 JNIEXPORT jlong JNICALL 117 Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this, 118 jobject fdo, jlong offset) 119 { 120 jint fd = fdval(env, fdo); 121 jlong result = 0; 122 123 if (offset < 0) { 124 result = lseek64(fd, 0, SEEK_CUR); 125 } else { 126 result = lseek64(fd, offset, SEEK_SET); 127 } 128 return handle(env, result, "Position failed"); 129 } 130 131 132 JNIEXPORT void JNICALL 133 Java_sun_nio_ch_FileChannelImpl_close0(JNIEnv *env, jobject this, jobject fdo) 134 { 135 jint fd = fdval(env, fdo); 136 if (fd != -1) { 137 jlong result = close(fd); 138 if (result < 0) { 139 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 140 } 141 } 142 } 143 144 JNIEXPORT jlong JNICALL 145 Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, 146 jint srcFD, 147 jlong position, jlong count, 148 jint dstFD) 149 { 150 #if defined(__linux__) 151 off64_t offset = (off64_t)position; 152 jlong n = sendfile64(dstFD, srcFD, &offset, (size_t)count); 153 if (n < 0) { 154 if (errno == EAGAIN) 155 return IOS_UNAVAILABLE; 156 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 157 return IOS_UNSUPPORTED_CASE; 158 if (errno == EINTR) { 159 return IOS_INTERRUPTED; 160 } 161 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 162 return IOS_THROWN; 163 } 164 return n; 165 #elif defined (__solaris__) 166 sendfilevec64_t sfv; 167 size_t numBytes = 0; 168 jlong result; 169 170 sfv.sfv_fd = srcFD; 171 sfv.sfv_flag = 0; 172 sfv.sfv_off = (off64_t)position; 173 sfv.sfv_len = count; 174 175 result = sendfilev64(dstFD, &sfv, 1, &numBytes); 176 177 /* Solaris sendfilev() will return -1 even if some bytes have been 178 * transferred, so we check numBytes first. 179 */ 180 if (numBytes > 0) 181 return numBytes; 182 if (result < 0) { 183 if (errno == EAGAIN) 184 return IOS_UNAVAILABLE; 185 if (errno == EOPNOTSUPP) 186 return IOS_UNSUPPORTED_CASE; 187 if ((errno == EINVAL) && ((ssize_t)count >= 0)) 188 return IOS_UNSUPPORTED_CASE; 189 if (errno == EINTR) 190 return IOS_INTERRUPTED; 191 JNU_ThrowIOExceptionWithLastError(env, "Transfer failed"); 192 return IOS_THROWN; 193 } 194 return result; 195 #else 196 return IOS_UNSUPPORTED_CASE; 197 #endif 198 }