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