1 /*
   2  * Copyright (c) 2000, 2009, 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 "nio.h"
  37 #include "nio_util.h"
  38 
  39 
  40 static int preCloseFD = -1;     /* File descriptor to which we dup other fd's
  41                                    before closing them for real */
  42 
  43 
  44 JNIEXPORT void JNICALL
  45 Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl)
  46 {
  47     int sp[2];
  48     if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
  49         JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
  50         return;
  51     }
  52     preCloseFD = sp[0];
  53     close(sp[1]);
  54 }
  55 
  56 JNIEXPORT jint JNICALL
  57 Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz,
  58                              jobject fdo, jlong address, jint len)
  59 {
  60     jint fd = fdval(env, fdo);
  61     void *buf = (void *)jlong_to_ptr(address);
  62 
  63     return convertReturnVal(env, read(fd, buf, len), JNI_TRUE);
  64 }
  65 
  66 JNIEXPORT jint JNICALL
  67 Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo,
  68                             jlong address, jint len, jlong offset)
  69 {
  70     jint fd = fdval(env, fdo);
  71     void *buf = (void *)jlong_to_ptr(address);
  72 
  73     return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE);
  74 }
  75 
  76 JNIEXPORT jlong JNICALL
  77 Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz,
  78                               jobject fdo, jlong address, jint len)
  79 {
  80     jint fd = fdval(env, fdo);
  81     struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
  82     if (len > 16) {
  83         len = 16;
  84     }
  85     return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE);
  86 }
  87 
  88 JNIEXPORT jint JNICALL
  89 Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz,
  90                               jobject fdo, jlong address, jint len)
  91 {
  92     jint fd = fdval(env, fdo);
  93     void *buf = (void *)jlong_to_ptr(address);
  94 
  95     return convertReturnVal(env, write(fd, buf, len), JNI_FALSE);
  96 }
  97 
  98 JNIEXPORT jint JNICALL
  99 Java_sun_nio_ch_FileDispatcherImpl_pwrite0(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     return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE);
 106 }
 107 
 108 JNIEXPORT jlong JNICALL
 109 Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz,
 110                                        jobject fdo, jlong address, jint len)
 111 {
 112     jint fd = fdval(env, fdo);
 113     struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
 114     if (len > 16) {
 115         len = 16;
 116     }
 117     return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE);
 118 }
 119 
 120 static jlong
 121 handle(JNIEnv *env, jlong rv, char *msg)
 122 {
 123     if (rv >= 0)
 124         return rv;
 125     if (errno == EINTR)
 126         return IOS_INTERRUPTED;
 127     JNU_ThrowIOExceptionWithLastError(env, msg);
 128     return IOS_THROWN;
 129 }
 130 
 131 JNIEXPORT jint JNICALL
 132 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
 133                                           jobject fdo, jboolean md)
 134 {
 135     jint fd = fdval(env, fdo);
 136     int result = 0;
 137 
 138     if (md == JNI_FALSE) {
 139         result = fdatasync(fd);
 140     } else {
 141         result = fsync(fd);
 142     }
 143     return handle(env, result, "Force failed");
 144 }
 145 
 146 JNIEXPORT jint JNICALL
 147 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
 148                                              jobject fdo, jlong size)
 149 {
 150     return handle(env,
 151                   ftruncate64(fdval(env, fdo), size),
 152                   "Truncation failed");
 153 }
 154 
 155 JNIEXPORT jlong JNICALL
 156 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
 157 {
 158     struct stat64 fbuf;
 159 
 160     if (fstat64(fdval(env, fdo), &fbuf) < 0)
 161         return handle(env, -1, "Size failed");
 162     return fbuf.st_size;
 163 }
 164 
 165 JNIEXPORT jint JNICALL
 166 Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
 167                                       jboolean block, jlong pos, jlong size,
 168                                       jboolean shared)
 169 {
 170     jint fd = fdval(env, fdo);
 171     jint lockResult = 0;
 172     int cmd = 0;
 173     struct flock64 fl;
 174 
 175     fl.l_whence = SEEK_SET;
 176     if (size == (jlong)java_lang_Long_MAX_VALUE) {
 177         fl.l_len = (off64_t)0;
 178     } else {
 179         fl.l_len = (off64_t)size;
 180     }
 181     fl.l_start = (off64_t)pos;
 182     if (shared == JNI_TRUE) {
 183         fl.l_type = F_RDLCK;
 184     } else {
 185         fl.l_type = F_WRLCK;
 186     }
 187     if (block == JNI_TRUE) {
 188         cmd = F_SETLKW64;
 189     } else {
 190         cmd = F_SETLK64;
 191     }
 192     lockResult = fcntl(fd, cmd, &fl);
 193     if (lockResult < 0) {
 194         if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES))
 195             return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 196         if (errno == EINTR)
 197             return sun_nio_ch_FileDispatcherImpl_INTERRUPTED;
 198         JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
 199     }
 200     return 0;
 201 }
 202 
 203 JNIEXPORT void JNICALL
 204 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this,
 205                                          jobject fdo, jlong pos, jlong size)
 206 {
 207     jint fd = fdval(env, fdo);
 208     jint lockResult = 0;
 209     struct flock64 fl;
 210     int cmd = F_SETLK64;
 211 
 212     fl.l_whence = SEEK_SET;
 213     if (size == (jlong)java_lang_Long_MAX_VALUE) {
 214         fl.l_len = (off64_t)0;
 215     } else {
 216         fl.l_len = (off64_t)size;
 217     }
 218     fl.l_start = (off64_t)pos;
 219     fl.l_type = F_UNLCK;
 220     lockResult = fcntl(fd, cmd, &fl);
 221     if (lockResult < 0) {
 222         JNU_ThrowIOExceptionWithLastError(env, "Release failed");
 223     }
 224 }
 225 
 226 
 227 static void closeFileDescriptor(JNIEnv *env, int fd) {
 228     if (fd != -1) {
 229         int result = close(fd);
 230         if (result < 0)
 231             JNU_ThrowIOExceptionWithLastError(env, "Close failed");
 232     }
 233 }
 234 
 235 JNIEXPORT void JNICALL
 236 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo)
 237 {
 238     jint fd = fdval(env, fdo);
 239     closeFileDescriptor(env, fd);
 240 }
 241 
 242 JNIEXPORT void JNICALL
 243 Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo)
 244 {
 245     jint fd = fdval(env, fdo);
 246     if (preCloseFD >= 0) {
 247         if (dup2(preCloseFD, fd) < 0)
 248             JNU_ThrowIOExceptionWithLastError(env, "dup2 failed");
 249     }
 250 }
 251 
 252 JNIEXPORT void JNICALL
 253 Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd)
 254 {
 255     closeFileDescriptor(env, fd);
 256 }