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 <windows.h>
  27 #include "jni.h"
  28 #include "jni_util.h"
  29 #include "jvm.h"
  30 #include "jlong.h"
  31 #include "sun_nio_ch_FileDispatcherImpl.h"
  32 #include <io.h>
  33 #include "nio.h"
  34 #include "nio_util.h"
  35 #include "jlong.h"
  36 
  37 
  38 /**************************************************************
  39  * FileDispatcherImpl.c
  40  */
  41 
  42 JNIEXPORT jint JNICALL
  43 Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, jobject fdo,
  44                                       jlong address, jint len)
  45 {
  46     DWORD read = 0;
  47     BOOL result = 0;
  48     HANDLE h = (HANDLE)(handleval(env, fdo));
  49 
  50     if (h == INVALID_HANDLE_VALUE) {
  51         JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
  52         return IOS_THROWN;
  53     }
  54     result = ReadFile(h,          /* File handle to read */
  55                       (LPVOID)address,    /* address to put data */
  56                       len,        /* number of bytes to read */
  57                       &read,      /* number of bytes read */
  58                       NULL);      /* no overlapped struct */
  59     if (result == 0) {
  60         int error = GetLastError();
  61         if (error == ERROR_BROKEN_PIPE) {
  62             return IOS_EOF;
  63         }
  64         if (error == ERROR_NO_DATA) {
  65             return IOS_UNAVAILABLE;
  66         }
  67         JNU_ThrowIOExceptionWithLastError(env, "Read failed");
  68         return IOS_THROWN;
  69     }
  70     return convertReturnVal(env, (jint)read, JNI_TRUE);
  71 }
  72 
  73 JNIEXPORT jlong JNICALL
  74 Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, jobject fdo,
  75                                        jlong address, jint len)
  76 {
  77     DWORD read = 0;
  78     BOOL result = 0;
  79     jlong totalRead = 0;
  80     LPVOID loc;
  81     int i = 0;
  82     DWORD num = 0;
  83     struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
  84     HANDLE h = (HANDLE)(handleval(env, fdo));
  85 
  86     if (h == INVALID_HANDLE_VALUE) {
  87         JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
  88         return IOS_THROWN;
  89     }
  90 
  91     for(i=0; i<len; i++) {
  92         loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
  93         num = iovecp[i].iov_len;
  94         result = ReadFile(h,                /* File handle to read */
  95                           loc,              /* address to put data */
  96                           num,              /* number of bytes to read */
  97                           &read,            /* number of bytes read */
  98                           NULL);            /* no overlapped struct */
  99         if (read > 0) {
 100             totalRead += read;
 101         }
 102         if (read < num) {
 103             break;
 104         }
 105     }
 106 
 107     if (result == 0) {
 108         int error = GetLastError();
 109         if (error == ERROR_BROKEN_PIPE) {
 110             return IOS_EOF;
 111         }
 112         if (error == ERROR_NO_DATA) {
 113             return IOS_UNAVAILABLE;
 114         }
 115         JNU_ThrowIOExceptionWithLastError(env, "Read failed");
 116         return IOS_THROWN;
 117     }
 118 
 119     return convertLongReturnVal(env, totalRead, JNI_TRUE);
 120 }
 121 
 122 JNIEXPORT jint JNICALL
 123 Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo,
 124                             jlong address, jint len, jlong offset)
 125 {
 126     DWORD read = 0;
 127     BOOL result = 0;
 128     HANDLE h = (HANDLE)(handleval(env, fdo));
 129     LARGE_INTEGER currPos;
 130     OVERLAPPED ov;
 131 
 132     if (h == INVALID_HANDLE_VALUE) {
 133         JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
 134         return IOS_THROWN;
 135     }
 136 
 137     currPos.QuadPart = 0;
 138     result = SetFilePointerEx(h, currPos, &currPos, FILE_CURRENT);
 139     if (result == 0) {
 140         JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 141         return IOS_THROWN;
 142     }
 143 
 144     ZeroMemory(&ov, sizeof(ov));
 145     ov.Offset = (DWORD)offset;
 146     ov.OffsetHigh = (DWORD)(offset >> 32);
 147 
 148     result = ReadFile(h,                /* File handle to read */
 149                       (LPVOID)address,  /* address to put data */
 150                       len,              /* number of bytes to read */
 151                       &read,            /* number of bytes read */
 152                       &ov);             /* position to read from */
 153 
 154     if (result == 0) {
 155         int error = GetLastError();
 156         if (error == ERROR_BROKEN_PIPE) {
 157             return IOS_EOF;
 158         }
 159         if (error == ERROR_NO_DATA) {
 160             return IOS_UNAVAILABLE;
 161         }
 162         if (error != ERROR_HANDLE_EOF) {
 163             JNU_ThrowIOExceptionWithLastError(env, "Read failed");
 164             return IOS_THROWN;
 165         }
 166     }
 167 
 168     result = SetFilePointerEx(h, currPos, NULL, FILE_BEGIN);
 169     if (result == 0) {
 170         JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 171         return IOS_THROWN;
 172     }
 173 
 174     return convertReturnVal(env, (jint)read, JNI_TRUE);
 175 }
 176 
 177 JNIEXPORT jint JNICALL
 178 Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo,
 179                                           jlong address, jint len, jboolean append)
 180 {
 181     BOOL result = 0;
 182     DWORD written = 0;
 183     HANDLE h = (HANDLE)(handleval(env, fdo));
 184 
 185     if (h != INVALID_HANDLE_VALUE) {
 186         OVERLAPPED ov;
 187         LPOVERLAPPED lpOv;
 188         if (append == JNI_TRUE) {
 189             ZeroMemory(&ov, sizeof(ov));
 190             ov.Offset = (DWORD)0xFFFFFFFF;
 191             ov.OffsetHigh = (DWORD)0xFFFFFFFF;
 192             lpOv = &ov;
 193         } else {
 194             lpOv = NULL;
 195         }
 196         result = WriteFile(h,                /* File handle to write */
 197                            (LPCVOID)address, /* pointer to the buffer */
 198                            len,              /* number of bytes to write */
 199                            &written,         /* receives number of bytes written */
 200                            lpOv);            /* overlapped struct */
 201     }
 202 
 203     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 204         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
 205         return IOS_THROWN;
 206     }
 207 
 208     return convertReturnVal(env, (jint)written, JNI_FALSE);
 209 }
 210 
 211 JNIEXPORT jlong JNICALL
 212 Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo,
 213                                            jlong address, jint len, jboolean append)
 214 {
 215     BOOL result = 0;
 216     DWORD written = 0;
 217     HANDLE h = (HANDLE)(handleval(env, fdo));
 218     jlong totalWritten = 0;
 219 
 220     if (h != INVALID_HANDLE_VALUE) {
 221         LPVOID loc;
 222         int i = 0;
 223         DWORD num = 0;
 224         struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
 225         OVERLAPPED ov;
 226         LPOVERLAPPED lpOv;
 227         if (append == JNI_TRUE) {
 228             ZeroMemory(&ov, sizeof(ov));
 229             ov.Offset = (DWORD)0xFFFFFFFF;
 230             ov.OffsetHigh = (DWORD)0xFFFFFFFF;
 231             lpOv = &ov;
 232         } else {
 233             lpOv = NULL;
 234         }
 235         for(i=0; i<len; i++) {
 236             loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
 237             num = iovecp[i].iov_len;
 238             result = WriteFile(h,       /* File handle to write */
 239                                loc,     /* pointers to the buffers */
 240                                num,     /* number of bytes to write */
 241                                &written,/* receives number of bytes written */
 242                                lpOv);   /* overlapped struct */
 243             if (written > 0) {
 244                 totalWritten += written;
 245             }
 246             if (written < num) {
 247                 break;
 248             }
 249         }
 250     }
 251 
 252     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 253         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
 254         return IOS_THROWN;
 255     }
 256 
 257     return convertLongReturnVal(env, totalWritten, JNI_FALSE);
 258 }
 259 
 260 JNIEXPORT jint JNICALL
 261 Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo,
 262                             jlong address, jint len, jlong offset)
 263 {
 264     BOOL result = 0;
 265     DWORD written = 0;
 266     HANDLE h = (HANDLE)(handleval(env, fdo));
 267     LARGE_INTEGER currPos;
 268     OVERLAPPED ov;
 269 
 270     currPos.QuadPart = 0;
 271     result = SetFilePointerEx(h, currPos, &currPos, FILE_CURRENT);
 272     if (result == 0) {
 273         JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 274         return IOS_THROWN;
 275     }
 276 
 277     ZeroMemory(&ov, sizeof(ov));
 278     ov.Offset = (DWORD)offset;
 279     ov.OffsetHigh = (DWORD)(offset >> 32);
 280 
 281     result = WriteFile(h,                /* File handle to write */
 282                        (LPCVOID)address, /* pointer to the buffer */
 283                        len,              /* number of bytes to write */
 284                        &written,         /* receives number of bytes written */
 285                        &ov);             /* position to write at */
 286 
 287     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 288         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
 289         return IOS_THROWN;
 290     }
 291 
 292     result = SetFilePointerEx(h, currPos, NULL, FILE_BEGIN);
 293     if (result == 0) {
 294         JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 295         return IOS_THROWN;
 296     }
 297 
 298     return convertReturnVal(env, (jint)written, JNI_FALSE);
 299 }
 300 
 301 JNIEXPORT jint JNICALL
 302 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
 303                                           jobject fdo, jboolean md)
 304 {
 305     int result = 0;
 306     HANDLE h = (HANDLE)(handleval(env, fdo));
 307 
 308     if (h != INVALID_HANDLE_VALUE) {
 309         result = FlushFileBuffers(h);
 310         if (result == 0) {
 311             int error = GetLastError();
 312             if (error != ERROR_ACCESS_DENIED) {
 313                 JNU_ThrowIOExceptionWithLastError(env, "Force failed");
 314                 return IOS_THROWN;
 315             }
 316         }
 317     } else {
 318         JNU_ThrowIOExceptionWithLastError(env, "Force failed");
 319         return IOS_THROWN;
 320     }
 321     return 0;
 322 }
 323 
 324 JNIEXPORT jint JNICALL
 325 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
 326                                              jobject fdo, jlong size)
 327 {
 328     BOOL result = 0;
 329     HANDLE h = (HANDLE)(handleval(env, fdo));
 330     FILE_END_OF_FILE_INFO eofInfo;
 331 
 332     eofInfo.EndOfFile.QuadPart = size;
 333     result = SetFileInformationByHandle(h,
 334                                         FileEndOfFileInfo,
 335                                         &eofInfo,
 336                                         sizeof(eofInfo));
 337     if (result == 0) {
 338         JNU_ThrowIOExceptionWithLastError(env, "Truncation failed");
 339         return IOS_THROWN;
 340     }
 341     return 0;
 342 }
 343 
 344 JNIEXPORT jlong JNICALL
 345 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
 346 {
 347     BOOL result = 0;
 348     HANDLE h = (HANDLE)(handleval(env, fdo));
 349     LARGE_INTEGER size;
 350 
 351     result = GetFileSizeEx(h, &size);
 352     if (result == 0) {
 353         JNU_ThrowIOExceptionWithLastError(env, "Size failed");
 354         return IOS_THROWN;
 355     }
 356     return (jlong)size.QuadPart;
 357 }
 358 
 359 JNIEXPORT jint JNICALL
 360 Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
 361                                       jboolean block, jlong pos, jlong size,
 362                                       jboolean shared)
 363 {
 364     HANDLE h = (HANDLE)(handleval(env, fdo));
 365     DWORD lowPos = (DWORD)pos;
 366     long highPos = (long)(pos >> 32);
 367     DWORD lowNumBytes = (DWORD)size;
 368     DWORD highNumBytes = (DWORD)(size >> 32);
 369     BOOL result;
 370     DWORD flags = 0;
 371     OVERLAPPED o;
 372     o.hEvent = 0;
 373     o.Offset = lowPos;
 374     o.OffsetHigh = highPos;
 375     if (block == JNI_FALSE) {
 376         flags |= LOCKFILE_FAIL_IMMEDIATELY;
 377     }
 378     if (shared == JNI_FALSE) {
 379         flags |= LOCKFILE_EXCLUSIVE_LOCK;
 380     }
 381     result = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, &o);
 382     if (result == 0) {
 383         int error = GetLastError();
 384         if (error == ERROR_IO_PENDING) {
 385             DWORD dwBytes;
 386             result = GetOverlappedResult(h, &o, &dwBytes, TRUE);
 387             if (result != 0) {
 388                 return sun_nio_ch_FileDispatcherImpl_LOCKED;
 389             }
 390             error = GetLastError();
 391         }
 392         if (error != ERROR_LOCK_VIOLATION) {
 393             JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
 394             return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 395         }
 396         if (flags & LOCKFILE_FAIL_IMMEDIATELY) {
 397             return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 398         }
 399         JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
 400         return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 401     }
 402     return sun_nio_ch_FileDispatcherImpl_LOCKED;
 403 }
 404 
 405 JNIEXPORT void JNICALL
 406 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this,
 407                                         jobject fdo, jlong pos, jlong size)
 408 {
 409     HANDLE h = (HANDLE)(handleval(env, fdo));
 410     DWORD lowPos = (DWORD)pos;
 411     long highPos = (long)(pos >> 32);
 412     DWORD lowNumBytes = (DWORD)size;
 413     DWORD highNumBytes = (DWORD)(size >> 32);
 414     BOOL result = 0;
 415     OVERLAPPED o;
 416     o.hEvent = 0;
 417     o.Offset = lowPos;
 418     o.OffsetHigh = highPos;
 419     result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o);
 420     if (result == 0) {
 421         int error = GetLastError();
 422         if (error == ERROR_IO_PENDING) {
 423             DWORD dwBytes;
 424             result = GetOverlappedResult(h, &o, &dwBytes, TRUE);
 425             if (result != 0) {
 426                 return;
 427             }
 428             error = GetLastError();
 429         }
 430         if (error != ERROR_NOT_LOCKED) {
 431             JNU_ThrowIOExceptionWithLastError(env, "Release failed");
 432         }
 433     }
 434 }
 435 
 436 JNIEXPORT void JNICALL
 437 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo)
 438 {
 439     HANDLE h = (HANDLE)handleval(env, fdo);
 440     if (h != INVALID_HANDLE_VALUE) {
 441         int result = CloseHandle(h);
 442         if (result == 0)
 443             JNU_ThrowIOExceptionWithLastError(env, "Close failed");
 444     }
 445 }
 446 
 447 JNIEXPORT jlong JNICALL
 448 Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong handle)
 449 {
 450     HANDLE hProcess = GetCurrentProcess();
 451     HANDLE hFile = jlong_to_ptr(handle);
 452     HANDLE hResult;
 453     BOOL res = DuplicateHandle(hProcess, hFile, hProcess, &hResult, 0, FALSE,
 454                                DUPLICATE_SAME_ACCESS);
 455     if (res == 0)
 456        JNU_ThrowIOExceptionWithLastError(env, "DuplicateHandle failed");
 457     return ptr_to_jlong(hResult);
 458 }