0N/A/*
6153N/A * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
3901N/A/* Access APIs for WinXP and above */
0N/A#ifndef _WIN32_WINNT
3901N/A#define _WIN32_WINNT 0x0501
0N/A#endif
0N/A
0N/A#include <assert.h>
0N/A#include <stdio.h>
0N/A#include <stdlib.h>
0N/A#include <ctype.h>
0N/A#include <direct.h>
0N/A#include <windows.h>
0N/A#include <io.h>
0N/A
0N/A#include "jni.h"
0N/A#include "io_util.h"
0N/A#include "jlong.h"
0N/A#include "io_util_md.h"
0N/A#include "dirent_md.h"
0N/A#include "java_io_FileSystem.h"
0N/A
0N/A#define MAX_PATH_LENGTH 1024
0N/A
0N/Astatic struct {
0N/A jfieldID path;
0N/A} ids;
0N/A
1575N/A/**
1575N/A * GetFinalPathNameByHandle is available on Windows Vista and newer
1575N/A */
1575N/Atypedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
1575N/Astatic GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
1575N/A
0N/AJNIEXPORT void JNICALL
0N/AJava_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
0N/A{
3901N/A HMODULE handle;
0N/A jclass fileClass = (*env)->FindClass(env, "java/io/File");
0N/A if (!fileClass) return;
0N/A ids.path =
0N/A (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
3901N/A
3901N/A // GetFinalPathNameByHandle requires Windows Vista or newer
3901N/A if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
3901N/A GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
3901N/A (LPCWSTR)&CreateFileW, &handle) != 0)
3901N/A {
1575N/A GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
1575N/A GetProcAddress(handle, "GetFinalPathNameByHandleW");
1575N/A }
0N/A}
0N/A
0N/A/* -- Path operations -- */
0N/A
0N/Aextern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
0N/Aextern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
0N/A
1575N/A/**
1575N/A * Retrieves the fully resolved (final) path for the given path or NULL
1575N/A * if the function fails.
1575N/A */
1575N/Astatic WCHAR* getFinalPath(const WCHAR *path)
1575N/A{
1575N/A HANDLE h;
1575N/A WCHAR *result;
1575N/A DWORD error;
1575N/A
1575N/A /* Need Windows Vista or newer to get the final path */
1575N/A if (GetFinalPathNameByHandle_func == NULL)
1575N/A return NULL;
1575N/A
1575N/A h = CreateFileW(path,
1575N/A FILE_READ_ATTRIBUTES,
1575N/A FILE_SHARE_DELETE |
1575N/A FILE_SHARE_READ | FILE_SHARE_WRITE,
1575N/A NULL,
1575N/A OPEN_EXISTING,
1575N/A FILE_FLAG_BACKUP_SEMANTICS,
1575N/A NULL);
1575N/A if (h == INVALID_HANDLE_VALUE)
1575N/A return NULL;
1575N/A
1575N/A /**
1575N/A * Allocate a buffer for the resolved path. For a long path we may need
1575N/A * to allocate a larger buffer.
1575N/A */
1575N/A result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR));
1575N/A if (result != NULL) {
1575N/A DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0);
1575N/A if (len >= MAX_PATH) {
1575N/A /* retry with a buffer of the right size */
5862N/A WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR));
5862N/A if (newResult != NULL) {
5862N/A result = newResult;
1575N/A len = (*GetFinalPathNameByHandle_func)(h, result, len, 0);
1575N/A } else {
1575N/A len = 0;
1575N/A }
1575N/A }
5862N/A
1575N/A if (len > 0) {
1575N/A /**
1575N/A * Strip prefix (should be \\?\ or \\?\UNC)
1575N/A */
1575N/A if (result[0] == L'\\' && result[1] == L'\\' &&
1575N/A result[2] == L'?' && result[3] == L'\\')
1575N/A {
1575N/A int isUnc = (result[4] == L'U' &&
1575N/A result[5] == L'N' &&
1575N/A result[6] == L'C');
1575N/A int prefixLen = (isUnc) ? 7 : 4;
1575N/A /* actual result length (includes terminator) */
1575N/A int resultLen = len - prefixLen + (isUnc ? 1 : 0) + 1;
1575N/A
1575N/A /* copy result without prefix into new buffer */
1575N/A WCHAR *tmp = (WCHAR*)malloc(resultLen * sizeof(WCHAR));
1575N/A if (tmp == NULL) {
1575N/A len = 0;
1575N/A } else {
1575N/A WCHAR *p = result;
1575N/A p += prefixLen;
1575N/A if (isUnc) {
1575N/A WCHAR *p2 = tmp;
1575N/A p2[0] = L'\\';
1575N/A p2++;
1575N/A wcscpy(p2, p);
1575N/A } else {
1575N/A wcscpy(tmp, p);
1575N/A }
1575N/A free(result);
1575N/A result = tmp;
1575N/A }
1575N/A }
1575N/A }
1575N/A
1575N/A /* unable to get final path */
1575N/A if (len == 0 && result != NULL) {
1575N/A free(result);
1575N/A result = NULL;
1575N/A }
1575N/A }
1575N/A
1575N/A error = GetLastError();
1575N/A if (CloseHandle(h))
1575N/A SetLastError(error);
1575N/A return result;
1575N/A}
1575N/A
1575N/A/**
1575N/A * Retrieves file information for the specified file. If the file is
1575N/A * symbolic link then the information on fully resolved target is
1575N/A * returned.
1575N/A */
1575N/Astatic BOOL getFileInformation(const WCHAR *path,
1575N/A BY_HANDLE_FILE_INFORMATION *finfo)
1575N/A{
1575N/A BOOL result;
1575N/A DWORD error;
1575N/A HANDLE h = CreateFileW(path,
1575N/A FILE_READ_ATTRIBUTES,
1575N/A FILE_SHARE_DELETE |
1575N/A FILE_SHARE_READ | FILE_SHARE_WRITE,
1575N/A NULL,
1575N/A OPEN_EXISTING,
1575N/A FILE_FLAG_BACKUP_SEMANTICS,
1575N/A NULL);
1575N/A if (h == INVALID_HANDLE_VALUE)
1575N/A return FALSE;
1575N/A result = GetFileInformationByHandle(h, finfo);
1575N/A error = GetLastError();
1575N/A if (CloseHandle(h))
1575N/A SetLastError(error);
1575N/A return result;
1575N/A}
1575N/A
1575N/A/**
1575N/A * If the given attributes are the attributes of a reparse point, then
6153N/A * read and return the attributes of the special cases.
1575N/A */
1575N/ADWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)
1575N/A{
1575N/A if ((a != INVALID_FILE_ATTRIBUTES) &&
1575N/A ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
1575N/A {
1575N/A BY_HANDLE_FILE_INFORMATION finfo;
1575N/A BOOL res = getFileInformation(path, &finfo);
1575N/A a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
1575N/A }
1575N/A return a;
1575N/A}
1575N/A
6153N/A/**
6153N/A * Take special cases into account when retrieving the attributes
6153N/A * of path
6153N/A */
6153N/ADWORD getFinalAttributes(WCHAR *path)
6153N/A{
6153N/A DWORD attr = INVALID_FILE_ATTRIBUTES;
6153N/A
6153N/A WIN32_FILE_ATTRIBUTE_DATA wfad;
6153N/A WIN32_FIND_DATAW wfd;
6153N/A HANDLE h;
6153N/A
6153N/A if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) {
6153N/A attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes);
6153N/A } else if (GetLastError() == ERROR_SHARING_VIOLATION &&
6153N/A (h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) {
6153N/A attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes);
6154N/A FindClose(h);
6153N/A }
6153N/A return attr;
6153N/A}
6153N/A
0N/AJNIEXPORT jstring JNICALL
0N/AJava_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
0N/A jstring pathname)
0N/A{
0N/A jstring rv = NULL;
0N/A WCHAR canonicalPath[MAX_PATH_LENGTH];
0N/A
0N/A WITH_UNICODE_STRING(env, pathname, path) {
0N/A /*we estimate the max length of memory needed as
0N/A "currentDir. length + pathname.length"
0N/A */
3499N/A int len = (int)wcslen(path);
0N/A len += currentDirLength(path, len);
0N/A if (len > MAX_PATH_LENGTH - 1) {
0N/A WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
0N/A if (cp != NULL) {
0N/A if (wcanonicalize(path, cp, len) >= 0) {
3499N/A rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
0N/A }
0N/A free(cp);
0N/A }
0N/A } else
0N/A if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
3499N/A rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
0N/A }
0N/A } END_UNICODE_STRING(env, path);
0N/A if (rv == NULL) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
0N/A }
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jstring JNICALL
0N/AJava_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
0N/A jstring canonicalPrefixString,
0N/A jstring pathWithCanonicalPrefixString)
0N/A{
0N/A jstring rv = NULL;
0N/A WCHAR canonicalPath[MAX_PATH_LENGTH];
0N/A WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {
0N/A WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
3499N/A int len = (int)wcslen(canonicalPrefix) + MAX_PATH;
0N/A if (len > MAX_PATH_LENGTH) {
0N/A WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
0N/A if (cp != NULL) {
0N/A if (wcanonicalizeWithPrefix(canonicalPrefix,
0N/A pathWithCanonicalPrefix,
0N/A cp, len) >= 0) {
3499N/A rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
0N/A }
0N/A free(cp);
0N/A }
0N/A } else
0N/A if (wcanonicalizeWithPrefix(canonicalPrefix,
0N/A pathWithCanonicalPrefix,
0N/A canonicalPath, MAX_PATH_LENGTH) >= 0) {
3499N/A rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
0N/A }
0N/A } END_UNICODE_STRING(env, pathWithCanonicalPrefix);
0N/A } END_UNICODE_STRING(env, canonicalPrefix);
0N/A if (rv == NULL) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
0N/A }
0N/A return rv;
0N/A}
0N/A
0N/A/* -- Attribute accessors -- */
0N/A
0N/A/* Check whether or not the file name in "path" is a Windows reserved
0N/A device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
0N/A returned result from GetFullPathName, which should be in thr form of
0N/A "\\.\[ReservedDeviceName]" if the path represents a reserved device
0N/A name.
0N/A Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer
0N/A important anyway) is a device name, so we don't check it here.
0N/A GetFileAttributesEx will catch it later by returning 0 on NT/XP/
0N/A 200X.
0N/A
0N/A Note2: Theoretically the implementation could just lookup the table
0N/A below linearly if the first 4 characters of the fullpath returned
0N/A from GetFullPathName are "\\.\". The current implementation should
0N/A achieve the same result. If Microsoft add more names into their
0N/A reserved device name repository in the future, which probably will
0N/A never happen, we will need to revisit the lookup implementation.
0N/A
0N/Astatic WCHAR* ReservedDEviceNames[] = {
0N/A L"CON", L"PRN", L"AUX", L"NUL",
0N/A L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9",
0N/A L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9",
0N/A L"CLOCK$"
0N/A};
0N/A */
0N/A
0N/Astatic BOOL isReservedDeviceNameW(WCHAR* path) {
0N/A#define BUFSIZE 9
0N/A WCHAR buf[BUFSIZE];
0N/A WCHAR *lpf = NULL;
0N/A DWORD retLen = GetFullPathNameW(path,
0N/A BUFSIZE,
0N/A buf,
0N/A &lpf);
0N/A if ((retLen == BUFSIZE - 1 || retLen == BUFSIZE - 2) &&
0N/A buf[0] == L'\\' && buf[1] == L'\\' &&
0N/A buf[2] == L'.' && buf[3] == L'\\') {
0N/A WCHAR* dname = _wcsupr(buf + 4);
0N/A if (wcscmp(dname, L"CON") == 0 ||
0N/A wcscmp(dname, L"PRN") == 0 ||
0N/A wcscmp(dname, L"AUX") == 0 ||
0N/A wcscmp(dname, L"NUL") == 0)
0N/A return TRUE;
0N/A if ((wcsncmp(dname, L"COM", 3) == 0 ||
0N/A wcsncmp(dname, L"LPT", 3) == 0) &&
0N/A dname[3] - L'0' > 0 &&
0N/A dname[3] - L'0' <= 9)
0N/A return TRUE;
0N/A }
0N/A return FALSE;
0N/A}
0N/A
0N/AJNIEXPORT jint JNICALL
0N/AJava_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jint rv = 0;
0N/A jint pathlen;
0N/A
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A if (pathbuf == NULL)
0N/A return rv;
0N/A if (!isReservedDeviceNameW(pathbuf)) {
6153N/A DWORD a = getFinalAttributes(pathbuf);
6153N/A if (a != INVALID_FILE_ATTRIBUTES) {
6153N/A rv = (java_io_FileSystem_BA_EXISTS
6153N/A | ((a & FILE_ATTRIBUTE_DIRECTORY)
6153N/A ? java_io_FileSystem_BA_DIRECTORY
6153N/A : java_io_FileSystem_BA_REGULAR)
6153N/A | ((a & FILE_ATTRIBUTE_HIDDEN)
6153N/A ? java_io_FileSystem_BA_HIDDEN : 0));
0N/A }
0N/A }
0N/A free(pathbuf);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean
0N/AJNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this,
0N/A jobject file, jint access)
0N/A{
357N/A DWORD attr;
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A if (pathbuf == NULL)
0N/A return JNI_FALSE;
357N/A attr = GetFileAttributesW(pathbuf);
1575N/A attr = getFinalAttributesIfReparsePoint(pathbuf, attr);
357N/A free(pathbuf);
357N/A if (attr == INVALID_FILE_ATTRIBUTES)
357N/A return JNI_FALSE;
0N/A switch (access) {
0N/A case java_io_FileSystem_ACCESS_READ:
0N/A case java_io_FileSystem_ACCESS_EXECUTE:
357N/A return JNI_TRUE;
0N/A case java_io_FileSystem_ACCESS_WRITE:
357N/A /* Read-only attribute ignored on directories */
357N/A if ((attr & FILE_ATTRIBUTE_DIRECTORY) ||
357N/A (attr & FILE_ATTRIBUTE_READONLY) == 0)
357N/A return JNI_TRUE;
357N/A else
357N/A return JNI_FALSE;
357N/A default:
357N/A assert(0);
357N/A return JNI_FALSE;
0N/A }
0N/A}
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_WinNTFileSystem_setPermission(JNIEnv *env, jobject this,
0N/A jobject file,
0N/A jint access,
0N/A jboolean enable,
0N/A jboolean owneronly)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A WCHAR *pathbuf;
0N/A DWORD a;
0N/A if (access == java_io_FileSystem_ACCESS_READ ||
0N/A access == java_io_FileSystem_ACCESS_EXECUTE) {
0N/A return enable;
0N/A }
0N/A pathbuf = fileToNTPath(env, file, ids.path);
0N/A if (pathbuf == NULL)
0N/A return JNI_FALSE;
0N/A a = GetFileAttributesW(pathbuf);
1575N/A
1575N/A /* if reparse point, get final target */
1575N/A if ((a != INVALID_FILE_ATTRIBUTES) &&
1575N/A ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
1575N/A {
1575N/A WCHAR *fp = getFinalPath(pathbuf);
1575N/A if (fp == NULL) {
1575N/A a = INVALID_FILE_ATTRIBUTES;
1575N/A } else {
1575N/A free(pathbuf);
1575N/A pathbuf = fp;
1575N/A a = GetFileAttributesW(pathbuf);
1575N/A }
1575N/A }
2918N/A if ((a != INVALID_FILE_ATTRIBUTES) &&
2918N/A ((a & FILE_ATTRIBUTE_DIRECTORY) == 0))
2918N/A {
0N/A if (enable)
0N/A a = a & ~FILE_ATTRIBUTE_READONLY;
0N/A else
0N/A a = a | FILE_ATTRIBUTE_READONLY;
0N/A if (SetFileAttributesW(pathbuf, a))
0N/A rv = JNI_TRUE;
0N/A }
0N/A free(pathbuf);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jlong JNICALL
0N/AJava_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jlong rv = 0;
0N/A LARGE_INTEGER modTime;
0N/A FILETIME t;
0N/A HANDLE h;
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A if (pathbuf == NULL)
0N/A return rv;
0N/A h = CreateFileW(pathbuf,
0N/A /* Device query access */
0N/A 0,
0N/A /* Share it */
0N/A FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
0N/A /* No security attributes */
0N/A NULL,
0N/A /* Open existing or fail */
0N/A OPEN_EXISTING,
0N/A /* Backup semantics for directories */
1575N/A FILE_FLAG_BACKUP_SEMANTICS,
0N/A /* No template file */
0N/A NULL);
0N/A if (h != INVALID_HANDLE_VALUE) {
1020N/A if (GetFileTime(h, NULL, NULL, &t)) {
1020N/A modTime.LowPart = (DWORD) t.dwLowDateTime;
1020N/A modTime.HighPart = (LONG) t.dwHighDateTime;
1020N/A rv = modTime.QuadPart / 10000;
1020N/A rv -= 11644473600000;
1020N/A }
0N/A CloseHandle(h);
0N/A }
0N/A free(pathbuf);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jlong JNICALL
0N/AJava_java_io_WinNTFileSystem_getLength(JNIEnv *env, jobject this, jobject file)
0N/A{
0N/A jlong rv = 0;
0N/A WIN32_FILE_ATTRIBUTE_DATA wfad;
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A if (pathbuf == NULL)
0N/A return rv;
0N/A if (GetFileAttributesExW(pathbuf,
0N/A GetFileExInfoStandard,
0N/A &wfad)) {
1575N/A if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
1575N/A rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;
1575N/A } else {
1575N/A /* file is a reparse point so read attributes of final target */
1575N/A BY_HANDLE_FILE_INFORMATION finfo;
1575N/A if (getFileInformation(pathbuf, &finfo)) {
1575N/A rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) +
1575N/A finfo.nFileSizeLow;
1575N/A }
1575N/A }
0N/A } else {
0N/A if (GetLastError() == ERROR_SHARING_VIOLATION) {
0N/A /* The error is "share violation", which means the file/dir
0N/A must exists. Try _wstati64, we know this at least works
0N/A for pagefile.sys and hiberfil.sys.
0N/A */
0N/A struct _stati64 sb;
0N/A if (_wstati64(pathbuf, &sb) == 0) {
0N/A rv = sb.st_size;
0N/A }
0N/A }
0N/A }
0N/A free(pathbuf);
0N/A return rv;
0N/A}
0N/A
0N/A/* -- File operations -- */
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls,
0N/A jstring path)
0N/A{
0N/A HANDLE h = NULL;
0N/A WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
0N/A if (pathbuf == NULL)
0N/A return JNI_FALSE;
6156N/A if (isReservedDeviceNameW(pathbuf)) {
6156N/A free(pathbuf);
6156N/A return JNI_FALSE;
6156N/A }
0N/A h = CreateFileW(
1575N/A pathbuf, /* Wide char path name */
1575N/A GENERIC_READ | GENERIC_WRITE, /* Read and write permission */
0N/A FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */
1575N/A NULL, /* Security attributes */
1575N/A CREATE_NEW, /* creation disposition */
1575N/A FILE_ATTRIBUTE_NORMAL |
1575N/A FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */
0N/A NULL);
0N/A
0N/A if (h == INVALID_HANDLE_VALUE) {
0N/A DWORD error = GetLastError();
0N/A if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
1575N/A // return false rather than throwing an exception when there is
1575N/A // an existing file.
1575N/A DWORD a = GetFileAttributesW(pathbuf);
1575N/A if (a == INVALID_FILE_ATTRIBUTES) {
0N/A SetLastError(error);
0N/A JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
0N/A }
0N/A }
0N/A free(pathbuf);
0N/A return JNI_FALSE;
1575N/A }
0N/A free(pathbuf);
0N/A CloseHandle(h);
0N/A return JNI_TRUE;
0N/A}
0N/A
0N/Astatic int
0N/AremoveFileOrDirectory(const jchar *path)
0N/A{
0N/A /* Returns 0 on success */
0N/A DWORD a;
0N/A
1575N/A SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
0N/A a = GetFileAttributesW(path);
1575N/A if (a == INVALID_FILE_ATTRIBUTES) {
0N/A return 1;
0N/A } else if (a & FILE_ATTRIBUTE_DIRECTORY) {
0N/A return !RemoveDirectoryW(path);
0N/A } else {
0N/A return !DeleteFileW(path);
0N/A }
0N/A}
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A if (pathbuf == NULL) {
0N/A return JNI_FALSE;
0N/A }
0N/A if (removeFileOrDirectory(pathbuf) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A free(pathbuf);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jobjectArray JNICALL
0N/AJava_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file)
0N/A{
0N/A WCHAR *search_path;
0N/A HANDLE handle;
0N/A WIN32_FIND_DATAW find_data;
0N/A int len, maxlen;
0N/A jobjectArray rv, old;
0N/A DWORD fattr;
0N/A jstring name;
0N/A
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A if (pathbuf == NULL)
0N/A return NULL;
0N/A search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);
0N/A if (search_path == 0) {
0N/A free (pathbuf);
0N/A errno = ENOMEM;
0N/A return NULL;
0N/A }
0N/A wcscpy(search_path, pathbuf);
0N/A free(pathbuf);
0N/A fattr = GetFileAttributesW(search_path);
0N/A if (fattr == INVALID_FILE_ATTRIBUTES) {
0N/A free(search_path);
0N/A return NULL;
0N/A } else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
0N/A free(search_path);
0N/A return NULL;
0N/A }
0N/A
0N/A /* Remove trailing space chars from directory name */
3499N/A len = (int)wcslen(search_path);
0N/A while (search_path[len-1] == ' ') {
0N/A len--;
0N/A }
0N/A search_path[len] = 0;
0N/A
0N/A /* Append "*", or possibly "\\*", to path */
0N/A if ((search_path[0] == L'\\' && search_path[1] == L'\0') ||
0N/A (search_path[1] == L':'
0N/A && (search_path[2] == L'\0'
0N/A || (search_path[2] == L'\\' && search_path[3] == L'\0')))) {
0N/A /* No '\\' needed for cases like "\" or "Z:" or "Z:\" */
0N/A wcscat(search_path, L"*");
0N/A } else {
0N/A wcscat(search_path, L"\\*");
0N/A }
0N/A
0N/A /* Open handle to the first file */
0N/A handle = FindFirstFileW(search_path, &find_data);
0N/A free(search_path);
0N/A if (handle == INVALID_HANDLE_VALUE) {
0N/A if (GetLastError() != ERROR_FILE_NOT_FOUND) {
0N/A // error
0N/A return NULL;
0N/A } else {
0N/A // No files found - return an empty array
0N/A rv = (*env)->NewObjectArray(env, 0, JNU_ClassString(env), NULL);
0N/A return rv;
0N/A }
0N/A }
0N/A
0N/A /* Allocate an initial String array */
0N/A len = 0;
0N/A maxlen = 16;
0N/A rv = (*env)->NewObjectArray(env, maxlen, JNU_ClassString(env), NULL);
0N/A if (rv == NULL) // Couldn't allocate an array
0N/A return NULL;
0N/A /* Scan the directory */
0N/A do {
0N/A if (!wcscmp(find_data.cFileName, L".")
0N/A || !wcscmp(find_data.cFileName, L".."))
0N/A continue;
0N/A name = (*env)->NewString(env, find_data.cFileName,
3499N/A (jsize)wcslen(find_data.cFileName));
0N/A if (name == NULL)
0N/A return NULL; // error;
0N/A if (len == maxlen) {
0N/A old = rv;
0N/A rv = (*env)->NewObjectArray(env, maxlen <<= 1,
0N/A JNU_ClassString(env), NULL);
0N/A if ( rv == NULL
0N/A || JNU_CopyObjectArray(env, rv, old, len) < 0)
0N/A return NULL; // error
0N/A (*env)->DeleteLocalRef(env, old);
0N/A }
0N/A (*env)->SetObjectArrayElement(env, rv, len++, name);
0N/A (*env)->DeleteLocalRef(env, name);
0N/A
0N/A } while (FindNextFileW(handle, &find_data));
0N/A
0N/A if (GetLastError() != ERROR_NO_MORE_FILES)
0N/A return NULL; // error
0N/A FindClose(handle);
0N/A
0N/A /* Copy the final results into an appropriately-sized array */
0N/A old = rv;
0N/A rv = (*env)->NewObjectArray(env, len, JNU_ClassString(env), NULL);
0N/A if (rv == NULL)
0N/A return NULL; /* error */
0N/A if (JNU_CopyObjectArray(env, rv, old, len) < 0)
0N/A return NULL; /* error */
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_WinNTFileSystem_createDirectory(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A BOOL h = FALSE;
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A if (pathbuf == NULL) {
0N/A /* Exception is pending */
0N/A return JNI_FALSE;
0N/A }
0N/A h = CreateDirectoryW(pathbuf, NULL);
0N/A free(pathbuf);
0N/A
0N/A if (h == 0) {
0N/A return JNI_FALSE;
0N/A }
0N/A
0N/A return JNI_TRUE;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_WinNTFileSystem_rename0(JNIEnv *env, jobject this, jobject from,
0N/A jobject to)
0N/A{
0N/A
0N/A jboolean rv = JNI_FALSE;
0N/A WCHAR *frompath = fileToNTPath(env, from, ids.path);
0N/A WCHAR *topath = fileToNTPath(env, to, ids.path);
0N/A if (frompath == NULL || topath == NULL)
0N/A return JNI_FALSE;
0N/A if (_wrename(frompath, topath) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A free(frompath);
0N/A free(topath);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_WinNTFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
0N/A jobject file, jlong time)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A HANDLE h;
0N/A if (pathbuf == NULL)
0N/A return JNI_FALSE;
1575N/A h = CreateFileW(pathbuf,
1575N/A FILE_WRITE_ATTRIBUTES,
1575N/A FILE_SHARE_READ | FILE_SHARE_WRITE,
1575N/A NULL,
1575N/A OPEN_EXISTING,
1575N/A FILE_FLAG_BACKUP_SEMANTICS,
1575N/A 0);
0N/A if (h != INVALID_HANDLE_VALUE) {
0N/A LARGE_INTEGER modTime;
0N/A FILETIME t;
0N/A modTime.QuadPart = (time + 11644473600000L) * 10000L;
0N/A t.dwLowDateTime = (DWORD)modTime.LowPart;
0N/A t.dwHighDateTime = (DWORD)modTime.HighPart;
0N/A if (SetFileTime(h, NULL, NULL, &t)) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A CloseHandle(h);
0N/A }
0N/A free(pathbuf);
0N/A
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_WinNTFileSystem_setReadOnly(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A DWORD a;
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A if (pathbuf == NULL)
0N/A return JNI_FALSE;
0N/A a = GetFileAttributesW(pathbuf);
1575N/A
1575N/A /* if reparse point, get final target */
1575N/A if ((a != INVALID_FILE_ATTRIBUTES) &&
1575N/A ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
1575N/A {
1575N/A WCHAR *fp = getFinalPath(pathbuf);
1575N/A if (fp == NULL) {
1575N/A a = INVALID_FILE_ATTRIBUTES;
1575N/A } else {
1575N/A free(pathbuf);
1575N/A pathbuf = fp;
1575N/A a = GetFileAttributesW(pathbuf);
1575N/A }
1575N/A }
1575N/A
2918N/A if ((a != INVALID_FILE_ATTRIBUTES) &&
2918N/A ((a & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
0N/A if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))
2918N/A rv = JNI_TRUE;
0N/A }
0N/A free(pathbuf);
0N/A return rv;
0N/A}
0N/A
0N/A/* -- Filesystem interface -- */
0N/A
0N/A
0N/AJNIEXPORT jobject JNICALL
0N/AJava_java_io_WinNTFileSystem_getDriveDirectory(JNIEnv *env, jobject this,
0N/A jint drive)
0N/A{
0N/A jstring ret = NULL;
2919N/A jchar *p = currentDir(drive);
0N/A jchar *pf = p;
0N/A if (p == NULL) return NULL;
0N/A if (iswalpha(*p) && (p[1] == L':')) p += 2;
3499N/A ret = (*env)->NewString(env, p, (jsize)wcslen(p));
0N/A free (pf);
0N/A return ret;
0N/A}
0N/A
0N/AJNIEXPORT jlong JNICALL
0N/AJava_java_io_WinNTFileSystem_getSpace0(JNIEnv *env, jobject this,
0N/A jobject file, jint t)
0N/A{
0N/A WCHAR volname[MAX_PATH_LENGTH + 1];
0N/A jlong rv = 0L;
0N/A WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
0N/A
3901N/A if (GetVolumePathNameW(pathbuf, volname, MAX_PATH_LENGTH)) {
0N/A ULARGE_INTEGER totalSpace, freeSpace, usableSpace;
0N/A if (GetDiskFreeSpaceExW(volname, &usableSpace, &totalSpace, &freeSpace)) {
0N/A switch(t) {
0N/A case java_io_FileSystem_SPACE_TOTAL:
0N/A rv = long_to_jlong(totalSpace.QuadPart);
0N/A break;
0N/A case java_io_FileSystem_SPACE_FREE:
0N/A rv = long_to_jlong(freeSpace.QuadPart);
0N/A break;
0N/A case java_io_FileSystem_SPACE_USABLE:
0N/A rv = long_to_jlong(usableSpace.QuadPart);
0N/A break;
0N/A default:
0N/A assert(0);
0N/A }
0N/A }
0N/A }
0N/A
0N/A free(pathbuf);
0N/A return rv;
0N/A}