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