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) 81 { 82 jint fd = fdval(env, fdo); 83 void *buf = (void *)jlong_to_ptr(address); 84 85 return convertReturnVal(env, read(fd, buf, len), JNI_TRUE); 86 } 87 88 JNIEXPORT jint JNICALL 89 Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, 90 jlong address, jint len, jlong offset) 91 { 92 jint fd = fdval(env, fdo); 93 void *buf = (void *)jlong_to_ptr(address); 94 95 return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE); 96 } 97 98 JNIEXPORT jlong JNICALL 99 Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, 100 jobject fdo, jlong address, jint len) 101 { 102 jint fd = fdval(env, fdo); 103 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 104 return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE); 105 } 106 107 JNIEXPORT jint JNICALL 108 Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, 109 jobject fdo, jlong address, jint len) 110 { 111 jint fd = fdval(env, fdo); 112 void *buf = (void *)jlong_to_ptr(address); 113 114 return convertReturnVal(env, write(fd, buf, len), JNI_FALSE); 115 } 116 117 JNIEXPORT jint JNICALL 118 Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, 119 jlong address, jint len, jlong offset) 120 { 121 jint fd = fdval(env, fdo); 122 void *buf = (void *)jlong_to_ptr(address); 123 124 return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE); 125 } 126 127 JNIEXPORT jlong JNICALL 128 Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, 129 jobject fdo, jlong address, jint len) 130 { 131 jint fd = fdval(env, fdo); 132 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 133 return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE); 134 } 135 136 static jlong 137 handle(JNIEnv *env, jlong rv, char *msg) 138 { 139 if (rv >= 0) 140 return rv; 141 if (errno == EINTR) 142 return IOS_INTERRUPTED; 143 JNU_ThrowIOExceptionWithLastError(env, msg); 144 return IOS_THROWN; 145 } 146 147 JNIEXPORT jlong JNICALL 148 Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv *env, jclass clazz, 149 jobject fdo, jlong offset) 150 { 151 jint fd = fdval(env, fdo); 152 off64_t result; 153 if (offset < 0) { 154 result = lseek64(fd, 0, SEEK_CUR); 155 } else { 156 result = lseek64(fd, offset, SEEK_SET); 157 } 158 return handle(env, (jlong)result, "lseek64 failed"); 159 } 160 161 JNIEXPORT jint JNICALL 162 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, 163 jobject fdo, jboolean md) 164 { 165 jint fd = fdval(env, fdo); 166 int result = 0; 167 168 #ifdef MACOSX 169 result = fcntl(fd, F_FULLFSYNC); 170 if (result == -1 && errno == ENOTSUP) { 171 /* Try fsync() in case F_FULLSYUNC is not implemented on the file system. */ 172 result = fsync(fd); 173 } 174 #else /* end MACOSX, begin not-MACOSX */ 175 if (md == JNI_FALSE) { 176 result = fdatasync(fd); 177 } else { 178 #ifdef _AIX 179 /* On AIX, calling fsync on a file descriptor that is opened only for 180 * reading results in an error ("EBADF: The FileDescriptor parameter is 181 * not a valid file descriptor open for writing."). 182 * However, at this point it is not possibly anymore to read the 183 * 'writable' attribute of the corresponding file channel so we have to 184 * use 'fcntl'. 185 */ 186 int getfl = fcntl(fd, F_GETFL); 187 if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) { 188 return 0; 189 } 190 #endif /* _AIX */ 191 result = fsync(fd); 192 } 193 #endif /* not-MACOSX */ 194 return handle(env, result, "Force failed"); 195 } 196 197 JNIEXPORT jint JNICALL 198 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, 199 jobject fdo, jlong size) 200 { 201 return handle(env, 202 ftruncate64(fdval(env, fdo), size), 203 "Truncation failed"); 204 } 205 206 JNIEXPORT jlong JNICALL 207 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) 208 { 209 jint fd = fdval(env, fdo); 210 struct stat64 fbuf; 211 212 if (fstat64(fd, &fbuf) < 0) 213 return handle(env, -1, "Size failed"); 214 215 #ifdef BLKGETSIZE64 216 if (S_ISBLK(fbuf.st_mode)) { 217 uint64_t size; 218 if (ioctl(fd, BLKGETSIZE64, &size) < 0) 219 return handle(env, -1, "Size failed"); 220 return (jlong)size; 221 } 222 #endif 223 224 return fbuf.st_size; 225 } 226 227 JNIEXPORT jint JNICALL 228 Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, 229 jboolean block, jlong pos, jlong size, 230 jboolean shared) 231 { 232 jint fd = fdval(env, fdo); 233 jint lockResult = 0; 234 int cmd = 0; 235 struct flock64 fl; 236 237 fl.l_whence = SEEK_SET; 238 if (size == (jlong)java_lang_Long_MAX_VALUE) { 239 fl.l_len = (off64_t)0; 240 } else { 241 fl.l_len = (off64_t)size; 242 } 243 fl.l_start = (off64_t)pos; 244 if (shared == JNI_TRUE) { 245 fl.l_type = F_RDLCK; 246 } else { 247 fl.l_type = F_WRLCK; 248 } 249 if (block == JNI_TRUE) { 250 cmd = F_SETLKW64; 251 } else { 252 cmd = F_SETLK64; 253 } 254 lockResult = fcntl(fd, cmd, &fl); 255 if (lockResult < 0) { 256 if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES)) 257 return sun_nio_ch_FileDispatcherImpl_NO_LOCK; 258 if (errno == EINTR) 259 return sun_nio_ch_FileDispatcherImpl_INTERRUPTED; 260 JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); 261 } 262 return 0; 263 } 264 265 JNIEXPORT void JNICALL 266 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, 267 jobject fdo, jlong pos, jlong size) 268 { 269 jint fd = fdval(env, fdo); 270 jint lockResult = 0; 271 struct flock64 fl; 272 int cmd = F_SETLK64; 273 274 fl.l_whence = SEEK_SET; 275 if (size == (jlong)java_lang_Long_MAX_VALUE) { 276 fl.l_len = (off64_t)0; 277 } else { 278 fl.l_len = (off64_t)size; 279 } 280 fl.l_start = (off64_t)pos; 281 fl.l_type = F_UNLCK; 282 lockResult = fcntl(fd, cmd, &fl); 283 if (lockResult < 0) { 284 JNU_ThrowIOExceptionWithLastError(env, "Release failed"); 285 } 286 } 287 288 289 static void closeFileDescriptor(JNIEnv *env, int fd) { 290 if (fd != -1) { 291 int result = close(fd); 292 if (result < 0) 293 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 294 } 295 } 296 297 JNIEXPORT void JNICALL 298 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) 299 { 300 jint fd = fdval(env, fdo); 301 closeFileDescriptor(env, fd); 302 } 303 304 JNIEXPORT void JNICALL 305 Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo) 306 { 307 jint fd = fdval(env, fdo); 308 if (preCloseFD >= 0) { 309 if (dup2(preCloseFD, fd) < 0) 310 JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); 311 } 312 } 313 314 JNIEXPORT void JNICALL 315 Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd) 316 { 317 closeFileDescriptor(env, fd); 318 } 319 320 JNIEXPORT jint JNICALL 321 Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass clazz, 322 jobject fdo) 323 { 324 jint fd = fdval(env, fdo); 325 jint result; 326 #ifdef MACOSX 327 struct statvfs file_stat; 328 #else 329 struct statvfs64 file_stat; 330 #endif 331 332 #if defined(O_DIRECT) || defined(F_NOCACHE) || defined(DIRECTIO_ON) 333 #ifdef O_DIRECT 334 jint orig_flag; 335 orig_flag = fcntl(fd, F_GETFL); 336 if (orig_flag == -1) { 337 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 338 return -1; 339 } 340 result = fcntl(fd, F_SETFL, orig_flag | O_DIRECT); 341 if (result == -1) { 342 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 343 return result; 344 } 345 #elif F_NOCACHE 346 result = fcntl(fd, F_NOCACHE, 1); 347 if (result == -1) { 348 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 349 return result; 350 } 351 #elif DIRECTIO_ON 352 result = directio(fd, DIRECTIO_ON); 353 if (result == -1) { 354 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 355 return result; 356 } 357 #endif 358 #ifdef MACOSX 359 result = fstatvfs(fd, &file_stat); 360 #else 361 result = fstatvfs64(fd, &file_stat); 362 #endif 363 if(result == -1) { 364 JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); 365 return result; 366 } else { 367 result = (int)file_stat.f_frsize; 368 } 369 #else 370 result == -1; 371 #endif 372 return result; 373 }