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