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     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 jlong JNICALL
 302 Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv *env, jclass clazz,
 303                                          jobject fdo, jlong offset)
 304 {
 305     BOOL result = 0;
 306     HANDLE h = (HANDLE)(handleval(env, fdo));
 307     LARGE_INTEGER where;
 308     DWORD whence;
 309 
 310     if (offset < 0) {
 311         where.QuadPart = 0;
 312         whence = FILE_CURRENT;
 313     } else {
 314         where.QuadPart = offset;
 315         whence = FILE_BEGIN;
 316     }
 317 
 318     result = SetFilePointerEx(h, where, &where, whence);
 319     if (result == 0) {
 320         JNU_ThrowIOExceptionWithLastError(env, "SetFilePointerEx failed");
 321         return IOS_THROWN;
 322     }
 323     return (jlong)where.QuadPart;
 324 }
 325 
 326 JNIEXPORT jint JNICALL
 327 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
 328                                           jobject fdo, jboolean md)
 329 {
 330     int result = 0;
 331     HANDLE h = (HANDLE)(handleval(env, fdo));
 332 
 333     if (h != INVALID_HANDLE_VALUE) {
 334         result = FlushFileBuffers(h);
 335         if (result == 0) {
 336             int error = GetLastError();
 337             if (error != ERROR_ACCESS_DENIED) {
 338                 JNU_ThrowIOExceptionWithLastError(env, "Force failed");
 339                 return IOS_THROWN;
 340             }
 341         }
 342     } else {
 343         JNU_ThrowIOExceptionWithLastError(env, "Force failed");
 344         return IOS_THROWN;
 345     }
 346     return 0;
 347 }
 348 
 349 JNIEXPORT jint JNICALL
 350 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
 351                                              jobject fdo, jlong size)
 352 {
 353     BOOL result = 0;
 354     HANDLE h = (HANDLE)(handleval(env, fdo));
 355     FILE_END_OF_FILE_INFO eofInfo;
 356 
 357     eofInfo.EndOfFile.QuadPart = size;
 358     result = SetFileInformationByHandle(h,
 359                                         FileEndOfFileInfo,
 360                                         &eofInfo,
 361                                         sizeof(eofInfo));
 362     if (result == 0) {
 363         JNU_ThrowIOExceptionWithLastError(env, "Truncation failed");
 364         return IOS_THROWN;
 365     }
 366     return 0;
 367 }
 368 
 369 JNIEXPORT jlong JNICALL
 370 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
 371 {
 372     BOOL result = 0;
 373     HANDLE h = (HANDLE)(handleval(env, fdo));
 374     LARGE_INTEGER size;
 375 
 376     result = GetFileSizeEx(h, &size);
 377     if (result == 0) {
 378         JNU_ThrowIOExceptionWithLastError(env, "Size failed");
 379         return IOS_THROWN;
 380     }
 381     return (jlong)size.QuadPart;
 382 }
 383 
 384 JNIEXPORT jint JNICALL
 385 Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
 386                                       jboolean block, jlong pos, jlong size,
 387                                       jboolean shared)
 388 {
 389     HANDLE h = (HANDLE)(handleval(env, fdo));
 390     DWORD lowPos = (DWORD)pos;
 391     long highPos = (long)(pos >> 32);
 392     DWORD lowNumBytes = (DWORD)size;
 393     DWORD highNumBytes = (DWORD)(size >> 32);
 394     BOOL result;
 395     DWORD flags = 0;
 396     OVERLAPPED o;
 397     o.hEvent = 0;
 398     o.Offset = lowPos;
 399     o.OffsetHigh = highPos;
 400     if (block == JNI_FALSE) {
 401         flags |= LOCKFILE_FAIL_IMMEDIATELY;
 402     }
 403     if (shared == JNI_FALSE) {
 404         flags |= LOCKFILE_EXCLUSIVE_LOCK;
 405     }
 406     result = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, &o);
 407     if (result == 0) {
 408         int error = GetLastError();
 409         if (error == ERROR_IO_PENDING) {
 410             DWORD dwBytes;
 411             result = GetOverlappedResult(h, &o, &dwBytes, TRUE);
 412             if (result != 0) {
 413                 return sun_nio_ch_FileDispatcherImpl_LOCKED;
 414             }
 415             error = GetLastError();
 416         }
 417         if (error != ERROR_LOCK_VIOLATION) {
 418             JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
 419             return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 420         }
 421         if (flags & LOCKFILE_FAIL_IMMEDIATELY) {
 422             return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 423         }
 424         JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
 425         return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 426     }
 427     return sun_nio_ch_FileDispatcherImpl_LOCKED;
 428 }
 429 
 430 JNIEXPORT void JNICALL
 431 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this,
 432                                         jobject fdo, jlong pos, jlong size)
 433 {
 434     HANDLE h = (HANDLE)(handleval(env, fdo));
 435     DWORD lowPos = (DWORD)pos;
 436     long highPos = (long)(pos >> 32);
 437     DWORD lowNumBytes = (DWORD)size;
 438     DWORD highNumBytes = (DWORD)(size >> 32);
 439     BOOL result = 0;
 440     OVERLAPPED o;
 441     o.hEvent = 0;
 442     o.Offset = lowPos;
 443     o.OffsetHigh = highPos;
 444     result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o);
 445     if (result == 0) {
 446         int error = GetLastError();
 447         if (error == ERROR_IO_PENDING) {
 448             DWORD dwBytes;
 449             result = GetOverlappedResult(h, &o, &dwBytes, TRUE);
 450             if (result != 0) {
 451                 return;
 452             }
 453             error = GetLastError();
 454         }
 455         if (error != ERROR_NOT_LOCKED) {
 456             JNU_ThrowIOExceptionWithLastError(env, "Release failed");
 457         }
 458     }
 459 }
 460 
 461 JNIEXPORT void JNICALL
 462 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo)
 463 {
 464     HANDLE h = (HANDLE)handleval(env, fdo);
 465     if (h != INVALID_HANDLE_VALUE) {
 466         int result = CloseHandle(h);
 467         if (result == 0)
 468             JNU_ThrowIOExceptionWithLastError(env, "Close failed");
 469     }
 470 }
 471 
 472 JNIEXPORT jlong JNICALL
 473 Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong handle)
 474 {
 475     HANDLE hProcess = GetCurrentProcess();
 476     HANDLE hFile = jlong_to_ptr(handle);
 477     HANDLE hResult;
 478     BOOL res = DuplicateHandle(hProcess, hFile, hProcess, &hResult, 0, FALSE,
 479                                DUPLICATE_SAME_ACCESS);
 480     if (res == 0)
 481        JNU_ThrowIOExceptionWithLastError(env, "DuplicateHandle failed");
 482     return ptr_to_jlong(hResult);
 483 }
 484 
 485 JNIEXPORT jint JNICALL
 486 Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass this,
 487                                               jobject fdObj, jobject buffer)
 488 {
 489     jint result = -1;
 490 
 491     HANDLE orig = (HANDLE)(handleval(env, fdObj));
 492 
 493     HANDLE modify = ReOpenFile(orig, 0, 0,
 494             FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH);
 495 
 496     if (modify != INVALID_HANDLE_VALUE) {
 497         DWORD sectorsPerCluster;
 498         DWORD bytesPerSector;
 499         DWORD numberOfFreeClusters;
 500         DWORD totalNumberOfClusters;
 501         LPCWSTR lpRootPathName = (*env)->GetDirectBufferAddress(env, buffer);
 502         BOOL res = GetDiskFreeSpaceW(lpRootPathName,
 503                                      &sectorsPerCluster,
 504                                      &bytesPerSector,
 505                                      &numberOfFreeClusters,
 506                                      &totalNumberOfClusters);
 507         if (res == 0) {
 508             JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
 509         }
 510         result = bytesPerSector;
 511     }
 512     return result;
 513 }