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 #if defined(__linux__) 38 #include <linux/fs.h> 39 #include <sys/ioctl.h> 40 #endif 41 #include "nio.h" 42 #include "nio_util.h" 43 44 #ifdef _ALLBSD_SOURCE 45 #define stat64 stat 46 #define flock64 flock 47 #define off64_t off_t 48 #define F_SETLKW64 F_SETLKW 49 #define F_SETLK64 F_SETLK 50 51 #define pread64 pread 52 #define pwrite64 pwrite 53 #define ftruncate64 ftruncate 54 #define fstat64 fstat 55 56 #define fdatasync fsync 57 #endif 58 59 static int preCloseFD = -1; /* File descriptor to which we dup other fd's 60 before closing them for real */ 61 62 63 JNIEXPORT void JNICALL 64 Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) 65 { 66 int sp[2]; 67 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { 68 JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); 69 return; 70 } 71 preCloseFD = sp[0]; 72 close(sp[1]); 73 } 74 75 JNIEXPORT jint JNICALL 76 Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, 77 jobject fdo, jlong address, jint len) 78 { 79 jint fd = fdval(env, fdo); 80 void *buf = (void *)jlong_to_ptr(address); 81 82 return convertReturnVal(env, read(fd, buf, len), JNI_TRUE); 83 } 84 85 JNIEXPORT jint JNICALL 86 Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, 87 jlong address, jint len, jlong offset) 88 { 89 jint fd = fdval(env, fdo); 90 void *buf = (void *)jlong_to_ptr(address); 91 92 return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE); 93 } 94 95 JNIEXPORT jlong JNICALL 96 Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, 97 jobject fdo, jlong address, jint len) 98 { 99 jint fd = fdval(env, fdo); 100 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 101 return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE); 102 } 103 104 JNIEXPORT jint JNICALL 105 Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, 106 jobject fdo, jlong address, jint len) 107 { 108 jint fd = fdval(env, fdo); 109 void *buf = (void *)jlong_to_ptr(address); 110 111 return convertReturnVal(env, write(fd, buf, len), JNI_FALSE); 112 } 113 114 JNIEXPORT jint JNICALL 115 Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, 116 jlong address, jint len, jlong offset) 117 { 118 jint fd = fdval(env, fdo); 119 void *buf = (void *)jlong_to_ptr(address); 120 121 return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE); 122 } 123 124 JNIEXPORT jlong JNICALL 125 Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, 126 jobject fdo, jlong address, jint len) 127 { 128 jint fd = fdval(env, fdo); 129 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 130 return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE); 131 } 132 133 static jlong 134 handle(JNIEnv *env, jlong rv, char *msg) 135 { 136 if (rv >= 0) 137 return rv; 138 if (errno == EINTR) 139 return IOS_INTERRUPTED; 140 JNU_ThrowIOExceptionWithLastError(env, msg); 141 return IOS_THROWN; 142 } 143 144 JNIEXPORT jint JNICALL 145 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, 146 jobject fdo, jboolean md) 147 { 148 jint fd = fdval(env, fdo); 149 int result = 0; 150 151 #ifdef MACOSX 152 result = fcntl(fd, F_FULLFSYNC); 153 if (result == -1 && errno == ENOTSUP) { 154 /* Try fsync() in case F_FULLSYUNC is not implemented on the file system. */ 155 result = fsync(fd); 156 } 157 #else /* end MACOSX, begin not-MACOSX */ 158 if (md == JNI_FALSE) { 159 result = fdatasync(fd); 160 } else { 161 #ifdef _AIX 162 /* On AIX, calling fsync on a file descriptor that is opened only for 163 * reading results in an error ("EBADF: The FileDescriptor parameter is 164 * not a valid file descriptor open for writing."). 165 * However, at this point it is not possibly anymore to read the 166 * 'writable' attribute of the corresponding file channel so we have to 167 * use 'fcntl'. 168 */ 169 int getfl = fcntl(fd, F_GETFL); 170 if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) { 171 return 0; 172 } 173 #endif /* _AIX */ 174 result = fsync(fd); 175 } 176 #endif /* not-MACOSX */ 177 return handle(env, result, "Force failed"); 178 } 179 180 JNIEXPORT jint JNICALL 181 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, 182 jobject fdo, jlong size) 183 { 184 return handle(env, 185 ftruncate64(fdval(env, fdo), size), 186 "Truncation failed"); 187 } 188 189 JNIEXPORT jlong JNICALL 190 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) 191 { 192 jint fd = fdval(env, fdo); 193 struct stat64 fbuf; 194 195 if (fstat64(fd, &fbuf) < 0) 196 return handle(env, -1, "Size failed"); 197 198 #ifdef BLKGETSIZE64 199 if (S_ISBLK(fbuf.st_mode)) { 200 uint64_t size; 201 if (ioctl(fd, BLKGETSIZE64, &size) < 0) 202 return handle(env, -1, "Size failed"); 203 return (jlong)size; 204 } 205 #endif 206 207 return fbuf.st_size; 208 } 209 210 JNIEXPORT jint JNICALL 211 Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, 212 jboolean block, jlong pos, jlong size, 213 jboolean shared) 214 { 215 jint fd = fdval(env, fdo); 216 jint lockResult = 0; 217 int cmd = 0; 218 struct flock64 fl; 219 220 fl.l_whence = SEEK_SET; 221 if (size == (jlong)java_lang_Long_MAX_VALUE) { 222 fl.l_len = (off64_t)0; 223 } else { 224 fl.l_len = (off64_t)size; 225 } 226 fl.l_start = (off64_t)pos; 227 if (shared == JNI_TRUE) { 228 fl.l_type = F_RDLCK; 229 } else { 230 fl.l_type = F_WRLCK; 231 } 232 if (block == JNI_TRUE) { 233 cmd = F_SETLKW64; 234 } else { 235 cmd = F_SETLK64; 236 } 237 lockResult = fcntl(fd, cmd, &fl); 238 if (lockResult < 0) { 239 if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES)) 240 return sun_nio_ch_FileDispatcherImpl_NO_LOCK; 241 if (errno == EINTR) 242 return sun_nio_ch_FileDispatcherImpl_INTERRUPTED; 243 JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); 244 } 245 return 0; 246 } 247 248 JNIEXPORT void JNICALL 249 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, 250 jobject fdo, jlong pos, jlong size) 251 { 252 jint fd = fdval(env, fdo); 253 jint lockResult = 0; 254 struct flock64 fl; 255 int cmd = F_SETLK64; 256 257 fl.l_whence = SEEK_SET; 258 if (size == (jlong)java_lang_Long_MAX_VALUE) { 259 fl.l_len = (off64_t)0; 260 } else { 261 fl.l_len = (off64_t)size; 262 } 263 fl.l_start = (off64_t)pos; 264 fl.l_type = F_UNLCK; 265 lockResult = fcntl(fd, cmd, &fl); 266 if (lockResult < 0) { 267 JNU_ThrowIOExceptionWithLastError(env, "Release failed"); 268 } 269 } 270 271 272 static void closeFileDescriptor(JNIEnv *env, int fd) { 273 if (fd != -1) { 274 int result = close(fd); 275 if (result < 0) 276 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 277 } 278 } 279 280 JNIEXPORT void JNICALL 281 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) 282 { 283 jint fd = fdval(env, fdo); 284 closeFileDescriptor(env, fd); 285 } 286 287 JNIEXPORT void JNICALL 288 Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo) 289 { 290 jint fd = fdval(env, fdo); 291 if (preCloseFD >= 0) { 292 if (dup2(preCloseFD, fd) < 0) 293 JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); 294 } 295 } 296 297 JNIEXPORT void JNICALL 298 Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd) 299 { 300 closeFileDescriptor(env, fd); 301 }