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 "jlong.h" 30 #include "sun_nio_ch_FileDispatcherImpl.h" 31 #include "java_lang_Long.h" 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 #include <fcntl.h> 35 #include <sys/uio.h> 36 #include <unistd.h> 37 #include "nio.h" 38 #include "nio_util.h" 39 40 #ifdef _ALLBSD_SOURCE 41 #define stat64 stat 42 #define flock64 flock 43 #define off64_t off_t 44 #define F_SETLKW64 F_SETLKW 45 #define F_SETLK64 F_SETLK 46 47 #define pread64 pread 48 #define pwrite64 pwrite 49 #define ftruncate64 ftruncate 50 #define fstat64 fstat 51 52 #define fdatasync fsync 53 #endif 54 55 static int preCloseFD = -1; /* File descriptor to which we dup other fd's 56 before closing them for real */ 57 58 59 JNIEXPORT void JNICALL 60 Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) 61 { 62 int sp[2]; 63 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { 64 JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); 65 return; 66 } 67 preCloseFD = sp[0]; 68 close(sp[1]); 69 } 70 71 JNIEXPORT jint JNICALL 72 Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, 73 jobject fdo, jlong address, jint len) 74 { 75 jint fd = fdval(env, fdo); 76 void *buf = (void *)jlong_to_ptr(address); 77 78 return convertReturnVal(env, read(fd, buf, len), JNI_TRUE); 79 } 80 81 JNIEXPORT jint JNICALL 82 Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, 83 jlong address, jint len, jlong offset) 84 { 85 jint fd = fdval(env, fdo); 86 void *buf = (void *)jlong_to_ptr(address); 87 88 return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE); 89 } 90 91 JNIEXPORT jlong JNICALL 92 Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, 93 jobject fdo, jlong address, jint len) 94 { 95 jint fd = fdval(env, fdo); 96 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 97 return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE); 98 } 99 100 JNIEXPORT jint JNICALL 101 Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, 102 jobject fdo, jlong address, jint len) 103 { 104 jint fd = fdval(env, fdo); 105 void *buf = (void *)jlong_to_ptr(address); 106 107 return convertReturnVal(env, write(fd, buf, len), JNI_FALSE); 108 } 109 110 JNIEXPORT jint JNICALL 111 Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, 112 jlong address, jint len, jlong offset) 113 { 114 jint fd = fdval(env, fdo); 115 void *buf = (void *)jlong_to_ptr(address); 116 117 return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE); 118 } 119 120 JNIEXPORT jlong JNICALL 121 Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, 122 jobject fdo, jlong address, jint len) 123 { 124 jint fd = fdval(env, fdo); 125 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 126 return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE); 127 } 128 129 static jlong 130 handle(JNIEnv *env, jlong rv, char *msg) 131 { 132 if (rv >= 0) 133 return rv; 134 if (errno == EINTR) 135 return IOS_INTERRUPTED; 136 JNU_ThrowIOExceptionWithLastError(env, msg); 137 return IOS_THROWN; 138 } 139 140 JNIEXPORT jint JNICALL 141 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, 142 jobject fdo, jboolean md) 143 { 144 jint fd = fdval(env, fdo); 145 int result = 0; 146 147 if (md == JNI_FALSE) { 148 result = fdatasync(fd); 149 } else { 150 result = fsync(fd); 151 } 152 return handle(env, result, "Force failed"); 153 } 154 155 JNIEXPORT jint JNICALL 156 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, 157 jobject fdo, jlong size) 158 { 159 return handle(env, 160 ftruncate64(fdval(env, fdo), size), 161 "Truncation failed"); 162 } 163 164 JNIEXPORT jlong JNICALL 165 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) 166 { 167 struct stat64 fbuf; 168 169 if (fstat64(fdval(env, fdo), &fbuf) < 0) 170 return handle(env, -1, "Size failed"); 171 return fbuf.st_size; 172 } 173 174 JNIEXPORT jint JNICALL 175 Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, 176 jboolean block, jlong pos, jlong size, 177 jboolean shared) 178 { 179 jint fd = fdval(env, fdo); 180 jint lockResult = 0; 181 int cmd = 0; 182 struct flock64 fl; 183 184 fl.l_whence = SEEK_SET; 185 if (size == (jlong)java_lang_Long_MAX_VALUE) { 186 fl.l_len = (off64_t)0; 187 } else { 188 fl.l_len = (off64_t)size; 189 } 190 fl.l_start = (off64_t)pos; 191 if (shared == JNI_TRUE) { 192 fl.l_type = F_RDLCK; 193 } else { 194 fl.l_type = F_WRLCK; 195 } 196 if (block == JNI_TRUE) { 197 cmd = F_SETLKW64; 198 } else { 199 cmd = F_SETLK64; 200 } 201 lockResult = fcntl(fd, cmd, &fl); 202 if (lockResult < 0) { 203 if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES)) 204 return sun_nio_ch_FileDispatcherImpl_NO_LOCK; 205 if (errno == EINTR) 206 return sun_nio_ch_FileDispatcherImpl_INTERRUPTED; 207 JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); 208 } 209 return 0; 210 } 211 212 JNIEXPORT void JNICALL 213 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, 214 jobject fdo, jlong pos, jlong size) 215 { 216 jint fd = fdval(env, fdo); 217 jint lockResult = 0; 218 struct flock64 fl; 219 int cmd = F_SETLK64; 220 221 fl.l_whence = SEEK_SET; 222 if (size == (jlong)java_lang_Long_MAX_VALUE) { 223 fl.l_len = (off64_t)0; 224 } else { 225 fl.l_len = (off64_t)size; 226 } 227 fl.l_start = (off64_t)pos; 228 fl.l_type = F_UNLCK; 229 lockResult = fcntl(fd, cmd, &fl); 230 if (lockResult < 0) { 231 JNU_ThrowIOExceptionWithLastError(env, "Release failed"); 232 } 233 } 234 235 236 static void closeFileDescriptor(JNIEnv *env, int fd) { 237 if (fd != -1) { 238 int result = close(fd); 239 if (result < 0) 240 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 241 } 242 } 243 244 JNIEXPORT void JNICALL 245 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) 246 { 247 jint fd = fdval(env, fdo); 248 closeFileDescriptor(env, fd); 249 } 250 251 JNIEXPORT void JNICALL 252 Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo) 253 { 254 jint fd = fdval(env, fdo); 255 if (preCloseFD >= 0) { 256 if (dup2(preCloseFD, fd) < 0) 257 JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); 258 } 259 } 260 261 JNIEXPORT void JNICALL 262 Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd) 263 { 264 closeFileDescriptor(env, fd); 265 }