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