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