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 
  39 static 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  */
  45 JNIEXPORT jlong JNICALL
  46 Java_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 
  61 JNIEXPORT jlong JNICALL
  62 Java_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 
 128 JNIEXPORT jint JNICALL
 129 Java_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 
 143 JNIEXPORT jlong JNICALL
 144 Java_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 
 168 JNIEXPORT jlong JNICALL
 169 Java_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 }