1 /*
   2  * Copyright (c) 2001, 2012, 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 
  33 #include <wchar.h>
  34 #include <io.h>
  35 #include <fcntl.h>
  36 #include <errno.h>
  37 #include <string.h>
  38 #include <sys/types.h>
  39 #include <sys/stat.h>
  40 #include <limits.h>
  41 #include <wincon.h>
  42 
  43 static DWORD MAX_INPUT_EVENTS = 2000;
  44 
  45 /* If this returns NULL then an exception is pending */
  46 WCHAR*
  47 fileToNTPath(JNIEnv *env, jobject file, jfieldID id) {
  48     jstring path = NULL;
  49     if (file != NULL) {
  50         path = (*env)->GetObjectField(env, file, id);
  51     }
  52     return pathToNTPath(env, path, JNI_FALSE);
  53 }
  54 
  55 /* Returns the working directory for the given drive, or NULL */
  56 WCHAR*
  57 currentDir(int di) {
  58     UINT dt;
  59     WCHAR root[4];
  60     // verify drive is valid as _wgetdcwd in the VC++ 2010 runtime
  61     // library does not handle invalid drives.
  62     root[0] = L'A' + (WCHAR)(di - 1);
  63     root[1] = L':';
  64     root[2] = L'\\';
  65     root[3] = L'\0';
  66     dt = GetDriveTypeW(root);
  67     if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR) {
  68         return NULL;
  69     } else {
  70         return _wgetdcwd(di, NULL, MAX_PATH);
  71     }
  72 }
  73 
  74 /* We cache the length of current working dir here to avoid
  75    calling _wgetcwd() every time we need to resolve a relative
  76    path. This piece of code needs to be revisited if chdir
  77    makes its way into java runtime.
  78 */
  79 
  80 int
  81 currentDirLength(const WCHAR* ps, int pathlen) {
  82     WCHAR *dir;
  83     if (pathlen > 2 && ps[1] == L':' && ps[2] != L'\\') {
  84         //drive-relative
  85         WCHAR d = ps[0];
  86         int dirlen = 0;
  87         int di = 0;
  88         if ((d >= L'a') && (d <= L'z')) di = d - L'a' + 1;
  89         else if ((d >= L'A') && (d <= L'Z')) di = d - L'A' + 1;
  90         else return 0; /* invalid drive name. */
  91         dir = currentDir(di);
  92         if (dir != NULL){
  93             dirlen = (int)wcslen(dir);
  94             free(dir);
  95         }
  96         return dirlen;
  97     } else {
  98         static int curDirLenCached = -1;
  99         //relative to both drive and directory
 100         if (curDirLenCached == -1) {
 101             int dirlen = -1;
 102             dir = _wgetcwd(NULL, MAX_PATH);
 103             if (dir != NULL) {
 104                 curDirLenCached = (int)wcslen(dir);
 105                 free(dir);
 106             }
 107         }
 108         return curDirLenCached;
 109     }
 110 }
 111 
 112 /*
 113   The "abpathlen" is the size of the buffer needed by _wfullpath. If the
 114   "path" is a relative path, it is "the length of the current dir" + "the
 115   length of the path", if it's "absolute" already, it's the same as
 116   pathlen which is the length of "path".
 117  */
 118 WCHAR* prefixAbpath(const WCHAR* path, int pathlen, int abpathlen) {
 119     WCHAR* pathbuf = NULL;
 120     WCHAR* abpath = NULL;
 121 
 122     abpathlen += 10;  //padding
 123     abpath = (WCHAR*)malloc(abpathlen * sizeof(WCHAR));
 124     if (abpath) {
 125         /* Collapse instances of "foo\.." and ensure absoluteness before
 126            going down to prefixing.
 127         */
 128         if (_wfullpath(abpath, path, abpathlen)) {
 129             pathbuf = getPrefixed(abpath, abpathlen);
 130         } else {
 131             /* _wfullpath fails if the pathlength exceeds 32k wchar.
 132                Instead of doing more fancy things we simply copy the
 133                ps into the return buffer, the subsequent win32 API will
 134                probably fail with FileNotFoundException, which is expected
 135             */
 136             pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
 137             if (pathbuf != 0) {
 138                 wcscpy(pathbuf, path);
 139             }
 140         }
 141         free(abpath);
 142     }
 143     return pathbuf;
 144 }
 145 
 146 /* If this returns NULL then an exception is pending */
 147 WCHAR*
 148 pathToNTPath(JNIEnv *env, jstring path, jboolean throwFNFE) {
 149     int pathlen = 0;
 150     WCHAR *pathbuf = NULL;
 151     int max_path = 248; /* CreateDirectoryW() has the limit of 248 */
 152 
 153     WITH_UNICODE_STRING(env, path, ps) {
 154         pathlen = (int)wcslen(ps);
 155         if (pathlen != 0) {
 156             if (pathlen > 2 &&
 157                 (ps[0] == L'\\' && ps[1] == L'\\' ||   //UNC
 158                  ps[1] == L':' && ps[2] == L'\\'))     //absolute
 159             {
 160                  if (pathlen > max_path - 1) {
 161                      pathbuf = prefixAbpath(ps, pathlen, pathlen);
 162                  } else {
 163                      pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
 164                      if (pathbuf != 0) {
 165                          wcscpy(pathbuf, ps);
 166                      }
 167                  }
 168             } else {
 169                 /* If the path came in as a relative path, need to verify if
 170                    its absolute form is bigger than max_path or not, if yes
 171                    need to (1)convert it to absolute and (2)prefix. This is
 172                    obviously a burden to all relative paths (The current dir/len
 173                    for "drive & directory" relative path is cached, so we only
 174                    calculate it once but for "drive-relative path we call
 175                    _wgetdcwd() and wcslen() everytime), but a hit we have
 176                    to take if we want to support relative path beyond max_path.
 177                    There is no way to predict how long the absolute path will be
 178                    (therefor allocate the sufficient memory block) before calling
 179                    _wfullpath(), we have to get the length of "current" dir first.
 180                 */
 181                 WCHAR *abpath = NULL;
 182                 int dirlen = currentDirLength(ps, pathlen);
 183                 if (dirlen + pathlen + 1 > max_path - 1) {
 184                     pathbuf = prefixAbpath(ps, pathlen, dirlen + pathlen);
 185                 } else {
 186                     pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
 187                     if (pathbuf != 0) {
 188                         wcscpy(pathbuf, ps);
 189                     }
 190                 }
 191             }
 192         }
 193     } END_UNICODE_STRING(env, ps);
 194 
 195     if (pathlen == 0) {
 196         if (throwFNFE == JNI_TRUE) {
 197             throwFileNotFoundException(env, path);
 198             return NULL;
 199         } else {
 200             pathbuf = (WCHAR*)malloc(sizeof(WCHAR));
 201             pathbuf[0] = L'\0';
 202         }
 203     }
 204     if (pathbuf == 0) {
 205         JNU_ThrowOutOfMemoryError(env, 0);
 206         return NULL;
 207     }
 208     return pathbuf;
 209 }
 210 
 211 jlong
 212 winFileHandleOpen(JNIEnv *env, jstring path, int flags)
 213 {
 214     const DWORD access =
 215         (flags & O_WRONLY) ?  GENERIC_WRITE :
 216         (flags & O_RDWR)   ? (GENERIC_READ | GENERIC_WRITE) :
 217         GENERIC_READ;
 218     const DWORD sharing =
 219         FILE_SHARE_READ | FILE_SHARE_WRITE;
 220     const DWORD disposition =
 221         /* Note: O_TRUNC overrides O_CREAT */
 222         (flags & O_TRUNC) ? CREATE_ALWAYS :
 223         (flags & O_CREAT) ? OPEN_ALWAYS   :
 224         OPEN_EXISTING;
 225     const DWORD  maybeWriteThrough =
 226         (flags & (O_SYNC | O_DSYNC)) ?
 227         FILE_FLAG_WRITE_THROUGH :
 228         FILE_ATTRIBUTE_NORMAL;
 229     const DWORD maybeDeleteOnClose =
 230         (flags & O_TEMPORARY) ?
 231         FILE_FLAG_DELETE_ON_CLOSE :
 232         FILE_ATTRIBUTE_NORMAL;
 233     const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
 234     HANDLE h = NULL;
 235 
 236     WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE);
 237     if (pathbuf == NULL) {
 238         /* Exception already pending */
 239         return -1;
 240     }
 241     h = CreateFileW(
 242         pathbuf,            /* Wide char path name */
 243         access,             /* Read and/or write permission */
 244         sharing,            /* File sharing flags */
 245         NULL,               /* Security attributes */
 246         disposition,        /* creation disposition */
 247         flagsAndAttributes, /* flags and attributes */
 248         NULL);
 249     free(pathbuf);
 250 
 251     if (h == INVALID_HANDLE_VALUE) {
 252         int error = GetLastError();
 253         if (error == ERROR_TOO_MANY_OPEN_FILES) {
 254             JNU_ThrowByName(env, JNU_JAVAIOPKG "IOException",
 255                             "Too many open files");
 256             return -1;
 257         }
 258         throwFileNotFoundException(env, path);
 259         return -1;
 260     }
 261     return (jlong) h;
 262 }
 263 
 264 void
 265 fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
 266 {
 267     jlong h = winFileHandleOpen(env, path, flags);
 268     if (h >= 0) {
 269         SET_FD(this, h, fid);
 270     }
 271 }
 272 
 273 /* These are functions that use a handle fd instead of the
 274    old C style int fd as is used in HPI layer */
 275 
 276 static int
 277 handleNonSeekAvailable(jlong, long *);
 278 static int
 279 handleStdinAvailable(jlong, long *);
 280 
 281 int
 282 handleAvailable(jlong fd, jlong *pbytes) {
 283     HANDLE h = (HANDLE)fd;
 284     DWORD type = 0;
 285 
 286     type = GetFileType(h);
 287     /* Handle is for keyboard or pipe */
 288     if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) {
 289         int ret;
 290         long lpbytes;
 291         HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE);
 292         if (stdInHandle == h) {
 293             ret = handleStdinAvailable(fd, &lpbytes); /* keyboard */
 294         } else {
 295             ret = handleNonSeekAvailable(fd, &lpbytes); /* pipe */
 296         }
 297         (*pbytes) = (jlong)(lpbytes);
 298         return ret;
 299     }
 300     /* Handle is for regular file */
 301     if (type == FILE_TYPE_DISK) {
 302         jlong current, end;
 303 
 304         LARGE_INTEGER filesize;
 305         current = handleLseek(fd, 0, SEEK_CUR);
 306         if (current < 0) {
 307             return FALSE;
 308         }
 309         if (GetFileSizeEx(h, &filesize) == 0) {
 310             return FALSE;
 311         }
 312         end = long_to_jlong(filesize.QuadPart);
 313         *pbytes = end - current;
 314         return TRUE;
 315     }
 316     return FALSE;
 317 }
 318 
 319 static int
 320 handleNonSeekAvailable(jlong fd, long *pbytes) {
 321     /* This is used for available on non-seekable devices
 322      * (like both named and anonymous pipes, such as pipes
 323      *  connected to an exec'd process).
 324      * Standard Input is a special case.
 325      *
 326      */
 327     HANDLE han;
 328 
 329     if ((han = (HANDLE) fd) == INVALID_HANDLE_VALUE) {
 330         return FALSE;
 331     }
 332 
 333     if (! PeekNamedPipe(han, NULL, 0, NULL, pbytes, NULL)) {
 334         /* PeekNamedPipe fails when at EOF.  In that case we
 335          * simply make *pbytes = 0 which is consistent with the
 336          * behavior we get on Solaris when an fd is at EOF.
 337          * The only alternative is to raise and Exception,
 338          * which isn't really warranted.
 339          */
 340         if (GetLastError() != ERROR_BROKEN_PIPE) {
 341             return FALSE;
 342         }
 343         *pbytes = 0;
 344     }
 345     return TRUE;
 346 }
 347 
 348 static int
 349 handleStdinAvailable(jlong fd, long *pbytes) {
 350     HANDLE han;
 351     DWORD numEventsRead = 0;    /* Number of events read from buffer */
 352     DWORD numEvents = 0;        /* Number of events in buffer */
 353     DWORD i = 0;                /* Loop index */
 354     DWORD curLength = 0;        /* Position marker */
 355     DWORD actualLength = 0;     /* Number of bytes readable */
 356     BOOL error = FALSE;         /* Error holder */
 357     INPUT_RECORD *lpBuffer;     /* Pointer to records of input events */
 358     DWORD bufferSize = 0;
 359 
 360     if ((han = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
 361         return FALSE;
 362     }
 363 
 364     /* Construct an array of input records in the console buffer */
 365     error = GetNumberOfConsoleInputEvents(han, &numEvents);
 366     if (error == 0) {
 367         return handleNonSeekAvailable(fd, pbytes);
 368     }
 369 
 370     /* lpBuffer must fit into 64K or else PeekConsoleInput fails */
 371     if (numEvents > MAX_INPUT_EVENTS) {
 372         numEvents = MAX_INPUT_EVENTS;
 373     }
 374 
 375     bufferSize = numEvents * sizeof(INPUT_RECORD);
 376     if (bufferSize == 0)
 377         bufferSize = 1;
 378     lpBuffer = malloc(bufferSize);
 379     if (lpBuffer == NULL) {
 380         return FALSE;
 381     }
 382 
 383     error = PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead);
 384     if (error == 0) {
 385         free(lpBuffer);
 386         return FALSE;
 387     }
 388 
 389     /* Examine input records for the number of bytes available */
 390     for(i=0; i<numEvents; i++) {
 391         if (lpBuffer[i].EventType == KEY_EVENT) {
 392             KEY_EVENT_RECORD *keyRecord = (KEY_EVENT_RECORD *)
 393                                           &(lpBuffer[i].Event);
 394             if (keyRecord->bKeyDown == TRUE) {
 395                 CHAR *keyPressed = (CHAR *) &(keyRecord->uChar);
 396                 curLength++;
 397                 if (*keyPressed == '\r')
 398                     actualLength = curLength;
 399             }
 400         }
 401     }
 402     if(lpBuffer != NULL)
 403         free(lpBuffer);
 404     *pbytes = (long) actualLength;
 405     return TRUE;
 406 }
 407 
 408 /*
 409  * This is documented to succeed on read-only files, but Win32's
 410  * FlushFileBuffers functions fails with "access denied" in such a
 411  * case.  So we only signal an error if the error is *not* "access
 412  * denied".
 413  */
 414 
 415 JNIEXPORT int
 416 handleSync(jlong fd) {
 417     /*
 418      * From the documentation:
 419      *
 420      *     On Windows NT, the function FlushFileBuffers fails if hFile
 421      *     is a handle to console output. That is because console
 422      *     output is not buffered. The function returns FALSE, and
 423      *     GetLastError returns ERROR_INVALID_HANDLE.
 424      *
 425      * On the other hand, on Win95, it returns without error.  I cannot
 426      * assume that 0, 1, and 2 are console, because if someone closes
 427      * System.out and then opens a file, they might get file descriptor
 428      * 1.  An error on *that* version of 1 should be reported, whereas
 429      * an error on System.out (which was the original 1) should be
 430      * ignored.  So I use isatty() to ensure that such an error was due
 431      * to this bogosity, and if it was, I ignore the error.
 432      */
 433 
 434     HANDLE handle = (HANDLE)fd;
 435 
 436     if (!FlushFileBuffers(handle)) {
 437         if (GetLastError() != ERROR_ACCESS_DENIED) {    /* from winerror.h */
 438             return -1;
 439         }
 440     }
 441     return 0;
 442 }
 443 
 444 
 445 int
 446 handleSetLength(jlong fd, jlong length) {
 447     HANDLE h = (HANDLE)fd;
 448     long high = (long)(length >> 32);
 449     DWORD ret;
 450 
 451     if (h == (HANDLE)(-1)) return -1;
 452     ret = SetFilePointer(h, (long)(length), &high, FILE_BEGIN);
 453     if (ret == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
 454         return -1;
 455     }
 456     if (SetEndOfFile(h) == FALSE) return -1;
 457     return 0;
 458 }
 459 
 460 JNIEXPORT
 461 jint
 462 handleRead(jlong fd, void *buf, jint len)
 463 {
 464     DWORD read = 0;
 465     BOOL result = 0;
 466     HANDLE h = (HANDLE)fd;
 467     if (h == INVALID_HANDLE_VALUE) {
 468         return -1;
 469     }
 470     result = ReadFile(h,          /* File handle to read */
 471                       buf,        /* address to put data */
 472                       len,        /* number of bytes to read */
 473                       &read,      /* number of bytes read */
 474                       NULL);      /* no overlapped struct */
 475     if (result == 0) {
 476         int error = GetLastError();
 477         if (error == ERROR_BROKEN_PIPE) {
 478             return 0; /* EOF */
 479         }
 480         return -1;
 481     }
 482     return (jint)read;
 483 }
 484 
 485 static jint writeInternal(jlong fd, const void *buf, jint len, jboolean append)
 486 {
 487     BOOL result = 0;
 488     DWORD written = 0;
 489     HANDLE h = (HANDLE)fd;
 490     if (h != INVALID_HANDLE_VALUE) {
 491         OVERLAPPED ov;
 492         LPOVERLAPPED lpOv;
 493         if (append == JNI_TRUE) {
 494             ov.Offset = (DWORD)0xFFFFFFFF;
 495             ov.OffsetHigh = (DWORD)0xFFFFFFFF;
 496             ov.hEvent = NULL;
 497             lpOv = &ov;
 498         } else {
 499             lpOv = NULL;
 500         }
 501         result = WriteFile(h,                /* File handle to write */
 502                            buf,              /* pointers to the buffers */
 503                            len,              /* number of bytes to write */
 504                            &written,         /* receives number of bytes written */
 505                            lpOv);            /* overlapped struct */
 506     }
 507     if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
 508         return -1;
 509     }
 510     return (jint)written;
 511 }
 512 
 513 JNIEXPORT
 514 jint handleWrite(jlong fd, const void *buf, jint len) {
 515     return writeInternal(fd, buf, len, JNI_FALSE);
 516 }
 517 
 518 JNIEXPORT
 519 jint handleAppend(jlong fd, const void *buf, jint len) {
 520     return writeInternal(fd, buf, len, JNI_TRUE);
 521 }
 522 
 523 jint
 524 handleClose(JNIEnv *env, jobject this, jfieldID fid)
 525 {
 526     FD fd = GET_FD(this, fid);
 527     HANDLE h = (HANDLE)fd;
 528 
 529     if (h == INVALID_HANDLE_VALUE) {
 530         return 0;
 531     }
 532 
 533     /* Set the fd to -1 before closing it so that the timing window
 534      * of other threads using the wrong fd (closed but recycled fd,
 535      * that gets re-opened with some other filename) is reduced.
 536      * Practically the chance of its occurance is low, however, we are
 537      * taking extra precaution over here.
 538      */
 539     SET_FD(this, -1, fid);
 540 
 541     if (CloseHandle(h) == 0) { /* Returns zero on failure */
 542         JNU_ThrowIOExceptionWithLastError(env, "close failed");
 543     }
 544     return 0;
 545 }
 546 
 547 jlong
 548 handleLseek(jlong fd, jlong offset, jint whence)
 549 {
 550     LARGE_INTEGER pos, distance;
 551     DWORD lowPos = 0;
 552     long highPos = 0;
 553     DWORD op = FILE_CURRENT;
 554     HANDLE h = (HANDLE)fd;
 555 
 556     if (whence == SEEK_END) {
 557         op = FILE_END;
 558     }
 559     if (whence == SEEK_CUR) {
 560         op = FILE_CURRENT;
 561     }
 562     if (whence == SEEK_SET) {
 563         op = FILE_BEGIN;
 564     }
 565 
 566     distance.QuadPart = offset;
 567     if (SetFilePointerEx(h, distance, &pos, op) == 0) {
 568         return -1;
 569     }
 570     return long_to_jlong(pos.QuadPart);
 571 }