Path: blob/master/src/java.base/windows/native/libjava/WinNTFileSystem_md.c
41119 views
/*1* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/* Access APIs for WinXP and above */26#ifndef _WIN32_WINNT27#define _WIN32_WINNT 0x050128#endif2930#include <assert.h>31#include <stdio.h>32#include <stdlib.h>33#include <ctype.h>34#include <direct.h>35#include <windows.h>36#include <io.h>37#include <limits.h>38#include <wchar.h>39#include <Winioctl.h>4041#include "jni.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"4748#define MAX_PATH_LENGTH 10244950static struct {51jfieldID path;52} ids;5354/**55* GetFinalPathNameByHandle is available on Windows Vista and newer56*/57typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);58static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;5960JNIEXPORT void JNICALL61Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)62{63HMODULE handle;64jclass fileClass;6566fileClass = (*env)->FindClass(env, "java/io/File");67CHECK_NULL(fileClass);68ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");69CHECK_NULL(ids.path);7071// GetFinalPathNameByHandle requires Windows Vista or newer72if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |73GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),74(LPCWSTR)&CreateFileW, &handle) != 0)75{76GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)77GetProcAddress(handle, "GetFinalPathNameByHandleW");78}79}8081/* -- Path operations -- */8283extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);84extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);8586/**87* Retrieves the fully resolved (final) path for the given path or NULL88* if the function fails.89*/90static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)91{92HANDLE h;93WCHAR *result;94DWORD error;9596/* Need Windows Vista or newer to get the final path */97if (GetFinalPathNameByHandle_func == NULL)98return NULL;99100h = CreateFileW(path,101FILE_READ_ATTRIBUTES,102FILE_SHARE_DELETE |103FILE_SHARE_READ | FILE_SHARE_WRITE,104NULL,105OPEN_EXISTING,106FILE_FLAG_BACKUP_SEMANTICS,107NULL);108if (h == INVALID_HANDLE_VALUE)109return NULL;110111/**112* Allocate a buffer for the resolved path. For a long path we may need113* to allocate a larger buffer.114*/115result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR));116if (result != NULL) {117DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0);118if (len >= MAX_PATH) {119/* retry with a buffer of the right size */120WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR));121if (newResult != NULL) {122result = newResult;123len = (*GetFinalPathNameByHandle_func)(h, result, len, 0);124} else {125len = 0;126JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");127}128}129130if (len > 0) {131/**132* Strip prefix (should be \\?\ or \\?\UNC)133*/134if (result[0] == L'\\' && result[1] == L'\\' &&135result[2] == L'?' && result[3] == L'\\')136{137int isUnc = (result[4] == L'U' &&138result[5] == L'N' &&139result[6] == L'C');140int prefixLen = (isUnc) ? 7 : 4;141int prefixToKeep = (isUnc) ? 1 : 0;142// the amount to copy includes terminator143int amountToCopy = len - prefixLen + 1;144wmemmove(result + prefixToKeep, result + prefixLen, amountToCopy);145}146}147148/* unable to get final path */149if (len == 0 && result != NULL) {150free(result);151result = NULL;152}153} else {154JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");155}156157error = GetLastError();158if (CloseHandle(h))159SetLastError(error);160return result;161}162163/**164* Retrieves file information for the specified file. If the file is165* symbolic link then the information on fully resolved target is166* returned.167*/168static BOOL getFileInformation(const WCHAR *path,169BY_HANDLE_FILE_INFORMATION *finfo)170{171BOOL result;172DWORD error;173HANDLE h = CreateFileW(path,174FILE_READ_ATTRIBUTES,175FILE_SHARE_DELETE |176FILE_SHARE_READ | FILE_SHARE_WRITE,177NULL,178OPEN_EXISTING,179FILE_FLAG_BACKUP_SEMANTICS,180NULL);181if (h == INVALID_HANDLE_VALUE)182return FALSE;183result = GetFileInformationByHandle(h, finfo);184error = GetLastError();185if (CloseHandle(h))186SetLastError(error);187return result;188}189190/**191* path is likely to be a Unix domain socket.192* Verify and if it is return its attributes193*/194static DWORD getFinalAttributesUnixSocket(const WCHAR *path)195{196DWORD result;197BY_HANDLE_FILE_INFORMATION finfo;198REPARSE_GUID_DATA_BUFFER reparse;199200HANDLE h = CreateFileW(path,201FILE_READ_ATTRIBUTES,202FILE_SHARE_DELETE |203FILE_SHARE_READ | FILE_SHARE_WRITE,204NULL,205OPEN_EXISTING,206FILE_FLAG_BACKUP_SEMANTICS |207FILE_FLAG_OPEN_REPARSE_POINT,208NULL);209210if (h == INVALID_HANDLE_VALUE)211return INVALID_FILE_ATTRIBUTES;212213214if (!GetFileInformationByHandle(h, &finfo)) {215DWORD error = GetLastError();216if (CloseHandle(h)) {217SetLastError(error);218}219return INVALID_FILE_ATTRIBUTES;220}221222if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {223CloseHandle(h);224return INVALID_FILE_ATTRIBUTES;225}226227/* check the reparse tag */228229if (DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, &reparse,230(DWORD)sizeof(reparse), &result, NULL) == 0) {231CloseHandle(h);232return INVALID_FILE_ATTRIBUTES;233}234235if (reparse.ReparseTag != IO_REPARSE_TAG_AF_UNIX) {236CloseHandle(h);237return INVALID_FILE_ATTRIBUTES;238}239240CloseHandle(h);241return finfo.dwFileAttributes;242}243244/**245* If the given attributes are the attributes of a reparse point, then246* read and return the attributes of the special cases.247*/248DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)249{250if ((a != INVALID_FILE_ATTRIBUTES) &&251((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))252{253BY_HANDLE_FILE_INFORMATION finfo;254BOOL res = getFileInformation(path, &finfo);255a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES;256}257return a;258}259260/**261* Take special cases into account when retrieving the attributes262* of path263*/264DWORD getFinalAttributes(WCHAR *path)265{266DWORD attr = INVALID_FILE_ATTRIBUTES;267268WIN32_FILE_ATTRIBUTE_DATA wfad;269WIN32_FIND_DATAW wfd;270HANDLE h;271272if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) {273attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes);274if (attr == INVALID_FILE_ATTRIBUTES) {275if (GetLastError() == ERROR_CANT_ACCESS_FILE) {276attr = getFinalAttributesUnixSocket(path);277}278}279} else {280DWORD lerr = GetLastError();281if ((lerr == ERROR_SHARING_VIOLATION || lerr == ERROR_ACCESS_DENIED) &&282(h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) {283attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes);284FindClose(h);285}286}287return attr;288}289290JNIEXPORT jstring JNICALL291Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,292jstring pathname)293{294jstring rv = NULL;295WCHAR canonicalPath[MAX_PATH_LENGTH];296297WITH_UNICODE_STRING(env, pathname, path) {298/* we estimate the max length of memory needed as299"currentDir. length + pathname.length"300*/301int len = (int)wcslen(path);302len += currentDirLength(path, len);303if (len > MAX_PATH_LENGTH - 1) {304WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));305if (cp != NULL) {306if (wcanonicalize(path, cp, len) >= 0) {307rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));308}309free(cp);310} else {311JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");312}313} else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {314rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));315}316} END_UNICODE_STRING(env, path);317if (rv == NULL && !(*env)->ExceptionCheck(env)) {318JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");319}320return rv;321}322323324JNIEXPORT jstring JNICALL325Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,326jstring canonicalPrefixString,327jstring pathWithCanonicalPrefixString)328{329jstring rv = NULL;330WCHAR canonicalPath[MAX_PATH_LENGTH];331WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {332WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {333int len = (int)wcslen(canonicalPrefix) + MAX_PATH;334if (len > MAX_PATH_LENGTH) {335WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));336if (cp != NULL) {337if (wcanonicalizeWithPrefix(canonicalPrefix,338pathWithCanonicalPrefix,339cp, len) >= 0) {340rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));341}342free(cp);343} else {344JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");345}346} else if (wcanonicalizeWithPrefix(canonicalPrefix,347pathWithCanonicalPrefix,348canonicalPath, MAX_PATH_LENGTH) >= 0) {349rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));350}351} END_UNICODE_STRING(env, pathWithCanonicalPrefix);352} END_UNICODE_STRING(env, canonicalPrefix);353if (rv == NULL && !(*env)->ExceptionCheck(env)) {354JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");355}356return rv;357}358359/* -- Attribute accessors -- */360361/* Check whether or not the file name in "path" is a Windows reserved362device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the363returned result from GetFullPathName, which should be in thr form of364"\\.\[ReservedDeviceName]" if the path represents a reserved device365name.366Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer367important anyway) is a device name, so we don't check it here.368GetFileAttributesEx will catch it later by returning 0 on NT/XP/369200X.370371Note2: Theoretically the implementation could just lookup the table372below linearly if the first 4 characters of the fullpath returned373from GetFullPathName are "\\.\". The current implementation should374achieve the same result. If Microsoft add more names into their375reserved device name repository in the future, which probably will376never happen, we will need to revisit the lookup implementation.377378static WCHAR* ReservedDEviceNames[] = {379L"CON", L"PRN", L"AUX", L"NUL",380L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9",381L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9",382L"CLOCK$"383};384*/385386static BOOL isReservedDeviceNameW(WCHAR* path) {387#define BUFSIZE 9388WCHAR buf[BUFSIZE];389WCHAR *lpf = NULL;390DWORD retLen = GetFullPathNameW(path,391BUFSIZE,392buf,393&lpf);394if ((retLen == BUFSIZE - 1 || retLen == BUFSIZE - 2) &&395buf[0] == L'\\' && buf[1] == L'\\' &&396buf[2] == L'.' && buf[3] == L'\\') {397WCHAR* dname = _wcsupr(buf + 4);398if (wcscmp(dname, L"CON") == 0 ||399wcscmp(dname, L"PRN") == 0 ||400wcscmp(dname, L"AUX") == 0 ||401wcscmp(dname, L"NUL") == 0)402return TRUE;403if ((wcsncmp(dname, L"COM", 3) == 0 ||404wcsncmp(dname, L"LPT", 3) == 0) &&405dname[3] - L'0' > 0 &&406dname[3] - L'0' <= 9)407return TRUE;408}409return FALSE;410}411412JNIEXPORT jint JNICALL413Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this,414jobject file)415{416jint rv = 0;417418WCHAR *pathbuf = fileToNTPath(env, file, ids.path);419if (pathbuf == NULL)420return rv;421if (!isReservedDeviceNameW(pathbuf)) {422DWORD a = getFinalAttributes(pathbuf);423if (a != INVALID_FILE_ATTRIBUTES) {424rv = (java_io_FileSystem_BA_EXISTS425| ((a & FILE_ATTRIBUTE_DIRECTORY)426? java_io_FileSystem_BA_DIRECTORY427: java_io_FileSystem_BA_REGULAR)428| ((a & FILE_ATTRIBUTE_HIDDEN)429? java_io_FileSystem_BA_HIDDEN : 0));430}431}432free(pathbuf);433return rv;434}435436437JNIEXPORT jboolean438JNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this,439jobject file, jint access)440{441DWORD attr;442WCHAR *pathbuf = fileToNTPath(env, file, ids.path);443if (pathbuf == NULL)444return JNI_FALSE;445attr = GetFileAttributesW(pathbuf);446attr = getFinalAttributesIfReparsePoint(pathbuf, attr);447free(pathbuf);448if (attr == INVALID_FILE_ATTRIBUTES)449return JNI_FALSE;450switch (access) {451case java_io_FileSystem_ACCESS_READ:452case java_io_FileSystem_ACCESS_EXECUTE:453return JNI_TRUE;454case java_io_FileSystem_ACCESS_WRITE:455/* Read-only attribute ignored on directories */456if ((attr & FILE_ATTRIBUTE_DIRECTORY) ||457(attr & FILE_ATTRIBUTE_READONLY) == 0)458return JNI_TRUE;459else460return JNI_FALSE;461default:462assert(0);463return JNI_FALSE;464}465}466467JNIEXPORT jboolean JNICALL468Java_java_io_WinNTFileSystem_setPermission(JNIEnv *env, jobject this,469jobject file,470jint access,471jboolean enable,472jboolean owneronly)473{474jboolean rv = JNI_FALSE;475WCHAR *pathbuf;476DWORD a;477if (access == java_io_FileSystem_ACCESS_READ ||478access == java_io_FileSystem_ACCESS_EXECUTE) {479return enable;480}481pathbuf = fileToNTPath(env, file, ids.path);482if (pathbuf == NULL)483return JNI_FALSE;484a = GetFileAttributesW(pathbuf);485486/* if reparse point, get final target */487if ((a != INVALID_FILE_ATTRIBUTES) &&488((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))489{490WCHAR *fp = getFinalPath(env, pathbuf);491if (fp == NULL) {492a = INVALID_FILE_ATTRIBUTES;493} else {494free(pathbuf);495pathbuf = fp;496a = GetFileAttributesW(pathbuf);497}498}499if ((a != INVALID_FILE_ATTRIBUTES) &&500((a & FILE_ATTRIBUTE_DIRECTORY) == 0))501{502if (enable)503a = a & ~FILE_ATTRIBUTE_READONLY;504else505a = a | FILE_ATTRIBUTE_READONLY;506if (SetFileAttributesW(pathbuf, a))507rv = JNI_TRUE;508}509free(pathbuf);510return rv;511}512513JNIEXPORT jlong JNICALL514Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,515jobject file)516{517jlong rv = 0;518ULARGE_INTEGER modTime;519FILETIME t;520HANDLE h;521WCHAR *pathbuf = fileToNTPath(env, file, ids.path);522if (pathbuf == NULL)523return rv;524h = CreateFileW(pathbuf,525/* Device query access */5260,527/* Share it */528FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,529/* No security attributes */530NULL,531/* Open existing or fail */532OPEN_EXISTING,533/* Backup semantics for directories */534FILE_FLAG_BACKUP_SEMANTICS,535/* No template file */536NULL);537if (h != INVALID_HANDLE_VALUE) {538if (GetFileTime(h, NULL, NULL, &t)) {539modTime.LowPart = (DWORD) t.dwLowDateTime;540modTime.HighPart = (LONG) t.dwHighDateTime;541rv = modTime.QuadPart / 10000;542rv -= 11644473600000;543}544CloseHandle(h);545}546free(pathbuf);547return rv;548}549550JNIEXPORT jlong JNICALL551Java_java_io_WinNTFileSystem_getLength(JNIEnv *env, jobject this, jobject file)552{553jlong rv = 0;554WIN32_FILE_ATTRIBUTE_DATA wfad;555WCHAR *pathbuf = fileToNTPath(env, file, ids.path);556if (pathbuf == NULL)557return rv;558if (GetFileAttributesExW(pathbuf,559GetFileExInfoStandard,560&wfad)) {561if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {562rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;563} else {564/* file is a reparse point so read attributes of final target */565BY_HANDLE_FILE_INFORMATION finfo;566if (getFileInformation(pathbuf, &finfo)) {567rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) +568finfo.nFileSizeLow;569}570}571} else {572if (GetLastError() == ERROR_SHARING_VIOLATION) {573//574// The error is a "share violation", which means the file/dir575// must exist. Try FindFirstFile, we know this at least works576// for pagefile.sys.577//578579WIN32_FIND_DATAW fileData;580HANDLE h = FindFirstFileW(pathbuf, &fileData);581if (h != INVALID_HANDLE_VALUE) {582if ((fileData.dwFileAttributes &583FILE_ATTRIBUTE_REPARSE_POINT) == 0) {584WCHAR backslash = L'\\';585WCHAR *pslash = wcsrchr(pathbuf, backslash);586if (pslash == NULL) {587pslash = pathbuf;588} else {589pslash++;590}591WCHAR *fslash = wcsrchr(fileData.cFileName, backslash);592if (fslash == NULL) {593fslash = fileData.cFileName;594} else {595fslash++;596}597if (wcscmp(pslash, fslash) == 0) {598ULARGE_INTEGER length;599length.LowPart = fileData.nFileSizeLow;600length.HighPart = fileData.nFileSizeHigh;601if (length.QuadPart <= _I64_MAX) {602rv = (jlong)length.QuadPart;603}604}605}606FindClose(h);607}608}609}610free(pathbuf);611return rv;612}613614/* -- File operations -- */615616JNIEXPORT jboolean JNICALL617Java_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls,618jstring path)619{620HANDLE h = NULL;621WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);622if (pathbuf == NULL)623return JNI_FALSE;624if (isReservedDeviceNameW(pathbuf)) {625free(pathbuf);626return JNI_FALSE;627}628h = CreateFileW(629pathbuf, /* Wide char path name */630GENERIC_READ | GENERIC_WRITE, /* Read and write permission */631FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */632NULL, /* Security attributes */633CREATE_NEW, /* creation disposition */634FILE_ATTRIBUTE_NORMAL |635FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */636NULL);637638if (h == INVALID_HANDLE_VALUE) {639DWORD error = GetLastError();640if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {641// return false rather than throwing an exception when there is642// an existing file.643DWORD a = GetFileAttributesW(pathbuf);644if (a == INVALID_FILE_ATTRIBUTES) {645SetLastError(error);646JNU_ThrowIOExceptionWithLastError(env, "Could not open file");647}648}649free(pathbuf);650return JNI_FALSE;651}652free(pathbuf);653CloseHandle(h);654return JNI_TRUE;655}656657static int658removeFileOrDirectory(const jchar *path)659{660/* Returns 0 on success */661DWORD a;662663SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);664a = GetFileAttributesW(path);665if (a == INVALID_FILE_ATTRIBUTES) {666return 1;667} else if (a & FILE_ATTRIBUTE_DIRECTORY) {668return !RemoveDirectoryW(path);669} else {670return !DeleteFileW(path);671}672}673674JNIEXPORT jboolean JNICALL675Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file)676{677jboolean rv = JNI_FALSE;678WCHAR *pathbuf = fileToNTPath(env, file, ids.path);679if (pathbuf == NULL) {680return JNI_FALSE;681}682if (removeFileOrDirectory(pathbuf) == 0) {683rv = JNI_TRUE;684}685free(pathbuf);686return rv;687}688689JNIEXPORT jobjectArray JNICALL690Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file)691{692WCHAR *search_path;693HANDLE handle;694WIN32_FIND_DATAW find_data;695int len, maxlen;696jobjectArray rv, old;697DWORD fattr;698jstring name;699jclass str_class;700WCHAR *pathbuf;701DWORD err;702703str_class = JNU_ClassString(env);704CHECK_NULL_RETURN(str_class, NULL);705706pathbuf = fileToNTPath(env, file, ids.path);707if (pathbuf == NULL)708return NULL;709search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);710if (search_path == 0) {711free (pathbuf);712errno = ENOMEM;713JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");714return NULL;715}716wcscpy(search_path, pathbuf);717free(pathbuf);718fattr = GetFileAttributesW(search_path);719if (fattr == INVALID_FILE_ATTRIBUTES) {720free(search_path);721return NULL;722} else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {723free(search_path);724return NULL;725}726727/* Remove trailing space chars from directory name */728len = (int)wcslen(search_path);729while (search_path[len-1] == L' ') {730len--;731}732search_path[len] = 0;733734/* Append "*", or possibly "\\*", to path */735if ((search_path[0] == L'\\' && search_path[1] == L'\0') ||736(search_path[1] == L':'737&& (search_path[2] == L'\0'738|| (search_path[2] == L'\\' && search_path[3] == L'\0')))) {739/* No '\\' needed for cases like "\" or "Z:" or "Z:\" */740wcscat(search_path, L"*");741} else {742wcscat(search_path, L"\\*");743}744745/* Open handle to the first file */746handle = FindFirstFileW(search_path, &find_data);747free(search_path);748if (handle == INVALID_HANDLE_VALUE) {749if (GetLastError() != ERROR_FILE_NOT_FOUND) {750// error751return NULL;752} else {753// No files found - return an empty array754rv = (*env)->NewObjectArray(env, 0, str_class, NULL);755return rv;756}757}758759/* Allocate an initial String array */760len = 0;761maxlen = 16;762rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);763if (rv == NULL) { // Couldn't allocate an array764FindClose(handle);765return NULL;766}767/* Scan the directory */768do {769if (!wcscmp(find_data.cFileName, L".")770|| !wcscmp(find_data.cFileName, L".."))771continue;772name = (*env)->NewString(env, find_data.cFileName,773(jsize)wcslen(find_data.cFileName));774if (name == NULL) {775FindClose(handle);776return NULL; // error777}778if (len == maxlen) {779old = rv;780rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);781if (rv == NULL || JNU_CopyObjectArray(env, rv, old, len) < 0) {782FindClose(handle);783return NULL; // error784}785(*env)->DeleteLocalRef(env, old);786}787(*env)->SetObjectArrayElement(env, rv, len++, name);788(*env)->DeleteLocalRef(env, name);789790} while (FindNextFileW(handle, &find_data));791792err = GetLastError();793FindClose(handle);794if (err != ERROR_NO_MORE_FILES) {795return NULL; // error796}797798if (len < maxlen) {799/* Copy the final results into an appropriately-sized array */800old = rv;801rv = (*env)->NewObjectArray(env, len, str_class, NULL);802if (rv == NULL)803return NULL; /* error */804if (JNU_CopyObjectArray(env, rv, old, len) < 0)805return NULL; /* error */806}807return rv;808}809810811JNIEXPORT jboolean JNICALL812Java_java_io_WinNTFileSystem_createDirectory(JNIEnv *env, jobject this,813jobject file)814{815BOOL h = FALSE;816WCHAR *pathbuf = fileToNTPath(env, file, ids.path);817if (pathbuf == NULL) {818/* Exception is pending */819return JNI_FALSE;820}821h = CreateDirectoryW(pathbuf, NULL);822free(pathbuf);823824if (h == 0) {825return JNI_FALSE;826}827828return JNI_TRUE;829}830831832JNIEXPORT jboolean JNICALL833Java_java_io_WinNTFileSystem_rename0(JNIEnv *env, jobject this, jobject from,834jobject to)835{836837jboolean rv = JNI_FALSE;838WCHAR *frompath = fileToNTPath(env, from, ids.path);839WCHAR *topath = fileToNTPath(env, to, ids.path);840if (frompath != NULL && topath != NULL && _wrename(frompath, topath) == 0) {841rv = JNI_TRUE;842}843free(frompath);844free(topath);845return rv;846}847848849JNIEXPORT jboolean JNICALL850Java_java_io_WinNTFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,851jobject file, jlong time)852{853jboolean rv = JNI_FALSE;854WCHAR *pathbuf = fileToNTPath(env, file, ids.path);855HANDLE h;856if (pathbuf == NULL)857return JNI_FALSE;858h = CreateFileW(pathbuf,859FILE_WRITE_ATTRIBUTES,860FILE_SHARE_READ | FILE_SHARE_WRITE,861NULL,862OPEN_EXISTING,863FILE_FLAG_BACKUP_SEMANTICS,8640);865if (h != INVALID_HANDLE_VALUE) {866ULARGE_INTEGER modTime;867FILETIME t;868modTime.QuadPart = (time + 11644473600000L) * 10000L;869t.dwLowDateTime = (DWORD)modTime.LowPart;870t.dwHighDateTime = (DWORD)modTime.HighPart;871if (SetFileTime(h, NULL, NULL, &t)) {872rv = JNI_TRUE;873}874CloseHandle(h);875}876free(pathbuf);877878return rv;879}880881882JNIEXPORT jboolean JNICALL883Java_java_io_WinNTFileSystem_setReadOnly(JNIEnv *env, jobject this,884jobject file)885{886jboolean rv = JNI_FALSE;887DWORD a;888WCHAR *pathbuf = fileToNTPath(env, file, ids.path);889if (pathbuf == NULL)890return JNI_FALSE;891a = GetFileAttributesW(pathbuf);892893/* if reparse point, get final target */894if ((a != INVALID_FILE_ATTRIBUTES) &&895((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))896{897WCHAR *fp = getFinalPath(env, pathbuf);898if (fp == NULL) {899a = INVALID_FILE_ATTRIBUTES;900} else {901free(pathbuf);902pathbuf = fp;903a = GetFileAttributesW(pathbuf);904}905}906907if ((a != INVALID_FILE_ATTRIBUTES) &&908((a & FILE_ATTRIBUTE_DIRECTORY) == 0)) {909if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))910rv = JNI_TRUE;911}912free(pathbuf);913return rv;914}915916/* -- Filesystem interface -- */917918919JNIEXPORT jobject JNICALL920Java_java_io_WinNTFileSystem_getDriveDirectory(JNIEnv *env, jobject this,921jint drive)922{923jstring ret = NULL;924jchar *p = currentDir(drive);925jchar *pf = p;926if (p == NULL) return NULL;927if (iswalpha(*p) && (p[1] == L':')) p += 2;928ret = (*env)->NewString(env, p, (jsize)wcslen(p));929free (pf);930return ret;931}932933JNIEXPORT jint JNICALL934Java_java_io_WinNTFileSystem_listRoots0(JNIEnv *env, jclass ignored)935{936return GetLogicalDrives();937}938939JNIEXPORT jlong JNICALL940Java_java_io_WinNTFileSystem_getSpace0(JNIEnv *env, jobject this,941jobject file, jint t)942{943WCHAR volname[MAX_PATH_LENGTH + 1];944jlong rv = 0L;945WCHAR *pathbuf = fileToNTPath(env, file, ids.path);946947if (GetVolumePathNameW(pathbuf, volname, MAX_PATH_LENGTH)) {948ULARGE_INTEGER totalSpace, freeSpace, usableSpace;949if (GetDiskFreeSpaceExW(volname, &usableSpace, &totalSpace, &freeSpace)) {950switch(t) {951case java_io_FileSystem_SPACE_TOTAL:952rv = long_to_jlong(totalSpace.QuadPart);953break;954case java_io_FileSystem_SPACE_FREE:955rv = long_to_jlong(freeSpace.QuadPart);956break;957case java_io_FileSystem_SPACE_USABLE:958rv = long_to_jlong(usableSpace.QuadPart);959break;960default:961assert(0);962}963}964}965966free(pathbuf);967return rv;968}969970// pathname is expected to be either null or to contain the root971// of the path terminated by a backslash972JNIEXPORT jint JNICALL973Java_java_io_WinNTFileSystem_getNameMax0(JNIEnv *env, jobject this,974jstring pathname)975{976BOOL res = 0;977DWORD maxComponentLength;978979if (pathname == NULL) {980res = GetVolumeInformationW(NULL,981NULL,9820,983NULL,984&maxComponentLength,985NULL,986NULL,9870);988} else {989WITH_UNICODE_STRING(env, pathname, path) {990res = GetVolumeInformationW(path,991NULL,9920,993NULL,994&maxComponentLength,995NULL,996NULL,9970);998} END_UNICODE_STRING(env, path);999}10001001if (res == 0) {1002JNU_ThrowIOExceptionWithLastError(env,1003"Could not get maximum component length");1004}10051006return (jint)maxComponentLength;1007}100810091010