1 /*
   2  * Copyright (c) 2000, 2009, 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     DWORD lowPos = 0;
 130     long highPos = 0;
 131     DWORD lowOffset = 0;
 132     long highOffset = 0;
 133 
 134     if (h == INVALID_HANDLE_VALUE) {
 135         JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
 136         return IOS_THROWN;
 137     }
 138 
 139     lowPos = SetFilePointer(h, 0, &highPos, FILE_CURRENT);
 140     if (lowPos == ((DWORD)-1)) {
 141         if (GetLastError() != ERROR_SUCCESS) {
 142             JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 143             return IOS_THROWN;
 144         }
 145     }
 146 
 147     lowOffset = (DWORD)offset;
 148     highOffset = (DWORD)(offset >> 32);
 149     lowOffset = SetFilePointer(h, lowOffset, &highOffset, FILE_BEGIN);
 150     if (lowOffset == ((DWORD)-1)) {
 151         if (GetLastError() != ERROR_SUCCESS) {
 152             JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 153             return IOS_THROWN;
 154         }
 155     }
 156 
 157     result = ReadFile(h,                /* File handle to read */
 158                       (LPVOID)address,  /* address to put data */
 159                       len,              /* number of bytes to read */
 160                       &read,            /* number of bytes read */
 161                       NULL);              /* struct with offset */
 162 
 163     if (result == 0) {
 164         int error = GetLastError();
 165         if (error == ERROR_BROKEN_PIPE) {
 166             return IOS_EOF;
 167         }
 168         if (error == ERROR_NO_DATA) {
 169             return IOS_UNAVAILABLE;
 170         }
 171         JNU_ThrowIOExceptionWithLastError(env, "Read failed");
 172         return IOS_THROWN;
 173     }
 174 
 175     lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN);
 176     if (lowPos == ((DWORD)-1)) {
 177         if (GetLastError() != ERROR_SUCCESS) {
 178             JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 179             return IOS_THROWN;
 180         }
 181     }
 182     return convertReturnVal(env, (jint)read, JNI_TRUE);
 183 }
 184 
 185 JNIEXPORT jint JNICALL
 186 Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo,
 187                                           jlong address, jint len, jboolean append)
 188 {
 189     BOOL result = 0;
 190     DWORD written = 0;
 191     HANDLE h = (HANDLE)(handleval(env, fdo));
 192 
 193     if (h != INVALID_HANDLE_VALUE) {
 194         OVERLAPPED ov;
 195         LPOVERLAPPED lpOv;
 196         if (append == JNI_TRUE) {
 197             ov.Offset = (DWORD)0xFFFFFFFF;
 198             ov.OffsetHigh = (DWORD)0xFFFFFFFF;
 199             ov.hEvent = NULL;
 200             lpOv = &ov;
 201         } else {
 202             lpOv = NULL;
 203         }
 204         result = WriteFile(h,           /* File handle to write */
 205                       (LPCVOID)address, /* pointers to the buffers */
 206                       len,              /* number of bytes to write */
 207                       &written,         /* receives number of bytes written */
 208                       lpOv);            /* overlapped struct */
 209     }
 210 
 211     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 212         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
 213     }
 214 
 215     return convertReturnVal(env, (jint)written, JNI_FALSE);
 216 }
 217 
 218 JNIEXPORT jlong JNICALL
 219 Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo,
 220                                            jlong address, jint len, jboolean append)
 221 {
 222     BOOL result = 0;
 223     DWORD written = 0;
 224     HANDLE h = (HANDLE)(handleval(env, fdo));
 225     jlong totalWritten = 0;
 226 
 227     if (h != INVALID_HANDLE_VALUE) {
 228         LPVOID loc;
 229         int i = 0;
 230         DWORD num = 0;
 231         struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
 232         OVERLAPPED ov;
 233         LPOVERLAPPED lpOv;
 234         if (append == JNI_TRUE) {
 235             ov.Offset = (DWORD)0xFFFFFFFF;
 236             ov.OffsetHigh = (DWORD)0xFFFFFFFF;
 237             ov.hEvent = NULL;
 238             lpOv = &ov;
 239         } else {
 240             lpOv = NULL;
 241         }
 242         for(i=0; i<len; i++) {
 243             loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
 244             num = iovecp[i].iov_len;
 245             result = WriteFile(h,       /* File handle to write */
 246                                loc,     /* pointers to the buffers */
 247                                num,     /* number of bytes to write */
 248                                &written,/* receives number of bytes written */
 249                                lpOv);   /* overlapped struct */
 250             if (written > 0) {
 251                 totalWritten += written;
 252             }
 253             if (written < num) {
 254                 break;
 255             }
 256         }
 257     }
 258 
 259     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 260         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
 261     }
 262 
 263     return convertLongReturnVal(env, totalWritten, JNI_FALSE);
 264 }
 265 
 266 JNIEXPORT jint JNICALL
 267 Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo,
 268                             jlong address, jint len, jlong offset)
 269 {
 270     BOOL result = 0;
 271     DWORD written = 0;
 272     HANDLE h = (HANDLE)(handleval(env, fdo));
 273     DWORD lowPos = 0;
 274     long highPos = 0;
 275     DWORD lowOffset = 0;
 276     long highOffset = 0;
 277 
 278     lowPos = SetFilePointer(h, 0, &highPos, FILE_CURRENT);
 279     if (lowPos == ((DWORD)-1)) {
 280         if (GetLastError() != ERROR_SUCCESS) {
 281             JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 282             return IOS_THROWN;
 283         }
 284     }
 285 
 286     lowOffset = (DWORD)offset;
 287     highOffset = (DWORD)(offset >> 32);
 288     lowOffset = SetFilePointer(h, lowOffset, &highOffset, FILE_BEGIN);
 289     if (lowOffset == ((DWORD)-1)) {
 290         if (GetLastError() != ERROR_SUCCESS) {
 291             JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 292             return IOS_THROWN;
 293         }
 294     }
 295 
 296     result = WriteFile(h,               /* File handle to write */
 297                       (LPCVOID)address, /* pointers to the buffers */
 298                       len,              /* number of bytes to write */
 299                       &written,         /* receives number of bytes written */
 300                       NULL);            /* no overlapped struct */
 301 
 302     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 303         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
 304         return IOS_THROWN;
 305     }
 306 
 307     lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN);
 308     if (lowPos == ((DWORD)-1)) {
 309         if (GetLastError() != ERROR_SUCCESS) {
 310             JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
 311             return IOS_THROWN;
 312         }
 313     }
 314 
 315     return convertReturnVal(env, (jint)written, JNI_FALSE);
 316 }
 317 
 318 JNIEXPORT jint JNICALL
 319 Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
 320                                           jobject fdo, jboolean md)
 321 {
 322     int result = 0;
 323     HANDLE h = (HANDLE)(handleval(env, fdo));
 324 
 325     if (h != INVALID_HANDLE_VALUE) {
 326         result = FlushFileBuffers(h);
 327         if (result == 0) {
 328             int error = GetLastError();
 329             if (error != ERROR_ACCESS_DENIED) {
 330                 JNU_ThrowIOExceptionWithLastError(env, "Force failed");
 331                 return IOS_THROWN;
 332             }
 333         }
 334     } else {
 335         JNU_ThrowIOExceptionWithLastError(env, "Force failed");
 336         return IOS_THROWN;
 337     }
 338     return 0;
 339 }
 340 
 341 JNIEXPORT jint JNICALL
 342 Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
 343                                              jobject fdo, jlong size)
 344 {
 345     DWORD lowPos = 0;
 346     long highPos = 0;
 347     BOOL result = 0;
 348     HANDLE h = (HANDLE)(handleval(env, fdo));
 349 
 350     lowPos = (DWORD)size;
 351     highPos = (long)(size >> 32);
 352     lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN);
 353     if (lowPos == ((DWORD)-1)) {
 354         if (GetLastError() != ERROR_SUCCESS) {
 355             JNU_ThrowIOExceptionWithLastError(env, "Truncation failed");
 356             return IOS_THROWN;
 357         }
 358     }
 359     result = SetEndOfFile(h);
 360     if (result == 0) {
 361         JNU_ThrowIOExceptionWithLastError(env, "Truncation failed");
 362         return IOS_THROWN;
 363     }
 364     return 0;
 365 }
 366 
 367 JNIEXPORT jlong JNICALL
 368 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
 369 {
 370     DWORD sizeLow = 0;
 371     DWORD sizeHigh = 0;
 372     HANDLE h = (HANDLE)(handleval(env, fdo));
 373 
 374     sizeLow = GetFileSize(h, &sizeHigh);
 375     if (sizeLow == ((DWORD)-1)) {
 376         if (GetLastError() != ERROR_SUCCESS) {
 377             JNU_ThrowIOExceptionWithLastError(env, "Size failed");
 378             return IOS_THROWN;
 379         }
 380     }
 381     return (((jlong)sizeHigh) << 32) | sizeLow;
 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_LOCK_VIOLATION) {
 410             JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
 411             return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 412         }
 413         if (flags & LOCKFILE_FAIL_IMMEDIATELY) {
 414             return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 415         }
 416         JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
 417         return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
 418     }
 419     return sun_nio_ch_FileDispatcherImpl_LOCKED;
 420 }
 421 
 422 JNIEXPORT void JNICALL
 423 Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this,
 424                                         jobject fdo, jlong pos, jlong size)
 425 {
 426     HANDLE h = (HANDLE)(handleval(env, fdo));
 427     DWORD lowPos = (DWORD)pos;
 428     long highPos = (long)(pos >> 32);
 429     DWORD lowNumBytes = (DWORD)size;
 430     DWORD highNumBytes = (DWORD)(size >> 32);
 431     jint result = 0;
 432     OVERLAPPED o;
 433     o.hEvent = 0;
 434     o.Offset = lowPos;
 435     o.OffsetHigh = highPos;
 436     result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o);
 437     if (result == 0 && GetLastError() != ERROR_NOT_LOCKED) {
 438         JNU_ThrowIOExceptionWithLastError(env, "Release failed");
 439     }
 440 }
 441 
 442 static void closeFile(JNIEnv *env, jlong fd) {
 443     HANDLE h = (HANDLE)fd;
 444     if (h != INVALID_HANDLE_VALUE) {
 445         int result = CloseHandle(h);
 446         if (result < 0)
 447             JNU_ThrowIOExceptionWithLastError(env, "Close failed");
 448     }
 449 }
 450 
 451 JNIEXPORT void JNICALL
 452 Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo)
 453 {
 454     jlong fd = handleval(env, fdo);
 455     closeFile(env, fd);
 456 }
 457 
 458 JNIEXPORT void JNICALL
 459 Java_sun_nio_ch_FileDispatcherImpl_closeByHandle(JNIEnv *env, jclass clazz,
 460                                              jlong fd)
 461 {
 462     closeFile(env, fd);
 463 }
 464 
 465 JNIEXPORT jlong JNICALL
 466 Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong handle)
 467 {
 468     HANDLE hProcess = GetCurrentProcess();
 469     HANDLE hFile = jlong_to_ptr(handle);
 470     HANDLE hResult;
 471     BOOL res = DuplicateHandle(hProcess, hFile, hProcess, &hResult, 0, FALSE,
 472                                DUPLICATE_SAME_ACCESS);
 473     if (res == 0)
 474        JNU_ThrowIOExceptionWithLastError(env, "DuplicateHandle failed");
 475     return ptr_to_jlong(hResult);
 476 }