1 /* 2 * Copyright (c) 2000, 2018, 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 <sys/types.h> 27 #include <sys/socket.h> 28 #include <fcntl.h> 29 #include <sys/uio.h> 30 #include <unistd.h> 31 #include <sys/stat.h> 32 #include <sys/statvfs.h> 33 34 #if defined(__linux__) 35 #include <linux/fs.h> 36 #include <sys/ioctl.h> 37 #endif 38 39 #if defined(_ALLBSD_SOURCE) 40 #define lseek64 lseek 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 #define pread64 pread 47 #define pwrite64 pwrite 48 #define ftruncate64 ftruncate 49 #define fstat64 fstat 50 #define fdatasync fsync 51 #endif 52 53 #include "jni.h" 54 #include "jni_util.h" 55 #include "jvm.h" 56 #include "jlong.h" 57 #include "nio.h" 58 #include "nio_util.h" 59 #include "sun_nio_ch_FileDispatcherImpl.h" 60 #include "java_lang_Long.h" 61 62 static int preCloseFD = -1; /* File descriptor to which we dup other fd's 63 before closing them for real */ 64 65 66 JNIEXPORT void JNICALL 67 Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) 68 { 69 int sp[2]; 70 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { 71 JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); 72 return; 73 } 74 preCloseFD = sp[0]; 75 close(sp[1]); 76 } 77 78 JNIEXPORT jint JNICALL 79 Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, 80 jobject fdo, jlong address, jint len, jboolean socket) 81 { 82 jint fd = fdval(env, fdo); 83 void *buf = (void *)jlong_to_ptr(address); 84 85 jint readBytes = read(fd, buf, len); 86 87 if (readBytes > 0) { 88 if (socket) { 89 JVM_callNetworkReadBytes(env, (jint) readBytes); 90 } else { 91 JVM_callFileReadBytes(env, (jint)readBytes); 92 } 93 } 94 95 return convertReturnVal(env, readBytes, JNI_TRUE); 96 } 97 98 JNIEXPORT jint JNICALL 99 Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, 100 jlong address, jint len, jlong offset) 101 { 102 jint fd = fdval(env, fdo); 103 void *buf = (void *)jlong_to_ptr(address); 104 105 jint readBytes = pread64(fd, buf, len, offset); 106 107 if (readBytes > 0) { 108 JVM_callFileReadBytes(env, (jint)readBytes); 109 } 110 111 return convertReturnVal(env, readBytes, JNI_TRUE); 112 } 113 114 JNIEXPORT jlong JNICALL 115 Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, 116 jobject fdo, jlong address, jint len, jboolean socket) 117 { 118 jint fd = fdval(env, fdo); 119 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 120 jint readBytes = readv(fd, iov, len); 121 122 if (readBytes > 0) { 123 if (socket) { 124 JVM_callNetworkReadBytes(env, (jint) readBytes); 125 } else { 126 JVM_callFileReadBytes(env, (jint)readBytes); 127 } 128 } 129 130 return convertLongReturnVal(env, readBytes, JNI_TRUE); 131 } 132 133 JNIEXPORT jint JNICALL 134 Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, 135 jobject fdo, jlong address, jint len, jboolean socket) 136 { 137 jint fd = fdval(env, fdo); 138 void *buf = (void *)jlong_to_ptr(address); 139 jint writtenBytes = write(fd, buf, len); 140 141 if (writtenBytes > 0) { 142 if (socket) { 143 JVM_callNetworkWriteBytes(env, (jint) writtenBytes); 144 } else { 145 JVM_callFileWriteBytes(env, (jint) writtenBytes); 146 } 147 } 148 149 return convertReturnVal(env, writtenBytes, JNI_FALSE); 150 } 151 152 JNIEXPORT jint JNICALL 153 Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, 154 jlong address, jint len, jlong offset) 155 { 156 jint fd = fdval(env, fdo); 157 void *buf = (void *)jlong_to_ptr(address); 158 jint writtenBytes = pwrite64(fd, buf, len, offset); 159 160 if (writtenBytes > 0) { 161 JVM_callFileWriteBytes(env, (jint) writtenBytes); 162 } 163 164 return convertReturnVal(env, writtenBytes, JNI_FALSE); 165 } 166 167 JNIEXPORT jlong JNICALL 168 Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, 169 jobject fdo, jlong address, jint len, jboolean socket) 170 { 171 jint fd = fdval(env, fdo); 172 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 173 jint writtenBytes = writev(fd, iov, len); 174 175 if (writtenBytes > 0) { 176 if (socket) { 177 JVM_callNetworkWriteBytes(env, (jint) writtenBytes); 178 } else { 179 JVM_callFileWriteBytes(env, (jint) writtenBytes); 180 } 181 } 182 183 return convertLongReturnVal(env, writtenBytes, JNI_FALSE); 184 } 185 186 static jlong 187 handle(JNIEnv *env, jlong rv, char *msg) 188 { 189 if (rv >= 0) 190 return rv; 191 if (errno == EINTR) 192 return IOS_INTERRUPTED; 193 JNU_ThrowIOExceptionWithLastError(env, msg); 194 return IOS_THROWN; 195 } 196 197 JNIEXPORT jlong JNICALL 198 Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv *env, jclass clazz, 199 jobject fdo, jlong offset) 200 { 201 jint fd = fdval(env, fdo); 202 off64_t result; 203 if (offset < 0) { 204 result = lseek64(fd, 0, SEEK_CUR); 205 } else { 206 result = lseek64(fd, offset, SEEK_SET); 207 } 208 return handle(env, (jlong)result, "lseek64 failed"); 209 } 210 211 JNIEXPORT jint JNICALL 212 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, 213 jobject fdo, jboolean md) 214 { 215 jint fd = fdval(env, fdo); 216 int result = 0; 217 218 #ifdef MACOSX 219 result = fcntl(fd, F_FULLFSYNC); 220 if (result == -1 && errno == ENOTSUP) { 221 /* Try fsync() in case F_FULLSYUNC is not implemented on the file system. */ 222 result = fsync(fd); 223 } 224 #else /* end MACOSX, begin not-MACOSX */ 225 if (md == JNI_FALSE) { 226 result = fdatasync(fd); 227 } else { 228 #ifdef _AIX 229 /* On AIX, calling fsync on a file descriptor that is opened only for 230 * reading results in an error ("EBADF: The FileDescriptor parameter is 231 * not a valid file descriptor open for writing."). 232 * However, at this point it is not possibly anymore to read the 233 * 'writable' attribute of the corresponding file channel so we have to 234 * use 'fcntl'. 235 */ 236 int getfl = fcntl(fd, F_GETFL); 237 if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) { 238 return 0; 239 } 240 #endif /* _AIX */ 241 result = fsync(fd); 242 } 243 #endif /* not-MACOSX */ 244 return handle(env, result, "Force failed"); 245 } 246 247 JNIEXPORT jint JNICALL 248 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, 249 jobject fdo, jlong size) 250 { 251 return handle(env, 252 ftruncate64(fdval(env, fdo), size), 253 "Truncation failed"); 254 } 255 256 JNIEXPORT jlong JNICALL 257 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) 258 { 259 jint fd = fdval(env, fdo); 260 struct stat64 fbuf; 261 262 if (fstat64(fd, &fbuf) < 0) 263 return handle(env, -1, "Size failed"); 264 265 #ifdef BLKGETSIZE64 266 if (S_ISBLK(fbuf.st_mode)) { 267 uint64_t size; 268 if (ioctl(fd, BLKGETSIZE64, &size) < 0) 269 return handle(env, -1, "Size failed"); 270 return (jlong)size; 271 } 272 #endif 273 274 return fbuf.st_size; 275 } 276 277 JNIEXPORT jint JNICALL 278 Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, 279 jboolean block, jlong pos, jlong size, 280 jboolean shared) 281 { 282 jint fd = fdval(env, fdo); 283 jint lockResult = 0; 284 int cmd = 0; 285 struct flock64 fl; 286 287 fl.l_whence = SEEK_SET; 288 if (size == (jlong)java_lang_Long_MAX_VALUE) { 289 fl.l_len = (off64_t)0; 290 } else { 291 fl.l_len = (off64_t)size; 292 } 293 fl.l_start = (off64_t)pos; 294 if (shared == JNI_TRUE) { 295 fl.l_type = F_RDLCK; 296 } else { 297 fl.l_type = F_WRLCK; 298 } 299 if (block == JNI_TRUE) { 300 cmd = F_SETLKW64; 301 } else { 302 cmd = F_SETLK64; 303 } 304 lockResult = fcntl(fd, cmd, &fl); 305 if (lockResult < 0) { 306 if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES)) 307 return sun_nio_ch_FileDispatcherImpl_NO_LOCK; 308 if (errno == EINTR) 309 return sun_nio_ch_FileDispatcherImpl_INTERRUPTED; 310 JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); 311 } 312 return 0; 313 } 314 315 JNIEXPORT void JNICALL 316 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, 317 jobject fdo, jlong pos, jlong size) 318 { 319 jint fd = fdval(env, fdo); 320 jint lockResult = 0; 321 struct flock64 fl; 322 int cmd = F_SETLK64; 323 324 fl.l_whence = SEEK_SET; 325 if (size == (jlong)java_lang_Long_MAX_VALUE) { 326 fl.l_len = (off64_t)0; 327 } else { 328 fl.l_len = (off64_t)size; 329 } 330 fl.l_start = (off64_t)pos; 331 fl.l_type = F_UNLCK; 332 lockResult = fcntl(fd, cmd, &fl); 333 if (lockResult < 0) { 334 JNU_ThrowIOExceptionWithLastError(env, "Release failed"); 335 } 336 } 337 338 339 static void closeFileDescriptor(JNIEnv *env, int fd) { 340 if (fd != -1) { 341 int result = close(fd); 342 if (result < 0) 343 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 344 } 345 } 346 347 JNIEXPORT void JNICALL 348 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) 349 { 350 jint fd = fdval(env, fdo); 351 closeFileDescriptor(env, fd); 352 } 353 354 JNIEXPORT void JNICALL 355 Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo) 356 { 357 jint fd = fdval(env, fdo); 358 if (preCloseFD >= 0) { 359 if (dup2(preCloseFD, fd) < 0) 360 JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); 361 } 362 } 363 364 JNIEXPORT void JNICALL 365 Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd) 366 { 367 closeFileDescriptor(env, fd); 368 } 369 370 JNIEXPORT jint JNICALL 371 Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass clazz, 372 jobject fdo) 373 { 374 jint fd = fdval(env, fdo); 375 jint result; 376 #ifdef MACOSX 377 struct statvfs file_stat; 378 #else 379 struct statvfs64 file_stat; 380 #endif 381 382 #if defined(O_DIRECT) || defined(F_NOCACHE) || defined(DIRECTIO_ON) 383 #ifdef O_DIRECT 384 jint orig_flag; 385 orig_flag = fcntl(fd, F_GETFL); 386 if (orig_flag == -1) { 387 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 388 return -1; 389 } 390 result = fcntl(fd, F_SETFL, orig_flag | O_DIRECT); 391 if (result == -1) { 392 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 393 return result; 394 } 395 #elif F_NOCACHE 396 result = fcntl(fd, F_NOCACHE, 1); 397 if (result == -1) { 398 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 399 return result; 400 } 401 #elif DIRECTIO_ON 402 result = directio(fd, DIRECTIO_ON); 403 if (result == -1) { 404 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 405 return result; 406 } 407 #endif 408 #ifdef MACOSX 409 result = fstatvfs(fd, &file_stat); 410 #else 411 result = fstatvfs64(fd, &file_stat); 412 #endif 413 if(result == -1) { 414 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 415 return result; 416 } else { 417 result = (int)file_stat.f_frsize; 418 } 419 #else 420 result == -1; 421 #endif 422 return result; 423 }