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