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