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*
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
262 void
fileOpen(JNIEnv * env,jobject this,jstring path,jfieldID fid,int flags)263 fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
264 {
265 FD h = winFileHandleOpen(env, path, flags);
266 if (h >= 0) {
267 jobject fdobj;
268 jboolean append;
269 SET_FD(this, h, fid);
270
271 fdobj = (*env)->GetObjectField(env, this, fid);
272 if (fdobj != NULL) {
273 append = (flags & O_APPEND) == 0 ? JNI_FALSE : JNI_TRUE;
274 (*env)->SetBooleanField(env, fdobj, IO_append_fdID, append);
275 }
276 }
277 }
278
279 /* These are functions that use a handle fd instead of the
280 old C style int fd as is used in HPI layer */
281
282 static int
283 handleNonSeekAvailable(FD, long *);
284 static int
285 handleStdinAvailable(FD, long *);
286
287 int
handleAvailable(FD fd,jlong * pbytes)288 handleAvailable(FD fd, jlong *pbytes) {
289 HANDLE h = (HANDLE)fd;
290 DWORD type = 0;
291
292 type = GetFileType(h);
293 /* Handle is for keyboard or pipe */
294 if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) {
295 int ret;
296 long lpbytes;
297 HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE);
298 if (stdInHandle == h) {
299 ret = handleStdinAvailable(fd, &lpbytes); /* keyboard */
300 } else {
301 ret = handleNonSeekAvailable(fd, &lpbytes); /* pipe */
302 }
303 (*pbytes) = (jlong)(lpbytes);
304 return ret;
305 }
306 /* Handle is for regular file */
307 if (type == FILE_TYPE_DISK) {
308 jlong current, end;
309
310 LARGE_INTEGER filesize;
311 current = handleLseek(fd, 0, SEEK_CUR);
312 if (current < 0) {
313 return FALSE;
314 }
315 if (GetFileSizeEx(h, &filesize) == 0) {
316 return FALSE;
317 }
318 end = long_to_jlong(filesize.QuadPart);
319 *pbytes = end - current;
320 return TRUE;
321 }
322 return FALSE;
323 }
324
325 static int
handleNonSeekAvailable(FD fd,long * pbytes)326 handleNonSeekAvailable(FD fd, long *pbytes) {
327 /* This is used for available on non-seekable devices
328 * (like both named and anonymous pipes, such as pipes
329 * connected to an exec'd process).
330 * Standard Input is a special case.
331 *
332 */
333 HANDLE han;
334
335 if ((han = (HANDLE) fd) == INVALID_HANDLE_VALUE) {
336 return FALSE;
337 }
338
339 if (! PeekNamedPipe(han, NULL, 0, NULL, pbytes, NULL)) {
340 /* PeekNamedPipe fails when at EOF. In that case we
341 * simply make *pbytes = 0 which is consistent with the
342 * behavior we get on Solaris when an fd is at EOF.
343 * The only alternative is to raise and Exception,
344 * which isn't really warranted.
345 */
346 if (GetLastError() != ERROR_BROKEN_PIPE) {
347 return FALSE;
348 }
349 *pbytes = 0;
350 }
351 return TRUE;
352 }
353
354 static int
handleStdinAvailable(FD fd,long * pbytes)355 handleStdinAvailable(FD fd, long *pbytes) {
356 HANDLE han;
357 DWORD numEventsRead = 0; /* Number of events read from buffer */
358 DWORD numEvents = 0; /* Number of events in buffer */
359 DWORD i = 0; /* Loop index */
360 DWORD curLength = 0; /* Position marker */
361 DWORD actualLength = 0; /* Number of bytes readable */
362 BOOL error = FALSE; /* Error holder */
363 INPUT_RECORD *lpBuffer; /* Pointer to records of input events */
364 DWORD bufferSize = 0;
365
366 if ((han = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
367 return FALSE;
368 }
369
370 /* Construct an array of input records in the console buffer */
371 error = GetNumberOfConsoleInputEvents(han, &numEvents);
372 if (error == 0) {
373 return handleNonSeekAvailable(fd, pbytes);
374 }
375
376 /* lpBuffer must fit into 64K or else PeekConsoleInput fails */
377 if (numEvents > MAX_INPUT_EVENTS) {
378 numEvents = MAX_INPUT_EVENTS;
379 }
380
381 bufferSize = numEvents * sizeof(INPUT_RECORD);
382 if (bufferSize == 0)
383 bufferSize = 1;
384 lpBuffer = malloc(bufferSize);
385 if (lpBuffer == NULL) {
386 return FALSE;
387 }
388
389 error = PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead);
390 if (error == 0) {
391 free(lpBuffer);
392 return FALSE;
393 }
394
395 /* Examine input records for the number of bytes available */
396 for(i=0; i<numEvents; i++) {
397 if (lpBuffer[i].EventType == KEY_EVENT) {
398 KEY_EVENT_RECORD *keyRecord = (KEY_EVENT_RECORD *)
399 &(lpBuffer[i].Event);
400 if (keyRecord->bKeyDown == TRUE) {
401 CHAR *keyPressed = (CHAR *) &(keyRecord->uChar);
402 curLength++;
403 if (*keyPressed == '\r')
404 actualLength = curLength;
405 }
406 }
407 }
408 if(lpBuffer != NULL)
409 free(lpBuffer);
410 *pbytes = (long) actualLength;
411 return TRUE;
412 }
413
414 /*
415 * This is documented to succeed on read-only files, but Win32's
416 * FlushFileBuffers functions fails with "access denied" in such a
417 * case. So we only signal an error if the error is *not* "access
418 * denied".
419 */
420
421 int
handleSync(FD fd)422 handleSync(FD fd) {
423 /*
424 * From the documentation:
425 *
426 * On Windows NT, the function FlushFileBuffers fails if hFile
427 * is a handle to console output. That is because console
428 * output is not buffered. The function returns FALSE, and
429 * GetLastError returns ERROR_INVALID_HANDLE.
430 *
431 * On the other hand, on Win95, it returns without error. I cannot
432 * assume that 0, 1, and 2 are console, because if someone closes
433 * System.out and then opens a file, they might get file descriptor
434 * 1. An error on *that* version of 1 should be reported, whereas
435 * an error on System.out (which was the original 1) should be
436 * ignored. So I use isatty() to ensure that such an error was due
437 * to this bogosity, and if it was, I ignore the error.
438 */
439
440 HANDLE handle = (HANDLE)fd;
441
442 if (!FlushFileBuffers(handle)) {
443 if (GetLastError() != ERROR_ACCESS_DENIED) { /* from winerror.h */
444 return -1;
445 }
446 }
447 return 0;
448 }
449
450 jint
handleSetLength(FD fd,jlong length)451 handleSetLength(FD fd, jlong length) {
452 HANDLE h = (HANDLE)fd;
453 FILE_END_OF_FILE_INFO eofInfo;
454
455 eofInfo.EndOfFile.QuadPart = length;
456
457 if (h == INVALID_HANDLE_VALUE) {
458 return -1;
459 }
460 if (!SetFileInformationByHandle(h, FileEndOfFileInfo, &eofInfo,
461 sizeof(FILE_END_OF_FILE_INFO))) {
462 return -1;
463 }
464 return 0;
465 }
466
467 JNIEXPORT
468 jint
handleRead(FD fd,void * buf,jint len)469 handleRead(FD fd, void *buf, jint len)
470 {
471 DWORD read = 0;
472 BOOL result = 0;
473 HANDLE h = (HANDLE)fd;
474 if (h == INVALID_HANDLE_VALUE) {
475 return -1;
476 }
477 result = ReadFile(h, /* File handle to read */
478 buf, /* address to put data */
479 len, /* number of bytes to read */
480 &read, /* number of bytes read */
481 NULL); /* no overlapped struct */
482 if (result == 0) {
483 int error = GetLastError();
484 if (error == ERROR_BROKEN_PIPE) {
485 return 0; /* EOF */
486 }
487 return -1;
488 }
489 return (jint)read;
490 }
491
writeInternal(FD fd,const void * buf,jint len,jboolean append)492 static jint writeInternal(FD fd, const void *buf, jint len, jboolean append)
493 {
494 BOOL result = 0;
495 DWORD written = 0;
496 HANDLE h = (HANDLE)fd;
497 if (h != INVALID_HANDLE_VALUE) {
498 OVERLAPPED ov;
499 LPOVERLAPPED lpOv;
500 if (append == JNI_TRUE) {
501 ov.Offset = (DWORD)0xFFFFFFFF;
502 ov.OffsetHigh = (DWORD)0xFFFFFFFF;
503 ov.hEvent = NULL;
504 lpOv = &ov;
505 } else {
506 lpOv = NULL;
507 }
508 result = WriteFile(h, /* File handle to write */
509 buf, /* pointers to the buffers */
510 len, /* number of bytes to write */
511 &written, /* receives number of bytes written */
512 lpOv); /* overlapped struct */
513 }
514 if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
515 return -1;
516 }
517 return (jint)written;
518 }
519
handleWrite(FD fd,const void * buf,jint len)520 jint handleWrite(FD fd, const void *buf, jint len) {
521 return writeInternal(fd, buf, len, JNI_FALSE);
522 }
523
handleAppend(FD fd,const void * buf,jint len)524 jint handleAppend(FD fd, const void *buf, jint len) {
525 return writeInternal(fd, buf, len, JNI_TRUE);
526 }
527
528 // Function to close the fd held by this FileDescriptor and set fd to -1.
529 void
fileDescriptorClose(JNIEnv * env,jobject this)530 fileDescriptorClose(JNIEnv *env, jobject this)
531 {
532 FD fd = (*env)->GetLongField(env, this, IO_handle_fdID);
533 HANDLE h = (HANDLE)fd;
534 if ((*env)->ExceptionOccurred(env)) {
535 return;
536 }
537
538 if (h == INVALID_HANDLE_VALUE) {
539 return;
540 }
541
542 /* Set the fd to -1 before closing it so that the timing window
543 * of other threads using the wrong fd (closed but recycled fd,
544 * that gets re-opened with some other filename) is reduced.
545 * Practically the chance of its occurance is low, however, we are
546 * taking extra precaution over here.
547 */
548 (*env)->SetLongField(env, this, IO_handle_fdID, -1);
549 if ((*env)->ExceptionOccurred(env)) {
550 return;
551 }
552
553 if (CloseHandle(h) == 0) { /* Returns zero on failure */
554 JNU_ThrowIOExceptionWithLastError(env, "close failed");
555 }
556 }
557
558 JNIEXPORT jlong JNICALL
handleLseek(FD fd,jlong offset,jint whence)559 handleLseek(FD fd, jlong offset, jint whence)
560 {
561 LARGE_INTEGER pos, distance;
562 DWORD lowPos = 0;
563 long highPos = 0;
564 DWORD op = FILE_CURRENT;
565 HANDLE h = (HANDLE)fd;
566
567 if (whence == SEEK_END) {
568 op = FILE_END;
569 }
570 if (whence == SEEK_CUR) {
571 op = FILE_CURRENT;
572 }
573 if (whence == SEEK_SET) {
574 op = FILE_BEGIN;
575 }
576
577 distance.QuadPart = offset;
578 if (SetFilePointerEx(h, distance, &pos, op) == 0) {
579 return -1;
580 }
581 return long_to_jlong(pos.QuadPart);
582 }
583
584 jlong
handleGetLength(FD fd)585 handleGetLength(FD fd) {
586 HANDLE h = (HANDLE) fd;
587 LARGE_INTEGER length;
588 if (GetFileSizeEx(h, &length) != 0) {
589 return long_to_jlong(length.QuadPart);
590 } else {
591 return -1;
592 }
593 }
594