1 /* 2 * Copyright (c) 2000, 2017, 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 <sys/statvfs.h> 38 #if defined(__linux__) 39 #include <linux/fs.h> 40 #include <sys/ioctl.h> 41 #endif 42 #include "nio.h" 43 #include "nio_util.h" 44 45 #ifdef _ALLBSD_SOURCE 46 #define stat64 stat 47 #define flock64 flock 48 #define off64_t off_t 49 #define F_SETLKW64 F_SETLKW 50 #define F_SETLK64 F_SETLK 51 52 #define pread64 pread 53 #define pwrite64 pwrite 54 #define ftruncate64 ftruncate 55 #define fstat64 fstat 56 57 #define fdatasync fsync 58 #endif 59 60 static int preCloseFD = -1; /* File descriptor to which we dup other fd's 61 before closing them for real */ 62 63 64 JNIEXPORT void JNICALL 65 Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) 66 { 67 int sp[2]; 68 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { 69 JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); 70 return; 71 } 72 preCloseFD = sp[0]; 73 close(sp[1]); 74 } 75 76 JNIEXPORT jint JNICALL 77 Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, 78 jobject fdo, jlong address, jint len) 79 { 80 jint fd = fdval(env, fdo); 81 void *buf = (void *)jlong_to_ptr(address); 82 83 return convertReturnVal(env, read(fd, buf, len), JNI_TRUE); 84 } 85 86 JNIEXPORT jint JNICALL 87 Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, 88 jlong address, jint len, jlong offset) 89 { 90 jint fd = fdval(env, fdo); 91 void *buf = (void *)jlong_to_ptr(address); 92 93 return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE); 94 } 95 96 JNIEXPORT jlong JNICALL 97 Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, 98 jobject fdo, jlong address, jint len) 99 { 100 jint fd = fdval(env, fdo); 101 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 102 return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE); 103 } 104 105 JNIEXPORT jint JNICALL 106 Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, 107 jobject fdo, jlong address, jint len) 108 { 109 jint fd = fdval(env, fdo); 110 void *buf = (void *)jlong_to_ptr(address); 111 112 return convertReturnVal(env, write(fd, buf, len), JNI_FALSE); 113 } 114 115 JNIEXPORT jint JNICALL 116 Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, 117 jlong address, jint len, jlong offset) 118 { 119 jint fd = fdval(env, fdo); 120 void *buf = (void *)jlong_to_ptr(address); 121 122 return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE); 123 } 124 125 JNIEXPORT jlong JNICALL 126 Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, 127 jobject fdo, jlong address, jint len) 128 { 129 jint fd = fdval(env, fdo); 130 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 131 return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE); 132 } 133 134 static jlong 135 handle(JNIEnv *env, jlong rv, char *msg) 136 { 137 if (rv >= 0) 138 return rv; 139 if (errno == EINTR) 140 return IOS_INTERRUPTED; 141 JNU_ThrowIOExceptionWithLastError(env, msg); 142 return IOS_THROWN; 143 } 144 145 JNIEXPORT jint JNICALL 146 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, 147 jobject fdo, jboolean md) 148 { 149 jint fd = fdval(env, fdo); 150 int result = 0; 151 152 #ifdef MACOSX 153 result = fcntl(fd, F_FULLFSYNC); 154 if (result == -1 && errno == ENOTSUP) { 155 /* Try fsync() in case F_FULLSYUNC is not implemented on the file system. */ 156 result = fsync(fd); 157 } 158 #else /* end MACOSX, begin not-MACOSX */ 159 if (md == JNI_FALSE) { 160 result = fdatasync(fd); 161 } else { 162 #ifdef _AIX 163 /* On AIX, calling fsync on a file descriptor that is opened only for 164 * reading results in an error ("EBADF: The FileDescriptor parameter is 165 * not a valid file descriptor open for writing."). 166 * However, at this point it is not possibly anymore to read the 167 * 'writable' attribute of the corresponding file channel so we have to 168 * use 'fcntl'. 169 */ 170 int getfl = fcntl(fd, F_GETFL); 171 if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) { 172 return 0; 173 } 174 #endif /* _AIX */ 175 result = fsync(fd); 176 } 177 #endif /* not-MACOSX */ 178 return handle(env, result, "Force failed"); 179 } 180 181 JNIEXPORT jint JNICALL 182 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, 183 jobject fdo, jlong size) 184 { 185 return handle(env, 186 ftruncate64(fdval(env, fdo), size), 187 "Truncation failed"); 188 } 189 190 JNIEXPORT jint JNICALL 191 Java_sun_nio_ch_FileDispatcherImpl_allocate0(JNIEnv *env, jobject this, 192 jobject fdo, jlong size) 193 { 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 // Return on success or if errno is neither EOPNOTSUPP nor ENOSYS 202 int result = fallocate64(fdval(env, fdo), 0, 0, size); 203 if (result == 0) { 204 return 0; 205 } else if (errno != EOPNOTSUPP && errno != ENOSYS) { 206 return handle(env, result, "Allocation failed"); 207 } 208 #endif 209 return handle(env, 210 ftruncate64(fdval(env, fdo), 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 } 327 328 JNIEXPORT jint JNICALL 329 Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass clazz, 330 jobject fdo) 331 { 332 jint fd = fdval(env, fdo); 333 jint result; 334 #ifdef MACOSX 335 struct statvfs file_stat; 336 #else 337 struct statvfs64 file_stat; 338 #endif 339 340 #if defined(O_DIRECT) || defined(F_NOCACHE) || defined(DIRECTIO_ON) 341 #ifdef O_DIRECT 342 jint orig_flag; 343 orig_flag = fcntl(fd, F_GETFL); 344 if (orig_flag == -1) { 345 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 346 return -1; 347 } 348 result = fcntl(fd, F_SETFL, orig_flag | O_DIRECT); 349 if (result == -1) { 350 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 351 return result; 352 } 353 #elif F_NOCACHE 354 result = fcntl(fd, F_NOCACHE, 1); 355 if (result == -1) { 356 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 357 return result; 358 } 359 #elif DIRECTIO_ON 360 result = directio(fd, DIRECTIO_ON); 361 if (result == -1) { 362 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 363 return result; 364 } 365 #endif 366 #ifdef MACOSX 367 result = fstatvfs(fd, &file_stat); 368 #else 369 result = fstatvfs64(fd, &file_stat); 370 #endif 371 if(result == -1) { 372 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 373 return result; 374 } else { 375 result = (int)file_stat.f_frsize; 376 } 377 #else 378 result == -1; 379 #endif 380 return result; 381 }