jdk/src/windows/native/java/io/WinNTFileSystem_md.c
changeset 3627 d0ad40d5adab
parent 2426 a528c0830862
child 5506 202f599c92aa
equal deleted inserted replaced
3626:78722c321f85 3627:d0ad40d5adab
    49 
    49 
    50 static struct {
    50 static struct {
    51     jfieldID path;
    51     jfieldID path;
    52 } ids;
    52 } ids;
    53 
    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 
    54 JNIEXPORT void JNICALL
    60 JNIEXPORT void JNICALL
    55 Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
    61 Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
    56 {
    62 {
       
    63     HANDLE handle;
    57     jclass fileClass = (*env)->FindClass(env, "java/io/File");
    64     jclass fileClass = (*env)->FindClass(env, "java/io/File");
    58     if (!fileClass) return;
    65     if (!fileClass) return;
    59     ids.path =
    66     ids.path =
    60              (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
    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     }
    61 }
    73 }
    62 
    74 
    63 /* -- Path operations -- */
    75 /* -- Path operations -- */
    64 
    76 
    65 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
    77 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
    66 extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, 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 && result != NULL) {
       
   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 }
    67 
   211 
    68 JNIEXPORT jstring JNICALL
   212 JNIEXPORT jstring JNICALL
    69 Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
   213 Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
    70                                            jstring pathname)
   214                                            jstring pathname)
    71 {
   215 {
   200     WIN32_FILE_ATTRIBUTE_DATA wfad;
   344     WIN32_FILE_ATTRIBUTE_DATA wfad;
   201     if (pathbuf == NULL)
   345     if (pathbuf == NULL)
   202         return rv;
   346         return rv;
   203     if (!isReservedDeviceNameW(pathbuf)) {
   347     if (!isReservedDeviceNameW(pathbuf)) {
   204         if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) {
   348         if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) {
   205             rv = (java_io_FileSystem_BA_EXISTS
   349             DWORD a = getFinalAttributesIfReparsePoint(pathbuf, wfad.dwFileAttributes);
   206                   | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
   350             if (a != INVALID_FILE_ATTRIBUTES) {
   207                      ? java_io_FileSystem_BA_DIRECTORY
   351                 rv = (java_io_FileSystem_BA_EXISTS
   208                      : java_io_FileSystem_BA_REGULAR)
   352                     | ((a & FILE_ATTRIBUTE_DIRECTORY)
   209                   | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
   353                         ? java_io_FileSystem_BA_DIRECTORY
   210                      ? java_io_FileSystem_BA_HIDDEN : 0));
   354                         : java_io_FileSystem_BA_REGULAR)
       
   355                     | ((a & FILE_ATTRIBUTE_HIDDEN)
       
   356                         ? java_io_FileSystem_BA_HIDDEN : 0));
       
   357             }
   211         } else { /* pagefile.sys is a special case */
   358         } else { /* pagefile.sys is a special case */
   212             if (GetLastError() == ERROR_SHARING_VIOLATION) {
   359             if (GetLastError() == ERROR_SHARING_VIOLATION) {
   213                 rv = java_io_FileSystem_BA_EXISTS;
   360                 rv = java_io_FileSystem_BA_EXISTS;
   214                 if ((pathlen = wcslen(pathbuf)) >= SPECIALFILE_NAMELEN &&
   361                 if ((pathlen = wcslen(pathbuf)) >= SPECIALFILE_NAMELEN &&
   215                     (_wcsicmp(pathbuf + pathlen - SPECIALFILE_NAMELEN,
   362                     (_wcsicmp(pathbuf + pathlen - SPECIALFILE_NAMELEN,
   232     DWORD attr;
   379     DWORD attr;
   233     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
   380     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
   234     if (pathbuf == NULL)
   381     if (pathbuf == NULL)
   235         return JNI_FALSE;
   382         return JNI_FALSE;
   236     attr = GetFileAttributesW(pathbuf);
   383     attr = GetFileAttributesW(pathbuf);
       
   384     attr = getFinalAttributesIfReparsePoint(pathbuf, attr);
   237     free(pathbuf);
   385     free(pathbuf);
   238     if (attr == INVALID_FILE_ATTRIBUTES)
   386     if (attr == INVALID_FILE_ATTRIBUTES)
   239         return JNI_FALSE;
   387         return JNI_FALSE;
   240     switch (access) {
   388     switch (access) {
   241     case java_io_FileSystem_ACCESS_READ:
   389     case java_io_FileSystem_ACCESS_READ:
   270     }
   418     }
   271     pathbuf = fileToNTPath(env, file, ids.path);
   419     pathbuf = fileToNTPath(env, file, ids.path);
   272     if (pathbuf == NULL)
   420     if (pathbuf == NULL)
   273         return JNI_FALSE;
   421         return JNI_FALSE;
   274     a = GetFileAttributesW(pathbuf);
   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     }
   275     if (a != INVALID_FILE_ATTRIBUTES) {
   437     if (a != INVALID_FILE_ATTRIBUTES) {
   276         if (enable)
   438         if (enable)
   277             a =  a & ~FILE_ATTRIBUTE_READONLY;
   439             a =  a & ~FILE_ATTRIBUTE_READONLY;
   278         else
   440         else
   279             a =  a | FILE_ATTRIBUTE_READONLY;
   441             a =  a | FILE_ATTRIBUTE_READONLY;
   303                     /* No security attributes */
   465                     /* No security attributes */
   304                     NULL,
   466                     NULL,
   305                     /* Open existing or fail */
   467                     /* Open existing or fail */
   306                     OPEN_EXISTING,
   468                     OPEN_EXISTING,
   307                     /* Backup semantics for directories */
   469                     /* Backup semantics for directories */
   308                     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
   470                     FILE_FLAG_BACKUP_SEMANTICS,
   309                     /* No template file */
   471                     /* No template file */
   310                     NULL);
   472                     NULL);
   311     if (h != INVALID_HANDLE_VALUE) {
   473     if (h != INVALID_HANDLE_VALUE) {
   312         if (GetFileTime(h, NULL, NULL, &t)) {
   474         if (GetFileTime(h, NULL, NULL, &t)) {
   313             modTime.LowPart = (DWORD) t.dwLowDateTime;
   475             modTime.LowPart = (DWORD) t.dwLowDateTime;
   330     if (pathbuf == NULL)
   492     if (pathbuf == NULL)
   331         return rv;
   493         return rv;
   332     if (GetFileAttributesExW(pathbuf,
   494     if (GetFileAttributesExW(pathbuf,
   333                              GetFileExInfoStandard,
   495                              GetFileExInfoStandard,
   334                              &wfad)) {
   496                              &wfad)) {
   335         rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;
   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         }
   336     } else {
   507     } else {
   337         if (GetLastError() == ERROR_SHARING_VIOLATION) {
   508         if (GetLastError() == ERROR_SHARING_VIOLATION) {
   338             /* The error is "share violation", which means the file/dir
   509             /* The error is "share violation", which means the file/dir
   339                must exists. Try _wstati64, we know this at least works
   510                must exists. Try _wstati64, we know this at least works
   340                for pagefile.sys and hiberfil.sys.
   511                for pagefile.sys and hiberfil.sys.
   358     HANDLE h = NULL;
   529     HANDLE h = NULL;
   359     WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
   530     WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
   360     if (pathbuf == NULL)
   531     if (pathbuf == NULL)
   361         return JNI_FALSE;
   532         return JNI_FALSE;
   362     h = CreateFileW(
   533     h = CreateFileW(
   363         pathbuf,                             /* Wide char path name */
   534         pathbuf,                              /* Wide char path name */
   364         GENERIC_READ | GENERIC_WRITE,  /* Read and write permission */
   535         GENERIC_READ | GENERIC_WRITE,         /* Read and write permission */
   365         FILE_SHARE_READ | FILE_SHARE_WRITE,   /* File sharing flags */
   536         FILE_SHARE_READ | FILE_SHARE_WRITE,   /* File sharing flags */
   366         NULL,                                /* Security attributes */
   537         NULL,                                 /* Security attributes */
   367         CREATE_NEW,                         /* creation disposition */
   538         CREATE_NEW,                           /* creation disposition */
   368         FILE_ATTRIBUTE_NORMAL,              /* flags and attributes */
   539         FILE_ATTRIBUTE_NORMAL |
       
   540             FILE_FLAG_OPEN_REPARSE_POINT,     /* flags and attributes */
   369         NULL);
   541         NULL);
   370 
   542 
   371     if (h == INVALID_HANDLE_VALUE) {
   543     if (h == INVALID_HANDLE_VALUE) {
   372         DWORD error = GetLastError();
   544         DWORD error = GetLastError();
   373         if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
   545         if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
   374 
   546             // return false rather than throwing an exception when there is
   375             // If a directory by the named path already exists,
   547             // an existing file.
   376             // return false (behavior of solaris and linux) instead of
   548             DWORD a = GetFileAttributesW(pathbuf);
   377             // throwing an exception
   549             if (a == INVALID_FILE_ATTRIBUTES) {
   378             DWORD fattr = GetFileAttributesW(pathbuf);
       
   379             if ((fattr == INVALID_FILE_ATTRIBUTES) ||
       
   380                     (fattr & ~FILE_ATTRIBUTE_DIRECTORY)) {
       
   381                 SetLastError(error);
   550                 SetLastError(error);
   382                 JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
   551                 JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
   383             }
   552             }
   384          }
   553          }
   385          free(pathbuf);
   554          free(pathbuf);
   386          return JNI_FALSE;
   555          return JNI_FALSE;
   387     }
   556         }
   388     free(pathbuf);
   557     free(pathbuf);
   389     CloseHandle(h);
   558     CloseHandle(h);
   390     return JNI_TRUE;
   559     return JNI_TRUE;
   391 }
   560 }
   392 
   561 
   394 removeFileOrDirectory(const jchar *path)
   563 removeFileOrDirectory(const jchar *path)
   395 {
   564 {
   396     /* Returns 0 on success */
   565     /* Returns 0 on success */
   397     DWORD a;
   566     DWORD a;
   398 
   567 
   399     SetFileAttributesW(path, 0);
   568     SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
   400     a = GetFileAttributesW(path);
   569     a = GetFileAttributesW(path);
   401     if (a == ((DWORD)-1)) {
   570     if (a == INVALID_FILE_ATTRIBUTES) {
   402         return 1;
   571         return 1;
   403     } else if (a & FILE_ATTRIBUTE_DIRECTORY) {
   572     } else if (a & FILE_ATTRIBUTE_DIRECTORY) {
   404         return !RemoveDirectoryW(path);
   573         return !RemoveDirectoryW(path);
   405     } else {
   574     } else {
   406         return !DeleteFileW(path);
   575         return !DeleteFileW(path);
   576     jboolean rv = JNI_FALSE;
   745     jboolean rv = JNI_FALSE;
   577     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
   746     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
   578     HANDLE h;
   747     HANDLE h;
   579     if (pathbuf == NULL)
   748     if (pathbuf == NULL)
   580         return JNI_FALSE;
   749         return JNI_FALSE;
   581     h = CreateFileW(pathbuf, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
   750     h = CreateFileW(pathbuf,
   582                     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
   751                     FILE_WRITE_ATTRIBUTES,
       
   752                     FILE_SHARE_READ | FILE_SHARE_WRITE,
       
   753                     NULL,
       
   754                     OPEN_EXISTING,
       
   755                     FILE_FLAG_BACKUP_SEMANTICS,
       
   756                     0);
   583     if (h != INVALID_HANDLE_VALUE) {
   757     if (h != INVALID_HANDLE_VALUE) {
   584         LARGE_INTEGER modTime;
   758         LARGE_INTEGER modTime;
   585         FILETIME t;
   759         FILETIME t;
   586         modTime.QuadPart = (time + 11644473600000L) * 10000L;
   760         modTime.QuadPart = (time + 11644473600000L) * 10000L;
   587         t.dwLowDateTime = (DWORD)modTime.LowPart;
   761         t.dwLowDateTime = (DWORD)modTime.LowPart;
   605     DWORD a;
   779     DWORD a;
   606     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
   780     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
   607     if (pathbuf == NULL)
   781     if (pathbuf == NULL)
   608         return JNI_FALSE;
   782         return JNI_FALSE;
   609     a = GetFileAttributesW(pathbuf);
   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 
   610     if (a != INVALID_FILE_ATTRIBUTES) {
   799     if (a != INVALID_FILE_ATTRIBUTES) {
   611         if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))
   800         if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))
   612         rv = JNI_TRUE;
   801         rv = JNI_TRUE;
   613     }
   802     }
   614     free(pathbuf);
   803     free(pathbuf);