Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/io/io_util_md.c
32287 views
1
/*
2
* Copyright (c) 2001, 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 "jni.h"
27
#include "jni_util.h"
28
#include "jvm.h"
29
#include "io_util.h"
30
#include "io_util_md.h"
31
#include <stdio.h>
32
#include <windows.h>
33
34
#include <wchar.h>
35
#include <io.h>
36
#include <fcntl.h>
37
#include <errno.h>
38
#include <string.h>
39
#include <sys/types.h>
40
#include <sys/stat.h>
41
#include <limits.h>
42
#include <wincon.h>
43
44
45
static DWORD MAX_INPUT_EVENTS = 2000;
46
47
/* If this returns NULL then an exception is pending */
48
WCHAR*
49
fileToNTPath(JNIEnv *env, jobject file, jfieldID id) {
50
jstring path = NULL;
51
if (file != NULL) {
52
path = (*env)->GetObjectField(env, file, id);
53
}
54
return pathToNTPath(env, path, JNI_FALSE);
55
}
56
57
/* Returns the working directory for the given drive, or NULL */
58
WCHAR*
59
currentDir(int di) {
60
UINT dt;
61
WCHAR root[4];
62
// verify drive is valid as _wgetdcwd in the VC++ 2010 runtime
63
// library does not handle invalid drives.
64
root[0] = L'A' + (WCHAR)(di - 1);
65
root[1] = L':';
66
root[2] = L'\\';
67
root[3] = L'\0';
68
dt = GetDriveTypeW(root);
69
if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR) {
70
return NULL;
71
} else {
72
return _wgetdcwd(di, NULL, MAX_PATH);
73
}
74
}
75
76
/* We cache the length of current working dir here to avoid
77
calling _wgetcwd() every time we need to resolve a relative
78
path. This piece of code needs to be revisited if chdir
79
makes its way into java runtime.
80
*/
81
82
int
83
currentDirLength(const WCHAR* ps, int pathlen) {
84
WCHAR *dir;
85
if (pathlen > 2 && ps[1] == L':' && ps[2] != L'\\') {
86
//drive-relative
87
WCHAR d = ps[0];
88
int dirlen = 0;
89
int di = 0;
90
if ((d >= L'a') && (d <= L'z')) di = d - L'a' + 1;
91
else if ((d >= L'A') && (d <= L'Z')) di = d - L'A' + 1;
92
else return 0; /* invalid drive name. */
93
dir = currentDir(di);
94
if (dir != NULL){
95
dirlen = (int)wcslen(dir);
96
free(dir);
97
}
98
return dirlen;
99
} else {
100
static int curDirLenCached = -1;
101
//relative to both drive and directory
102
if (curDirLenCached == -1) {
103
int dirlen = -1;
104
dir = _wgetcwd(NULL, MAX_PATH);
105
if (dir != NULL) {
106
curDirLenCached = (int)wcslen(dir);
107
free(dir);
108
}
109
}
110
return curDirLenCached;
111
}
112
}
113
114
/*
115
The "abpathlen" is the size of the buffer needed by _wfullpath. If the
116
"path" is a relative path, it is "the length of the current dir" + "the
117
length of the path", if it's "absolute" already, it's the same as
118
pathlen which is the length of "path".
119
*/
120
WCHAR* prefixAbpath(const WCHAR* path, int pathlen, int abpathlen) {
121
WCHAR* pathbuf = NULL;
122
WCHAR* abpath = NULL;
123
124
abpathlen += 10; //padding
125
abpath = (WCHAR*)malloc(abpathlen * sizeof(WCHAR));
126
if (abpath) {
127
/* Collapse instances of "foo\.." and ensure absoluteness before
128
going down to prefixing.
129
*/
130
if (_wfullpath(abpath, path, abpathlen)) {
131
pathbuf = getPrefixed(abpath, abpathlen);
132
} else {
133
/* _wfullpath fails if the pathlength exceeds 32k wchar.
134
Instead of doing more fancy things we simply copy the
135
ps into the return buffer, the subsequent win32 API will
136
probably fail with FileNotFoundException, which is expected
137
*/
138
pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
139
if (pathbuf != 0) {
140
wcscpy(pathbuf, path);
141
}
142
}
143
free(abpath);
144
}
145
return pathbuf;
146
}
147
148
/* If this returns NULL then an exception is pending */
149
WCHAR*
150
pathToNTPath(JNIEnv *env, jstring path, jboolean throwFNFE) {
151
int pathlen = 0;
152
WCHAR *pathbuf = NULL;
153
int max_path = 248; /* CreateDirectoryW() has the limit of 248 */
154
155
WITH_UNICODE_STRING(env, path, ps) {
156
pathlen = (int)wcslen(ps);
157
if (pathlen != 0) {
158
if (pathlen > 2 &&
159
(ps[0] == L'\\' && ps[1] == L'\\' || //UNC
160
ps[1] == L':' && ps[2] == L'\\')) //absolute
161
{
162
if (pathlen > max_path - 1) {
163
pathbuf = prefixAbpath(ps, pathlen, pathlen);
164
if (pathbuf == NULL) {
165
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
166
return NULL;
167
}
168
} else {
169
pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
170
if (pathbuf != 0) {
171
wcscpy(pathbuf, ps);
172
}
173
}
174
} else {
175
/* If the path came in as a relative path, need to verify if
176
its absolute form is bigger than max_path or not, if yes
177
need to (1)convert it to absolute and (2)prefix. This is
178
obviously a burden to all relative paths (The current dir/len
179
for "drive & directory" relative path is cached, so we only
180
calculate it once but for "drive-relative path we call
181
_wgetdcwd() and wcslen() everytime), but a hit we have
182
to take if we want to support relative path beyond max_path.
183
There is no way to predict how long the absolute path will be
184
(therefor allocate the sufficient memory block) before calling
185
_wfullpath(), we have to get the length of "current" dir first.
186
*/
187
WCHAR *abpath = NULL;
188
int dirlen = currentDirLength(ps, pathlen);
189
if (dirlen + pathlen + 1 > max_path - 1) {
190
pathbuf = prefixAbpath(ps, pathlen, dirlen + pathlen);
191
if (pathbuf == NULL) {
192
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
193
return NULL;
194
}
195
} else {
196
pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
197
if (pathbuf != 0) {
198
wcscpy(pathbuf, ps);
199
}
200
}
201
}
202
}
203
} END_UNICODE_STRING(env, ps);
204
205
if (pathlen == 0) {
206
if (throwFNFE == JNI_TRUE) {
207
if (!(*env)->ExceptionCheck(env)) {
208
throwFileNotFoundException(env, path);
209
}
210
return NULL;
211
} else {
212
pathbuf = (WCHAR*)malloc(sizeof(WCHAR));
213
if (pathbuf != NULL) {
214
pathbuf[0] = L'\0';
215
}
216
}
217
}
218
if (pathbuf == 0) {
219
if (!(*env)->ExceptionCheck(env)) {
220
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
221
}
222
}
223
return pathbuf;
224
}
225
226
FD
227
winFileHandleOpen(JNIEnv *env, jstring path, int flags)
228
{
229
const DWORD access =
230
(flags & O_WRONLY) ? GENERIC_WRITE :
231
(flags & O_RDWR) ? (GENERIC_READ | GENERIC_WRITE) :
232
GENERIC_READ;
233
const DWORD sharing =
234
FILE_SHARE_READ | FILE_SHARE_WRITE;
235
const DWORD disposition =
236
/* Note: O_TRUNC overrides O_CREAT */
237
(flags & O_TRUNC) ? CREATE_ALWAYS :
238
(flags & O_CREAT) ? OPEN_ALWAYS :
239
OPEN_EXISTING;
240
const DWORD maybeWriteThrough =
241
(flags & (O_SYNC | O_DSYNC)) ?
242
FILE_FLAG_WRITE_THROUGH :
243
FILE_ATTRIBUTE_NORMAL;
244
const DWORD maybeDeleteOnClose =
245
(flags & O_TEMPORARY) ?
246
FILE_FLAG_DELETE_ON_CLOSE :
247
FILE_ATTRIBUTE_NORMAL;
248
const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
249
HANDLE h = NULL;
250
251
WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE);
252
if (pathbuf == NULL) {
253
/* Exception already pending */
254
return -1;
255
}
256
h = CreateFileW(
257
pathbuf, /* Wide char path name */
258
access, /* Read and/or write permission */
259
sharing, /* File sharing flags */
260
NULL, /* Security attributes */
261
disposition, /* creation disposition */
262
flagsAndAttributes, /* flags and attributes */
263
NULL);
264
free(pathbuf);
265
266
if (h == INVALID_HANDLE_VALUE) {
267
throwFileNotFoundException(env, path);
268
return -1;
269
}
270
return (jlong) h;
271
}
272
273
void
274
fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
275
{
276
FD h = winFileHandleOpen(env, path, flags);
277
if (h >= 0) {
278
SET_FD(this, h, fid);
279
}
280
}
281
282
/* These are functions that use a handle fd instead of the
283
old C style int fd as is used in HPI layer */
284
285
static int
286
handleNonSeekAvailable(FD, long *);
287
static int
288
handleStdinAvailable(FD, long *);
289
290
int
291
handleAvailable(FD fd, jlong *pbytes) {
292
HANDLE h = (HANDLE)fd;
293
DWORD type = 0;
294
295
type = GetFileType(h);
296
/* Handle is for keyboard or pipe */
297
if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) {
298
int ret;
299
long lpbytes;
300
HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE);
301
if (stdInHandle == h) {
302
ret = handleStdinAvailable(fd, &lpbytes); /* keyboard */
303
} else {
304
ret = handleNonSeekAvailable(fd, &lpbytes); /* pipe */
305
}
306
(*pbytes) = (jlong)(lpbytes);
307
return ret;
308
}
309
/* Handle is for regular file */
310
if (type == FILE_TYPE_DISK) {
311
jlong current, end;
312
313
LARGE_INTEGER filesize;
314
current = handleLseek(fd, 0, SEEK_CUR);
315
if (current < 0) {
316
return FALSE;
317
}
318
if (GetFileSizeEx(h, &filesize) == 0) {
319
return FALSE;
320
}
321
end = long_to_jlong(filesize.QuadPart);
322
*pbytes = end - current;
323
return TRUE;
324
}
325
return FALSE;
326
}
327
328
static int
329
handleNonSeekAvailable(FD fd, long *pbytes) {
330
/* This is used for available on non-seekable devices
331
* (like both named and anonymous pipes, such as pipes
332
* connected to an exec'd process).
333
* Standard Input is a special case.
334
*
335
*/
336
HANDLE han;
337
338
if ((han = (HANDLE) fd) == INVALID_HANDLE_VALUE) {
339
return FALSE;
340
}
341
342
if (! PeekNamedPipe(han, NULL, 0, NULL, pbytes, NULL)) {
343
/* PeekNamedPipe fails when at EOF. In that case we
344
* simply make *pbytes = 0 which is consistent with the
345
* behavior we get on Solaris when an fd is at EOF.
346
* The only alternative is to raise and Exception,
347
* which isn't really warranted.
348
*/
349
if (GetLastError() != ERROR_BROKEN_PIPE) {
350
return FALSE;
351
}
352
*pbytes = 0;
353
}
354
return TRUE;
355
}
356
357
static int
358
handleStdinAvailable(FD fd, long *pbytes) {
359
HANDLE han;
360
DWORD numEventsRead = 0; /* Number of events read from buffer */
361
DWORD numEvents = 0; /* Number of events in buffer */
362
DWORD i = 0; /* Loop index */
363
DWORD curLength = 0; /* Position marker */
364
DWORD actualLength = 0; /* Number of bytes readable */
365
BOOL error = FALSE; /* Error holder */
366
INPUT_RECORD *lpBuffer; /* Pointer to records of input events */
367
DWORD bufferSize = 0;
368
369
if ((han = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
370
return FALSE;
371
}
372
373
/* Construct an array of input records in the console buffer */
374
error = GetNumberOfConsoleInputEvents(han, &numEvents);
375
if (error == 0) {
376
return handleNonSeekAvailable(fd, pbytes);
377
}
378
379
/* lpBuffer must fit into 64K or else PeekConsoleInput fails */
380
if (numEvents > MAX_INPUT_EVENTS) {
381
numEvents = MAX_INPUT_EVENTS;
382
}
383
384
bufferSize = numEvents * sizeof(INPUT_RECORD);
385
if (bufferSize == 0)
386
bufferSize = 1;
387
lpBuffer = malloc(bufferSize);
388
if (lpBuffer == NULL) {
389
return FALSE;
390
}
391
392
error = PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead);
393
if (error == 0) {
394
free(lpBuffer);
395
return FALSE;
396
}
397
398
/* Examine input records for the number of bytes available */
399
for(i=0; i<numEvents; i++) {
400
if (lpBuffer[i].EventType == KEY_EVENT) {
401
KEY_EVENT_RECORD *keyRecord = (KEY_EVENT_RECORD *)
402
&(lpBuffer[i].Event);
403
if (keyRecord->bKeyDown == TRUE) {
404
CHAR *keyPressed = (CHAR *) &(keyRecord->uChar);
405
curLength++;
406
if (*keyPressed == '\r')
407
actualLength = curLength;
408
}
409
}
410
}
411
if(lpBuffer != NULL)
412
free(lpBuffer);
413
*pbytes = (long) actualLength;
414
return TRUE;
415
}
416
417
/*
418
* This is documented to succeed on read-only files, but Win32's
419
* FlushFileBuffers functions fails with "access denied" in such a
420
* case. So we only signal an error if the error is *not* "access
421
* denied".
422
*/
423
424
int
425
handleSync(FD fd) {
426
/*
427
* From the documentation:
428
*
429
* On Windows NT, the function FlushFileBuffers fails if hFile
430
* is a handle to console output. That is because console
431
* output is not buffered. The function returns FALSE, and
432
* GetLastError returns ERROR_INVALID_HANDLE.
433
*
434
* On the other hand, on Win95, it returns without error. I cannot
435
* assume that 0, 1, and 2 are console, because if someone closes
436
* System.out and then opens a file, they might get file descriptor
437
* 1. An error on *that* version of 1 should be reported, whereas
438
* an error on System.out (which was the original 1) should be
439
* ignored. So I use isatty() to ensure that such an error was due
440
* to this bogosity, and if it was, I ignore the error.
441
*/
442
443
HANDLE handle = (HANDLE)fd;
444
445
if (!FlushFileBuffers(handle)) {
446
if (GetLastError() != ERROR_ACCESS_DENIED) { /* from winerror.h */
447
return -1;
448
}
449
}
450
return 0;
451
}
452
453
454
int
455
handleSetLength(FD fd, jlong length) {
456
HANDLE h = (HANDLE)fd;
457
long high = (long)(length >> 32);
458
DWORD ret;
459
460
if (h == (HANDLE)(-1)) return -1;
461
ret = SetFilePointer(h, (long)(length), &high, FILE_BEGIN);
462
if (ret == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
463
return -1;
464
}
465
if (SetEndOfFile(h) == FALSE) return -1;
466
return 0;
467
}
468
469
JNIEXPORT
470
jint
471
handleRead(FD fd, void *buf, jint len)
472
{
473
DWORD read = 0;
474
BOOL result = 0;
475
HANDLE h = (HANDLE)fd;
476
if (h == INVALID_HANDLE_VALUE) {
477
return -1;
478
}
479
result = ReadFile(h, /* File handle to read */
480
buf, /* address to put data */
481
len, /* number of bytes to read */
482
&read, /* number of bytes read */
483
NULL); /* no overlapped struct */
484
if (result == 0) {
485
int error = GetLastError();
486
if (error == ERROR_BROKEN_PIPE) {
487
return 0; /* EOF */
488
}
489
return -1;
490
}
491
return (jint)read;
492
}
493
494
static jint writeInternal(FD fd, const void *buf, jint len, jboolean append)
495
{
496
BOOL result = 0;
497
DWORD written = 0;
498
HANDLE h = (HANDLE)fd;
499
if (h != INVALID_HANDLE_VALUE) {
500
OVERLAPPED ov;
501
LPOVERLAPPED lpOv;
502
if (append == JNI_TRUE) {
503
ov.Offset = (DWORD)0xFFFFFFFF;
504
ov.OffsetHigh = (DWORD)0xFFFFFFFF;
505
ov.hEvent = NULL;
506
lpOv = &ov;
507
} else {
508
lpOv = NULL;
509
}
510
result = WriteFile(h, /* File handle to write */
511
buf, /* pointers to the buffers */
512
len, /* number of bytes to write */
513
&written, /* receives number of bytes written */
514
lpOv); /* overlapped struct */
515
}
516
if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
517
return -1;
518
}
519
return (jint)written;
520
}
521
522
jint handleWrite(FD fd, const void *buf, jint len) {
523
return writeInternal(fd, buf, len, JNI_FALSE);
524
}
525
526
jint handleAppend(FD fd, const void *buf, jint len) {
527
return writeInternal(fd, buf, len, JNI_TRUE);
528
}
529
530
jint
531
handleClose(JNIEnv *env, jobject this, jfieldID fid)
532
{
533
FD fd = GET_FD(this, fid);
534
HANDLE h = (HANDLE)fd;
535
536
if (h == INVALID_HANDLE_VALUE) {
537
return 0;
538
}
539
540
/* Set the fd to -1 before closing it so that the timing window
541
* of other threads using the wrong fd (closed but recycled fd,
542
* that gets re-opened with some other filename) is reduced.
543
* Practically the chance of its occurance is low, however, we are
544
* taking extra precaution over here.
545
*/
546
SET_FD(this, -1, fid);
547
548
if (CloseHandle(h) == 0) { /* Returns zero on failure */
549
JNU_ThrowIOExceptionWithLastError(env, "close failed");
550
}
551
return 0;
552
}
553
554
jlong
555
handleLseek(FD fd, jlong offset, jint whence)
556
{
557
LARGE_INTEGER pos, distance;
558
DWORD lowPos = 0;
559
long highPos = 0;
560
DWORD op = FILE_CURRENT;
561
HANDLE h = (HANDLE)fd;
562
563
if (whence == SEEK_END) {
564
op = FILE_END;
565
}
566
if (whence == SEEK_CUR) {
567
op = FILE_CURRENT;
568
}
569
if (whence == SEEK_SET) {
570
op = FILE_BEGIN;
571
}
572
573
distance.QuadPart = offset;
574
if (SetFilePointerEx(h, distance, &pos, op) == 0) {
575
return -1;
576
}
577
return long_to_jlong(pos.QuadPart);
578
}
579
580
size_t
581
getLastErrorString(char *utf8_jvmErrorMsg, size_t cbErrorMsg)
582
{
583
size_t n = 0;
584
if (cbErrorMsg > 0) {
585
BOOLEAN noError = FALSE;
586
WCHAR *utf16_osErrorMsg = (WCHAR *)malloc(cbErrorMsg*sizeof(WCHAR));
587
if (utf16_osErrorMsg == NULL) {
588
// OOM accident
589
strncpy(utf8_jvmErrorMsg, "Out of memory", cbErrorMsg);
590
// truncate if too long
591
utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0';
592
n = strlen(utf8_jvmErrorMsg);
593
} else {
594
DWORD errval = GetLastError();
595
if (errval != 0) {
596
// WIN32 error
597
n = (size_t)FormatMessageW(
598
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
599
NULL,
600
errval,
601
0,
602
utf16_osErrorMsg,
603
(DWORD)cbErrorMsg,
604
NULL);
605
if (n > 3) {
606
// Drop final '.', CR, LF
607
if (utf16_osErrorMsg[n - 1] == L'\n') --n;
608
if (utf16_osErrorMsg[n - 1] == L'\r') --n;
609
if (utf16_osErrorMsg[n - 1] == L'.') --n;
610
utf16_osErrorMsg[n] = L'\0';
611
}
612
} else if (errno != 0) {
613
// C runtime error that has no corresponding WIN32 error code
614
const WCHAR *rtError = _wcserror(errno);
615
if (rtError != NULL) {
616
wcsncpy(utf16_osErrorMsg, rtError, cbErrorMsg);
617
// truncate if too long
618
utf16_osErrorMsg[cbErrorMsg - 1] = L'\0';
619
n = wcslen(utf16_osErrorMsg);
620
}
621
} else
622
noError = TRUE; //OS has no error to report
623
624
if (!noError) {
625
if (n > 0) {
626
n = WideCharToMultiByte(
627
CP_UTF8,
628
0,
629
utf16_osErrorMsg,
630
n,
631
utf8_jvmErrorMsg,
632
cbErrorMsg,
633
NULL,
634
NULL);
635
636
// no way to die
637
if (n > 0)
638
utf8_jvmErrorMsg[min(cbErrorMsg - 1, n)] = '\0';
639
}
640
641
if (n <= 0) {
642
strncpy(utf8_jvmErrorMsg, "Secondary error while OS message extraction", cbErrorMsg);
643
// truncate if too long
644
utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0';
645
n = strlen(utf8_jvmErrorMsg);
646
}
647
}
648
free(utf16_osErrorMsg);
649
}
650
}
651
return n;
652
}
653
654