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 | #include <sys/mman.h> |
27 | #include <sys/stat.h> |
28 | #include <fcntl.h> |
29 | #include <sys/types.h> |
30 | #include <unistd.h> |
31 | |
32 | #if defined(__linux__) || defined(__solaris__) |
33 | #include <sys/sendfile.h> |
34 | #elif defined(_AIX) |
35 | #include <sys/socket.h> |
36 | #elif defined(_ALLBSD_SOURCE) |
37 | #include <sys/socket.h> |
38 | #include <sys/uio.h> |
39 | #define lseek64 lseek |
40 | #define mmap64 mmap |
41 | #endif |
42 | |
43 | #include "jni.h" |
44 | #include "jni_util.h" |
45 | #include "jlong.h" |
46 | #include "nio.h" |
47 | #include "nio_util.h" |
48 | #include "sun_nio_ch_FileChannelImpl.h" |
49 | #include "java_lang_Integer.h" |
50 | |
51 | static jfieldID chan_fd; /* jobject 'fd' in sun.nio.ch.FileChannelImpl */ |
52 | |
53 | JNIEXPORT jlong JNICALL |
54 | Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz) |
55 | { |
56 | jlong pageSize = sysconf(_SC_PAGESIZE); |
57 | chan_fd = (*env)->GetFieldID(env, clazz, "fd" , "Ljava/io/FileDescriptor;" ); |
58 | return pageSize; |
59 | } |
60 | |
61 | static jlong |
62 | handle(JNIEnv *env, jlong rv, char *msg) |
63 | { |
64 | if (rv >= 0) |
65 | return rv; |
66 | if (errno == EINTR) |
67 | return IOS_INTERRUPTED; |
68 | JNU_ThrowIOExceptionWithLastError(env, msg); |
69 | return IOS_THROWN; |
70 | } |
71 | |
72 | |
73 | JNIEXPORT jlong JNICALL |
74 | Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this, |
75 | jint prot, jlong off, jlong len) |
76 | { |
77 | void *mapAddress = 0; |
78 | jobject fdo = (*env)->GetObjectField(env, this, chan_fd); |
79 | jint fd = fdval(env, fdo); |
80 | int protections = 0; |
81 | int flags = 0; |
82 | |
83 | if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) { |
84 | protections = PROT_READ; |
85 | flags = MAP_SHARED; |
86 | } else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) { |
87 | protections = PROT_WRITE | PROT_READ; |
88 | flags = MAP_SHARED; |
89 | } else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) { |
90 | protections = PROT_WRITE | PROT_READ; |
91 | flags = MAP_PRIVATE; |
92 | } |
93 | |
94 | mapAddress = mmap64( |
95 | 0, /* Let OS decide location */ |
96 | len, /* Number of bytes to map */ |
97 | protections, /* File permissions */ |
98 | flags, /* Changes are shared */ |
99 | fd, /* File descriptor of mapped file */ |
100 | off); /* Offset into file */ |
101 | |
102 | if (mapAddress == MAP_FAILED) { |
103 | if (errno == ENOMEM) { |
104 | JNU_ThrowOutOfMemoryError(env, "Map failed" ); |
105 | return IOS_THROWN; |
106 | } |
107 | return handle(env, -1, "Map failed" ); |
108 | } |
109 | |
110 | return ((jlong) (unsigned long) mapAddress); |
111 | } |
112 | |
113 | |
114 | JNIEXPORT jint JNICALL |
115 | Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this, |
116 | jlong address, jlong len) |
117 | { |
118 | void *a = (void *)jlong_to_ptr(address); |
119 | return handle(env, |
120 | munmap(a, (size_t)len), |
121 | "Unmap failed" ); |
122 | } |
123 | |
124 | JNIEXPORT jlong JNICALL |
125 | Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, |
126 | jobject srcFDO, |
127 | jlong position, jlong count, |
128 | jobject dstFDO) |
129 | { |
130 | jint srcFD = fdval(env, srcFDO); |
131 | jint dstFD = fdval(env, dstFDO); |
132 | |
133 | #if defined(__linux__) |
134 | off64_t offset = (off64_t)position; |
135 | jlong n = sendfile64(dstFD, srcFD, &offset, (size_t)count); |
136 | if (n < 0) { |
137 | if (errno == EAGAIN) |
138 | return IOS_UNAVAILABLE; |
139 | if ((errno == EINVAL) && ((ssize_t)count >= 0)) |
140 | return IOS_UNSUPPORTED_CASE; |
141 | if (errno == EINTR) { |
142 | return IOS_INTERRUPTED; |
143 | } |
144 | JNU_ThrowIOExceptionWithLastError(env, "Transfer failed" ); |
145 | return IOS_THROWN; |
146 | } |
147 | return n; |
148 | #elif defined (__solaris__) |
149 | sendfilevec64_t sfv; |
150 | size_t numBytes = 0; |
151 | jlong result; |
152 | |
153 | sfv.sfv_fd = srcFD; |
154 | sfv.sfv_flag = 0; |
155 | sfv.sfv_off = (off64_t)position; |
156 | sfv.sfv_len = count; |
157 | |
158 | result = sendfilev64(dstFD, &sfv, 1, &numBytes); |
159 | |
160 | /* Solaris sendfilev() will return -1 even if some bytes have been |
161 | * transferred, so we check numBytes first. |
162 | */ |
163 | if (numBytes > 0) |
164 | return numBytes; |
165 | if (result < 0) { |
166 | if (errno == EAGAIN) |
167 | return IOS_UNAVAILABLE; |
168 | if (errno == EOPNOTSUPP) |
169 | return IOS_UNSUPPORTED_CASE; |
170 | if ((errno == EINVAL) && ((ssize_t)count >= 0)) |
171 | return IOS_UNSUPPORTED_CASE; |
172 | if (errno == EINTR) |
173 | return IOS_INTERRUPTED; |
174 | JNU_ThrowIOExceptionWithLastError(env, "Transfer failed" ); |
175 | return IOS_THROWN; |
176 | } |
177 | return result; |
178 | #elif defined(__APPLE__) |
179 | off_t numBytes; |
180 | int result; |
181 | |
182 | numBytes = count; |
183 | |
184 | result = sendfile(srcFD, dstFD, position, &numBytes, NULL, 0); |
185 | |
186 | if (numBytes > 0) |
187 | return numBytes; |
188 | |
189 | if (result == -1) { |
190 | if (errno == EAGAIN) |
191 | return IOS_UNAVAILABLE; |
192 | if (errno == EOPNOTSUPP || errno == ENOTSOCK || errno == ENOTCONN) |
193 | return IOS_UNSUPPORTED_CASE; |
194 | if ((errno == EINVAL) && ((ssize_t)count >= 0)) |
195 | return IOS_UNSUPPORTED_CASE; |
196 | if (errno == EINTR) |
197 | return IOS_INTERRUPTED; |
198 | JNU_ThrowIOExceptionWithLastError(env, "Transfer failed" ); |
199 | return IOS_THROWN; |
200 | } |
201 | |
202 | return result; |
203 | |
204 | #elif defined(_AIX) |
205 | jlong max = (jlong)java_lang_Integer_MAX_VALUE; |
206 | struct sf_parms sf_iobuf; |
207 | jlong result; |
208 | |
209 | if (position > max) |
210 | return IOS_UNSUPPORTED_CASE; |
211 | |
212 | if (count > max) |
213 | count = max; |
214 | |
215 | memset(&sf_iobuf, 0, sizeof(sf_iobuf)); |
216 | sf_iobuf.file_descriptor = srcFD; |
217 | sf_iobuf.file_offset = (off_t)position; |
218 | sf_iobuf.file_bytes = count; |
219 | |
220 | result = send_file(&dstFD, &sf_iobuf, SF_SYNC_CACHE); |
221 | |
222 | /* AIX send_file() will return 0 when this operation complete successfully, |
223 | * return 1 when partial bytes transfered and return -1 when an error has |
224 | * Occured. |
225 | */ |
226 | if (result == -1) { |
227 | if (errno == EWOULDBLOCK) |
228 | return IOS_UNAVAILABLE; |
229 | if ((errno == EINVAL) && ((ssize_t)count >= 0)) |
230 | return IOS_UNSUPPORTED_CASE; |
231 | if (errno == EINTR) |
232 | return IOS_INTERRUPTED; |
233 | if (errno == ENOTSOCK) |
234 | return IOS_UNSUPPORTED; |
235 | JNU_ThrowIOExceptionWithLastError(env, "Transfer failed" ); |
236 | return IOS_THROWN; |
237 | } |
238 | |
239 | if (sf_iobuf.bytes_sent > 0) |
240 | return (jlong)sf_iobuf.bytes_sent; |
241 | |
242 | return IOS_UNSUPPORTED_CASE; |
243 | #else |
244 | return IOS_UNSUPPORTED_CASE; |
245 | #endif |
246 | } |
247 | |
248 | |