1 /*
   2  * Copyright (c) 2001, 2017, 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 FD
 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 
 462 int
 463 handleSetLength(FD fd, jlong length) {
 464     HANDLE h = (HANDLE)fd;
 465     long high = (long)(length >> 32);
 466     DWORD ret;
 467 
 468     if (h == (HANDLE)(-1)) return -1;
 469     ret = SetFilePointer(h, (long)(length), &high, FILE_BEGIN);
 470     if (ret == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
 471         return -1;
 472     }
 473     if (SetEndOfFile(h) == FALSE) return -1;
 474     return 0;
 475 }
 476 
 477 JNIEXPORT
 478 jint
 479 handleRead(FD fd, void *buf, jint len)
 480 {
 481     DWORD read = 0;
 482     BOOL result = 0;
 483     HANDLE h = (HANDLE)fd;
 484     if (h == INVALID_HANDLE_VALUE) {
 485         return -1;
 486     }
 487     result = ReadFile(h,          /* File handle to read */
 488                       buf,        /* address to put data */
 489                       len,        /* number of bytes to read */
 490                       &read,      /* number of bytes read */
 491                       NULL);      /* no overlapped struct */
 492     if (result == 0) {
 493         int error = GetLastError();
 494         if (error == ERROR_BROKEN_PIPE) {
 495             return 0; /* EOF */
 496         }
 497         return -1;
 498     }
 499     return (jint)read;
 500 }
 501 
 502 static jint writeInternal(FD fd, const void *buf, jint len, jboolean append)
 503 {
 504     BOOL result = 0;
 505     DWORD written = 0;
 506     HANDLE h = (HANDLE)fd;
 507     if (h != INVALID_HANDLE_VALUE) {
 508         OVERLAPPED ov;
 509         LPOVERLAPPED lpOv;
 510         if (append == JNI_TRUE) {
 511             ov.Offset = (DWORD)0xFFFFFFFF;
 512             ov.OffsetHigh = (DWORD)0xFFFFFFFF;
 513             ov.hEvent = NULL;
 514             lpOv = &ov;
 515         } else {
 516             lpOv = NULL;
 517         }
 518         result = WriteFile(h,                /* File handle to write */
 519                            buf,              /* pointers to the buffers */
 520                            len,              /* number of bytes to write */
 521                            &written,         /* receives number of bytes written */
 522                            lpOv);            /* overlapped struct */
 523     }
 524     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 525         return -1;
 526     }
 527     return (jint)written;
 528 }
 529 
 530 jint handleWrite(FD fd, const void *buf, jint len) {
 531     return writeInternal(fd, buf, len, JNI_FALSE);
 532 }
 533 
 534 jint handleAppend(FD fd, const void *buf, jint len) {
 535     return writeInternal(fd, buf, len, JNI_TRUE);
 536 }
 537 
 538 void
 539 handleClose(JNIEnv *env, jobject this, jfieldID fid)
 540 {
 541     jobject fileDescriptor = (*env)->GetObjectField(env, (this), (fid));
 542     if (fileDescriptor == NULL) {
 543         return;
 544     }
 545     fileDescriptorClose(env, fileDescriptor);
 546 }
 547 
 548 // Function to close the fd held by this FileDescriptor and set fd to -1.
 549 void
 550 fileDescriptorClose(JNIEnv *env, jobject this)
 551 {
 552     FD fd = (*env)->GetLongField(env, this, IO_handle_fdID);
 553     HANDLE h = (HANDLE)fd;
 554     if ((*env)->ExceptionOccurred(env)) {
 555         return;
 556     }
 557 
 558     if (h == INVALID_HANDLE_VALUE) {
 559         return;
 560     }
 561 
 562     /* Set the fd to -1 before closing it so that the timing window
 563      * of other threads using the wrong fd (closed but recycled fd,
 564      * that gets re-opened with some other filename) is reduced.
 565      * Practically the chance of its occurance is low, however, we are
 566      * taking extra precaution over here.
 567      */
 568     (*env)->SetLongField(env, this, IO_handle_fdID, -1);
 569     if ((*env)->ExceptionOccurred(env)) {
 570         return;
 571     }
 572 
 573     if (CloseHandle(h) == 0) { /* Returns zero on failure */
 574         JNU_ThrowIOExceptionWithLastError(env, "close failed");
 575     }
 576 }
 577 
 578 jlong
 579 handleLseek(FD fd, jlong offset, jint whence)
 580 {
 581     LARGE_INTEGER pos, distance;
 582     DWORD lowPos = 0;
 583     long highPos = 0;
 584     DWORD op = FILE_CURRENT;
 585     HANDLE h = (HANDLE)fd;
 586 
 587     if (whence == SEEK_END) {
 588         op = FILE_END;
 589     }
 590     if (whence == SEEK_CUR) {
 591         op = FILE_CURRENT;
 592     }
 593     if (whence == SEEK_SET) {
 594         op = FILE_BEGIN;
 595     }
 596 
 597     distance.QuadPart = offset;
 598     if (SetFilePointerEx(h, distance, &pos, op) == 0) {
 599         return -1;
 600     }
 601     return long_to_jlong(pos.QuadPart);
 602 }
 603 
 604 jlong
 605 handleGetLength(FD fd) {
 606     HANDLE h = (HANDLE) fd;
 607     LARGE_INTEGER length;
 608     if (GetFileSizeEx(h, &length) != 0) {
 609         return long_to_jlong(length.QuadPart);
 610     } else {
 611         return -1;
 612     }
 613 }