1 /* 2 * Copyright (c) 2001, 2018, 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 } else { 169 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed"); 170 return NULL; 171 } 172 } 173 } else { 174 /* If the path came in as a relative path, need to verify if 175 its absolute form is bigger than max_path or not, if yes 176 need to (1)convert it to absolute and (2)prefix. This is 177 obviously a burden to all relative paths (The current dir/len 178 for "drive & directory" relative path is cached, so we only 179 calculate it once but for "drive-relative path we call 180 _wgetdcwd() and wcslen() everytime), but a hit we have 181 to take if we want to support relative path beyond max_path. 182 There is no way to predict how long the absolute path will be 183 (therefor allocate the sufficient memory block) before calling 184 _wfullpath(), we have to get the length of "current" dir first. 185 */ 186 WCHAR *abpath = NULL; 187 int dirlen = currentDirLength(ps, pathlen); 188 if (dirlen + pathlen + 1 > max_path - 1) { 189 pathbuf = prefixAbpath(ps, pathlen, dirlen + pathlen); 190 } else { 191 pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); 192 if (pathbuf != 0) { 193 wcscpy(pathbuf, ps); 194 } else { 195 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed"); 196 return NULL; 197 } 198 } 199 } 200 } 201 } END_UNICODE_STRING(env, ps); 202 203 if (pathlen == 0) { 204 if (throwFNFE == JNI_TRUE) { 205 if (!(*env)->ExceptionCheck(env)) { 206 throwFileNotFoundException(env, path); 207 } 208 return NULL; 209 } else { 210 pathbuf = (WCHAR*)malloc(sizeof(WCHAR)); 211 if (pathbuf != NULL) { 212 pathbuf[0] = L'\0'; 213 } else { 214 JNU_ThrowOutOfMemoryError(env, 0); 215 return NULL; 216 } 217 } 218 } 219 if (pathbuf == 0) { 220 JNU_ThrowOutOfMemoryError(env, 0); 221 return NULL; 222 } 223 return pathbuf; 224 } 225 226 JNIEXPORT FD JNICALL 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 WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE); 252 if (pathbuf == NULL) { 253 /* Exception already pending */ 254 return -1; 255 } 256 h = CreateFileW( 257 pathbuf, /* Wide char path name */ 258 access, /* Read and/or write permission */ 259 sharing, /* File sharing flags */ 260 NULL, /* Security attributes */ 261 disposition, /* creation disposition */ 262 flagsAndAttributes, /* flags and attributes */ 263 NULL); 264 free(pathbuf); 265 266 if (h == INVALID_HANDLE_VALUE) { 267 throwFileNotFoundException(env, path); 268 return -1; 269 } 270 return (jlong) h; 271 } 272 273 void 274 fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags) 275 { 276 FD h = winFileHandleOpen(env, path, flags); 277 if (h >= 0) { 278 jobject fdobj; 279 jboolean append; 280 SET_FD(this, h, fid); 281 282 fdobj = (*env)->GetObjectField(env, this, fid); 283 if (fdobj != NULL) { 284 append = (flags & O_APPEND) == 0 ? JNI_FALSE : JNI_TRUE; 285 (*env)->SetBooleanField(env, fdobj, IO_append_fdID, append); 286 } 287 } 288 } 289 290 /* These are functions that use a handle fd instead of the 291 old C style int fd as is used in HPI layer */ 292 293 static int 294 handleNonSeekAvailable(FD, long *); 295 static int 296 handleStdinAvailable(FD, long *); 297 298 int 299 handleAvailable(FD fd, jlong *pbytes) { 300 HANDLE h = (HANDLE)fd; 301 DWORD type = 0; 302 303 type = GetFileType(h); 304 /* Handle is for keyboard or pipe */ 305 if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) { 306 int ret; 307 long lpbytes; 308 HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE); 309 if (stdInHandle == h) { 310 ret = handleStdinAvailable(fd, &lpbytes); /* keyboard */ 311 } else { 312 ret = handleNonSeekAvailable(fd, &lpbytes); /* pipe */ 313 } 314 (*pbytes) = (jlong)(lpbytes); 315 return ret; 316 } 317 /* Handle is for regular file */ 318 if (type == FILE_TYPE_DISK) { 319 jlong current, end; 320 321 LARGE_INTEGER filesize; 322 current = handleLseek(fd, 0, SEEK_CUR); 323 if (current < 0) { 324 return FALSE; 325 } 326 if (GetFileSizeEx(h, &filesize) == 0) { 327 return FALSE; 328 } 329 end = long_to_jlong(filesize.QuadPart); 330 *pbytes = end - current; 331 return TRUE; 332 } 333 return FALSE; 334 } 335 336 static int 337 handleNonSeekAvailable(FD fd, long *pbytes) { 338 /* This is used for available on non-seekable devices 339 * (like both named and anonymous pipes, such as pipes 340 * connected to an exec'd process). 341 * Standard Input is a special case. 342 * 343 */ 344 HANDLE han; 345 346 if ((han = (HANDLE) fd) == INVALID_HANDLE_VALUE) { 347 return FALSE; 348 } 349 350 if (! PeekNamedPipe(han, NULL, 0, NULL, pbytes, NULL)) { 351 /* PeekNamedPipe fails when at EOF. In that case we 352 * simply make *pbytes = 0 which is consistent with the 353 * behavior we get on Solaris when an fd is at EOF. 354 * The only alternative is to raise and Exception, 355 * which isn't really warranted. 356 */ 357 if (GetLastError() != ERROR_BROKEN_PIPE) { 358 return FALSE; 359 } 360 *pbytes = 0; 361 } 362 return TRUE; 363 } 364 365 static int 366 handleStdinAvailable(FD fd, long *pbytes) { 367 HANDLE han; 368 DWORD numEventsRead = 0; /* Number of events read from buffer */ 369 DWORD numEvents = 0; /* Number of events in buffer */ 370 DWORD i = 0; /* Loop index */ 371 DWORD curLength = 0; /* Position marker */ 372 DWORD actualLength = 0; /* Number of bytes readable */ 373 BOOL error = FALSE; /* Error holder */ 374 INPUT_RECORD *lpBuffer; /* Pointer to records of input events */ 375 DWORD bufferSize = 0; 376 377 if ((han = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { 378 return FALSE; 379 } 380 381 /* Construct an array of input records in the console buffer */ 382 error = GetNumberOfConsoleInputEvents(han, &numEvents); 383 if (error == 0) { 384 return handleNonSeekAvailable(fd, pbytes); 385 } 386 387 /* lpBuffer must fit into 64K or else PeekConsoleInput fails */ 388 if (numEvents > MAX_INPUT_EVENTS) { 389 numEvents = MAX_INPUT_EVENTS; 390 } 391 392 bufferSize = numEvents * sizeof(INPUT_RECORD); 393 if (bufferSize == 0) 394 bufferSize = 1; 395 lpBuffer = malloc(bufferSize); 396 if (lpBuffer == NULL) { 397 return FALSE; 398 } 399 400 error = PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead); 401 if (error == 0) { 402 free(lpBuffer); 403 return FALSE; 404 } 405 406 /* Examine input records for the number of bytes available */ 407 for(i=0; i<numEvents; i++) { 408 if (lpBuffer[i].EventType == KEY_EVENT) { 409 KEY_EVENT_RECORD *keyRecord = (KEY_EVENT_RECORD *) 410 &(lpBuffer[i].Event); 411 if (keyRecord->bKeyDown == TRUE) { 412 CHAR *keyPressed = (CHAR *) &(keyRecord->uChar); 413 curLength++; 414 if (*keyPressed == '\r') 415 actualLength = curLength; 416 } 417 } 418 } 419 if(lpBuffer != NULL) 420 free(lpBuffer); 421 *pbytes = (long) actualLength; 422 return TRUE; 423 } 424 425 /* 426 * This is documented to succeed on read-only files, but Win32's 427 * FlushFileBuffers functions fails with "access denied" in such a 428 * case. So we only signal an error if the error is *not* "access 429 * denied". 430 */ 431 432 int 433 handleSync(FD fd) { 434 /* 435 * From the documentation: 436 * 437 * On Windows NT, the function FlushFileBuffers fails if hFile 438 * is a handle to console output. That is because console 439 * output is not buffered. The function returns FALSE, and 440 * GetLastError returns ERROR_INVALID_HANDLE. 441 * 442 * On the other hand, on Win95, it returns without error. I cannot 443 * assume that 0, 1, and 2 are console, because if someone closes 444 * System.out and then opens a file, they might get file descriptor 445 * 1. An error on *that* version of 1 should be reported, whereas 446 * an error on System.out (which was the original 1) should be 447 * ignored. So I use isatty() to ensure that such an error was due 448 * to this bogosity, and if it was, I ignore the error. 449 */ 450 451 HANDLE handle = (HANDLE)fd; 452 453 if (!FlushFileBuffers(handle)) { 454 if (GetLastError() != ERROR_ACCESS_DENIED) { /* from winerror.h */ 455 return -1; 456 } 457 } 458 return 0; 459 } 460 461 462 int 463 handleSetLength(FD fd, jlong length) { 464 HANDLE h = (HANDLE)fd; 465 long high = (long)(length >> 32); 466 DWORD ret; 467 468 if (h == (HANDLE)(-1)) return -1; 469 ret = SetFilePointer(h, (long)(length), &high, FILE_BEGIN); 470 if (ret == 0xFFFFFFFF && GetLastError() != NO_ERROR) { 471 return -1; 472 } 473 if (SetEndOfFile(h) == FALSE) return -1; 474 return 0; 475 } 476 477 JNIEXPORT 478 jint 479 handleRead(FD fd, void *buf, jint len) 480 { 481 DWORD read = 0; 482 BOOL result = 0; 483 HANDLE h = (HANDLE)fd; 484 if (h == INVALID_HANDLE_VALUE) { 485 return -1; 486 } 487 result = ReadFile(h, /* File handle to read */ 488 buf, /* address to put data */ 489 len, /* number of bytes to read */ 490 &read, /* number of bytes read */ 491 NULL); /* no overlapped struct */ 492 if (result == 0) { 493 int error = GetLastError(); 494 if (error == ERROR_BROKEN_PIPE) { 495 return 0; /* EOF */ 496 } 497 return -1; 498 } 499 return (jint)read; 500 } 501 502 static jint writeInternal(FD fd, const void *buf, jint len, jboolean append) 503 { 504 BOOL result = 0; 505 DWORD written = 0; 506 HANDLE h = (HANDLE)fd; 507 if (h != INVALID_HANDLE_VALUE) { 508 OVERLAPPED ov; 509 LPOVERLAPPED lpOv; 510 if (append == JNI_TRUE) { 511 ov.Offset = (DWORD)0xFFFFFFFF; 512 ov.OffsetHigh = (DWORD)0xFFFFFFFF; 513 ov.hEvent = NULL; 514 lpOv = &ov; 515 } else { 516 lpOv = NULL; 517 } 518 result = WriteFile(h, /* File handle to write */ 519 buf, /* pointers to the buffers */ 520 len, /* number of bytes to write */ 521 &written, /* receives number of bytes written */ 522 lpOv); /* overlapped struct */ 523 } 524 if ((h == INVALID_HANDLE_VALUE) || (result == 0)) { 525 return -1; 526 } 527 return (jint)written; 528 } 529 530 jint handleWrite(FD fd, const void *buf, jint len) { 531 return writeInternal(fd, buf, len, JNI_FALSE); 532 } 533 534 jint handleAppend(FD fd, const void *buf, jint len) { 535 return writeInternal(fd, buf, len, JNI_TRUE); 536 } 537 538 void 539 handleClose(JNIEnv *env, jobject this, jfieldID fid) 540 { 541 jobject fileDescriptor = (*env)->GetObjectField(env, (this), (fid)); 542 if (fileDescriptor == NULL) { 543 return; 544 } 545 fileDescriptorClose(env, fileDescriptor); 546 } 547 548 // Function to close the fd held by this FileDescriptor and set fd to -1. 549 void 550 fileDescriptorClose(JNIEnv *env, jobject this) 551 { 552 FD fd = (*env)->GetLongField(env, this, IO_handle_fdID); 553 HANDLE h = (HANDLE)fd; 554 if ((*env)->ExceptionOccurred(env)) { 555 return; 556 } 557 558 if (h == INVALID_HANDLE_VALUE) { 559 return; 560 } 561 562 /* Set the fd to -1 before closing it so that the timing window 563 * of other threads using the wrong fd (closed but recycled fd, 564 * that gets re-opened with some other filename) is reduced. 565 * Practically the chance of its occurance is low, however, we are 566 * taking extra precaution over here. 567 */ 568 (*env)->SetLongField(env, this, IO_handle_fdID, -1); 569 if ((*env)->ExceptionOccurred(env)) { 570 return; 571 } 572 573 if (CloseHandle(h) == 0) { /* Returns zero on failure */ 574 JNU_ThrowIOExceptionWithLastError(env, "close failed"); 575 } 576 } 577 578 JNIEXPORT jlong JNICALL 579 handleLseek(FD fd, jlong offset, jint whence) 580 { 581 LARGE_INTEGER pos, distance; 582 DWORD lowPos = 0; 583 long highPos = 0; 584 DWORD op = FILE_CURRENT; 585 HANDLE h = (HANDLE)fd; 586 587 if (whence == SEEK_END) { 588 op = FILE_END; 589 } 590 if (whence == SEEK_CUR) { 591 op = FILE_CURRENT; 592 } 593 if (whence == SEEK_SET) { 594 op = FILE_BEGIN; 595 } 596 597 distance.QuadPart = offset; 598 if (SetFilePointerEx(h, distance, &pos, op) == 0) { 599 return -1; 600 } 601 return long_to_jlong(pos.QuadPart); 602 } 603 604 jlong 605 handleGetLength(FD fd) { 606 HANDLE h = (HANDLE) fd; 607 LARGE_INTEGER length; 608 if (GetFileSizeEx(h, &length) != 0) { 609 return long_to_jlong(length.QuadPart); 610 } else { 611 return -1; 612 } 613 }