annotate src/windows/native/java/io/WinNTFileSystem_md.c @ 10983:935758609767

Added tag jdk8u60-b28 for changeset 48e79820c798
author asaha
date Tue, 13 Oct 2015 08:18:35 -0700
parents 7a3d9b221f8a
children
rev   line source
duke@0 1 /*
msheppar@9691 2 * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
ohair@2362 7 * published by the Free Software Foundation. Oracle designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
ohair@2362 9 * by Oracle in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
ohair@2362 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2362 22 * or visit www.oracle.com if you need additional information or have any
ohair@2362 23 * questions.
duke@0 24 */
duke@0 25
alanb@3901 26 /* Access APIs for WinXP and above */
duke@0 27 #ifndef _WIN32_WINNT
alanb@3901 28 #define _WIN32_WINNT 0x0501
duke@0 29 #endif
duke@0 30
duke@0 31 #include <assert.h>
duke@0 32 #include <stdio.h>
duke@0 33 #include <stdlib.h>
duke@0 34 #include <ctype.h>
duke@0 35 #include <direct.h>
duke@0 36 #include <windows.h>
duke@0 37 #include <io.h>
duke@0 38
duke@0 39 #include "jni.h"
duke@0 40 #include "io_util.h"
duke@0 41 #include "jlong.h"
duke@0 42 #include "io_util_md.h"
duke@0 43 #include "dirent_md.h"
duke@0 44 #include "java_io_FileSystem.h"
duke@0 45
duke@0 46 #define MAX_PATH_LENGTH 1024
duke@0 47
duke@0 48 static struct {
duke@0 49 jfieldID path;
duke@0 50 } ids;
duke@0 51
alanb@1575 52 /**
alanb@1575 53 * GetFinalPathNameByHandle is available on Windows Vista and newer
alanb@1575 54 */
alanb@1575 55 typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
alanb@1575 56 static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
alanb@1575 57
duke@0 58 JNIEXPORT void JNICALL
duke@0 59 Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
duke@0 60 {
alanb@3901 61 HMODULE handle;
alanb@10473 62 jclass fileClass;
alanb@10473 63
alanb@10473 64 fileClass = (*env)->FindClass(env, "java/io/File");
alanb@10473 65 CHECK_NULL(fileClass);
alanb@10473 66 ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
alanb@10473 67 CHECK_NULL(ids.path);
alanb@3901 68
alanb@3901 69 // GetFinalPathNameByHandle requires Windows Vista or newer
alanb@3901 70 if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
alanb@3901 71 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
alanb@3901 72 (LPCWSTR)&CreateFileW, &handle) != 0)
alanb@3901 73 {
alanb@1575 74 GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
alanb@1575 75 GetProcAddress(handle, "GetFinalPathNameByHandleW");
alanb@1575 76 }
duke@0 77 }
duke@0 78
duke@0 79 /* -- Path operations -- */
duke@0 80
duke@0 81 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
duke@0 82 extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
duke@0 83
alanb@1575 84 /**
alanb@1575 85 * Retrieves the fully resolved (final) path for the given path or NULL
alanb@1575 86 * if the function fails.
alanb@1575 87 */
msheppar@9691 88 static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)
alanb@1575 89 {
alanb@1575 90 HANDLE h;
alanb@1575 91 WCHAR *result;
alanb@1575 92 DWORD error;
alanb@1575 93
alanb@1575 94 /* Need Windows Vista or newer to get the final path */
alanb@1575 95 if (GetFinalPathNameByHandle_func == NULL)
alanb@1575 96 return NULL;
alanb@1575 97
alanb@1575 98 h = CreateFileW(path,
alanb@1575 99 FILE_READ_ATTRIBUTES,
alanb@1575 100 FILE_SHARE_DELETE |
alanb@1575 101 FILE_SHARE_READ | FILE_SHARE_WRITE,
alanb@1575 102 NULL,
alanb@1575 103 OPEN_EXISTING,
alanb@1575 104 FILE_FLAG_BACKUP_SEMANTICS,
alanb@1575 105 NULL);
alanb@1575 106 if (h == INVALID_HANDLE_VALUE)
alanb@1575 107 return NULL;
alanb@1575 108
alanb@1575 109 /**
alanb@1575 110 * Allocate a buffer for the resolved path. For a long path we may need
alanb@1575 111 * to allocate a larger buffer.
alanb@1575 112 */
alanb@1575 113 result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR));
alanb@1575 114 if (result != NULL) {
alanb@1575 115 DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0);
alanb@1575 116 if (len >= MAX_PATH) {
alanb@1575 117 /* retry with a buffer of the right size */
jzavgren@6646 118 WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR));
jzavgren@6646 119 if (newResult != NULL) {
jzavgren@6646 120 result = newResult;
alanb@1575 121 len = (*GetFinalPathNameByHandle_func)(h, result, len, 0);
alanb@1575 122 } else {
alanb@1575 123 len = 0;
msheppar@9691 124 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
alanb@1575 125 }
alanb@1575 126 }
jzavgren@6646 127
alanb@1575 128 if (len > 0) {
alanb@1575 129 /**
alanb@1575 130 * Strip prefix (should be \\?\ or \\?\UNC)
alanb@1575 131 */
alanb@1575 132 if (result[0] == L'\\' && result[1] == L'\\' &&
alanb@1575 133 result[2] == L'?' && result[3] == L'\\')
alanb@1575 134 {
alanb@1575 135 int isUnc = (result[4] == L'U' &&
alanb@1575 136 result[5] == L'N' &&
alanb@1575 137 result[6] == L'C');
alanb@1575 138 int prefixLen = (isUnc) ? 7 : 4;
alanb@1575 139 /* actual result length (includes terminator) */
alanb@1575 140 int resultLen = len - prefixLen + (isUnc ? 1 : 0) + 1;
alanb@1575 141
alanb@1575 142 /* copy result without prefix into new buffer */
alanb@1575 143 WCHAR *tmp = (WCHAR*)malloc(resultLen * sizeof(WCHAR));
alanb@1575 144 if (tmp == NULL) {
msheppar@9691 145 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
alanb@1575 146 len = 0;
alanb@1575 147 } else {
alanb@1575 148 WCHAR *p = result;
alanb@1575 149 p += prefixLen;
alanb@1575 150 if (isUnc) {
alanb@1575 151 WCHAR *p2 = tmp;
alanb@1575 152 p2[0] = L'\\';
alanb@1575 153 p2++;
alanb@1575 154 wcscpy(p2, p);
alanb@1575 155 } else {
alanb@1575 156 wcscpy(tmp, p);
alanb@1575 157 }
alanb@1575 158 free(result);
alanb@1575 159 result = tmp;
alanb@1575 160 }
alanb@1575 161 }
alanb@1575 162 }
alanb@1575 163
alanb@1575 164 /* unable to get final path */
alanb@1575 165 if (len == 0 && result != NULL) {
alanb@1575 166 free(result);
alanb@1575 167 result = NULL;
alanb@1575 168 }
msheppar@9691 169 } else {
msheppar@9691 170 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
alanb@1575 171 }
alanb@1575 172
alanb@1575 173 error = GetLastError();
alanb@1575 174 if (CloseHandle(h))
alanb@1575 175 SetLastError(error);
alanb@1575 176 return result;
alanb@1575 177 }
alanb@1575 178
alanb@1575 179 /**
alanb@1575 180 * Retrieves file information for the specified file. If the file is
alanb@1575 181 * symbolic link then the information on fully resolved target is
alanb@1575 182 * returned.
alanb@1575 183 */
alanb@1575 184 static BOOL getFileInformation(const WCHAR *path,
alanb@1575 185 BY_HANDLE_FILE_INFORMATION *finfo)
alanb@1575 186 {
alanb@1575 187 BOOL result;
alanb@1575 188 DWORD error;
alanb@1575 189 HANDLE h = CreateFileW(path,
alanb@1575 190 FILE_READ_ATTRIBUTES,
alanb@1575 191 FILE_SHARE_DELETE |
alanb@1575 192 FILE_SHARE_READ | FILE_SHARE_WRITE,
alanb@1575 193 NULL,
alanb@1575 194 OPEN_EXISTING,
alanb@1575 195 FILE_FLAG_BACKUP_SEMANTICS,
alanb@1575 196 NULL);
alanb@1575 197 if (h == INVALID_HANDLE_VALUE)
alanb@1575 198 return FALSE;
alanb@1575 199 result = GetFileInformationByHandle(h, finfo);
alanb@1575 200 error = GetLastError();
alanb@1575 201 if (CloseHandle(h))
alanb@1575 202 SetLastError(error);
alanb@1575 203 return result;
alanb@1575 204 }
alanb@1575 205
alanb@1575 206 /**
alanb@1575 207 * If the given attributes are the attributes of a reparse point, then
robm@7227 208 * read and return the attributes of the special cases.
alanb@1575 209 */
alanb@1575 210 DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)
alanb@1575 211 {
alanb@1575 212 if ((a != INVALID_FILE_ATTRIBUTES) &&
alanb@1575 213 ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
alanb@1575 214 {
alanb@1575 215 BY_HANDLE_FILE_INFORMATION finfo;
alanb@1575 216 BOOL res = getFileInformation(path, &finfo);
alanb@1575 217 a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
alanb@1575 218 }
alanb@1575 219 return a;
alanb@1575 220 }
alanb@1575 221
robm@7227 222 /**
robm@7227 223 * Take special cases into account when retrieving the attributes
robm@7227 224 * of path
robm@7227 225 */
robm@7227 226 DWORD getFinalAttributes(WCHAR *path)
robm@7227 227 {
robm@7227 228 DWORD attr = INVALID_FILE_ATTRIBUTES;
robm@7227 229
robm@7227 230 WIN32_FILE_ATTRIBUTE_DATA wfad;
robm@7227 231 WIN32_FIND_DATAW wfd;
robm@7227 232 HANDLE h;
robm@7227 233
robm@7227 234 if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) {
robm@7227 235 attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes);
robm@7227 236 } else if (GetLastError() == ERROR_SHARING_VIOLATION &&
robm@7227 237 (h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) {
robm@7227 238 attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes);
robm@7353 239 FindClose(h);
robm@7227 240 }
robm@7227 241 return attr;
robm@7227 242 }
robm@7227 243
duke@0 244 JNIEXPORT jstring JNICALL
duke@0 245 Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
duke@0 246 jstring pathname)
duke@0 247 {
duke@0 248 jstring rv = NULL;
duke@0 249 WCHAR canonicalPath[MAX_PATH_LENGTH];
duke@0 250
duke@0 251 WITH_UNICODE_STRING(env, pathname, path) {
alanb@10473 252 /* we estimate the max length of memory needed as
alanb@10473 253 "currentDir. length + pathname.length"
duke@0 254 */
alanb@3499 255 int len = (int)wcslen(path);
duke@0 256 len += currentDirLength(path, len);
duke@0 257 if (len > MAX_PATH_LENGTH - 1) {
duke@0 258 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
duke@0 259 if (cp != NULL) {
duke@0 260 if (wcanonicalize(path, cp, len) >= 0) {
alanb@3499 261 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
duke@0 262 }
duke@0 263 free(cp);
msheppar@9691 264 } else {
msheppar@9691 265 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
duke@0 266 }
alanb@10473 267 } else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
alanb@3499 268 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
duke@0 269 }
duke@0 270 } END_UNICODE_STRING(env, path);
alanb@10473 271 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
duke@0 272 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
duke@0 273 }
duke@0 274 return rv;
duke@0 275 }
duke@0 276
duke@0 277
duke@0 278 JNIEXPORT jstring JNICALL
duke@0 279 Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
duke@0 280 jstring canonicalPrefixString,
duke@0 281 jstring pathWithCanonicalPrefixString)
duke@0 282 {
duke@0 283 jstring rv = NULL;
duke@0 284 WCHAR canonicalPath[MAX_PATH_LENGTH];
duke@0 285 WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {
duke@0 286 WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
alanb@3499 287 int len = (int)wcslen(canonicalPrefix) + MAX_PATH;
duke@0 288 if (len > MAX_PATH_LENGTH) {
duke@0 289 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
duke@0 290 if (cp != NULL) {
duke@0 291 if (wcanonicalizeWithPrefix(canonicalPrefix,
duke@0 292 pathWithCanonicalPrefix,
duke@0 293 cp, len) >= 0) {
alanb@3499 294 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
duke@0 295 }
duke@0 296 free(cp);
msheppar@9691 297 } else {
msheppar@9691 298 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
duke@0 299 }
alanb@10473 300 } else if (wcanonicalizeWithPrefix(canonicalPrefix,
alanb@10473 301 pathWithCanonicalPrefix,
alanb@10473 302 canonicalPath, MAX_PATH_LENGTH) >= 0) {
alanb@3499 303 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
duke@0 304 }
duke@0 305 } END_UNICODE_STRING(env, pathWithCanonicalPrefix);
duke@0 306 } END_UNICODE_STRING(env, canonicalPrefix);
alanb@10473 307 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
duke@0 308 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
duke@0 309 }
duke@0 310 return rv;
duke@0 311 }
duke@0 312
duke@0 313 /* -- Attribute accessors -- */
duke@0 314
duke@0 315 /* Check whether or not the file name in "path" is a Windows reserved
duke@0 316 device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
duke@0 317 returned result from GetFullPathName, which should be in thr form of
duke@0 318 "\\.\[ReservedDeviceName]" if the path represents a reserved device
duke@0 319 name.
duke@0 320 Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer
duke@0 321 important anyway) is a device name, so we don't check it here.
duke@0 322 GetFileAttributesEx will catch it later by returning 0 on NT/XP/
duke@0 323 200X.
duke@0 324
duke@0 325 Note2: Theoretically the implementation could just lookup the table
duke@0 326 below linearly if the first 4 characters of the fullpath returned
duke@0 327 from GetFullPathName are "\\.\". The current implementation should
duke@0 328 achieve the same result. If Microsoft add more names into their
duke@0 329 reserved device name repository in the future, which probably will
duke@0 330 never happen, we will need to revisit the lookup implementation.
duke@0 331
duke@0 332 static WCHAR* ReservedDEviceNames[] = {
duke@0 333 L"CON", L"PRN", L"AUX", L"NUL",
duke@0 334 L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9",
duke@0 335 L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9",
duke@0 336 L"CLOCK$"
duke@0 337 };
duke@0 338 */
duke@0 339
duke@0 340 static BOOL isReservedDeviceNameW(WCHAR* path) {
duke@0 341 #define BUFSIZE 9
duke@0 342 WCHAR buf[BUFSIZE];
duke@0 343 WCHAR *lpf = NULL;
duke@0 344 DWORD retLen = GetFullPathNameW(path,
duke@0 345 BUFSIZE,
duke@0 346 buf,
duke@0 347 &lpf);
duke@0 348 if ((retLen == BUFSIZE - 1 || retLen == BUFSIZE - 2) &&
duke@0 349 buf[0] == L'\\' && buf[1] == L'\\' &&
duke@0 350 buf[2] == L'.' && buf[3] == L'\\') {
duke@0 351 WCHAR* dname = _wcsupr(buf + 4);
duke@0 352 if (wcscmp(dname, L"CON") == 0 ||
duke@0 353 wcscmp(dname, L"PRN") == 0 ||
duke@0 354 wcscmp(dname, L"AUX") == 0 ||
duke@0 355 wcscmp(dname, L"NUL") == 0)
duke@0 356 return TRUE;
duke@0 357 if ((wcsncmp(dname, L"COM", 3) == 0 ||
duke@0 358 wcsncmp(dname, L"LPT", 3) == 0) &&
duke@0 359 dname[3] - L'0' > 0 &&
duke@0 360 dname[3] - L'0' <= 9)
duke@0 361 return TRUE;
duke@0 362 }
duke@0 363 return FALSE;
duke@0 364 }
duke@0 365
duke@0 366 JNIEXPORT jint JNICALL
duke@0 367 Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this,
duke@0 368 jobject file)
duke@0 369 {
duke@0 370 jint rv = 0;
duke@0 371 jint pathlen;
duke@0 372
duke@0 373 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
duke@0 374 if (pathbuf == NULL)
duke@0 375 return rv;
duke@0 376 if (!isReservedDeviceNameW(pathbuf)) {
robm@7227 377 DWORD a = getFinalAttributes(pathbuf);
robm@7227 378 if (a != INVALID_FILE_ATTRIBUTES) {
robm@7227 379 rv = (java_io_FileSystem_BA_EXISTS
robm@7227 380 | ((a & FILE_ATTRIBUTE_DIRECTORY)
robm@7227 381 ? java_io_FileSystem_BA_DIRECTORY
robm@7227 382 : java_io_FileSystem_BA_REGULAR)
robm@7227 383 | ((a & FILE_ATTRIBUTE_HIDDEN)
robm@7227 384 ? java_io_FileSystem_BA_HIDDEN : 0));
duke@0 385 }
duke@0 386 }
duke@0 387 free(pathbuf);
duke@0 388 return rv;
duke@0 389 }
duke@0 390
duke@0 391
duke@0 392 JNIEXPORT jboolean
duke@0 393 JNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this,
duke@0 394 jobject file, jint access)
duke@0 395 {
alanb@357 396 DWORD attr;
duke@0 397 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
duke@0 398 if (pathbuf == NULL)
duke@0 399 return JNI_FALSE;
alanb@357 400 attr = GetFileAttributesW(pathbuf);
alanb@1575 401 attr = getFinalAttributesIfReparsePoint(pathbuf, attr);
alanb@357 402 free(pathbuf);
alanb@357 403 if (attr == INVALID_FILE_ATTRIBUTES)
alanb@357 404 return JNI_FALSE;
duke@0 405 switch (access) {
duke@0 406 case java_io_FileSystem_ACCESS_READ:
duke@0 407 case java_io_FileSystem_ACCESS_EXECUTE:
alanb@357 408 return JNI_TRUE;
duke@0 409 case java_io_FileSystem_ACCESS_WRITE:
alanb@357 410 /* Read-only attribute ignored on directories */
alanb@357 411 if ((attr & FILE_ATTRIBUTE_DIRECTORY) ||
alanb@357 412 (attr & FILE_ATTRIBUTE_READONLY) == 0)
alanb@357 413 return JNI_TRUE;
alanb@357 414 else
alanb@357 415 return JNI_FALSE;
alanb@357 416 default:
alanb@357 417 assert(0);
alanb@357 418 return JNI_FALSE;
duke@0 419 }
duke@0 420 }
duke@0 421
duke@0 422 JNIEXPORT jboolean JNICALL
duke@0 423 Java_java_io_WinNTFileSystem_setPermission(JNIEnv *env, jobject this,
duke@0 424 jobject file,
duke@0 425 jint access,
duke@0 426 jboolean enable,
duke@0 427 jboolean owneronly)
duke@0 428 {
duke@0 429 jboolean rv = JNI_FALSE;
duke@0 430 WCHAR *pathbuf;
duke@0 431 DWORD a;
duke@0 432 if (access == java_io_FileSystem_ACCESS_READ ||
duke@0 433 access == java_io_FileSystem_ACCESS_EXECUTE) {
duke@0 434 return enable;
duke@0 435 }
duke@0 436 pathbuf = fileToNTPath(env, file, ids.path);
duke@0 437 if (pathbuf == NULL)
duke@0 438 return JNI_FALSE;
duke@0 439 a = GetFileAttributesW(pathbuf);
alanb@1575 440
alanb@1575 441 /* if reparse point, get final target */
alanb@1575 442 if ((a != INVALID_FILE_ATTRIBUTES) &&
alanb@1575 443 ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
alanb@1575 444 {
msheppar@9691 445 WCHAR *fp = getFinalPath(env, pathbuf);
alanb@1575 446 if (fp == NULL) {
alanb@1575 447 a = INVALID_FILE_ATTRIBUTES;
alanb@1575 448 } else {
alanb@1575 449 free(pathbuf);
alanb@1575 450 pathbuf = fp;
alanb@1575 451 a = GetFileAttributesW(pathbuf);
alanb@1575 452 }
alanb@1575 453 }
alanb@2918 454 if ((a != INVALID_FILE_ATTRIBUTES) &&
alanb@2918 455 ((a & FILE_ATTRIBUTE_DIRECTORY) == 0))
alanb@2918 456 {
duke@0 457 if (enable)
duke@0 458 a = a & ~FILE_ATTRIBUTE_READONLY;
duke@0 459 else
duke@0 460 a = a | FILE_ATTRIBUTE_READONLY;
duke@0 461 if (SetFileAttributesW(pathbuf, a))
duke@0 462 rv = JNI_TRUE;
duke@0 463 }
duke@0 464 free(pathbuf);
duke@0 465 return rv;
duke@0 466 }
duke@0 467
duke@0 468 JNIEXPORT jlong JNICALL
duke@0 469 Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
duke@0 470 jobject file)
duke@0 471 {
duke@0 472 jlong rv = 0;
duke@0 473 LARGE_INTEGER modTime;
duke@0 474 FILETIME t;
duke@0 475 HANDLE h;
duke@0 476 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
duke@0 477 if (pathbuf == NULL)
duke@0 478 return rv;
duke@0 479 h = CreateFileW(pathbuf,
duke@0 480 /* Device query access */
duke@0 481 0,
duke@0 482 /* Share it */
duke@0 483 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
duke@0 484 /* No security attributes */
duke@0 485 NULL,
duke@0 486 /* Open existing or fail */
duke@0 487 OPEN_EXISTING,
duke@0 488 /* Backup semantics for directories */
alanb@1575 489 FILE_FLAG_BACKUP_SEMANTICS,
duke@0 490 /* No template file */
duke@0 491 NULL);
duke@0 492 if (h != INVALID_HANDLE_VALUE) {
alanb@1020 493 if (GetFileTime(h, NULL, NULL, &t)) {
alanb@1020 494 modTime.LowPart = (DWORD) t.dwLowDateTime;
alanb@1020 495 modTime.HighPart = (LONG) t.dwHighDateTime;
alanb@1020 496 rv = modTime.QuadPart / 10000;
alanb@1020 497 rv -= 11644473600000;
alanb@1020 498 }
duke@0 499 CloseHandle(h);
duke@0 500 }
duke@0 501 free(pathbuf);
duke@0 502 return rv;
duke@0 503 }
duke@0 504
duke@0 505 JNIEXPORT jlong JNICALL
duke@0 506 Java_java_io_WinNTFileSystem_getLength(JNIEnv *env, jobject this, jobject file)
duke@0 507 {
duke@0 508 jlong rv = 0;
duke@0 509 WIN32_FILE_ATTRIBUTE_DATA wfad;
duke@0 510 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
duke@0 511 if (pathbuf == NULL)
duke@0 512 return rv;
duke@0 513 if (GetFileAttributesExW(pathbuf,
duke@0 514 GetFileExInfoStandard,
duke@0 515 &wfad)) {
alanb@1575 516 if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
alanb@1575 517 rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;
alanb@1575 518 } else {
alanb@1575 519 /* file is a reparse point so read attributes of final target */
alanb@1575 520 BY_HANDLE_FILE_INFORMATION finfo;
alanb@1575 521 if (getFileInformation(pathbuf, &finfo)) {
alanb@1575 522 rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) +
alanb@1575 523 finfo.nFileSizeLow;
alanb@1575 524 }
alanb@1575 525 }
duke@0 526 } else {
duke@0 527 if (GetLastError() == ERROR_SHARING_VIOLATION) {
duke@0 528 /* The error is "share violation", which means the file/dir
duke@0 529 must exists. Try _wstati64, we know this at least works
duke@0 530 for pagefile.sys and hiberfil.sys.
duke@0 531 */
duke@0 532 struct _stati64 sb;
duke@0 533 if (_wstati64(pathbuf, &sb) == 0) {
duke@0 534 rv = sb.st_size;
duke@0 535 }
duke@0 536 }
duke@0 537 }
duke@0 538 free(pathbuf);
duke@0 539 return rv;
duke@0 540 }
duke@0 541
duke@0 542 /* -- File operations -- */
duke@0 543
duke@0 544 JNIEXPORT jboolean JNICALL
duke@0 545 Java_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls,
duke@0 546 jstring path)
duke@0 547 {
duke@0 548 HANDLE h = NULL;
duke@0 549 WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
duke@0 550 if (pathbuf == NULL)
duke@0 551 return JNI_FALSE;
dxu@7366 552 if (isReservedDeviceNameW(pathbuf)) {
dxu@7366 553 free(pathbuf);
dxu@7366 554 return JNI_FALSE;
dxu@7366 555 }
duke@0 556 h = CreateFileW(
alanb@1575 557 pathbuf, /* Wide char path name */
alanb@1575 558 GENERIC_READ | GENERIC_WRITE, /* Read and write permission */
duke@0 559 FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */
alanb@1575 560 NULL, /* Security attributes */
alanb@1575 561 CREATE_NEW, /* creation disposition */
alanb@1575 562 FILE_ATTRIBUTE_NORMAL |
alanb@1575 563 FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */
duke@0 564 NULL);
duke@0 565
duke@0 566 if (h == INVALID_HANDLE_VALUE) {
duke@0 567 DWORD error = GetLastError();
duke@0 568 if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
alanb@1575 569 // return false rather than throwing an exception when there is
alanb@1575 570 // an existing file.
alanb@1575 571 DWORD a = GetFileAttributesW(pathbuf);
alanb@1575 572 if (a == INVALID_FILE_ATTRIBUTES) {
duke@0 573 SetLastError(error);
duke@0 574 JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
duke@0 575 }
duke@0 576 }
duke@0 577 free(pathbuf);
duke@0 578 return JNI_FALSE;
alanb@1575 579 }
duke@0 580 free(pathbuf);
duke@0 581 CloseHandle(h);
duke@0 582 return JNI_TRUE;
duke@0 583 }
duke@0 584
duke@0 585 static int
duke@0 586 removeFileOrDirectory(const jchar *path)
duke@0 587 {
duke@0 588 /* Returns 0 on success */
duke@0 589 DWORD a;
duke@0 590
alanb@1575 591 SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
duke@0 592 a = GetFileAttributesW(path);
alanb@1575 593 if (a == INVALID_FILE_ATTRIBUTES) {
duke@0 594 return 1;
duke@0 595 } else if (a & FILE_ATTRIBUTE_DIRECTORY) {
duke@0 596 return !RemoveDirectoryW(path);
duke@0 597 } else {
duke@0 598 return !DeleteFileW(path);
duke@0 599 }
duke@0 600 }
duke@0 601
duke@0 602 JNIEXPORT jboolean JNICALL
duke@0 603 Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file)
duke@0 604 {
duke@0 605 jboolean rv = JNI_FALSE;
duke@0 606 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
duke@0 607 if (pathbuf == NULL) {
duke@0 608 return JNI_FALSE;
duke@0 609 }
duke@0 610 if (removeFileOrDirectory(pathbuf) == 0) {
duke@0 611 rv = JNI_TRUE;
duke@0 612 }
duke@0 613 free(pathbuf);
duke@0 614 return rv;
duke@0 615 }
duke@0 616
duke@0 617 JNIEXPORT jobjectArray JNICALL
duke@0 618 Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file)
duke@0 619 {
duke@0 620 WCHAR *search_path;
duke@0 621 HANDLE handle;
duke@0 622 WIN32_FIND_DATAW find_data;
duke@0 623 int len, maxlen;
duke@0 624 jobjectArray rv, old;
duke@0 625 DWORD fattr;
duke@0 626 jstring name;
alanb@10473 627 jclass str_class;
alanb@10473 628 WCHAR *pathbuf;
duke@0 629
alanb@10473 630 str_class = JNU_ClassString(env);
alanb@10473 631 CHECK_NULL_RETURN(str_class, NULL);
alanb@10473 632
alanb@10473 633 pathbuf = fileToNTPath(env, file, ids.path);
duke@0 634 if (pathbuf == NULL)
duke@0 635 return NULL;
duke@0 636 search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);
duke@0 637 if (search_path == 0) {
duke@0 638 free (pathbuf);
duke@0 639 errno = ENOMEM;
msheppar@9691 640 JNU_ThrowOutOfMemoryError(env, "native memory allocation faiuled");
duke@0 641 return NULL;
duke@0 642 }
duke@0 643 wcscpy(search_path, pathbuf);
duke@0 644 free(pathbuf);
duke@0 645 fattr = GetFileAttributesW(search_path);
duke@0 646 if (fattr == INVALID_FILE_ATTRIBUTES) {
duke@0 647 free(search_path);
duke@0 648 return NULL;
duke@0 649 } else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
duke@0 650 free(search_path);
duke@0 651 return NULL;
duke@0 652 }
duke@0 653
duke@0 654 /* Remove trailing space chars from directory name */
alanb@3499 655 len = (int)wcslen(search_path);
duke@0 656 while (search_path[len-1] == ' ') {
duke@0 657 len--;
duke@0 658 }
duke@0 659 search_path[len] = 0;
duke@0 660
duke@0 661 /* Append "*", or possibly "\\*", to path */
duke@0 662 if ((search_path[0] == L'\\' && search_path[1] == L'\0') ||
duke@0 663 (search_path[1] == L':'
duke@0 664 && (search_path[2] == L'\0'
duke@0 665 || (search_path[2] == L'\\' && search_path[3] == L'\0')))) {
duke@0 666 /* No '\\' needed for cases like "\" or "Z:" or "Z:\" */
duke@0 667 wcscat(search_path, L"*");
duke@0 668 } else {
duke@0 669 wcscat(search_path, L"\\*");
duke@0 670 }
duke@0 671
duke@0 672 /* Open handle to the first file */
duke@0 673 handle = FindFirstFileW(search_path, &find_data);
duke@0 674 free(search_path);
duke@0 675 if (handle == INVALID_HANDLE_VALUE) {
duke@0 676 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
duke@0 677 // error
duke@0 678 return NULL;
duke@0 679 } else {
duke@0 680 // No files found - return an empty array
alanb@10473 681 rv = (*env)->NewObjectArray(env, 0, str_class, NULL);
duke@0 682 return rv;
duke@0 683 }
duke@0 684 }
duke@0 685
duke@0 686 /* Allocate an initial String array */
duke@0 687 len = 0;
duke@0 688 maxlen = 16;
alanb@10473 689 rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);
duke@0 690 if (rv == NULL) // Couldn't allocate an array
duke@0 691 return NULL;
duke@0 692 /* Scan the directory */
duke@0 693 do {
duke@0 694 if (!wcscmp(find_data.cFileName, L".")
duke@0 695 || !wcscmp(find_data.cFileName, L".."))
duke@0 696 continue;
duke@0 697 name = (*env)->NewString(env, find_data.cFileName,
alanb@3499 698 (jsize)wcslen(find_data.cFileName));
duke@0 699 if (name == NULL)
duke@0 700 return NULL; // error;
duke@0 701 if (len == maxlen) {
duke@0 702 old = rv;
alanb@10473 703 rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);
alanb@10473 704 if (rv == NULL || JNU_CopyObjectArray(env, rv, old, len) < 0)
duke@0 705 return NULL; // error
duke@0 706 (*env)->DeleteLocalRef(env, old);
duke@0 707 }
duke@0 708 (*env)->SetObjectArrayElement(env, rv, len++, name);
duke@0 709 (*env)->DeleteLocalRef(env, name);
duke@0 710
duke@0 711 } while (FindNextFileW(handle, &find_data));
duke@0 712
duke@0 713 if (GetLastError() != ERROR_NO_MORE_FILES)
duke@0 714 return NULL; // error
duke@0 715 FindClose(handle);
duke@0 716
duke@0 717 /* Copy the final results into an appropriately-sized array */
duke@0 718 old = rv;
alanb@10473 719 rv = (*env)->NewObjectArray(env, len, str_class, NULL);
duke@0 720 if (rv == NULL)
duke@0 721 return NULL; /* error */
duke@0 722 if (JNU_CopyObjectArray(env, rv, old, len) < 0)
duke@0 723 return NULL; /* error */
duke@0 724 return rv;
duke@0 725 }
duke@0 726
duke@0 727
duke@0 728 JNIEXPORT jboolean JNICALL
duke@0 729 Java_java_io_WinNTFileSystem_createDirectory(JNIEnv *env, jobject this,
duke@0 730 jobject file)
duke@0 731 {
duke@0 732 BOOL h = FALSE;
duke@0 733 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
duke@0 734 if (pathbuf == NULL) {
duke@0 735 /* Exception is pending */
duke@0 736 return JNI_FALSE;
duke@0 737 }
duke@0 738 h = CreateDirectoryW(pathbuf, NULL);
duke@0 739 free(pathbuf);
duke@0 740
duke@0 741 if (h == 0) {
duke@0 742 return JNI_FALSE;
duke@0 743 }
duke@0 744
duke@0 745 return JNI_TRUE;
duke@0 746 }
duke@0 747
duke@0 748
duke@0 749 JNIEXPORT jboolean JNICALL
duke@0 750 Java_java_io_WinNTFileSystem_rename0(JNIEnv *env, jobject this, jobject from,
duke@0 751 jobject to)
duke@0 752 {
duke@0 753
duke@0 754 jboolean rv = JNI_FALSE;
duke@0 755 WCHAR *frompath = fileToNTPath(env, from, ids.path);
duke@0 756 WCHAR *topath = fileToNTPath(env, to, ids.path);
duke@0 757 if (frompath == NULL || topath == NULL)
duke@0 758 return JNI_FALSE;
duke@0 759 if (_wrename(frompath, topath) == 0) {
duke@0 760 rv = JNI_TRUE;
duke@0 761 }
duke@0 762 free(frompath);
duke@0 763 free(topath);
duke@0 764 return rv;
duke@0 765 }
duke@0 766
duke@0 767
duke@0 768 JNIEXPORT jboolean JNICALL
duke@0 769 Java_java_io_WinNTFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
duke@0 770 jobject file, jlong time)
duke@0 771 {
duke@0 772 jboolean rv = JNI_FALSE;
duke@0 773 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
duke@0 774 HANDLE h;
duke@0 775 if (pathbuf == NULL)
duke@0 776 return JNI_FALSE;
alanb@1575 777 h = CreateFileW(pathbuf,
alanb@1575 778 FILE_WRITE_ATTRIBUTES,
alanb@1575 779 FILE_SHARE_READ | FILE_SHARE_WRITE,
alanb@1575 780 NULL,
alanb@1575 781 OPEN_EXISTING,
alanb@1575 782 FILE_FLAG_BACKUP_SEMANTICS,
alanb@1575 783 0);
duke@0 784 if (h != INVALID_HANDLE_VALUE) {
duke@0 785 LARGE_INTEGER modTime;
duke@0 786 FILETIME t;
duke@0 787 modTime.QuadPart = (time + 11644473600000L) * 10000L;
duke@0 788 t.dwLowDateTime = (DWORD)modTime.LowPart;
duke@0 789 t.dwHighDateTime = (DWORD)modTime.HighPart;
duke@0 790 if (SetFileTime(h, NULL, NULL, &t)) {
duke@0 791 rv = JNI_TRUE;
duke@0 792 }
duke@0 793 CloseHandle(h);
duke@0 794 }
duke@0 795 free(pathbuf);
duke@0 796
duke@0 797 return rv;
duke@0 798 }
duke@0 799
duke@0 800
duke@0 801 JNIEXPORT jboolean JNICALL
duke@0 802 Java_java_io_WinNTFileSystem_setReadOnly(JNIEnv *env, jobject this,
duke@0 803 jobject file)
duke@0 804 {
duke@0 805 jboolean rv = JNI_FALSE;
duke@0 806 DWORD a;
duke@0 807 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
duke@0 808 if (pathbuf == NULL)
duke@0 809 return JNI_FALSE;
duke@0 810 a = GetFileAttributesW(pathbuf);
alanb@1575 811
alanb@1575 812 /* if reparse point, get final target */
alanb@1575 813 if ((a != INVALID_FILE_ATTRIBUTES) &&
alanb@1575 814 ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
alanb@1575 815 {
msheppar@9691 816 WCHAR *fp = getFinalPath(env, pathbuf);
alanb@1575 817 if (fp == NULL) {
alanb@1575 818 a = INVALID_FILE_ATTRIBUTES;
alanb@1575 819 } else {
alanb@1575 820 free(pathbuf);
alanb@1575 821 pathbuf = fp;
alanb@1575 822 a = GetFileAttributesW(pathbuf);
alanb@1575 823 }
alanb@1575 824 }
alanb@1575 825
alanb@2918 826 if ((a != INVALID_FILE_ATTRIBUTES) &&
alanb@2918 827 ((a & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
duke@0 828 if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))
alanb@2918 829 rv = JNI_TRUE;
duke@0 830 }
duke@0 831 free(pathbuf);
duke@0 832 return rv;
duke@0 833 }
duke@0 834
duke@0 835 /* -- Filesystem interface -- */
duke@0 836
duke@0 837
duke@0 838 JNIEXPORT jobject JNICALL
duke@0 839 Java_java_io_WinNTFileSystem_getDriveDirectory(JNIEnv *env, jobject this,
duke@0 840 jint drive)
duke@0 841 {
duke@0 842 jstring ret = NULL;
alanb@2919 843 jchar *p = currentDir(drive);
duke@0 844 jchar *pf = p;
duke@0 845 if (p == NULL) return NULL;
duke@0 846 if (iswalpha(*p) && (p[1] == L':')) p += 2;
alanb@3499 847 ret = (*env)->NewString(env, p, (jsize)wcslen(p));
duke@0 848 free (pf);
duke@0 849 return ret;
duke@0 850 }
duke@0 851
dxu@5971 852 JNIEXPORT jint JNICALL
dxu@5971 853 Java_java_io_WinNTFileSystem_listRoots0(JNIEnv *env, jclass ignored)
dxu@5971 854 {
dxu@5971 855 return GetLogicalDrives();
dxu@5971 856 }
dxu@5971 857
duke@0 858 JNIEXPORT jlong JNICALL
duke@0 859 Java_java_io_WinNTFileSystem_getSpace0(JNIEnv *env, jobject this,
duke@0 860 jobject file, jint t)
duke@0 861 {
duke@0 862 WCHAR volname[MAX_PATH_LENGTH + 1];
duke@0 863 jlong rv = 0L;
duke@0 864 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
duke@0 865
alanb@3901 866 if (GetVolumePathNameW(pathbuf, volname, MAX_PATH_LENGTH)) {
duke@0 867 ULARGE_INTEGER totalSpace, freeSpace, usableSpace;
duke@0 868 if (GetDiskFreeSpaceExW(volname, &usableSpace, &totalSpace, &freeSpace)) {
duke@0 869 switch(t) {
duke@0 870 case java_io_FileSystem_SPACE_TOTAL:
duke@0 871 rv = long_to_jlong(totalSpace.QuadPart);
duke@0 872 break;
duke@0 873 case java_io_FileSystem_SPACE_FREE:
duke@0 874 rv = long_to_jlong(freeSpace.QuadPart);
duke@0 875 break;
duke@0 876 case java_io_FileSystem_SPACE_USABLE:
duke@0 877 rv = long_to_jlong(usableSpace.QuadPart);
duke@0 878 break;
duke@0 879 default:
duke@0 880 assert(0);
duke@0 881 }
duke@0 882 }
duke@0 883 }
duke@0 884
duke@0 885 free(pathbuf);
duke@0 886 return rv;
duke@0 887 }