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
Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint len)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
Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint len)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
Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint len,jlong offset)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
Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint len,jboolean append)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
Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint len,jboolean append)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
Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint len,jlong offset)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
Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv * env,jclass clazz,jobject fdo,jlong offset)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
Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv * env,jobject this,jobject fdo,jboolean md)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
Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv * env,jobject this,jobject fdo,jlong size)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
Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv * env,jobject this,jobject fdo)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
Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv * env,jobject this,jobject fdo,jboolean block,jlong pos,jlong size,jboolean shared)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
Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv * env,jobject this,jobject fdo,jlong pos,jlong size)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
Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv * env,jclass clazz,jobject fdo)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
Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv * env,jclass this,jlong handle)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
Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv * env,jclass this,jobject fdObj,jobject buffer)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 }
514