src/windows/native/java/io/WinNTFileSystem_md.c

Print this page




  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);


 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);


 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;




  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 /**
  55  * GetFinalPathNameByHandle is available on Windows Vista and newer
  56  */
  57 typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
  58 static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
  59 
  60 JNIEXPORT void JNICALL
  61 Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
  62 {
  63     HANDLE handle;
  64     jclass fileClass = (*env)->FindClass(env, "java/io/File");
  65     if (!fileClass) return;
  66     ids.path =
  67              (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
  68     handle = LoadLibrary("kernel32");
  69     if (handle != NULL) {
  70         GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
  71             GetProcAddress(handle, "GetFinalPathNameByHandleW");
  72     }
  73 }
  74 
  75 /* -- Path operations -- */
  76 
  77 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
  78 extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
  79 
  80 /**
  81  * Retrieves the fully resolved (final) path for the given path or NULL
  82  * if the function fails.
  83  */
  84 static WCHAR* getFinalPath(const WCHAR *path)
  85 {
  86     HANDLE h;
  87     WCHAR *result;
  88     DWORD error;
  89 
  90     /* Need Windows Vista or newer to get the final path */
  91     if (GetFinalPathNameByHandle_func == NULL)
  92         return NULL;
  93 
  94     h = CreateFileW(path,
  95                     FILE_READ_ATTRIBUTES,
  96                     FILE_SHARE_DELETE |
  97                         FILE_SHARE_READ | FILE_SHARE_WRITE,
  98                     NULL,
  99                     OPEN_EXISTING,
 100                     FILE_FLAG_BACKUP_SEMANTICS,
 101                     NULL);
 102     if (h == INVALID_HANDLE_VALUE)
 103         return NULL;
 104 
 105     /**
 106      * Allocate a buffer for the resolved path. For a long path we may need
 107      * to allocate a larger buffer.
 108      */
 109     result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR));
 110     if (result != NULL) {
 111         DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0);
 112         if (len >= MAX_PATH) {
 113             /* retry with a buffer of the right size */
 114             result = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR));
 115             if (result != NULL) {
 116                 len = (*GetFinalPathNameByHandle_func)(h, result, len, 0);
 117             } else {
 118                 len = 0;
 119             }
 120         }
 121         if (len > 0) {
 122             /**
 123              * Strip prefix (should be \\?\ or \\?\UNC */
 124              */
 125             if (result[0] == L'\\' && result[1] == L'\\' &&
 126                 result[2] == L'?' && result[3] == L'\\')
 127             {
 128                 int isUnc = (result[4] == L'U' &&
 129                              result[5] == L'N' &&
 130                              result[6] == L'C');
 131                 int prefixLen = (isUnc) ? 7 : 4;
 132                 /* actual result length (includes terminator) */
 133                 int resultLen = len - prefixLen + (isUnc ? 1 : 0) + 1;
 134 
 135                 /* copy result without prefix into new buffer */
 136                 WCHAR *tmp = (WCHAR*)malloc(resultLen * sizeof(WCHAR));
 137                 if (tmp == NULL) {
 138                     len = 0;
 139                 } else {
 140                     WCHAR *p = result;
 141                     p += prefixLen;
 142                     if (isUnc) {
 143                         WCHAR *p2 = tmp;
 144                         p2[0] = L'\\';
 145                         p2++;
 146                         wcscpy(p2, p);
 147                     } else {
 148                         wcscpy(tmp, p);
 149                     }
 150                     free(result);
 151                     result = tmp;
 152                 }
 153             }
 154         }
 155 
 156         /* unable to get final path */
 157         if (len == 0) {
 158             free(result);
 159             result = NULL;
 160         }
 161     }
 162 
 163     error = GetLastError();
 164     if (CloseHandle(h))
 165         SetLastError(error);
 166     return result;
 167 }
 168 
 169 /**
 170  * Retrieves file information for the specified file. If the file is
 171  * symbolic link then the information on fully resolved target is
 172  * returned.
 173  */
 174 static BOOL getFileInformation(const WCHAR *path,
 175                                BY_HANDLE_FILE_INFORMATION *finfo)
 176 {
 177     BOOL result;
 178     DWORD error;
 179     HANDLE h = CreateFileW(path,
 180                            FILE_READ_ATTRIBUTES,
 181                            FILE_SHARE_DELETE |
 182                                FILE_SHARE_READ | FILE_SHARE_WRITE,
 183                            NULL,
 184                            OPEN_EXISTING,
 185                            FILE_FLAG_BACKUP_SEMANTICS,
 186                            NULL);
 187     if (h == INVALID_HANDLE_VALUE)
 188         return FALSE;
 189     result = GetFileInformationByHandle(h, finfo);
 190     error = GetLastError();
 191     if (CloseHandle(h))
 192         SetLastError(error);
 193     return result;
 194 }
 195 
 196 /**
 197  * If the given attributes are the attributes of a reparse point, then
 198  * read and return the attributes of the final target.
 199  */
 200 DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)
 201 {
 202     if ((a != INVALID_FILE_ATTRIBUTES) &&
 203         ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
 204     {
 205         BY_HANDLE_FILE_INFORMATION finfo;
 206         BOOL res = getFileInformation(path, &finfo);
 207         a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
 208     }
 209     return a;
 210 }
 211 
 212 JNIEXPORT jstring JNICALL
 213 Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
 214                                            jstring pathname)
 215 {
 216     jstring rv = NULL;
 217     WCHAR canonicalPath[MAX_PATH_LENGTH];
 218 
 219     WITH_UNICODE_STRING(env, pathname, path) {
 220         /*we estimate the max length of memory needed as
 221           "currentDir. length + pathname.length"
 222          */
 223         int len = wcslen(path);
 224         len += currentDirLength(path, len);
 225         if (len  > MAX_PATH_LENGTH - 1) {
 226             WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
 227             if (cp != NULL) {
 228                 if (wcanonicalize(path, cp, len) >= 0) {
 229                     rv = (*env)->NewString(env, cp, wcslen(cp));
 230                 }
 231                 free(cp);


 329     return FALSE;
 330 }
 331 
 332 JNIEXPORT jint JNICALL
 333 Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this,
 334                                                   jobject file)
 335 {
 336 
 337     jint rv = 0;
 338     jint pathlen;
 339 
 340     /* both pagefile.sys and hiberfil.sys have length 12 */
 341 #define SPECIALFILE_NAMELEN 12
 342 
 343     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
 344     WIN32_FILE_ATTRIBUTE_DATA wfad;
 345     if (pathbuf == NULL)
 346         return rv;
 347     if (!isReservedDeviceNameW(pathbuf)) {
 348         if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) {
 349             DWORD a = getFinalAttributesIfReparsePoint(pathbuf, wfad.dwFileAttributes);
 350             if (a != INVALID_FILE_ATTRIBUTES) {
 351                 rv = (java_io_FileSystem_BA_EXISTS
 352                     | ((a & FILE_ATTRIBUTE_DIRECTORY)
 353                         ? java_io_FileSystem_BA_DIRECTORY
 354                         : java_io_FileSystem_BA_REGULAR)
 355                     | ((a & FILE_ATTRIBUTE_HIDDEN)
 356                         ? java_io_FileSystem_BA_HIDDEN : 0));
 357             }
 358         } else { /* pagefile.sys is a special case */
 359             if (GetLastError() == ERROR_SHARING_VIOLATION) {
 360                 rv = java_io_FileSystem_BA_EXISTS;
 361                 if ((pathlen = wcslen(pathbuf)) >= SPECIALFILE_NAMELEN &&
 362                     (_wcsicmp(pathbuf + pathlen - SPECIALFILE_NAMELEN,
 363                               L"pagefile.sys") == 0) ||
 364                     (_wcsicmp(pathbuf + pathlen - SPECIALFILE_NAMELEN,
 365                               L"hiberfil.sys") == 0))
 366                   rv |= java_io_FileSystem_BA_REGULAR;
 367             }
 368         }
 369     }
 370     free(pathbuf);
 371     return rv;
 372 }
 373 
 374 
 375 JNIEXPORT jboolean
 376 JNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this,
 377                                                  jobject file, jint access)
 378 {
 379     DWORD attr;
 380     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
 381     if (pathbuf == NULL)
 382         return JNI_FALSE;
 383     attr = GetFileAttributesW(pathbuf);
 384     attr = getFinalAttributesIfReparsePoint(pathbuf, attr);
 385     free(pathbuf);
 386     if (attr == INVALID_FILE_ATTRIBUTES)
 387         return JNI_FALSE;
 388     switch (access) {
 389     case java_io_FileSystem_ACCESS_READ:
 390     case java_io_FileSystem_ACCESS_EXECUTE:
 391         return JNI_TRUE;
 392     case java_io_FileSystem_ACCESS_WRITE:
 393         /* Read-only attribute ignored on directories */
 394         if ((attr & FILE_ATTRIBUTE_DIRECTORY) ||
 395             (attr & FILE_ATTRIBUTE_READONLY) == 0)
 396             return JNI_TRUE;
 397         else
 398             return JNI_FALSE;
 399     default:
 400         assert(0);
 401         return JNI_FALSE;
 402     }
 403 }
 404 
 405 JNIEXPORT jboolean JNICALL
 406 Java_java_io_WinNTFileSystem_setPermission(JNIEnv *env, jobject this,
 407                                            jobject file,
 408                                            jint access,
 409                                            jboolean enable,
 410                                            jboolean owneronly)
 411 {
 412     jboolean rv = JNI_FALSE;
 413     WCHAR *pathbuf;
 414     DWORD a;
 415     if (access == java_io_FileSystem_ACCESS_READ ||
 416         access == java_io_FileSystem_ACCESS_EXECUTE) {
 417         return enable;
 418     }
 419     pathbuf = fileToNTPath(env, file, ids.path);
 420     if (pathbuf == NULL)
 421         return JNI_FALSE;
 422     a = GetFileAttributesW(pathbuf);
 423 
 424     /* if reparse point, get final target */
 425     if ((a != INVALID_FILE_ATTRIBUTES) &&
 426         ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
 427     {
 428         WCHAR *fp = getFinalPath(pathbuf);
 429         if (fp == NULL) {
 430             a = INVALID_FILE_ATTRIBUTES;
 431         } else {
 432             free(pathbuf);
 433             pathbuf = fp;
 434             a = GetFileAttributesW(pathbuf);
 435         }
 436     }
 437     if (a != INVALID_FILE_ATTRIBUTES) {
 438         if (enable)
 439             a =  a & ~FILE_ATTRIBUTE_READONLY;
 440         else
 441             a =  a | FILE_ATTRIBUTE_READONLY;
 442         if (SetFileAttributesW(pathbuf, a))
 443             rv = JNI_TRUE;
 444     }
 445     free(pathbuf);
 446     return rv;
 447 }
 448 
 449 JNIEXPORT jlong JNICALL
 450 Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
 451                                                  jobject file)
 452 {
 453     jlong rv = 0;
 454     LARGE_INTEGER modTime;
 455     FILETIME t;
 456     HANDLE h;
 457     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
 458     if (pathbuf == NULL)
 459         return rv;
 460     h = CreateFileW(pathbuf,
 461                     /* Device query access */
 462                     0,
 463                     /* Share it */
 464                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
 465                     /* No security attributes */
 466                     NULL,
 467                     /* Open existing or fail */
 468                     OPEN_EXISTING,
 469                     /* Backup semantics for directories */
 470                     FILE_FLAG_BACKUP_SEMANTICS,
 471                     /* No template file */
 472                     NULL);
 473     if (h != INVALID_HANDLE_VALUE) {
 474         if (GetFileTime(h, NULL, NULL, &t)) {
 475             modTime.LowPart = (DWORD) t.dwLowDateTime;
 476             modTime.HighPart = (LONG) t.dwHighDateTime;
 477             rv = modTime.QuadPart / 10000;
 478             rv -= 11644473600000;
 479         }
 480         CloseHandle(h);
 481     }
 482     free(pathbuf);
 483     return rv;
 484 }
 485 
 486 JNIEXPORT jlong JNICALL
 487 Java_java_io_WinNTFileSystem_getLength(JNIEnv *env, jobject this, jobject file)
 488 {
 489     jlong rv = 0;
 490     WIN32_FILE_ATTRIBUTE_DATA wfad;
 491     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
 492     if (pathbuf == NULL)
 493         return rv;
 494     if (GetFileAttributesExW(pathbuf,
 495                              GetFileExInfoStandard,
 496                              &wfad)) {
 497         if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
 498             rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;
 499         } else {
 500             /* file is a reparse point so read attributes of final target */
 501             BY_HANDLE_FILE_INFORMATION finfo;
 502             if (getFileInformation(pathbuf, &finfo)) {
 503                 rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) +
 504                     finfo.nFileSizeLow;
 505             }
 506         }
 507     } else {
 508         if (GetLastError() == ERROR_SHARING_VIOLATION) {
 509             /* The error is "share violation", which means the file/dir
 510                must exists. Try _wstati64, we know this at least works
 511                for pagefile.sys and hiberfil.sys.
 512             */
 513             struct _stati64 sb;
 514             if (_wstati64(pathbuf, &sb) == 0) {
 515                 rv = sb.st_size;
 516             }
 517         }
 518     }
 519     free(pathbuf);
 520     return rv;
 521 }
 522 
 523 /* -- File operations -- */
 524 
 525 JNIEXPORT jboolean JNICALL
 526 Java_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls,
 527                                                    jstring path)
 528 {
 529     HANDLE h = NULL;
 530     WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
 531     if (pathbuf == NULL)
 532         return JNI_FALSE;
 533     h = CreateFileW(
 534         pathbuf,                              /* Wide char path name */
 535         GENERIC_READ | GENERIC_WRITE,         /* Read and write permission */
 536         FILE_SHARE_READ | FILE_SHARE_WRITE,   /* File sharing flags */
 537         NULL,                                 /* Security attributes */
 538         CREATE_NEW,                           /* creation disposition */
 539         FILE_ATTRIBUTE_NORMAL |
 540             FILE_FLAG_OPEN_REPARSE_POINT,     /* flags and attributes */
 541         NULL);
 542 
 543     if (h == INVALID_HANDLE_VALUE) {
 544         DWORD error = GetLastError();
 545         if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
 546             // return false rather than throwing an exception when there is
 547             // an existing file.
 548             DWORD a = GetFileAttributesW(pathbuf);
 549             if (a == INVALID_FILE_ATTRIBUTES) {



 550                 SetLastError(error);
 551                 JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
 552             }
 553          }
 554          free(pathbuf);
 555          return JNI_FALSE;
 556         }
 557     free(pathbuf);
 558     CloseHandle(h);
 559     return JNI_TRUE;
 560 }
 561 
 562 static int
 563 removeFileOrDirectory(const jchar *path)
 564 {
 565     /* Returns 0 on success */
 566     DWORD a;
 567 
 568     SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
 569     a = GetFileAttributesW(path);
 570     if (a == INVALID_FILE_ATTRIBUTES) {
 571         return 1;
 572     } else if (a & FILE_ATTRIBUTE_DIRECTORY) {
 573         return !RemoveDirectoryW(path);
 574     } else {
 575         return !DeleteFileW(path);
 576     }
 577 }
 578 
 579 JNIEXPORT jboolean JNICALL
 580 Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file)
 581 {
 582     jboolean rv = JNI_FALSE;
 583     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
 584     if (pathbuf == NULL) {
 585         return JNI_FALSE;
 586     }
 587     if (removeFileOrDirectory(pathbuf) == 0) {
 588         rv = JNI_TRUE;
 589     }
 590     free(pathbuf);


 730     if (frompath == NULL || topath == NULL)
 731         return JNI_FALSE;
 732     if (_wrename(frompath, topath) == 0) {
 733         rv = JNI_TRUE;
 734     }
 735     free(frompath);
 736     free(topath);
 737     return rv;
 738 }
 739 
 740 
 741 JNIEXPORT jboolean JNICALL
 742 Java_java_io_WinNTFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
 743                                                  jobject file, jlong time)
 744 {
 745     jboolean rv = JNI_FALSE;
 746     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
 747     HANDLE h;
 748     if (pathbuf == NULL)
 749         return JNI_FALSE;
 750     h = CreateFileW(pathbuf,
 751                     FILE_WRITE_ATTRIBUTES,
 752                     FILE_SHARE_READ | FILE_SHARE_WRITE,
 753                     NULL,
 754                     OPEN_EXISTING,
 755                     FILE_FLAG_BACKUP_SEMANTICS,
 756                     0);
 757     if (h != INVALID_HANDLE_VALUE) {
 758         LARGE_INTEGER modTime;
 759         FILETIME t;
 760         modTime.QuadPart = (time + 11644473600000L) * 10000L;
 761         t.dwLowDateTime = (DWORD)modTime.LowPart;
 762         t.dwHighDateTime = (DWORD)modTime.HighPart;
 763         if (SetFileTime(h, NULL, NULL, &t)) {
 764             rv = JNI_TRUE;
 765         }
 766         CloseHandle(h);
 767     }
 768     free(pathbuf);
 769 
 770     return rv;
 771 }
 772 
 773 
 774 JNIEXPORT jboolean JNICALL
 775 Java_java_io_WinNTFileSystem_setReadOnly(JNIEnv *env, jobject this,
 776                                          jobject file)
 777 {
 778     jboolean rv = JNI_FALSE;
 779     DWORD a;
 780     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
 781     if (pathbuf == NULL)
 782         return JNI_FALSE;
 783     a = GetFileAttributesW(pathbuf);
 784 
 785     /* if reparse point, get final target */
 786     if ((a != INVALID_FILE_ATTRIBUTES) &&
 787         ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
 788     {
 789         WCHAR *fp = getFinalPath(pathbuf);
 790         if (fp == NULL) {
 791             a = INVALID_FILE_ATTRIBUTES;
 792         } else {
 793             free(pathbuf);
 794             pathbuf = fp;
 795             a = GetFileAttributesW(pathbuf);
 796         }
 797     }
 798 
 799     if (a != INVALID_FILE_ATTRIBUTES) {
 800         if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))
 801         rv = JNI_TRUE;
 802     }
 803     free(pathbuf);
 804     return rv;
 805 }
 806 
 807 /* -- Filesystem interface -- */
 808 
 809 
 810 JNIEXPORT jobject JNICALL
 811 Java_java_io_WinNTFileSystem_getDriveDirectory(JNIEnv *env, jobject this,
 812                                                jint drive)
 813 {
 814     jstring ret = NULL;
 815     jchar *p = _wgetdcwd(drive, NULL, MAX_PATH);
 816     jchar *pf = p;
 817     if (p == NULL) return NULL;
 818     if (iswalpha(*p) && (p[1] == L':')) p += 2;