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