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