1 /* 2 * Copyright (c) 2000, 2016, 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 jint JNICALL 190 Java_sun_nio_ch_FileDispatcherImpl_allocate0(JNIEnv *env, jobject this, 191 jobject fdo, jlong size) 192 { 193 jint fd = fdval(env, fdo); 194 #if defined(__linux__) 195 /* 196 * On Linux, if the file size is being increased, then ftruncate64() 197 * will modify the metadata value of the size without actually allocating 198 * any blocks which can cause a SIGBUS error if the file is subsequently 199 * memory-mapped. 200 */ 201 struct stat64 fbuf; 202 203 if (fstat64(fd, &fbuf) == 0 && size > fbuf.st_blocks*512) { 204 return handle(env, 205 fallocate64(fd, 0, 0, size), 206 "Allocation failed"); 207 } 208 #endif 209 return handle(env, 210 ftruncate64(fd, size), 211 "Truncation failed"); 212 } 213 214 JNIEXPORT jlong JNICALL 215 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) 216 { 217 jint fd = fdval(env, fdo); 218 struct stat64 fbuf; 219 220 if (fstat64(fd, &fbuf) < 0) 221 return handle(env, -1, "Size failed"); 222 223 #ifdef BLKGETSIZE64 224 if (S_ISBLK(fbuf.st_mode)) { 225 uint64_t size; 226 if (ioctl(fd, BLKGETSIZE64, &size) < 0) 227 return handle(env, -1, "Size failed"); 228 return (jlong)size; 229 } 230 #endif 231 232 return fbuf.st_size; 233 } 234 235 JNIEXPORT jint JNICALL 236 Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, 237 jboolean block, jlong pos, jlong size, 238 jboolean shared) 239 { 240 jint fd = fdval(env, fdo); 241 jint lockResult = 0; 242 int cmd = 0; 243 struct flock64 fl; 244 245 fl.l_whence = SEEK_SET; 246 if (size == (jlong)java_lang_Long_MAX_VALUE) { 247 fl.l_len = (off64_t)0; 248 } else { 249 fl.l_len = (off64_t)size; 250 } 251 fl.l_start = (off64_t)pos; 252 if (shared == JNI_TRUE) { 253 fl.l_type = F_RDLCK; 254 } else { 255 fl.l_type = F_WRLCK; 256 } 257 if (block == JNI_TRUE) { 258 cmd = F_SETLKW64; 259 } else { 260 cmd = F_SETLK64; 261 } 262 lockResult = fcntl(fd, cmd, &fl); 263 if (lockResult < 0) { 264 if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES)) 265 return sun_nio_ch_FileDispatcherImpl_NO_LOCK; 266 if (errno == EINTR) 267 return sun_nio_ch_FileDispatcherImpl_INTERRUPTED; 268 JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); 269 } 270 return 0; 271 } 272 273 JNIEXPORT void JNICALL 274 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, 275 jobject fdo, jlong pos, jlong size) 276 { 277 jint fd = fdval(env, fdo); 278 jint lockResult = 0; 279 struct flock64 fl; 280 int cmd = F_SETLK64; 281 282 fl.l_whence = SEEK_SET; 283 if (size == (jlong)java_lang_Long_MAX_VALUE) { 284 fl.l_len = (off64_t)0; 285 } else { 286 fl.l_len = (off64_t)size; 287 } 288 fl.l_start = (off64_t)pos; 289 fl.l_type = F_UNLCK; 290 lockResult = fcntl(fd, cmd, &fl); 291 if (lockResult < 0) { 292 JNU_ThrowIOExceptionWithLastError(env, "Release failed"); 293 } 294 } 295 296 297 static void closeFileDescriptor(JNIEnv *env, int fd) { 298 if (fd != -1) { 299 int result = close(fd); 300 if (result < 0) 301 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 302 } 303 } 304 305 JNIEXPORT void JNICALL 306 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) 307 { 308 jint fd = fdval(env, fdo); 309 closeFileDescriptor(env, fd); 310 } 311 312 JNIEXPORT void JNICALL 313 Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo) 314 { 315 jint fd = fdval(env, fdo); 316 if (preCloseFD >= 0) { 317 if (dup2(preCloseFD, fd) < 0) 318 JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); 319 } 320 } 321 322 JNIEXPORT void JNICALL 323 Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd) 324 { 325 closeFileDescriptor(env, fd); 326 }