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