Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/windows/native/libjava/io_util_md.c
41119 views
1
/*
2
* Copyright (c) 2001, 2020, 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
} else {
165
pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
166
if (pathbuf != 0) {
167
wcscpy(pathbuf, ps);
168
}
169
}
170
} else {
171
/* If the path came in as a relative path, need to verify if
172
its absolute form is bigger than max_path or not, if yes
173
need to (1)convert it to absolute and (2)prefix. This is
174
obviously a burden to all relative paths (The current dir/len
175
for "drive & directory" relative path is cached, so we only
176
calculate it once but for "drive-relative path we call
177
_wgetdcwd() and wcslen() everytime), but a hit we have
178
to take if we want to support relative path beyond max_path.
179
There is no way to predict how long the absolute path will be
180
(therefor allocate the sufficient memory block) before calling
181
_wfullpath(), we have to get the length of "current" dir first.
182
*/
183
WCHAR *abpath = NULL;
184
int dirlen = currentDirLength(ps, pathlen);
185
if (dirlen + pathlen + 1 > max_path - 1) {
186
pathbuf = prefixAbpath(ps, pathlen, dirlen + pathlen);
187
} else {
188
pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
189
if (pathbuf != 0) {
190
wcscpy(pathbuf, ps);
191
}
192
}
193
}
194
}
195
} END_UNICODE_STRING(env, ps);
196
197
if (pathlen == 0) {
198
if (throwFNFE == JNI_TRUE) {
199
if (!(*env)->ExceptionCheck(env)) {
200
throwFileNotFoundException(env, path);
201
}
202
return NULL;
203
} else {
204
pathbuf = (WCHAR*)malloc(sizeof(WCHAR));
205
if (pathbuf != NULL) {
206
pathbuf[0] = L'\0';
207
}
208
}
209
}
210
if (pathbuf == 0) {
211
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
212
}
213
return pathbuf;
214
}
215
216
FD winFileHandleOpen(JNIEnv *env, jstring path, int flags)
217
{
218
const DWORD access =
219
(flags & O_WRONLY) ? GENERIC_WRITE :
220
(flags & O_RDWR) ? (GENERIC_READ | GENERIC_WRITE) :
221
GENERIC_READ;
222
const DWORD sharing =
223
FILE_SHARE_READ | FILE_SHARE_WRITE;
224
const DWORD disposition =
225
/* Note: O_TRUNC overrides O_CREAT */
226
(flags & O_TRUNC) ? CREATE_ALWAYS :
227
(flags & O_CREAT) ? OPEN_ALWAYS :
228
OPEN_EXISTING;
229
const DWORD maybeWriteThrough =
230
(flags & (O_SYNC | O_DSYNC)) ?
231
FILE_FLAG_WRITE_THROUGH :
232
FILE_ATTRIBUTE_NORMAL;
233
const DWORD maybeDeleteOnClose =
234
(flags & O_TEMPORARY) ?
235
FILE_FLAG_DELETE_ON_CLOSE :
236
FILE_ATTRIBUTE_NORMAL;
237
const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
238
HANDLE h = NULL;
239
240
WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE);
241
if (pathbuf == NULL) {
242
/* Exception already pending */
243
return -1;
244
}
245
h = CreateFileW(
246
pathbuf, /* Wide char path name */
247
access, /* Read and/or write permission */
248
sharing, /* File sharing flags */
249
NULL, /* Security attributes */
250
disposition, /* creation disposition */
251
flagsAndAttributes, /* flags and attributes */
252
NULL);
253
free(pathbuf);
254
255
if (h == INVALID_HANDLE_VALUE) {
256
throwFileNotFoundException(env, path);
257
return -1;
258
}
259
return (jlong) h;
260
}
261
262
FD getFD(JNIEnv *env, jobject obj, jfieldID fid) {
263
jobject fdo = (*env)->GetObjectField(env, obj, fid);
264
if (fdo == NULL) {
265
return -1;
266
}
267
return (*env)->GetLongField(env, fdo, IO_handle_fdID);
268
}
269
270
void
271
fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
272
{
273
FD h = winFileHandleOpen(env, path, flags);
274
if (h >= 0) {
275
jobject fdobj;
276
jboolean append;
277
fdobj = (*env)->GetObjectField(env, this, fid);
278
if (fdobj != NULL) {
279
// Set FD
280
(*env)->SetLongField(env, fdobj, IO_handle_fdID, h);
281
append = (flags & O_APPEND) == 0 ? JNI_FALSE : JNI_TRUE;
282
(*env)->SetBooleanField(env, fdobj, IO_append_fdID, append);
283
}
284
}
285
}
286
287
/* These are functions that use a handle fd instead of the
288
old C style int fd as is used in HPI layer */
289
290
static int
291
handleNonSeekAvailable(FD, long *);
292
static int
293
handleStdinAvailable(FD, long *);
294
295
int
296
handleAvailable(FD fd, jlong *pbytes) {
297
HANDLE h = (HANDLE)fd;
298
DWORD type = 0;
299
300
type = GetFileType(h);
301
/* Handle is for keyboard or pipe */
302
if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) {
303
int ret;
304
long lpbytes;
305
HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE);
306
if (stdInHandle == h) {
307
ret = handleStdinAvailable(fd, &lpbytes); /* keyboard */
308
} else {
309
ret = handleNonSeekAvailable(fd, &lpbytes); /* pipe */
310
}
311
(*pbytes) = (jlong)(lpbytes);
312
return ret;
313
}
314
/* Handle is for regular file */
315
if (type == FILE_TYPE_DISK) {
316
jlong current, end;
317
318
LARGE_INTEGER filesize;
319
current = handleLseek(fd, 0, SEEK_CUR);
320
if (current < 0) {
321
return FALSE;
322
}
323
if (GetFileSizeEx(h, &filesize) == 0) {
324
return FALSE;
325
}
326
end = long_to_jlong(filesize.QuadPart);
327
*pbytes = end - current;
328
return TRUE;
329
}
330
return FALSE;
331
}
332
333
static int
334
handleNonSeekAvailable(FD fd, long *pbytes) {
335
/* This is used for available on non-seekable devices
336
* (like both named and anonymous pipes, such as pipes
337
* connected to an exec'd process).
338
* Standard Input is a special case.
339
*
340
*/
341
HANDLE han;
342
343
if ((han = (HANDLE) fd) == INVALID_HANDLE_VALUE) {
344
return FALSE;
345
}
346
347
if (! PeekNamedPipe(han, NULL, 0, NULL, pbytes, NULL)) {
348
/* PeekNamedPipe fails when at EOF. In that case we
349
* simply make *pbytes = 0 which is consistent with the
350
* behavior we get on Solaris when an fd is at EOF.
351
* The only alternative is to raise and Exception,
352
* which isn't really warranted.
353
*/
354
if (GetLastError() != ERROR_BROKEN_PIPE) {
355
return FALSE;
356
}
357
*pbytes = 0;
358
}
359
return TRUE;
360
}
361
362
static int
363
handleStdinAvailable(FD fd, long *pbytes) {
364
HANDLE han;
365
DWORD numEventsRead = 0; /* Number of events read from buffer */
366
DWORD numEvents = 0; /* Number of events in buffer */
367
DWORD i = 0; /* Loop index */
368
DWORD curLength = 0; /* Position marker */
369
DWORD actualLength = 0; /* Number of bytes readable */
370
BOOL error = FALSE; /* Error holder */
371
INPUT_RECORD *lpBuffer; /* Pointer to records of input events */
372
DWORD bufferSize = 0;
373
374
if ((han = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
375
return FALSE;
376
}
377
378
/* Construct an array of input records in the console buffer */
379
error = GetNumberOfConsoleInputEvents(han, &numEvents);
380
if (error == 0) {
381
return handleNonSeekAvailable(fd, pbytes);
382
}
383
384
/* lpBuffer must fit into 64K or else PeekConsoleInput fails */
385
if (numEvents > MAX_INPUT_EVENTS) {
386
numEvents = MAX_INPUT_EVENTS;
387
}
388
389
bufferSize = numEvents * sizeof(INPUT_RECORD);
390
if (bufferSize == 0)
391
bufferSize = 1;
392
lpBuffer = malloc(bufferSize);
393
if (lpBuffer == NULL) {
394
return FALSE;
395
}
396
397
error = PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead);
398
if (error == 0) {
399
free(lpBuffer);
400
return FALSE;
401
}
402
403
/* Examine input records for the number of bytes available */
404
for(i=0; i<numEvents; i++) {
405
if (lpBuffer[i].EventType == KEY_EVENT) {
406
KEY_EVENT_RECORD *keyRecord = (KEY_EVENT_RECORD *)
407
&(lpBuffer[i].Event);
408
if (keyRecord->bKeyDown == TRUE) {
409
CHAR *keyPressed = (CHAR *) &(keyRecord->uChar);
410
curLength++;
411
if (*keyPressed == '\r')
412
actualLength = curLength;
413
}
414
}
415
}
416
if(lpBuffer != NULL)
417
free(lpBuffer);
418
*pbytes = (long) actualLength;
419
return TRUE;
420
}
421
422
/*
423
* This is documented to succeed on read-only files, but Win32's
424
* FlushFileBuffers functions fails with "access denied" in such a
425
* case. So we only signal an error if the error is *not* "access
426
* denied".
427
*/
428
429
int
430
handleSync(FD fd) {
431
/*
432
* From the documentation:
433
*
434
* On Windows NT, the function FlushFileBuffers fails if hFile
435
* is a handle to console output. That is because console
436
* output is not buffered. The function returns FALSE, and
437
* GetLastError returns ERROR_INVALID_HANDLE.
438
*
439
* On the other hand, on Win95, it returns without error. I cannot
440
* assume that 0, 1, and 2 are console, because if someone closes
441
* System.out and then opens a file, they might get file descriptor
442
* 1. An error on *that* version of 1 should be reported, whereas
443
* an error on System.out (which was the original 1) should be
444
* ignored. So I use isatty() to ensure that such an error was due
445
* to this bogosity, and if it was, I ignore the error.
446
*/
447
448
HANDLE handle = (HANDLE)fd;
449
450
if (!FlushFileBuffers(handle)) {
451
if (GetLastError() != ERROR_ACCESS_DENIED) { /* from winerror.h */
452
return -1;
453
}
454
}
455
return 0;
456
}
457
458
jint
459
handleSetLength(FD fd, jlong length) {
460
HANDLE h = (HANDLE)fd;
461
FILE_END_OF_FILE_INFO eofInfo;
462
463
eofInfo.EndOfFile.QuadPart = length;
464
465
if (h == INVALID_HANDLE_VALUE) {
466
return -1;
467
}
468
if (!SetFileInformationByHandle(h, FileEndOfFileInfo, &eofInfo,
469
sizeof(FILE_END_OF_FILE_INFO))) {
470
return -1;
471
}
472
return 0;
473
}
474
475
JNIEXPORT
476
jint
477
handleRead(FD fd, void *buf, jint len)
478
{
479
DWORD read = 0;
480
BOOL result = 0;
481
HANDLE h = (HANDLE)fd;
482
if (h == INVALID_HANDLE_VALUE) {
483
return -1;
484
}
485
result = ReadFile(h, /* File handle to read */
486
buf, /* address to put data */
487
len, /* number of bytes to read */
488
&read, /* number of bytes read */
489
NULL); /* no overlapped struct */
490
if (result == 0) {
491
int error = GetLastError();
492
if (error == ERROR_BROKEN_PIPE) {
493
return 0; /* EOF */
494
}
495
return -1;
496
}
497
return (jint)read;
498
}
499
500
static jint writeInternal(FD fd, const void *buf, jint len, jboolean append)
501
{
502
BOOL result = 0;
503
DWORD written = 0;
504
HANDLE h = (HANDLE)fd;
505
if (h != INVALID_HANDLE_VALUE) {
506
OVERLAPPED ov;
507
LPOVERLAPPED lpOv;
508
if (append == JNI_TRUE) {
509
ov.Offset = (DWORD)0xFFFFFFFF;
510
ov.OffsetHigh = (DWORD)0xFFFFFFFF;
511
ov.hEvent = NULL;
512
lpOv = &ov;
513
} else {
514
lpOv = NULL;
515
}
516
result = WriteFile(h, /* File handle to write */
517
buf, /* pointers to the buffers */
518
len, /* number of bytes to write */
519
&written, /* receives number of bytes written */
520
lpOv); /* overlapped struct */
521
}
522
if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
523
return -1;
524
}
525
return (jint)written;
526
}
527
528
jint handleWrite(FD fd, const void *buf, jint len) {
529
return writeInternal(fd, buf, len, JNI_FALSE);
530
}
531
532
jint handleAppend(FD fd, const void *buf, jint len) {
533
return writeInternal(fd, buf, len, JNI_TRUE);
534
}
535
536
// Function to close the fd held by this FileDescriptor and set fd to -1.
537
void
538
fileDescriptorClose(JNIEnv *env, jobject this)
539
{
540
FD fd = (*env)->GetLongField(env, this, IO_handle_fdID);
541
HANDLE h = (HANDLE)fd;
542
if ((*env)->ExceptionOccurred(env)) {
543
return;
544
}
545
546
if (h == INVALID_HANDLE_VALUE) {
547
return;
548
}
549
550
/* Set the fd to -1 before closing it so that the timing window
551
* of other threads using the wrong fd (closed but recycled fd,
552
* that gets re-opened with some other filename) is reduced.
553
* Practically the chance of its occurance is low, however, we are
554
* taking extra precaution over here.
555
*/
556
(*env)->SetLongField(env, this, IO_handle_fdID, -1);
557
if ((*env)->ExceptionOccurred(env)) {
558
return;
559
}
560
561
if (CloseHandle(h) == 0) { /* Returns zero on failure */
562
JNU_ThrowIOExceptionWithLastError(env, "close failed");
563
}
564
}
565
566
JNIEXPORT jlong JNICALL
567
handleLseek(FD fd, jlong offset, jint whence)
568
{
569
LARGE_INTEGER pos, distance;
570
DWORD op = FILE_CURRENT;
571
HANDLE h = (HANDLE)fd;
572
573
if (whence == SEEK_END) {
574
op = FILE_END;
575
}
576
if (whence == SEEK_CUR) {
577
op = FILE_CURRENT;
578
}
579
if (whence == SEEK_SET) {
580
op = FILE_BEGIN;
581
}
582
583
distance.QuadPart = offset;
584
if (SetFilePointerEx(h, distance, &pos, op) == 0) {
585
return -1;
586
}
587
return long_to_jlong(pos.QuadPart);
588
}
589
590
jlong
591
handleGetLength(FD fd) {
592
HANDLE h = (HANDLE) fd;
593
LARGE_INTEGER length;
594
if (GetFileSizeEx(h, &length) != 0) {
595
return long_to_jlong(length.QuadPart);
596
} else {
597
return -1;
598
}
599
}
600
601