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 #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 } 169 } 170 } else { 171 /* If the path came in as a relative path, need to verify if 172 its absolute form is bigger than max_path or not, if yes 173 need to (1)convert it to absolute and (2)prefix. This is 174 obviously a burden to all relative paths (The current dir/len 175 for "drive & directory" relative path is cached, so we only 176 calculate it once but for "drive-relative path we call 177 _wgetdcwd() and wcslen() everytime), but a hit we have 178 to take if we want to support relative path beyond max_path. 179 There is no way to predict how long the absolute path will be 180 (therefor allocate the sufficient memory block) before calling 181 _wfullpath(), we have to get the length of "current" dir first. 182 */ 183 WCHAR *abpath = NULL; 184 int dirlen = currentDirLength(ps, pathlen); 185 if (dirlen + pathlen + 1 > max_path - 1) { 186 pathbuf = prefixAbpath(ps, pathlen, dirlen + pathlen); 187 } else { 188 pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); 189 if (pathbuf != 0) { 190 wcscpy(pathbuf, ps); 191 } 192 } 193 } 194 } 195 } END_UNICODE_STRING(env, ps); 196 197 if (pathlen == 0) { 198 if (throwFNFE == JNI_TRUE) { 199 throwFileNotFoundException(env, path); 200 return NULL; 201 } else { 202 pathbuf = (WCHAR*)malloc(sizeof(WCHAR)); 203 pathbuf[0] = L'\0'; 204 } 205 } 206 if (pathbuf == 0) { 207 JNU_ThrowOutOfMemoryError(env, 0); 208 return NULL; 209 } 210 return pathbuf; 211 } 212 213 FD 214 winFileHandleOpen(JNIEnv *env, jstring path, int flags) 215 { 216 const DWORD access = 217 (flags & O_WRONLY) ? GENERIC_WRITE : 218 (flags & O_RDWR) ? (GENERIC_READ | GENERIC_WRITE) : 219 GENERIC_READ; 220 const DWORD sharing = 221 FILE_SHARE_READ | FILE_SHARE_WRITE; 222 const DWORD disposition = 223 /* Note: O_TRUNC overrides O_CREAT */ 224 (flags & O_TRUNC) ? CREATE_ALWAYS : 225 (flags & O_CREAT) ? OPEN_ALWAYS : 226 OPEN_EXISTING; 227 const DWORD maybeWriteThrough = 228 (flags & (O_SYNC | O_DSYNC)) ? 229 FILE_FLAG_WRITE_THROUGH : 230 FILE_ATTRIBUTE_NORMAL; 231 const DWORD maybeDeleteOnClose = 232 (flags & O_TEMPORARY) ? 233 FILE_FLAG_DELETE_ON_CLOSE : 234 FILE_ATTRIBUTE_NORMAL; 235 const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose; 236 HANDLE h = NULL; 237 238 WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE); 239 if (pathbuf == NULL) { 240 /* Exception already pending */ 241 return -1; 242 } 243 h = CreateFileW( 244 pathbuf, /* Wide char path name */ 245 access, /* Read and/or write permission */ 246 sharing, /* File sharing flags */ 247 NULL, /* Security attributes */ 248 disposition, /* creation disposition */ 249 flagsAndAttributes, /* flags and attributes */ 250 NULL); 251 free(pathbuf); 252 253 if (h == INVALID_HANDLE_VALUE) { 254 int error = GetLastError(); 255 if (error == ERROR_TOO_MANY_OPEN_FILES) { 256 JNU_ThrowByName(env, JNU_JAVAIOPKG "IOException", 257 "Too many open files"); 258 return -1; 259 } 260 throwFileNotFoundException(env, path); 261 return -1; 262 } 263 return (jlong) h; 264 } 265 266 void 267 fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags) 268 { 269 FD h = winFileHandleOpen(env, path, flags); 270 if (h >= 0) { 271 SET_FD(this, h, fid); 272 } 273 } 274 275 /* These are functions that use a handle fd instead of the 276 old C style int fd as is used in HPI layer */ 277 278 static int 279 handleNonSeekAvailable(FD, long *); 280 static int 281 handleStdinAvailable(FD, long *); 282 283 int 284 handleAvailable(FD fd, jlong *pbytes) { 285 HANDLE h = (HANDLE)fd; 286 DWORD type = 0; 287 288 type = GetFileType(h); 289 /* Handle is for keyboard or pipe */ 290 if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) { 291 int ret; 292 long lpbytes; 293 HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE); 294 if (stdInHandle == h) { 295 ret = handleStdinAvailable(fd, &lpbytes); /* keyboard */ 296 } else { 297 ret = handleNonSeekAvailable(fd, &lpbytes); /* pipe */ 298 } 299 (*pbytes) = (jlong)(lpbytes); 300 return ret; 301 } 302 /* Handle is for regular file */ 303 if (type == FILE_TYPE_DISK) { 304 jlong current, end; 305 306 LARGE_INTEGER filesize; 307 current = handleLseek(fd, 0, SEEK_CUR); 308 if (current < 0) { 309 return FALSE; 310 } 311 if (GetFileSizeEx(h, &filesize) == 0) { 312 return FALSE; 313 } 314 end = long_to_jlong(filesize.QuadPart); 315 *pbytes = end - current; 316 return TRUE; 317 } 318 return FALSE; 319 } 320 321 static int 322 handleNonSeekAvailable(FD fd, long *pbytes) { 323 /* This is used for available on non-seekable devices 324 * (like both named and anonymous pipes, such as pipes 325 * connected to an exec'd process). 326 * Standard Input is a special case. 327 * 328 */ 329 HANDLE han; 330 331 if ((han = (HANDLE) fd) == INVALID_HANDLE_VALUE) { 332 return FALSE; 333 } 334 335 if (! PeekNamedPipe(han, NULL, 0, NULL, pbytes, NULL)) { 336 /* PeekNamedPipe fails when at EOF. In that case we 337 * simply make *pbytes = 0 which is consistent with the 338 * behavior we get on Solaris when an fd is at EOF. 339 * The only alternative is to raise and Exception, 340 * which isn't really warranted. 341 */ 342 if (GetLastError() != ERROR_BROKEN_PIPE) { 343 return FALSE; 344 } 345 *pbytes = 0; 346 } 347 return TRUE; 348 } 349 350 static int 351 handleStdinAvailable(FD fd, long *pbytes) { 352 HANDLE han; 353 DWORD numEventsRead = 0; /* Number of events read from buffer */ 354 DWORD numEvents = 0; /* Number of events in buffer */ 355 DWORD i = 0; /* Loop index */ 356 DWORD curLength = 0; /* Position marker */ 357 DWORD actualLength = 0; /* Number of bytes readable */ 358 BOOL error = FALSE; /* Error holder */ 359 INPUT_RECORD *lpBuffer; /* Pointer to records of input events */ 360 DWORD bufferSize = 0; 361 362 if ((han = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { 363 return FALSE; 364 } 365 366 /* Construct an array of input records in the console buffer */ 367 error = GetNumberOfConsoleInputEvents(han, &numEvents); 368 if (error == 0) { 369 return handleNonSeekAvailable(fd, pbytes); 370 } 371 372 /* lpBuffer must fit into 64K or else PeekConsoleInput fails */ 373 if (numEvents > MAX_INPUT_EVENTS) { 374 numEvents = MAX_INPUT_EVENTS; 375 } 376 377 bufferSize = numEvents * sizeof(INPUT_RECORD); 378 if (bufferSize == 0) 379 bufferSize = 1; 380 lpBuffer = malloc(bufferSize); 381 if (lpBuffer == NULL) { 382 return FALSE; 383 } 384 385 error = PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead); 386 if (error == 0) { 387 free(lpBuffer); 388 return FALSE; 389 } 390 391 /* Examine input records for the number of bytes available */ 392 for(i=0; i<numEvents; i++) { 393 if (lpBuffer[i].EventType == KEY_EVENT) { 394 KEY_EVENT_RECORD *keyRecord = (KEY_EVENT_RECORD *) 395 &(lpBuffer[i].Event); 396 if (keyRecord->bKeyDown == TRUE) { 397 CHAR *keyPressed = (CHAR *) &(keyRecord->uChar); 398 curLength++; 399 if (*keyPressed == '\r') 400 actualLength = curLength; 401 } 402 } 403 } 404 if(lpBuffer != NULL) 405 free(lpBuffer); 406 *pbytes = (long) actualLength; 407 return TRUE; 408 } 409 410 /* 411 * This is documented to succeed on read-only files, but Win32's 412 * FlushFileBuffers functions fails with "access denied" in such a 413 * case. So we only signal an error if the error is *not* "access 414 * denied". 415 */ 416 417 int 418 handleSync(FD fd) { 419 /* 420 * From the documentation: 421 * 422 * On Windows NT, the function FlushFileBuffers fails if hFile 423 * is a handle to console output. That is because console 424 * output is not buffered. The function returns FALSE, and 425 * GetLastError returns ERROR_INVALID_HANDLE. 426 * 427 * On the other hand, on Win95, it returns without error. I cannot 428 * assume that 0, 1, and 2 are console, because if someone closes 429 * System.out and then opens a file, they might get file descriptor 430 * 1. An error on *that* version of 1 should be reported, whereas 431 * an error on System.out (which was the original 1) should be 432 * ignored. So I use isatty() to ensure that such an error was due 433 * to this bogosity, and if it was, I ignore the error. 434 */ 435 436 HANDLE handle = (HANDLE)fd; 437 438 if (!FlushFileBuffers(handle)) { 439 if (GetLastError() != ERROR_ACCESS_DENIED) { /* from winerror.h */ 440 return -1; 441 } 442 } 443 return 0; 444 } 445 446 447 int 448 handleSetLength(FD fd, jlong length) { 449 HANDLE h = (HANDLE)fd; 450 long high = (long)(length >> 32); 451 DWORD ret; 452 453 if (h == (HANDLE)(-1)) return -1; 454 ret = SetFilePointer(h, (long)(length), &high, FILE_BEGIN); 455 if (ret == 0xFFFFFFFF && GetLastError() != NO_ERROR) { 456 return -1; 457 } 458 if (SetEndOfFile(h) == FALSE) return -1; 459 return 0; 460 } 461 462 JNIEXPORT 463 jint 464 handleRead(FD fd, void *buf, jint len) 465 { 466 DWORD read = 0; 467 BOOL result = 0; 468 HANDLE h = (HANDLE)fd; 469 if (h == INVALID_HANDLE_VALUE) { 470 return -1; 471 } 472 result = ReadFile(h, /* File handle to read */ 473 buf, /* address to put data */ 474 len, /* number of bytes to read */ 475 &read, /* number of bytes read */ 476 NULL); /* no overlapped struct */ 477 if (result == 0) { 478 int error = GetLastError(); 479 if (error == ERROR_BROKEN_PIPE) { 480 return 0; /* EOF */ 481 } 482 return -1; 483 } 484 return (jint)read; 485 } 486 487 static jint writeInternal(FD fd, const void *buf, jint len, jboolean append) 488 { 489 BOOL result = 0; 490 DWORD written = 0; 491 HANDLE h = (HANDLE)fd; 492 if (h != INVALID_HANDLE_VALUE) { 493 OVERLAPPED ov; 494 LPOVERLAPPED lpOv; 495 if (append == JNI_TRUE) { 496 ov.Offset = (DWORD)0xFFFFFFFF; 497 ov.OffsetHigh = (DWORD)0xFFFFFFFF; 498 ov.hEvent = NULL; 499 lpOv = &ov; 500 } else { 501 lpOv = NULL; 502 } 503 result = WriteFile(h, /* File handle to write */ 504 buf, /* pointers to the buffers */ 505 len, /* number of bytes to write */ 506 &written, /* receives number of bytes written */ 507 lpOv); /* overlapped struct */ 508 } 509 if ((h == INVALID_HANDLE_VALUE) || (result == 0)) { 510 return -1; 511 } 512 return (jint)written; 513 } 514 515 jint handleWrite(FD fd, const void *buf, jint len) { 516 return writeInternal(fd, buf, len, JNI_FALSE); 517 } 518 519 jint handleAppend(FD 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(FD 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 } 572 573 size_t 574 getLastErrorString(char *utf8_jvmErrorMsg, size_t cbErrorMsg) 575 { 576 size_t n = 0; 577 if (cbErrorMsg > 0) { 578 BOOLEAN noError = FALSE; 579 WCHAR *utf16_osErrorMsg = (WCHAR *)malloc(cbErrorMsg*sizeof(WCHAR)); 580 if (utf16_osErrorMsg == NULL) { 581 // OOM accident 582 strncpy(utf8_jvmErrorMsg, "Out of memory", cbErrorMsg); 583 // truncate if too long 584 utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0'; 585 n = strlen(utf8_jvmErrorMsg); 586 } else { 587 DWORD errval = GetLastError(); 588 if (errval != 0) { 589 // WIN32 error 590 n = (size_t)FormatMessageW( 591 FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 592 NULL, 593 errval, 594 0, 595 utf16_osErrorMsg, 596 (DWORD)cbErrorMsg, 597 NULL); 598 if (n > 3) { 599 // Drop final '.', CR, LF 600 if (utf16_osErrorMsg[n - 1] == L'\n') --n; 601 if (utf16_osErrorMsg[n - 1] == L'\r') --n; 602 if (utf16_osErrorMsg[n - 1] == L'.') --n; 603 utf16_osErrorMsg[n] = L'\0'; 604 } 605 } else if (errno != 0) { 606 // C runtime error that has no corresponding WIN32 error code 607 const WCHAR *rtError = _wcserror(errno); 608 if (rtError != NULL) { 609 wcsncpy(utf16_osErrorMsg, rtError, cbErrorMsg); 610 // truncate if too long 611 utf16_osErrorMsg[cbErrorMsg - 1] = L'\0'; 612 n = wcslen(utf16_osErrorMsg); 613 } 614 } else 615 noError = TRUE; //OS has no error to report 616 617 if (!noError) { 618 if (n > 0) { 619 n = WideCharToMultiByte( 620 CP_UTF8, 621 0, 622 utf16_osErrorMsg, 623 n, 624 utf8_jvmErrorMsg, 625 cbErrorMsg, 626 NULL, 627 NULL); 628 629 // no way to die 630 if (n > 0) 631 utf8_jvmErrorMsg[min(cbErrorMsg - 1, n)] = '\0'; 632 } 633 634 if (n <= 0) { 635 strncpy(utf8_jvmErrorMsg, "Secondary error while OS message extraction", cbErrorMsg); 636 // truncate if too long 637 utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0'; 638 n = strlen(utf8_jvmErrorMsg); 639 } 640 } 641 free(utf16_osErrorMsg); 642 } 643 } 644 return n; 645 }