Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/io/WinNTFileSystem_md.c
32287 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>3839#include "jni.h"40#include "io_util.h"41#include "jlong.h"42#include "io_util_md.h"43#include "dirent_md.h"44#include "java_io_FileSystem.h"4546#define MAX_PATH_LENGTH 10244748static struct {49jfieldID path;50} ids;5152/**53* GetFinalPathNameByHandle is available on Windows Vista and newer54*/55typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);56static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;5758JNIEXPORT void JNICALL59Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)60{61HMODULE handle;62jclass fileClass;6364fileClass = (*env)->FindClass(env, "java/io/File");65CHECK_NULL(fileClass);66ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");67CHECK_NULL(ids.path);6869// GetFinalPathNameByHandle requires Windows Vista or newer70if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |71GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),72(LPCWSTR)&CreateFileW, &handle) != 0)73{74GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)75GetProcAddress(handle, "GetFinalPathNameByHandleW");76}77}7879/* -- Path operations -- */8081extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);82extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);8384/**85* Retrieves the fully resolved (final) path for the given path or NULL86* if the function fails.87*/88static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)89{90HANDLE h;91WCHAR *result;92DWORD error;9394/* Need Windows Vista or newer to get the final path */95if (GetFinalPathNameByHandle_func == NULL)96return NULL;9798h = CreateFileW(path,99FILE_READ_ATTRIBUTES,100FILE_SHARE_DELETE |101FILE_SHARE_READ | FILE_SHARE_WRITE,102NULL,103OPEN_EXISTING,104FILE_FLAG_BACKUP_SEMANTICS,105NULL);106if (h == INVALID_HANDLE_VALUE)107return NULL;108109/**110* Allocate a buffer for the resolved path. For a long path we may need111* to allocate a larger buffer.112*/113result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR));114if (result != NULL) {115DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0);116if (len >= MAX_PATH) {117/* retry with a buffer of the right size */118WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR));119if (newResult != NULL) {120result = newResult;121len = (*GetFinalPathNameByHandle_func)(h, result, len, 0);122} else {123len = 0;124JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");125}126}127128if (len > 0) {129/**130* Strip prefix (should be \\?\ or \\?\UNC)131*/132if (result[0] == L'\\' && result[1] == L'\\' &&133result[2] == L'?' && result[3] == L'\\')134{135int isUnc = (result[4] == L'U' &&136result[5] == L'N' &&137result[6] == L'C');138int prefixLen = (isUnc) ? 7 : 4;139/* actual result length (includes terminator) */140int resultLen = len - prefixLen + (isUnc ? 1 : 0) + 1;141142/* copy result without prefix into new buffer */143WCHAR *tmp = (WCHAR*)malloc(resultLen * sizeof(WCHAR));144if (tmp == NULL) {145JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");146len = 0;147} else {148WCHAR *p = result;149p += prefixLen;150if (isUnc) {151WCHAR *p2 = tmp;152p2[0] = L'\\';153p2++;154wcscpy(p2, p);155} else {156wcscpy(tmp, p);157}158free(result);159result = tmp;160}161}162}163164/* unable to get final path */165if (len == 0 && result != NULL) {166free(result);167result = NULL;168}169} else {170JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");171}172173error = GetLastError();174if (CloseHandle(h))175SetLastError(error);176return result;177}178179/**180* Retrieves file information for the specified file. If the file is181* symbolic link then the information on fully resolved target is182* returned.183*/184static BOOL getFileInformation(const WCHAR *path,185BY_HANDLE_FILE_INFORMATION *finfo)186{187BOOL result;188DWORD error;189HANDLE h = CreateFileW(path,190FILE_READ_ATTRIBUTES,191FILE_SHARE_DELETE |192FILE_SHARE_READ | FILE_SHARE_WRITE,193NULL,194OPEN_EXISTING,195FILE_FLAG_BACKUP_SEMANTICS,196NULL);197if (h == INVALID_HANDLE_VALUE)198return FALSE;199result = GetFileInformationByHandle(h, finfo);200error = GetLastError();201if (CloseHandle(h))202SetLastError(error);203return result;204}205206/**207* If the given attributes are the attributes of a reparse point, then208* read and return the attributes of the special cases.209*/210DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)211{212if ((a != INVALID_FILE_ATTRIBUTES) &&213((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))214{215BY_HANDLE_FILE_INFORMATION finfo;216BOOL res = getFileInformation(path, &finfo);217a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES;218}219return a;220}221222/**223* Take special cases into account when retrieving the attributes224* of path225*/226DWORD getFinalAttributes(WCHAR *path)227{228DWORD attr = INVALID_FILE_ATTRIBUTES;229230WIN32_FILE_ATTRIBUTE_DATA wfad;231WIN32_FIND_DATAW wfd;232HANDLE h;233234if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) {235attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes);236} else if (GetLastError() == ERROR_SHARING_VIOLATION &&237(h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) {238attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes);239FindClose(h);240}241return attr;242}243244JNIEXPORT jstring JNICALL245Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,246jstring pathname)247{248jstring rv = NULL;249WCHAR canonicalPath[MAX_PATH_LENGTH];250251WITH_UNICODE_STRING(env, pathname, path) {252/* we estimate the max length of memory needed as253"currentDir. length + pathname.length"254*/255int len = (int)wcslen(path);256len += currentDirLength(path, len);257if (len > MAX_PATH_LENGTH - 1) {258WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));259if (cp != NULL) {260if (wcanonicalize(path, cp, len) >= 0) {261rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));262}263free(cp);264} else {265JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");266}267} else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {268rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));269}270} END_UNICODE_STRING(env, path);271if (rv == NULL && !(*env)->ExceptionCheck(env)) {272JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");273}274return rv;275}276277278JNIEXPORT jstring JNICALL279Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,280jstring canonicalPrefixString,281jstring pathWithCanonicalPrefixString)282{283jstring rv = NULL;284WCHAR canonicalPath[MAX_PATH_LENGTH];285WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {286WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {287int len = (int)wcslen(canonicalPrefix) + MAX_PATH;288if (len > MAX_PATH_LENGTH) {289WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));290if (cp != NULL) {291if (wcanonicalizeWithPrefix(canonicalPrefix,292pathWithCanonicalPrefix,293cp, len) >= 0) {294rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));295}296free(cp);297} else {298JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");299}300} else if (wcanonicalizeWithPrefix(canonicalPrefix,301pathWithCanonicalPrefix,302canonicalPath, MAX_PATH_LENGTH) >= 0) {303rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));304}305} END_UNICODE_STRING(env, pathWithCanonicalPrefix);306} END_UNICODE_STRING(env, canonicalPrefix);307if (rv == NULL && !(*env)->ExceptionCheck(env)) {308JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");309}310return rv;311}312313/* -- Attribute accessors -- */314315/* Check whether or not the file name in "path" is a Windows reserved316device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the317returned result from GetFullPathName, which should be in thr form of318"\\.\[ReservedDeviceName]" if the path represents a reserved device319name.320Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer321important anyway) is a device name, so we don't check it here.322GetFileAttributesEx will catch it later by returning 0 on NT/XP/323200X.324325Note2: Theoretically the implementation could just lookup the table326below linearly if the first 4 characters of the fullpath returned327from GetFullPathName are "\\.\". The current implementation should328achieve the same result. If Microsoft add more names into their329reserved device name repository in the future, which probably will330never happen, we will need to revisit the lookup implementation.331332static WCHAR* ReservedDEviceNames[] = {333L"CON", L"PRN", L"AUX", L"NUL",334L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9",335L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9",336L"CLOCK$"337};338*/339340static BOOL isReservedDeviceNameW(WCHAR* path) {341#define BUFSIZE 9342WCHAR buf[BUFSIZE];343WCHAR *lpf = NULL;344DWORD retLen = GetFullPathNameW(path,345BUFSIZE,346buf,347&lpf);348if ((retLen == BUFSIZE - 1 || retLen == BUFSIZE - 2) &&349buf[0] == L'\\' && buf[1] == L'\\' &&350buf[2] == L'.' && buf[3] == L'\\') {351WCHAR* dname = _wcsupr(buf + 4);352if (wcscmp(dname, L"CON") == 0 ||353wcscmp(dname, L"PRN") == 0 ||354wcscmp(dname, L"AUX") == 0 ||355wcscmp(dname, L"NUL") == 0)356return TRUE;357if ((wcsncmp(dname, L"COM", 3) == 0 ||358wcsncmp(dname, L"LPT", 3) == 0) &&359dname[3] - L'0' > 0 &&360dname[3] - L'0' <= 9)361return TRUE;362}363return FALSE;364}365366JNIEXPORT jint JNICALL367Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this,368jobject file)369{370jint rv = 0;371jint pathlen;372373WCHAR *pathbuf = fileToNTPath(env, file, ids.path);374if (pathbuf == NULL)375return rv;376if (!isReservedDeviceNameW(pathbuf)) {377DWORD a = getFinalAttributes(pathbuf);378if (a != INVALID_FILE_ATTRIBUTES) {379rv = (java_io_FileSystem_BA_EXISTS380| ((a & FILE_ATTRIBUTE_DIRECTORY)381? java_io_FileSystem_BA_DIRECTORY382: java_io_FileSystem_BA_REGULAR)383| ((a & FILE_ATTRIBUTE_HIDDEN)384? java_io_FileSystem_BA_HIDDEN : 0));385}386}387free(pathbuf);388return rv;389}390391392JNIEXPORT jboolean393JNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this,394jobject file, jint access)395{396DWORD attr;397WCHAR *pathbuf = fileToNTPath(env, file, ids.path);398if (pathbuf == NULL)399return JNI_FALSE;400attr = GetFileAttributesW(pathbuf);401attr = getFinalAttributesIfReparsePoint(pathbuf, attr);402free(pathbuf);403if (attr == INVALID_FILE_ATTRIBUTES)404return JNI_FALSE;405switch (access) {406case java_io_FileSystem_ACCESS_READ:407case java_io_FileSystem_ACCESS_EXECUTE:408return JNI_TRUE;409case java_io_FileSystem_ACCESS_WRITE:410/* Read-only attribute ignored on directories */411if ((attr & FILE_ATTRIBUTE_DIRECTORY) ||412(attr & FILE_ATTRIBUTE_READONLY) == 0)413return JNI_TRUE;414else415return JNI_FALSE;416default:417assert(0);418return JNI_FALSE;419}420}421422JNIEXPORT jboolean JNICALL423Java_java_io_WinNTFileSystem_setPermission(JNIEnv *env, jobject this,424jobject file,425jint access,426jboolean enable,427jboolean owneronly)428{429jboolean rv = JNI_FALSE;430WCHAR *pathbuf;431DWORD a;432if (access == java_io_FileSystem_ACCESS_READ ||433access == java_io_FileSystem_ACCESS_EXECUTE) {434return enable;435}436pathbuf = fileToNTPath(env, file, ids.path);437if (pathbuf == NULL)438return JNI_FALSE;439a = GetFileAttributesW(pathbuf);440441/* if reparse point, get final target */442if ((a != INVALID_FILE_ATTRIBUTES) &&443((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))444{445WCHAR *fp = getFinalPath(env, pathbuf);446if (fp == NULL) {447a = INVALID_FILE_ATTRIBUTES;448} else {449free(pathbuf);450pathbuf = fp;451a = GetFileAttributesW(pathbuf);452}453}454if ((a != INVALID_FILE_ATTRIBUTES) &&455((a & FILE_ATTRIBUTE_DIRECTORY) == 0))456{457if (enable)458a = a & ~FILE_ATTRIBUTE_READONLY;459else460a = a | FILE_ATTRIBUTE_READONLY;461if (SetFileAttributesW(pathbuf, a))462rv = JNI_TRUE;463}464free(pathbuf);465return rv;466}467468JNIEXPORT jlong JNICALL469Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,470jobject file)471{472jlong rv = 0;473LARGE_INTEGER modTime;474FILETIME t;475HANDLE h;476WCHAR *pathbuf = fileToNTPath(env, file, ids.path);477if (pathbuf == NULL)478return rv;479h = CreateFileW(pathbuf,480/* Device query access */4810,482/* Share it */483FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,484/* No security attributes */485NULL,486/* Open existing or fail */487OPEN_EXISTING,488/* Backup semantics for directories */489FILE_FLAG_BACKUP_SEMANTICS,490/* No template file */491NULL);492if (h != INVALID_HANDLE_VALUE) {493if (GetFileTime(h, NULL, NULL, &t)) {494modTime.LowPart = (DWORD) t.dwLowDateTime;495modTime.HighPart = (LONG) t.dwHighDateTime;496rv = modTime.QuadPart / 10000;497rv -= 11644473600000;498}499CloseHandle(h);500}501free(pathbuf);502return rv;503}504505JNIEXPORT jlong JNICALL506Java_java_io_WinNTFileSystem_getLength(JNIEnv *env, jobject this, jobject file)507{508jlong rv = 0;509WIN32_FILE_ATTRIBUTE_DATA wfad;510WCHAR *pathbuf = fileToNTPath(env, file, ids.path);511if (pathbuf == NULL)512return rv;513if (GetFileAttributesExW(pathbuf,514GetFileExInfoStandard,515&wfad)) {516if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {517rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;518} else {519/* file is a reparse point so read attributes of final target */520BY_HANDLE_FILE_INFORMATION finfo;521if (getFileInformation(pathbuf, &finfo)) {522rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) +523finfo.nFileSizeLow;524}525}526} else {527if (GetLastError() == ERROR_SHARING_VIOLATION) {528//529// The error is a "share violation", which means the file/dir530// must exist. Try FindFirstFile, we know this at least works531// for pagefile.sys.532//533534WIN32_FIND_DATAW fileData;535HANDLE h = FindFirstFileW(pathbuf, &fileData);536if (h != INVALID_HANDLE_VALUE) {537if ((fileData.dwFileAttributes &538FILE_ATTRIBUTE_REPARSE_POINT) == 0) {539WCHAR backslash = L'\\';540WCHAR *pslash = wcsrchr(pathbuf, backslash);541WCHAR *fslash = wcsrchr(fileData.cFileName, backslash);542if (pslash == NULL) {543pslash = pathbuf;544} else {545pslash++;546}547if (fslash == NULL) {548fslash = fileData.cFileName;549} else {550fslash++;551}552if (wcscmp(pslash, fslash) == 0) {553ULARGE_INTEGER length;554length.LowPart = fileData.nFileSizeLow;555length.HighPart = fileData.nFileSizeHigh;556if (length.QuadPart <= _I64_MAX) {557rv = (jlong)length.QuadPart;558}559}560}561FindClose(h);562}563}564}565free(pathbuf);566return rv;567}568569/* -- File operations -- */570571JNIEXPORT jboolean JNICALL572Java_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls,573jstring path)574{575HANDLE h = NULL;576WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);577if (pathbuf == NULL)578return JNI_FALSE;579if (isReservedDeviceNameW(pathbuf)) {580free(pathbuf);581return JNI_FALSE;582}583h = CreateFileW(584pathbuf, /* Wide char path name */585GENERIC_READ | GENERIC_WRITE, /* Read and write permission */586FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */587NULL, /* Security attributes */588CREATE_NEW, /* creation disposition */589FILE_ATTRIBUTE_NORMAL |590FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */591NULL);592593if (h == INVALID_HANDLE_VALUE) {594DWORD error = GetLastError();595if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {596// return false rather than throwing an exception when there is597// an existing file.598DWORD a = GetFileAttributesW(pathbuf);599if (a == INVALID_FILE_ATTRIBUTES) {600SetLastError(error);601JNU_ThrowIOExceptionWithLastError(env, "Could not open file");602}603}604free(pathbuf);605return JNI_FALSE;606}607free(pathbuf);608CloseHandle(h);609return JNI_TRUE;610}611612static int613removeFileOrDirectory(const jchar *path)614{615/* Returns 0 on success */616DWORD a;617618SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);619a = GetFileAttributesW(path);620if (a == INVALID_FILE_ATTRIBUTES) {621return 1;622} else if (a & FILE_ATTRIBUTE_DIRECTORY) {623return !RemoveDirectoryW(path);624} else {625return !DeleteFileW(path);626}627}628629JNIEXPORT jboolean JNICALL630Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file)631{632jboolean rv = JNI_FALSE;633WCHAR *pathbuf = fileToNTPath(env, file, ids.path);634if (pathbuf == NULL) {635return JNI_FALSE;636}637if (removeFileOrDirectory(pathbuf) == 0) {638rv = JNI_TRUE;639}640free(pathbuf);641return rv;642}643644JNIEXPORT jobjectArray JNICALL645Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file)646{647WCHAR *search_path;648HANDLE handle;649WIN32_FIND_DATAW find_data;650int len, maxlen;651jobjectArray rv, old;652DWORD fattr;653jstring name;654jclass str_class;655WCHAR *pathbuf;656DWORD err;657658str_class = JNU_ClassString(env);659CHECK_NULL_RETURN(str_class, NULL);660661pathbuf = fileToNTPath(env, file, ids.path);662if (pathbuf == NULL)663return NULL;664search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);665if (search_path == 0) {666free (pathbuf);667errno = ENOMEM;668JNU_ThrowOutOfMemoryError(env, "native memory allocation faiuled");669return NULL;670}671wcscpy(search_path, pathbuf);672free(pathbuf);673fattr = GetFileAttributesW(search_path);674if (fattr == INVALID_FILE_ATTRIBUTES) {675free(search_path);676return NULL;677} else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {678free(search_path);679return NULL;680}681682/* Remove trailing space chars from directory name */683len = (int)wcslen(search_path);684while (search_path[len-1] == ' ') {685len--;686}687search_path[len] = 0;688689/* Append "*", or possibly "\\*", to path */690if ((search_path[0] == L'\\' && search_path[1] == L'\0') ||691(search_path[1] == L':'692&& (search_path[2] == L'\0'693|| (search_path[2] == L'\\' && search_path[3] == L'\0')))) {694/* No '\\' needed for cases like "\" or "Z:" or "Z:\" */695wcscat(search_path, L"*");696} else {697wcscat(search_path, L"\\*");698}699700/* Open handle to the first file */701handle = FindFirstFileW(search_path, &find_data);702free(search_path);703if (handle == INVALID_HANDLE_VALUE) {704if (GetLastError() != ERROR_FILE_NOT_FOUND) {705// error706return NULL;707} else {708// No files found - return an empty array709rv = (*env)->NewObjectArray(env, 0, str_class, NULL);710return rv;711}712}713714/* Allocate an initial String array */715len = 0;716maxlen = 16;717rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);718if (rv == NULL) { // Couldn't allocate an array719FindClose(handle);720return NULL;721}722/* Scan the directory */723do {724if (!wcscmp(find_data.cFileName, L".")725|| !wcscmp(find_data.cFileName, L".."))726continue;727name = (*env)->NewString(env, find_data.cFileName,728(jsize)wcslen(find_data.cFileName));729if (name == NULL) {730FindClose(handle);731return NULL; // error732}733if (len == maxlen) {734old = rv;735rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);736if (rv == NULL || JNU_CopyObjectArray(env, rv, old, len) < 0) {737FindClose(handle);738return NULL; // error739}740(*env)->DeleteLocalRef(env, old);741}742(*env)->SetObjectArrayElement(env, rv, len++, name);743(*env)->DeleteLocalRef(env, name);744745} while (FindNextFileW(handle, &find_data));746747err = GetLastError();748FindClose(handle);749if (err != ERROR_NO_MORE_FILES) {750return NULL; // error751}752753/* Copy the final results into an appropriately-sized array */754old = rv;755rv = (*env)->NewObjectArray(env, len, str_class, NULL);756if (rv == NULL)757return NULL; /* error */758if (JNU_CopyObjectArray(env, rv, old, len) < 0)759return NULL; /* error */760return rv;761}762763764JNIEXPORT jboolean JNICALL765Java_java_io_WinNTFileSystem_createDirectory(JNIEnv *env, jobject this,766jobject file)767{768BOOL h = FALSE;769WCHAR *pathbuf = fileToNTPath(env, file, ids.path);770if (pathbuf == NULL) {771/* Exception is pending */772return JNI_FALSE;773}774h = CreateDirectoryW(pathbuf, NULL);775free(pathbuf);776777if (h == 0) {778return JNI_FALSE;779}780781return JNI_TRUE;782}783784785JNIEXPORT jboolean JNICALL786Java_java_io_WinNTFileSystem_rename0(JNIEnv *env, jobject this, jobject from,787jobject to)788{789790jboolean rv = JNI_FALSE;791WCHAR *frompath = fileToNTPath(env, from, ids.path);792WCHAR *topath = fileToNTPath(env, to, ids.path);793if (frompath == NULL || topath == NULL)794return JNI_FALSE;795if (_wrename(frompath, topath) == 0) {796rv = JNI_TRUE;797}798free(frompath);799free(topath);800return rv;801}802803804JNIEXPORT jboolean JNICALL805Java_java_io_WinNTFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,806jobject file, jlong time)807{808jboolean rv = JNI_FALSE;809WCHAR *pathbuf = fileToNTPath(env, file, ids.path);810HANDLE h;811if (pathbuf == NULL)812return JNI_FALSE;813h = CreateFileW(pathbuf,814FILE_WRITE_ATTRIBUTES,815FILE_SHARE_READ | FILE_SHARE_WRITE,816NULL,817OPEN_EXISTING,818FILE_FLAG_BACKUP_SEMANTICS,8190);820if (h != INVALID_HANDLE_VALUE) {821LARGE_INTEGER modTime;822FILETIME t;823modTime.QuadPart = (time + 11644473600000L) * 10000L;824t.dwLowDateTime = (DWORD)modTime.LowPart;825t.dwHighDateTime = (DWORD)modTime.HighPart;826if (SetFileTime(h, NULL, NULL, &t)) {827rv = JNI_TRUE;828}829CloseHandle(h);830}831free(pathbuf);832833return rv;834}835836837JNIEXPORT jboolean JNICALL838Java_java_io_WinNTFileSystem_setReadOnly(JNIEnv *env, jobject this,839jobject file)840{841jboolean rv = JNI_FALSE;842DWORD a;843WCHAR *pathbuf = fileToNTPath(env, file, ids.path);844if (pathbuf == NULL)845return JNI_FALSE;846a = GetFileAttributesW(pathbuf);847848/* if reparse point, get final target */849if ((a != INVALID_FILE_ATTRIBUTES) &&850((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))851{852WCHAR *fp = getFinalPath(env, pathbuf);853if (fp == NULL) {854a = INVALID_FILE_ATTRIBUTES;855} else {856free(pathbuf);857pathbuf = fp;858a = GetFileAttributesW(pathbuf);859}860}861862if ((a != INVALID_FILE_ATTRIBUTES) &&863((a & FILE_ATTRIBUTE_DIRECTORY) == 0)) {864if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))865rv = JNI_TRUE;866}867free(pathbuf);868return rv;869}870871/* -- Filesystem interface -- */872873874JNIEXPORT jobject JNICALL875Java_java_io_WinNTFileSystem_getDriveDirectory(JNIEnv *env, jobject this,876jint drive)877{878jstring ret = NULL;879jchar *p = currentDir(drive);880jchar *pf = p;881if (p == NULL) return NULL;882if (iswalpha(*p) && (p[1] == L':')) p += 2;883ret = (*env)->NewString(env, p, (jsize)wcslen(p));884free (pf);885return ret;886}887888JNIEXPORT jint JNICALL889Java_java_io_WinNTFileSystem_listRoots0(JNIEnv *env, jclass ignored)890{891return GetLogicalDrives();892}893894JNIEXPORT jlong JNICALL895Java_java_io_WinNTFileSystem_getSpace0(JNIEnv *env, jobject this,896jobject file, jint t)897{898WCHAR volname[MAX_PATH_LENGTH + 1];899jlong rv = 0L;900WCHAR *pathbuf = fileToNTPath(env, file, ids.path);901902if (GetVolumePathNameW(pathbuf, volname, MAX_PATH_LENGTH)) {903ULARGE_INTEGER totalSpace, freeSpace, usableSpace;904if (GetDiskFreeSpaceExW(volname, &usableSpace, &totalSpace, &freeSpace)) {905switch(t) {906case java_io_FileSystem_SPACE_TOTAL:907rv = long_to_jlong(totalSpace.QuadPart);908break;909case java_io_FileSystem_SPACE_FREE:910rv = long_to_jlong(freeSpace.QuadPart);911break;912case java_io_FileSystem_SPACE_USABLE:913rv = long_to_jlong(usableSpace.QuadPart);914break;915default:916assert(0);917}918}919}920921free(pathbuf);922return rv;923}924925926