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*
fileToNTPath(JNIEnv * env,jobject file,jfieldID id)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*
currentDir(int di)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
currentDirLength(const WCHAR * ps,int pathlen)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 */
prefixAbpath(const WCHAR * path,int pathlen,int abpathlen)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*
pathToNTPath(JNIEnv * env,jstring path,jboolean throwFNFE)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
winFileHandleOpen(JNIEnv * env,jstring path,int flags)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
getFD(JNIEnv * env,jobject obj,jfieldID fid)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
fileOpen(JNIEnv * env,jobject this,jstring path,jfieldID fid,int flags)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
handleAvailable(FD fd,jlong * pbytes)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
handleNonSeekAvailable(FD fd,long * pbytes)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
handleStdinAvailable(FD fd,long * pbytes)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
handleSync(FD fd)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
handleSetLength(FD fd,jlong length)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
handleRead(FD fd,void * buf,jint len)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
writeInternal(FD fd,const void * buf,jint len,jboolean append)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
handleWrite(FD fd,const void * buf,jint len)528 jint handleWrite(FD fd, const void *buf, jint len) {
529 return writeInternal(fd, buf, len, JNI_FALSE);
530 }
531
handleAppend(FD fd,const void * buf,jint len)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
fileDescriptorClose(JNIEnv * env,jobject this)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
handleLseek(FD fd,jlong offset,jint whence)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
handleGetLength(FD fd)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