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