1 /*
2  * Copyright (c) 2000, 2019, 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 <string.h>
36 #include <sys/socket.h>
37 #elif defined(_ALLBSD_SOURCE)
38 #include <sys/socket.h>
39 #include <sys/uio.h>
40 #define lseek64 lseek
41 #define mmap64 mmap
42 #endif
43 
44 #include "jni.h"
45 #include "jni_util.h"
46 #include "jlong.h"
47 #include "nio.h"
48 #include "nio_util.h"
49 #include "sun_nio_ch_FileChannelImpl.h"
50 #include "java_lang_Integer.h"
51 #include <assert.h>
52 
53 static jfieldID chan_fd;        /* jobject 'fd' in sun.nio.ch.FileChannelImpl */
54 
55 JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv * env,jclass clazz)56 Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz)
57 {
58     jlong pageSize = sysconf(_SC_PAGESIZE);
59     chan_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;");
60     return pageSize;
61 }
62 
63 static jlong
handle(JNIEnv * env,jlong rv,char * msg)64 handle(JNIEnv *env, jlong rv, char *msg)
65 {
66     if (rv >= 0)
67         return rv;
68     if (errno == EINTR)
69         return IOS_INTERRUPTED;
70     JNU_ThrowIOExceptionWithLastError(env, msg);
71     return IOS_THROWN;
72 }
73 
74 
75 JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv * env,jobject this,jint prot,jlong off,jlong len,jboolean map_sync)76 Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this,
77                                      jint prot, jlong off, jlong len, jboolean map_sync)
78 {
79     void *mapAddress = 0;
80     jobject fdo = (*env)->GetObjectField(env, this, chan_fd);
81     jint fd = fdval(env, fdo);
82     int protections = 0;
83     int flags = 0;
84 
85     // should never be called with map_sync and prot == PRIVATE
86     assert((prot != sun_nio_ch_FileChannelImpl_MAP_PV) || !map_sync);
87 
88     if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) {
89         protections = PROT_READ;
90         flags = MAP_SHARED;
91     } else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) {
92         protections = PROT_WRITE | PROT_READ;
93         flags = MAP_SHARED;
94     } else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) {
95         protections =  PROT_WRITE | PROT_READ;
96         flags = MAP_PRIVATE;
97     }
98 
99     // if MAP_SYNC and MAP_SHARED_VALIDATE are not defined then it is
100     // best to define them here. This ensures the code compiles on old
101     // OS releases which do not provide the relevant headers. If run
102     // on the same machine then it will work if the kernel contains
103     // the necessary support otherwise mmap should fail with an
104     // invalid argument error
105 
106 #ifndef MAP_SYNC
107 #define MAP_SYNC 0x80000
108 #endif
109 #ifndef MAP_SHARED_VALIDATE
110 #define MAP_SHARED_VALIDATE 0x03
111 #endif
112 
113     if (map_sync) {
114         // ensure
115         //  1) this is Linux on AArch64 or x86_64
116         //  2) the mmap APIs are available/ at compile time
117 #if !defined(LINUX) || ! (defined(aarch64) || (defined(amd64) && defined(_LP64)))
118         // TODO - implement for solaris/AIX/BSD/WINDOWS and for 32 bit
119         JNU_ThrowInternalError(env, "should never call map on platform where MAP_SYNC is unimplemented");
120         return IOS_THROWN;
121 #else
122         flags |= MAP_SYNC | MAP_SHARED_VALIDATE;
123 #endif
124     }
125 
126     mapAddress = mmap64(
127         0,                    /* Let OS decide location */
128         len,                  /* Number of bytes to map */
129         protections,          /* File permissions */
130         flags,                /* Changes are shared */
131         fd,                   /* File descriptor of mapped file */
132         off);                 /* Offset into file */
133 
134     if (mapAddress == MAP_FAILED) {
135         if (map_sync && errno == ENOTSUP) {
136             JNU_ThrowIOExceptionWithLastError(env, "map with mode MAP_SYNC unsupported");
137             return IOS_THROWN;
138         }
139 
140         if (errno == ENOMEM) {
141             JNU_ThrowOutOfMemoryError(env, "Map failed");
142             return IOS_THROWN;
143         }
144         return handle(env, -1, "Map failed");
145     }
146 
147     return ((jlong) (unsigned long) mapAddress);
148 }
149 
150 
151 JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv * env,jobject this,jlong address,jlong len)152 Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this,
153                                        jlong address, jlong len)
154 {
155     void *a = (void *)jlong_to_ptr(address);
156     return handle(env,
157                   munmap(a, (size_t)len),
158                   "Unmap failed");
159 }
160 
161 JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv * env,jobject this,jobject srcFDO,jlong position,jlong count,jobject dstFDO)162 Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this,
163                                             jobject srcFDO,
164                                             jlong position, jlong count,
165                                             jobject dstFDO)
166 {
167     jint srcFD = fdval(env, srcFDO);
168     jint dstFD = fdval(env, dstFDO);
169 
170 #if defined(__linux__)
171     off64_t offset = (off64_t)position;
172     jlong n = sendfile64(dstFD, srcFD, &offset, (size_t)count);
173     if (n < 0) {
174         if (errno == EAGAIN)
175             return IOS_UNAVAILABLE;
176         if ((errno == EINVAL) && ((ssize_t)count >= 0))
177             return IOS_UNSUPPORTED_CASE;
178         if (errno == EINTR) {
179             return IOS_INTERRUPTED;
180         }
181         JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
182         return IOS_THROWN;
183     }
184     return n;
185 #elif defined (__solaris__)
186     sendfilevec64_t sfv;
187     size_t numBytes = 0;
188     jlong result;
189 
190     sfv.sfv_fd = srcFD;
191     sfv.sfv_flag = 0;
192     sfv.sfv_off = (off64_t)position;
193     sfv.sfv_len = count;
194 
195     result = sendfilev64(dstFD, &sfv, 1, &numBytes);
196 
197     /* Solaris sendfilev() will return -1 even if some bytes have been
198      * transferred, so we check numBytes first.
199      */
200     if (numBytes > 0)
201         return numBytes;
202     if (result < 0) {
203         if (errno == EAGAIN)
204             return IOS_UNAVAILABLE;
205         if (errno == EOPNOTSUPP)
206             return IOS_UNSUPPORTED_CASE;
207         if ((errno == EINVAL) && ((ssize_t)count >= 0))
208             return IOS_UNSUPPORTED_CASE;
209         if (errno == EINTR)
210             return IOS_INTERRUPTED;
211         JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
212         return IOS_THROWN;
213     }
214     return result;
215 #elif defined(__APPLE__)
216     off_t numBytes;
217     int result;
218 
219     numBytes = count;
220 
221     result = sendfile(srcFD, dstFD, position, &numBytes, NULL, 0);
222 
223     if (numBytes > 0)
224         return numBytes;
225 
226     if (result == -1) {
227         if (errno == EAGAIN)
228             return IOS_UNAVAILABLE;
229         if (errno == EOPNOTSUPP || errno == ENOTSOCK || errno == ENOTCONN)
230             return IOS_UNSUPPORTED_CASE;
231         if ((errno == EINVAL) && ((ssize_t)count >= 0))
232             return IOS_UNSUPPORTED_CASE;
233         if (errno == EINTR)
234             return IOS_INTERRUPTED;
235         JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
236         return IOS_THROWN;
237     }
238 
239     return result;
240 
241 #elif defined(_AIX)
242     jlong max = (jlong)java_lang_Integer_MAX_VALUE;
243     struct sf_parms sf_iobuf;
244     jlong result;
245 
246     if (position > max)
247         return IOS_UNSUPPORTED_CASE;
248 
249     if (count > max)
250         count = max;
251 
252     memset(&sf_iobuf, 0, sizeof(sf_iobuf));
253     sf_iobuf.file_descriptor = srcFD;
254     sf_iobuf.file_offset = (off_t)position;
255     sf_iobuf.file_bytes = count;
256 
257     result = send_file(&dstFD, &sf_iobuf, SF_SYNC_CACHE);
258 
259     /* AIX send_file() will return 0 when this operation complete successfully,
260      * return 1 when partial bytes transfered and return -1 when an error has
261      * Occured.
262      */
263     if (result == -1) {
264         if (errno == EWOULDBLOCK)
265             return IOS_UNAVAILABLE;
266         if ((errno == EINVAL) && ((ssize_t)count >= 0))
267             return IOS_UNSUPPORTED_CASE;
268         if (errno == EINTR)
269             return IOS_INTERRUPTED;
270         if (errno == ENOTSOCK)
271             return IOS_UNSUPPORTED;
272         JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
273         return IOS_THROWN;
274     }
275 
276     if (sf_iobuf.bytes_sent > 0)
277         return (jlong)sf_iobuf.bytes_sent;
278 
279     return IOS_UNSUPPORTED_CASE;
280 #else
281     return IOS_UNSUPPORTED_CASE;
282 #endif
283 }
284 
285