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