1/*
2 * Copyright (c) 2000, 2017, 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 <io.h>
31#include "nio.h"
32#include "nio_util.h"
33#include "sun_nio_ch_FileChannelImpl.h"
34#include "java_lang_Integer.h"
35
36#include <Mswsock.h>
37#pragma comment(lib, "Mswsock.lib")
38
39static jfieldID chan_fd; /* id for jobject 'fd' in java.io.FileChannel */
40
41/**************************************************************
42 * static method to store field ID's in initializers
43 * and retrieve the allocation granularity
44 */
45JNIEXPORT jlong JNICALL
46Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz)
47{
48    SYSTEM_INFO si;
49    jint align;
50    GetSystemInfo(&si);
51    align = si.dwAllocationGranularity;
52    chan_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;");
53    return align;
54}
55
56
57/**************************************************************
58 * Channel
59 */
60
61JNIEXPORT jlong JNICALL
62Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this,
63                               jint prot, jlong off, jlong len)
64{
65    void *mapAddress = 0;
66    jint lowOffset = (jint)off;
67    jint highOffset = (jint)(off >> 32);
68    jlong maxSize = off + len;
69    jint lowLen = (jint)(maxSize);
70    jint highLen = (jint)(maxSize >> 32);
71    jobject fdo = (*env)->GetObjectField(env, this, chan_fd);
72    HANDLE fileHandle = (HANDLE)(handleval(env, fdo));
73    HANDLE mapping;
74    DWORD mapAccess = FILE_MAP_READ;
75    DWORD fileProtect = PAGE_READONLY;
76    DWORD mapError;
77    BOOL result;
78
79    if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) {
80        fileProtect = PAGE_READONLY;
81        mapAccess = FILE_MAP_READ;
82    } else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) {
83        fileProtect = PAGE_READWRITE;
84        mapAccess = FILE_MAP_WRITE;
85    } else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) {
86        fileProtect = PAGE_WRITECOPY;
87        mapAccess = FILE_MAP_COPY;
88    }
89
90    mapping = CreateFileMapping(
91        fileHandle,      /* Handle of file */
92        NULL,            /* Not inheritable */
93        fileProtect,     /* Read and write */
94        highLen,         /* High word of max size */
95        lowLen,          /* Low word of max size */
96        NULL);           /* No name for object */
97
98    if (mapping == NULL) {
99        JNU_ThrowIOExceptionWithLastError(env, "Map failed");
100        return IOS_THROWN;
101    }
102
103    mapAddress = MapViewOfFile(
104        mapping,             /* Handle of file mapping object */
105        mapAccess,           /* Read and write access */
106        highOffset,          /* High word of offset */
107        lowOffset,           /* Low word of offset */
108        (DWORD)len);         /* Number of bytes to map */
109    mapError = GetLastError();
110
111    result = CloseHandle(mapping);
112    if (result == 0) {
113        JNU_ThrowIOExceptionWithLastError(env, "Map failed");
114        return IOS_THROWN;
115    }
116
117    if (mapAddress == NULL) {
118        if (mapError == ERROR_NOT_ENOUGH_MEMORY)
119            JNU_ThrowOutOfMemoryError(env, "Map failed");
120        else
121            JNU_ThrowIOExceptionWithLastError(env, "Map failed");
122        return IOS_THROWN;
123    }
124
125    return ptr_to_jlong(mapAddress);
126}
127
128JNIEXPORT jint JNICALL
129Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this,
130                                 jlong address, jlong len)
131{
132    BOOL result;
133    void *a = (void *) jlong_to_ptr(address);
134
135    result = UnmapViewOfFile(a);
136    if (result == 0) {
137        JNU_ThrowIOExceptionWithLastError(env, "Unmap failed");
138        return IOS_THROWN;
139    }
140    return 0;
141}
142
143JNIEXPORT jlong JNICALL
144Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this,
145                                          jobject fdo, jlong offset)
146{
147    BOOL result = 0;
148    HANDLE h = (HANDLE)(handleval(env, fdo));
149    LARGE_INTEGER where;
150    DWORD whence;
151
152    if (offset < 0) {
153        where.QuadPart = 0;
154        whence = FILE_CURRENT;
155    } else {
156        where.QuadPart = offset;
157        whence = FILE_BEGIN;
158    }
159
160    result = SetFilePointerEx(h, where, &where, whence);
161    if (result == 0) {
162        JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
163        return IOS_THROWN;
164    }
165    return (jlong)where.QuadPart;
166}
167
168JNIEXPORT jlong JNICALL
169Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this,
170                                            jobject srcFD,
171                                            jlong position, jlong count,
172                                            jobject dstFD)
173{
174    const int PACKET_SIZE = 524288;
175
176    HANDLE src = (HANDLE)(handleval(env, srcFD));
177    SOCKET dst = (SOCKET)(fdval(env, dstFD));
178    DWORD chunkSize = (count > java_lang_Integer_MAX_VALUE) ?
179        java_lang_Integer_MAX_VALUE : (DWORD)count;
180    BOOL result = 0;
181
182    jlong pos = Java_sun_nio_ch_FileChannelImpl_position0(env, this, srcFD, position);
183    if (pos == IOS_THROWN) {
184        return IOS_THROWN;
185    }
186
187    result = TransmitFile(
188        dst,
189        src,
190        chunkSize,
191        PACKET_SIZE,
192        NULL,
193        NULL,
194        TF_USE_KERNEL_APC
195    );
196    if (!result) {
197        int error = WSAGetLastError();
198        if (WSAEINVAL == error && count >= 0) {
199            return IOS_UNSUPPORTED_CASE;
200        }
201        if (WSAENOTSOCK == error) {
202            return IOS_UNSUPPORTED_CASE;
203        }
204        JNU_ThrowIOExceptionWithLastError(env, "transfer failed");
205        return IOS_THROWN;
206    }
207    return chunkSize;
208}
209