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 <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 
  71     if (read > 0) {
  72       JVM_callFileReadBytes(env, (jint) read);
  73     }
  74 
  75 
  76     return convertReturnVal(env, (jint)read, JNI_TRUE);
  77 }
  78 
  79 JNIEXPORT jlong JNICALL
  80 Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, jobject fdo,
  81                                        jlong address, jint len)
  82 {
  83     DWORD read = 0;
  84     BOOL result = 0;
  85     jlong totalRead = 0;
  86     LPVOID loc;
  87     int i = 0;
  88     DWORD num = 0;
  89     struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
  90     HANDLE h = (HANDLE)(handleval(env, fdo));
  91 
  92     if (h == INVALID_HANDLE_VALUE) {
  93         JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
  94         return IOS_THROWN;
  95     }
  96 
  97     for(i=0; i<len; i++) {
  98         loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
  99         num = iovecp[i].iov_len;
 100         result = ReadFile(h,                /* File handle to read */
 101                           loc,              /* address to put data */
 102                           num,              /* number of bytes to read */
 103                           &read,            /* number of bytes read */
 104                           NULL);            /* no overlapped struct */
 105         if (read > 0) {
 106            totalRead += read;
 107            JVM_callFileReadBytes(env, (jint) read);
 108         }
 109         if (read < num) {
 110             break;
 111         }
 112     }
 113 
 114     if (result == 0) {
 115         int error = GetLastError();
 116         if (error == ERROR_BROKEN_PIPE) {
 117             return IOS_EOF;
 118         }
 119         if (error == ERROR_NO_DATA) {
 120             return IOS_UNAVAILABLE;
 121         }
 122         JNU_ThrowIOExceptionWithLastError(env, "Read failed");
 123         return IOS_THROWN;
 124     }
 125 
 126     return convertLongReturnVal(env, totalRead, JNI_TRUE);
 127 }
 128 
 129 JNIEXPORT jint JNICALL
 130 Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo,
 131                             jlong address, jint len, jlong offset)
 132 {
 133     DWORD read = 0;
 134     BOOL result = 0;
 135     HANDLE h = (HANDLE)(handleval(env, fdo));
 136     LARGE_INTEGER currPos;
 137     OVERLAPPED ov;
 138 
 139     if (h == INVALID_HANDLE_VALUE) {
 140         JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
 141         return IOS_THROWN;
 142     }
 143 
 144     currPos.QuadPart = 0;
 145     result = SetFilePointerEx(h, currPos, &currPos, FILE_CURRENT);
 146     if (result == 0) {
 147         JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 148         return IOS_THROWN;
 149     }
 150 
 151     ZeroMemory(&ov, sizeof(ov));
 152     ov.Offset = (DWORD)offset;
 153     ov.OffsetHigh = (DWORD)(offset >> 32);
 154 
 155     result = ReadFile(h,                /* File handle to read */
 156                       (LPVOID)address,  /* address to put data */
 157                       len,              /* number of bytes to read */
 158                       &read,            /* number of bytes read */
 159                       &ov);             /* position to read from */
 160 
 161     if (read > 0) {
 162       JVM_callFileReadBytes(env, (jint) read);
 163     }
 164 
 165     if (result == 0) {
 166         int error = GetLastError();
 167         if (error == ERROR_BROKEN_PIPE) {
 168             return IOS_EOF;
 169         }
 170         if (error == ERROR_NO_DATA) {
 171             return IOS_UNAVAILABLE;
 172         }
 173         if (error != ERROR_HANDLE_EOF) {
 174             JNU_ThrowIOExceptionWithLastError(env, "Read failed");
 175             return IOS_THROWN;
 176         }
 177     }
 178 
 179     result = SetFilePointerEx(h, currPos, NULL, FILE_BEGIN);
 180     if (result == 0) {
 181         JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 182         return IOS_THROWN;
 183     }
 184 
 185     return convertReturnVal(env, (jint)read, JNI_TRUE);
 186 }
 187 
 188 JNIEXPORT jint JNICALL
 189 Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo,
 190                                           jlong address, jint len, jboolean append)
 191 {
 192     BOOL result = 0;
 193     DWORD written = 0;
 194     HANDLE h = (HANDLE)(handleval(env, fdo));
 195 
 196     if (h != INVALID_HANDLE_VALUE) {
 197         OVERLAPPED ov;
 198         LPOVERLAPPED lpOv;
 199         if (append == JNI_TRUE) {
 200             ZeroMemory(&ov, sizeof(ov));
 201             ov.Offset = (DWORD)0xFFFFFFFF;
 202             ov.OffsetHigh = (DWORD)0xFFFFFFFF;
 203             lpOv = &ov;
 204         } else {
 205             lpOv = NULL;
 206         }
 207         result = WriteFile(h,                /* File handle to write */
 208                            (LPCVOID)address, /* pointer to the buffer */
 209                            len,              /* number of bytes to write */
 210                            &written,         /* receives number of bytes written */
 211                            lpOv);            /* overlapped struct */
 212         JVM_callFileWriteBytes(env, (jint) written);
 213 
 214     }
 215 
 216     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 217         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
 218         return IOS_THROWN;
 219     }
 220 
 221     return convertReturnVal(env, (jint)written, JNI_FALSE);
 222 }
 223 
 224 JNIEXPORT jlong JNICALL
 225 Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo,
 226                                            jlong address, jint len, jboolean append)
 227 {
 228     BOOL result = 0;
 229     DWORD written = 0;
 230     HANDLE h = (HANDLE)(handleval(env, fdo));
 231     jlong totalWritten = 0;
 232 
 233     if (h != INVALID_HANDLE_VALUE) {
 234         LPVOID loc;
 235         int i = 0;
 236         DWORD num = 0;
 237         struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
 238         OVERLAPPED ov;
 239         LPOVERLAPPED lpOv;
 240         if (append == JNI_TRUE) {
 241             ZeroMemory(&ov, sizeof(ov));
 242             ov.Offset = (DWORD)0xFFFFFFFF;
 243             ov.OffsetHigh = (DWORD)0xFFFFFFFF;
 244             lpOv = &ov;
 245         } else {
 246             lpOv = NULL;
 247         }
 248         for(i=0; i<len; i++) {
 249             loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
 250             num = iovecp[i].iov_len;
 251             result = WriteFile(h,       /* File handle to write */
 252                                loc,     /* pointers to the buffers */
 253                                num,     /* number of bytes to write */
 254                                &written,/* receives number of bytes written */
 255                                lpOv);   /* overlapped struct */
 256             if (written > 0) {
 257                 totalWritten += written;
 258                 JVM_callFileWriteBytes(env, (jint) written);
 259             }
 260             if (written < num) {
 261                 break;
 262             }
 263         }
 264     }
 265 
 266     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 267         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
 268         return IOS_THROWN;
 269     }
 270 
 271     return convertLongReturnVal(env, totalWritten, JNI_FALSE);
 272 }
 273 
 274 JNIEXPORT jint JNICALL
 275 Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo,
 276                             jlong address, jint len, jlong offset)
 277 {
 278     BOOL result = 0;
 279     DWORD written = 0;
 280     HANDLE h = (HANDLE)(handleval(env, fdo));
 281     LARGE_INTEGER currPos;
 282     OVERLAPPED ov;
 283 
 284     currPos.QuadPart = 0;
 285     result = SetFilePointerEx(h, currPos, &currPos, FILE_CURRENT);
 286     if (result == 0) {
 287         JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 288         return IOS_THROWN;
 289     }
 290 
 291     ZeroMemory(&ov, sizeof(ov));
 292     ov.Offset = (DWORD)offset;
 293     ov.OffsetHigh = (DWORD)(offset >> 32);
 294 
 295     result = WriteFile(h,                /* File handle to write */
 296                        (LPCVOID)address, /* pointer to the buffer */
 297                        len,              /* number of bytes to write */
 298                        &written,         /* receives number of bytes written */
 299                        &ov);             /* position to write at */
 300 
 301     if (written > 0) {
 302       JVM_callFileWriteBytes(env, (jint) written);
 303     }
 304 
 305     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 306         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
 307         return IOS_THROWN;
 308     }
 309 
 310     result = SetFilePointerEx(h, currPos, NULL, FILE_BEGIN);
 311     if (result == 0) {
 312         JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 313         return IOS_THROWN;
 314     }
 315 
 316     return convertReturnVal(env, (jint)written, JNI_FALSE);
 317 }
 318 
 319 JNIEXPORT jlong JNICALL
 320 Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv *env, jclass clazz,
 321                                          jobject fdo, jlong offset)
 322 {
 323     BOOL result = 0;
 324     HANDLE h = (HANDLE)(handleval(env, fdo));
 325     LARGE_INTEGER where;
 326     DWORD whence;
 327 
 328     if (offset < 0) {
 329         where.QuadPart = 0;
 330         whence = FILE_CURRENT;
 331     } else {
 332         where.QuadPart = offset;
 333         whence = FILE_BEGIN;
 334     }
 335 
 336     result = SetFilePointerEx(h, where, &where, whence);
 337     if (result == 0) {
 338         JNU_ThrowIOExceptionWithLastError(env, "SetFilePointerEx failed");
 339         return IOS_THROWN;
 340     }
 341     return (jlong)where.QuadPart;
 342 }
 343 
 344 JNIEXPORT jint JNICALL
 345 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
 346                                           jobject fdo, jboolean md)
 347 {
 348     int result = 0;
 349     HANDLE h = (HANDLE)(handleval(env, fdo));
 350 
 351     if (h != INVALID_HANDLE_VALUE) {
 352         result = FlushFileBuffers(h);
 353         if (result == 0) {
 354             int error = GetLastError();
 355             if (error != ERROR_ACCESS_DENIED) {
 356                 JNU_ThrowIOExceptionWithLastError(env, "Force failed");
 357                 return IOS_THROWN;
 358             }
 359         }
 360     } else {
 361         JNU_ThrowIOExceptionWithLastError(env, "Force failed");
 362         return IOS_THROWN;
 363     }
 364     return 0;
 365 }
 366 
 367 JNIEXPORT jint JNICALL
 368 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
 369                                              jobject fdo, jlong size)
 370 {
 371     BOOL result = 0;
 372     HANDLE h = (HANDLE)(handleval(env, fdo));
 373     FILE_END_OF_FILE_INFO eofInfo;
 374 
 375     eofInfo.EndOfFile.QuadPart = size;
 376     result = SetFileInformationByHandle(h,
 377                                         FileEndOfFileInfo,
 378                                         &eofInfo,
 379                                         sizeof(eofInfo));
 380     if (result == 0) {
 381         JNU_ThrowIOExceptionWithLastError(env, "Truncation failed");
 382         return IOS_THROWN;
 383     }
 384     return 0;
 385 }
 386 
 387 JNIEXPORT jlong JNICALL
 388 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
 389 {
 390     BOOL result = 0;
 391     HANDLE h = (HANDLE)(handleval(env, fdo));
 392     LARGE_INTEGER size;
 393 
 394     result = GetFileSizeEx(h, &size);
 395     if (result == 0) {
 396         JNU_ThrowIOExceptionWithLastError(env, "Size failed");
 397         return IOS_THROWN;
 398     }
 399     return (jlong)size.QuadPart;
 400 }
 401 
 402 JNIEXPORT jint JNICALL
 403 Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
 404                                       jboolean block, jlong pos, jlong size,
 405                                       jboolean shared)
 406 {
 407     HANDLE h = (HANDLE)(handleval(env, fdo));
 408     DWORD lowPos = (DWORD)pos;
 409     long highPos = (long)(pos >> 32);
 410     DWORD lowNumBytes = (DWORD)size;
 411     DWORD highNumBytes = (DWORD)(size >> 32);
 412     BOOL result;
 413     DWORD flags = 0;
 414     OVERLAPPED o;
 415     o.hEvent = 0;
 416     o.Offset = lowPos;
 417     o.OffsetHigh = highPos;
 418     if (block == JNI_FALSE) {
 419         flags |= LOCKFILE_FAIL_IMMEDIATELY;
 420     }
 421     if (shared == JNI_FALSE) {
 422         flags |= LOCKFILE_EXCLUSIVE_LOCK;
 423     }
 424     result = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, &o);
 425     if (result == 0) {
 426         int error = GetLastError();
 427         if (error == ERROR_IO_PENDING) {
 428             DWORD dwBytes;
 429             result = GetOverlappedResult(h, &o, &dwBytes, TRUE);
 430             if (result != 0) {
 431                 return sun_nio_ch_FileDispatcherImpl_LOCKED;
 432             }
 433             error = GetLastError();
 434         }
 435         if (error != ERROR_LOCK_VIOLATION) {
 436             JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
 437             return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 438         }
 439         if (flags & LOCKFILE_FAIL_IMMEDIATELY) {
 440             return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 441         }
 442         JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
 443         return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 444     }
 445     return sun_nio_ch_FileDispatcherImpl_LOCKED;
 446 }
 447 
 448 JNIEXPORT void JNICALL
 449 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this,
 450                                         jobject fdo, jlong pos, jlong size)
 451 {
 452     HANDLE h = (HANDLE)(handleval(env, fdo));
 453     DWORD lowPos = (DWORD)pos;
 454     long highPos = (long)(pos >> 32);
 455     DWORD lowNumBytes = (DWORD)size;
 456     DWORD highNumBytes = (DWORD)(size >> 32);
 457     BOOL result = 0;
 458     OVERLAPPED o;
 459     o.hEvent = 0;
 460     o.Offset = lowPos;
 461     o.OffsetHigh = highPos;
 462     result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o);
 463     if (result == 0) {
 464         int error = GetLastError();
 465         if (error == ERROR_IO_PENDING) {
 466             DWORD dwBytes;
 467             result = GetOverlappedResult(h, &o, &dwBytes, TRUE);
 468             if (result != 0) {
 469                 return;
 470             }
 471             error = GetLastError();
 472         }
 473         if (error != ERROR_NOT_LOCKED) {
 474             JNU_ThrowIOExceptionWithLastError(env, "Release failed");
 475         }
 476     }
 477 }
 478 
 479 JNIEXPORT void JNICALL
 480 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo)
 481 {
 482     HANDLE h = (HANDLE)handleval(env, fdo);
 483     if (h != INVALID_HANDLE_VALUE) {
 484         int result = CloseHandle(h);
 485         if (result == 0)
 486             JNU_ThrowIOExceptionWithLastError(env, "Close failed");
 487     }
 488 }
 489 
 490 JNIEXPORT jlong JNICALL
 491 Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong handle)
 492 {
 493     HANDLE hProcess = GetCurrentProcess();
 494     HANDLE hFile = jlong_to_ptr(handle);
 495     HANDLE hResult;
 496     BOOL res = DuplicateHandle(hProcess, hFile, hProcess, &hResult, 0, FALSE,
 497                                DUPLICATE_SAME_ACCESS);
 498     if (res == 0)
 499        JNU_ThrowIOExceptionWithLastError(env, "DuplicateHandle failed");
 500     return ptr_to_jlong(hResult);
 501 }
 502 
 503 JNIEXPORT jint JNICALL
 504 Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass this,
 505                                               jobject fdObj, jobject buffer)
 506 {
 507     jint result = -1;
 508 
 509     HANDLE orig = (HANDLE)(handleval(env, fdObj));
 510 
 511     HANDLE modify = ReOpenFile(orig, 0, 0,
 512             FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH);
 513 
 514     if (modify != INVALID_HANDLE_VALUE) {
 515         DWORD sectorsPerCluster;
 516         DWORD bytesPerSector;
 517         DWORD numberOfFreeClusters;
 518         DWORD totalNumberOfClusters;
 519         LPCWSTR lpRootPathName = (*env)->GetDirectBufferAddress(env, buffer);
 520         BOOL res = GetDiskFreeSpaceW(lpRootPathName,
 521                                      &sectorsPerCluster,
 522                                      &bytesPerSector,
 523                                      &numberOfFreeClusters,
 524                                      &totalNumberOfClusters);
 525         if (res == 0) {
 526             JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
 527         }
 528         result = bytesPerSector;
 529     }
 530     return result;
 531 }