1 /* 2 * Copyright 2001-2008 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 /* Access APIs for Win2K and above */ 27 #ifndef _WIN32_WINNT 28 #define _WIN32_WINNT 0x0500 29 #endif 30 31 #include <assert.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <ctype.h> 35 #include <direct.h> 36 #include <windows.h> 37 #include <io.h> 38 39 #include "jvm.h" 40 #include "jni.h" 41 #include "jni_util.h" 42 #include "io_util.h" 43 #include "jlong.h" 44 #include "io_util_md.h" 45 #include "dirent_md.h" 46 #include "java_io_FileSystem.h" 47 48 #define MAX_PATH_LENGTH 1024 49 50 static struct { 51 jfieldID path; 52 } ids; 53 54 JNIEXPORT void JNICALL 55 Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls) 56 { 57 jclass fileClass = (*env)->FindClass(env, "java/io/File"); 58 if (!fileClass) return; 59 ids.path = 60 (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;"); 61 } 62 63 /* -- Path operations -- */ 64 65 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len); 66 extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len); 67 68 JNIEXPORT jstring JNICALL 69 Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this, 70 jstring pathname) 71 { 72 jstring rv = NULL; 73 WCHAR canonicalPath[MAX_PATH_LENGTH]; 74 75 WITH_UNICODE_STRING(env, pathname, path) { 76 /*we estimate the max length of memory needed as 77 "currentDir. length + pathname.length" 78 */ 79 int len = wcslen(path); 80 len += currentDirLength(path, len); 81 if (len > MAX_PATH_LENGTH - 1) { 82 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR)); 83 if (cp != NULL) { 84 if (wcanonicalize(path, cp, len) >= 0) { 85 rv = (*env)->NewString(env, cp, wcslen(cp)); 86 } 87 free(cp); 88 } 89 } else 90 if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) { 91 rv = (*env)->NewString(env, canonicalPath, wcslen(canonicalPath)); 92 } 93 } END_UNICODE_STRING(env, path); 94 if (rv == NULL) { 95 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname"); 96 } 97 return rv; 98 } 99 100 101 JNIEXPORT jstring JNICALL 102 Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this, 103 jstring canonicalPrefixString, 104 jstring pathWithCanonicalPrefixString) 105 { 106 jstring rv = NULL; 107 WCHAR canonicalPath[MAX_PATH_LENGTH]; 108 WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) { 109 WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) { 110 int len = wcslen(canonicalPrefix) + MAX_PATH; 111 if (len > MAX_PATH_LENGTH) { 112 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR)); 113 if (cp != NULL) { 114 if (wcanonicalizeWithPrefix(canonicalPrefix, 115 pathWithCanonicalPrefix, 116 cp, len) >= 0) { 117 rv = (*env)->NewString(env, cp, wcslen(cp)); 118 } 119 free(cp); 120 } 121 } else 122 if (wcanonicalizeWithPrefix(canonicalPrefix, 123 pathWithCanonicalPrefix, 124 canonicalPath, MAX_PATH_LENGTH) >= 0) { 125 rv = (*env)->NewString(env, canonicalPath, wcslen(canonicalPath)); 126 } 127 } END_UNICODE_STRING(env, pathWithCanonicalPrefix); 128 } END_UNICODE_STRING(env, canonicalPrefix); 129 if (rv == NULL) { 130 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname"); 131 } 132 return rv; 133 } 134 135 /* -- Attribute accessors -- */ 136 137 /* Check whether or not the file name in "path" is a Windows reserved 138 device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the 139 returned result from GetFullPathName, which should be in thr form of 140 "\\.\[ReservedDeviceName]" if the path represents a reserved device 141 name. 142 Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer 143 important anyway) is a device name, so we don't check it here. 144 GetFileAttributesEx will catch it later by returning 0 on NT/XP/ 145 200X. 146 147 Note2: Theoretically the implementation could just lookup the table 148 below linearly if the first 4 characters of the fullpath returned 149 from GetFullPathName are "\\.\". The current implementation should 150 achieve the same result. If Microsoft add more names into their 151 reserved device name repository in the future, which probably will 152 never happen, we will need to revisit the lookup implementation. 153 154 static WCHAR* ReservedDEviceNames[] = { 155 L"CON", L"PRN", L"AUX", L"NUL", 156 L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9", 157 L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9", 158 L"CLOCK$" 159 }; 160 */ 161 162 static BOOL isReservedDeviceNameW(WCHAR* path) { 163 #define BUFSIZE 9 164 WCHAR buf[BUFSIZE]; 165 WCHAR *lpf = NULL; 166 DWORD retLen = GetFullPathNameW(path, 167 BUFSIZE, 168 buf, 169 &lpf); 170 if ((retLen == BUFSIZE - 1 || retLen == BUFSIZE - 2) && 171 buf[0] == L'\\' && buf[1] == L'\\' && 172 buf[2] == L'.' && buf[3] == L'\\') { 173 WCHAR* dname = _wcsupr(buf + 4); 174 if (wcscmp(dname, L"CON") == 0 || 175 wcscmp(dname, L"PRN") == 0 || 176 wcscmp(dname, L"AUX") == 0 || 177 wcscmp(dname, L"NUL") == 0) 178 return TRUE; 179 if ((wcsncmp(dname, L"COM", 3) == 0 || 180 wcsncmp(dname, L"LPT", 3) == 0) && 181 dname[3] - L'0' > 0 && 182 dname[3] - L'0' <= 9) 183 return TRUE; 184 } 185 return FALSE; 186 } 187 188 JNIEXPORT jint JNICALL 189 Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this, 190 jobject file) 191 { 192 193 jint rv = 0; 194 jint pathlen; 195 196 /* both pagefile.sys and hiberfil.sys have length 12 */ 197 #define SPECIALFILE_NAMELEN 12 198 199 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 200 WIN32_FILE_ATTRIBUTE_DATA wfad; 201 if (pathbuf == NULL) 202 return rv; 203 if (!isReservedDeviceNameW(pathbuf)) { 204 if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) { 205 rv = (java_io_FileSystem_BA_EXISTS 206 | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 207 ? java_io_FileSystem_BA_DIRECTORY 208 : java_io_FileSystem_BA_REGULAR) 209 | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 210 ? java_io_FileSystem_BA_HIDDEN : 0)); 211 } else { /* pagefile.sys is a special case */ 212 if (GetLastError() == ERROR_SHARING_VIOLATION) { 213 rv = java_io_FileSystem_BA_EXISTS; 214 if ((pathlen = wcslen(pathbuf)) >= SPECIALFILE_NAMELEN && 215 (_wcsicmp(pathbuf + pathlen - SPECIALFILE_NAMELEN, 216 L"pagefile.sys") == 0) || 217 (_wcsicmp(pathbuf + pathlen - SPECIALFILE_NAMELEN, 218 L"hiberfil.sys") == 0)) 219 rv |= java_io_FileSystem_BA_REGULAR; 220 } 221 } 222 } 223 free(pathbuf); 224 return rv; 225 } 226 227 228 JNIEXPORT jboolean 229 JNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this, 230 jobject file, jint access) 231 { 232 DWORD attr; 233 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 234 if (pathbuf == NULL) 235 return JNI_FALSE; 236 attr = GetFileAttributesW(pathbuf); 237 free(pathbuf); 238 if (attr == INVALID_FILE_ATTRIBUTES) 239 return JNI_FALSE; 240 switch (access) { 241 case java_io_FileSystem_ACCESS_READ: 242 case java_io_FileSystem_ACCESS_EXECUTE: 243 return JNI_TRUE; 244 case java_io_FileSystem_ACCESS_WRITE: 245 /* Read-only attribute ignored on directories */ 246 if ((attr & FILE_ATTRIBUTE_DIRECTORY) || 247 (attr & FILE_ATTRIBUTE_READONLY) == 0) 248 return JNI_TRUE; 249 else 250 return JNI_FALSE; 251 default: 252 assert(0); 253 return JNI_FALSE; 254 } 255 } 256 257 JNIEXPORT jboolean JNICALL 258 Java_java_io_WinNTFileSystem_setPermission(JNIEnv *env, jobject this, 259 jobject file, 260 jint access, 261 jboolean enable, 262 jboolean owneronly) 263 { 264 jboolean rv = JNI_FALSE; 265 WCHAR *pathbuf; 266 DWORD a; 267 if (access == java_io_FileSystem_ACCESS_READ || 268 access == java_io_FileSystem_ACCESS_EXECUTE) { 269 return enable; 270 } 271 pathbuf = fileToNTPath(env, file, ids.path); 272 if (pathbuf == NULL) 273 return JNI_FALSE; 274 a = GetFileAttributesW(pathbuf); 275 if (a != INVALID_FILE_ATTRIBUTES) { 276 if (enable) 277 a = a & ~FILE_ATTRIBUTE_READONLY; 278 else 279 a = a | FILE_ATTRIBUTE_READONLY; 280 if (SetFileAttributesW(pathbuf, a)) 281 rv = JNI_TRUE; 282 } 283 free(pathbuf); 284 return rv; 285 } 286 287 JNIEXPORT jlong JNICALL 288 Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this, 289 jobject file) 290 { 291 jlong rv = 0; 292 LARGE_INTEGER modTime; 293 FILETIME t; 294 HANDLE h; 295 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 296 if (pathbuf == NULL) 297 return rv; 298 h = CreateFileW(pathbuf, 299 /* Device query access */ 300 0, 301 /* Share it */ 302 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 303 /* No security attributes */ 304 NULL, 305 /* Open existing or fail */ 306 OPEN_EXISTING, 307 /* Backup semantics for directories */ 308 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 309 /* No template file */ 310 NULL); 311 if (h != INVALID_HANDLE_VALUE) { 312 if (GetFileTime(h, NULL, NULL, &t)) { 313 modTime.LowPart = (DWORD) t.dwLowDateTime; 314 modTime.HighPart = (LONG) t.dwHighDateTime; 315 rv = modTime.QuadPart / 10000; 316 rv -= 11644473600000; 317 } 318 CloseHandle(h); 319 } 320 free(pathbuf); 321 return rv; 322 } 323 324 JNIEXPORT jlong JNICALL 325 Java_java_io_WinNTFileSystem_getLength(JNIEnv *env, jobject this, jobject file) 326 { 327 jlong rv = 0; 328 WIN32_FILE_ATTRIBUTE_DATA wfad; 329 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 330 if (pathbuf == NULL) 331 return rv; 332 if (GetFileAttributesExW(pathbuf, 333 GetFileExInfoStandard, 334 &wfad)) { 335 rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow; 336 } else { 337 if (GetLastError() == ERROR_SHARING_VIOLATION) { 338 /* The error is "share violation", which means the file/dir 339 must exists. Try _wstati64, we know this at least works 340 for pagefile.sys and hiberfil.sys. 341 */ 342 struct _stati64 sb; 343 if (_wstati64(pathbuf, &sb) == 0) { 344 rv = sb.st_size; 345 } 346 } 347 } 348 free(pathbuf); 349 return rv; 350 } 351 352 /* -- File operations -- */ 353 354 JNIEXPORT jboolean JNICALL 355 Java_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls, 356 jstring path) 357 { 358 HANDLE h = NULL; 359 WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE); 360 if (pathbuf == NULL) 361 return JNI_FALSE; 362 h = CreateFileW( 363 pathbuf, /* Wide char path name */ 364 GENERIC_READ | GENERIC_WRITE, /* Read and write permission */ 365 FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */ 366 NULL, /* Security attributes */ 367 CREATE_NEW, /* creation disposition */ 368 FILE_ATTRIBUTE_NORMAL, /* flags and attributes */ 369 NULL); 370 371 if (h == INVALID_HANDLE_VALUE) { 372 DWORD error = GetLastError(); 373 if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) { 374 375 // If a directory by the named path already exists, 376 // return false (behavior of solaris and linux) instead of 377 // throwing an exception 378 DWORD fattr = GetFileAttributesW(pathbuf); 379 if ((fattr == INVALID_FILE_ATTRIBUTES) || 380 (fattr & ~FILE_ATTRIBUTE_DIRECTORY)) { 381 SetLastError(error); 382 JNU_ThrowIOExceptionWithLastError(env, "Could not open file"); 383 } 384 } 385 free(pathbuf); 386 return JNI_FALSE; 387 } 388 free(pathbuf); 389 CloseHandle(h); 390 return JNI_TRUE; 391 } 392 393 static int 394 removeFileOrDirectory(const jchar *path) 395 { 396 /* Returns 0 on success */ 397 DWORD a; 398 399 SetFileAttributesW(path, 0); 400 a = GetFileAttributesW(path); 401 if (a == ((DWORD)-1)) { 402 return 1; 403 } else if (a & FILE_ATTRIBUTE_DIRECTORY) { 404 return !RemoveDirectoryW(path); 405 } else { 406 return !DeleteFileW(path); 407 } 408 } 409 410 JNIEXPORT jboolean JNICALL 411 Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file) 412 { 413 jboolean rv = JNI_FALSE; 414 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 415 if (pathbuf == NULL) { 416 return JNI_FALSE; 417 } 418 if (removeFileOrDirectory(pathbuf) == 0) { 419 rv = JNI_TRUE; 420 } 421 free(pathbuf); 422 return rv; 423 } 424 425 JNIEXPORT jobjectArray JNICALL 426 Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file) 427 { 428 WCHAR *search_path; 429 HANDLE handle; 430 WIN32_FIND_DATAW find_data; 431 int len, maxlen; 432 jobjectArray rv, old; 433 DWORD fattr; 434 jstring name; 435 436 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 437 if (pathbuf == NULL) 438 return NULL; 439 search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6); 440 if (search_path == 0) { 441 free (pathbuf); 442 errno = ENOMEM; 443 return NULL; 444 } 445 wcscpy(search_path, pathbuf); 446 free(pathbuf); 447 fattr = GetFileAttributesW(search_path); 448 if (fattr == INVALID_FILE_ATTRIBUTES) { 449 free(search_path); 450 return NULL; 451 } else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) { 452 free(search_path); 453 return NULL; 454 } 455 456 /* Remove trailing space chars from directory name */ 457 len = wcslen(search_path); 458 while (search_path[len-1] == ' ') { 459 len--; 460 } 461 search_path[len] = 0; 462 463 /* Append "*", or possibly "\\*", to path */ 464 if ((search_path[0] == L'\\' && search_path[1] == L'\0') || 465 (search_path[1] == L':' 466 && (search_path[2] == L'\0' 467 || (search_path[2] == L'\\' && search_path[3] == L'\0')))) { 468 /* No '\\' needed for cases like "\" or "Z:" or "Z:\" */ 469 wcscat(search_path, L"*"); 470 } else { 471 wcscat(search_path, L"\\*"); 472 } 473 474 /* Open handle to the first file */ 475 handle = FindFirstFileW(search_path, &find_data); 476 free(search_path); 477 if (handle == INVALID_HANDLE_VALUE) { 478 if (GetLastError() != ERROR_FILE_NOT_FOUND) { 479 // error 480 return NULL; 481 } else { 482 // No files found - return an empty array 483 rv = (*env)->NewObjectArray(env, 0, JNU_ClassString(env), NULL); 484 return rv; 485 } 486 } 487 488 /* Allocate an initial String array */ 489 len = 0; 490 maxlen = 16; 491 rv = (*env)->NewObjectArray(env, maxlen, JNU_ClassString(env), NULL); 492 if (rv == NULL) // Couldn't allocate an array 493 return NULL; 494 /* Scan the directory */ 495 do { 496 if (!wcscmp(find_data.cFileName, L".") 497 || !wcscmp(find_data.cFileName, L"..")) 498 continue; 499 name = (*env)->NewString(env, find_data.cFileName, 500 wcslen(find_data.cFileName)); 501 if (name == NULL) 502 return NULL; // error; 503 if (len == maxlen) { 504 old = rv; 505 rv = (*env)->NewObjectArray(env, maxlen <<= 1, 506 JNU_ClassString(env), NULL); 507 if ( rv == NULL 508 || JNU_CopyObjectArray(env, rv, old, len) < 0) 509 return NULL; // error 510 (*env)->DeleteLocalRef(env, old); 511 } 512 (*env)->SetObjectArrayElement(env, rv, len++, name); 513 (*env)->DeleteLocalRef(env, name); 514 515 } while (FindNextFileW(handle, &find_data)); 516 517 if (GetLastError() != ERROR_NO_MORE_FILES) 518 return NULL; // error 519 FindClose(handle); 520 521 /* Copy the final results into an appropriately-sized array */ 522 old = rv; 523 rv = (*env)->NewObjectArray(env, len, JNU_ClassString(env), NULL); 524 if (rv == NULL) 525 return NULL; /* error */ 526 if (JNU_CopyObjectArray(env, rv, old, len) < 0) 527 return NULL; /* error */ 528 return rv; 529 } 530 531 532 JNIEXPORT jboolean JNICALL 533 Java_java_io_WinNTFileSystem_createDirectory(JNIEnv *env, jobject this, 534 jobject file) 535 { 536 BOOL h = FALSE; 537 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 538 if (pathbuf == NULL) { 539 /* Exception is pending */ 540 return JNI_FALSE; 541 } 542 h = CreateDirectoryW(pathbuf, NULL); 543 free(pathbuf); 544 545 if (h == 0) { 546 return JNI_FALSE; 547 } 548 549 return JNI_TRUE; 550 } 551 552 553 JNIEXPORT jboolean JNICALL 554 Java_java_io_WinNTFileSystem_rename0(JNIEnv *env, jobject this, jobject from, 555 jobject to) 556 { 557 558 jboolean rv = JNI_FALSE; 559 WCHAR *frompath = fileToNTPath(env, from, ids.path); 560 WCHAR *topath = fileToNTPath(env, to, ids.path); 561 if (frompath == NULL || topath == NULL) 562 return JNI_FALSE; 563 if (_wrename(frompath, topath) == 0) { 564 rv = JNI_TRUE; 565 } 566 free(frompath); 567 free(topath); 568 return rv; 569 } 570 571 572 JNIEXPORT jboolean JNICALL 573 Java_java_io_WinNTFileSystem_setLastModifiedTime(JNIEnv *env, jobject this, 574 jobject file, jlong time) 575 { 576 jboolean rv = JNI_FALSE; 577 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 578 HANDLE h; 579 if (pathbuf == NULL) 580 return JNI_FALSE; 581 h = CreateFileW(pathbuf, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 582 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0); 583 if (h != INVALID_HANDLE_VALUE) { 584 LARGE_INTEGER modTime; 585 FILETIME t; 586 modTime.QuadPart = (time + 11644473600000L) * 10000L; 587 t.dwLowDateTime = (DWORD)modTime.LowPart; 588 t.dwHighDateTime = (DWORD)modTime.HighPart; 589 if (SetFileTime(h, NULL, NULL, &t)) { 590 rv = JNI_TRUE; 591 } 592 CloseHandle(h); 593 } 594 free(pathbuf); 595 596 return rv; 597 } 598 599 600 JNIEXPORT jboolean JNICALL 601 Java_java_io_WinNTFileSystem_setReadOnly(JNIEnv *env, jobject this, 602 jobject file) 603 { 604 jboolean rv = JNI_FALSE; 605 DWORD a; 606 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 607 if (pathbuf == NULL) 608 return JNI_FALSE; 609 a = GetFileAttributesW(pathbuf); 610 if (a != INVALID_FILE_ATTRIBUTES) { 611 if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY)) 612 rv = JNI_TRUE; 613 } 614 free(pathbuf); 615 return rv; 616 } 617 618 /* -- Filesystem interface -- */ 619 620 621 JNIEXPORT jobject JNICALL 622 Java_java_io_WinNTFileSystem_getDriveDirectory(JNIEnv *env, jobject this, 623 jint drive) 624 { 625 jstring ret = NULL; 626 jchar *p = _wgetdcwd(drive, NULL, MAX_PATH); 627 jchar *pf = p; 628 if (p == NULL) return NULL; 629 if (iswalpha(*p) && (p[1] == L':')) p += 2; 630 ret = (*env)->NewString(env, p, wcslen(p)); 631 free (pf); 632 return ret; 633 } 634 635 typedef BOOL (WINAPI* GetVolumePathNameProc) (LPCWSTR, LPWSTR, DWORD); 636 637 JNIEXPORT jlong JNICALL 638 Java_java_io_WinNTFileSystem_getSpace0(JNIEnv *env, jobject this, 639 jobject file, jint t) 640 { 641 WCHAR volname[MAX_PATH_LENGTH + 1]; 642 jlong rv = 0L; 643 WCHAR *pathbuf = fileToNTPath(env, file, ids.path); 644 645 HMODULE h = LoadLibrary("kernel32"); 646 GetVolumePathNameProc getVolumePathNameW = NULL; 647 if (h) { 648 getVolumePathNameW 649 = (GetVolumePathNameProc)GetProcAddress(h, "GetVolumePathNameW"); 650 } 651 652 if (getVolumePathNameW(pathbuf, volname, MAX_PATH_LENGTH)) { 653 ULARGE_INTEGER totalSpace, freeSpace, usableSpace; 654 if (GetDiskFreeSpaceExW(volname, &usableSpace, &totalSpace, &freeSpace)) { 655 switch(t) { 656 case java_io_FileSystem_SPACE_TOTAL: 657 rv = long_to_jlong(totalSpace.QuadPart); 658 break; 659 case java_io_FileSystem_SPACE_FREE: 660 rv = long_to_jlong(freeSpace.QuadPart); 661 break; 662 case java_io_FileSystem_SPACE_USABLE: 663 rv = long_to_jlong(usableSpace.QuadPart); 664 break; 665 default: 666 assert(0); 667 } 668 } 669 } 670 671 if (h) { 672 FreeLibrary(h); 673 } 674 free(pathbuf); 675 return rv; 676 }