1 /*
   2  * Copyright (c) 2001, 2013, 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 FD
 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     FD 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(FD, long *);
 278 static int
 279 handleStdinAvailable(FD, long *);
 280 
 281 int
 282 handleAvailable(FD 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(FD 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(FD 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 int
 416 handleSync(FD 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(FD 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(FD 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(FD 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 jint handleWrite(FD fd, const void *buf, jint len) {

 514     return writeInternal(fd, buf, len, JNI_FALSE);
 515 }
 516 
 517 jint handleAppend(FD fd, const void *buf, jint len) {

 518     return writeInternal(fd, buf, len, JNI_TRUE);
 519 }
 520 
 521 jint
 522 handleClose(JNIEnv *env, jobject this, jfieldID fid)
 523 {
 524     FD fd = GET_FD(this, fid);
 525     HANDLE h = (HANDLE)fd;
 526 
 527     if (h == INVALID_HANDLE_VALUE) {
 528         return 0;
 529     }
 530 
 531     /* Set the fd to -1 before closing it so that the timing window
 532      * of other threads using the wrong fd (closed but recycled fd,
 533      * that gets re-opened with some other filename) is reduced.
 534      * Practically the chance of its occurance is low, however, we are
 535      * taking extra precaution over here.
 536      */
 537     SET_FD(this, -1, fid);
 538 
 539     if (CloseHandle(h) == 0) { /* Returns zero on failure */
 540         JNU_ThrowIOExceptionWithLastError(env, "close failed");
 541     }
 542     return 0;
 543 }
 544 
 545 jlong
 546 handleLseek(FD fd, jlong offset, jint whence)
 547 {
 548     LARGE_INTEGER pos, distance;
 549     DWORD lowPos = 0;
 550     long highPos = 0;
 551     DWORD op = FILE_CURRENT;
 552     HANDLE h = (HANDLE)fd;
 553 
 554     if (whence == SEEK_END) {
 555         op = FILE_END;
 556     }
 557     if (whence == SEEK_CUR) {
 558         op = FILE_CURRENT;
 559     }
 560     if (whence == SEEK_SET) {
 561         op = FILE_BEGIN;
 562     }
 563 
 564     distance.QuadPart = offset;
 565     if (SetFilePointerEx(h, distance, &pos, op) == 0) {
 566         return -1;
 567     }
 568     return long_to_jlong(pos.QuadPart);
 569 }
 570 
 571 size_t
 572 getLastErrorString(char *buf, size_t len)
 573 {
 574     DWORD errval;
 575     if (len > 0) {
 576         if ((errval = GetLastError()) != 0) {
 577             // DOS error
 578             size_t n = (size_t)FormatMessage(
 579                 FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
 580                 NULL,
 581                 errval,
 582                 0,
 583                 buf,
 584                 (DWORD)len,
 585                 NULL);
 586             if (n > 3) {
 587                 // Drop final '.', CR, LF
 588                 if (buf[n - 1] == '\n') n--;
 589                 if (buf[n - 1] == '\r') n--;
 590                 if (buf[n - 1] == '.') n--;
 591                 buf[n] = '\0';
 592             }
 593             return n;
 594         }
 595 
 596         if (errno != 0) {
 597             // C runtime error that has no corresponding DOS error code
 598             const char *err = strerror(errno);
 599             size_t n = strlen(err);
 600             if (n >= len)
 601                 n = len - 1;
 602 
 603             strncpy(buf, err, n);
 604             buf[n] = '\0';
 605             return n;
 606         }
 607     }
 608 
 609     return 0;
 610 }
--- EOF ---