40
#include "io_util_md.h"
41
#include "java_io_FileSystem.h"
43
#define MAX_PATH_LENGTH 1024
52
typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
53
static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
56
Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
61
fileClass = (*env)->FindClass(env, "java/io/File");
62
CHECK_NULL(fileClass);
63
ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
67
if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
68
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
69
(LPCWSTR)&CreateFileW, &handle) != 0)
71
GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
72
GetProcAddress(handle, "GetFinalPathNameByHandleW");
78
extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
79
extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
85
static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)
92
if (GetFinalPathNameByHandle_func == NULL)
98
FILE_SHARE_READ | FILE_SHARE_WRITE,
101
FILE_FLAG_BACKUP_SEMANTICS,
103
if (h == INVALID_HANDLE_VALUE)
110
result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR));
111
if (result != NULL) {
112
DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0);
113
if (len >= MAX_PATH) {
115
WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR));
116
if (newResult != NULL) {
118
len = (*GetFinalPathNameByHandle_func)(h, result, len, 0);
121
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
129
if (result[0] == L'\\' && result[1] == L'\\' &&
130
result[2] == L'?' && result[3] == L'\\')
132
int isUnc = (result[4] == L'U' &&
135
int prefixLen = (isUnc) ? 7 : 4;
136
int prefixToKeep = (isUnc) ? 1 : 0;
138
int amountToCopy = len - prefixLen + 1;
139
wmemmove(result + prefixToKeep, result + prefixLen, amountToCopy);
144
if (len == 0 && result != NULL) {
149
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
152
error = GetLastError();
163
static BOOL getFileInformation(const WCHAR *path,
164
BY_HANDLE_FILE_INFORMATION *finfo)
168
HANDLE h = CreateFileW(path,
169
FILE_READ_ATTRIBUTES,
171
FILE_SHARE_READ | FILE_SHARE_WRITE,
174
FILE_FLAG_BACKUP_SEMANTICS,
176
if (h == INVALID_HANDLE_VALUE)
178
result = GetFileInformationByHandle(h, finfo);
179
error = GetLastError();
189
static DWORD getFinalAttributesUnixSocket(const WCHAR *path)
192
BY_HANDLE_FILE_INFORMATION finfo;
193
REPARSE_GUID_DATA_BUFFER reparse;
195
HANDLE h = CreateFileW(path,
196
FILE_READ_ATTRIBUTES,
198
FILE_SHARE_READ | FILE_SHARE_WRITE,
201
FILE_FLAG_BACKUP_SEMANTICS |
202
FILE_FLAG_OPEN_REPARSE_POINT,
205
if (h == INVALID_HANDLE_VALUE)
206
return INVALID_FILE_ATTRIBUTES;
209
if (!GetFileInformationByHandle(h, &finfo)) {
210
DWORD error = GetLastError();
211
if (CloseHandle(h)) {
214
return INVALID_FILE_ATTRIBUTES;
217
if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
219
return INVALID_FILE_ATTRIBUTES;
224
if (DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, &reparse,
225
(DWORD)sizeof(reparse), &result, NULL) == 0) {
227
return INVALID_FILE_ATTRIBUTES;
230
if (reparse.ReparseTag != IO_REPARSE_TAG_AF_UNIX) {
232
return INVALID_FILE_ATTRIBUTES;
236
return finfo.dwFileAttributes;
243
DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)
245
if ((a != INVALID_FILE_ATTRIBUTES) &&
246
((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
248
BY_HANDLE_FILE_INFORMATION finfo;
249
BOOL res = getFileInformation(path, &finfo);
250
a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
259
DWORD getFinalAttributes(WCHAR *path)
261
DWORD attr = INVALID_FILE_ATTRIBUTES;
263
WIN32_FILE_ATTRIBUTE_DATA wfad;
264
WIN32_FIND_DATAW wfd;
267
if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) {
268
attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes);
269
if (attr == INVALID_FILE_ATTRIBUTES) {
270
if (GetLastError() == ERROR_CANT_ACCESS_FILE) {
271
attr = getFinalAttributesUnixSocket(path);
275
DWORD lerr = GetLastError();
276
if ((lerr == ERROR_SHARING_VIOLATION || lerr == ERROR_ACCESS_DENIED) &&
277
(h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) {
278
attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes);
285
JNIEXPORT jstring JNICALL
286
Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
290
WCHAR canonicalPath[MAX_PATH_LENGTH];
292
WITH_UNICODE_STRING(env, pathname, path) {
296
int len = (int)wcslen(path);
297
len += currentDirLength(path, len);
298
if (len > MAX_PATH_LENGTH - 1) {
299
WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
301
if (wcanonicalize(path, cp, len) >= 0) {
302
rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
306
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
308
} else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
309
rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
311
} END_UNICODE_STRING(env, path);
312
if (rv == NULL && !(*env)->ExceptionCheck(env)) {
313
JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
319
JNIEXPORT jstring JNICALL
320
Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
321
jstring canonicalPrefixString,
322
jstring pathWithCanonicalPrefixString)
325
WCHAR canonicalPath[MAX_PATH_LENGTH];
326
WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {
327
WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
328
int len = (int)wcslen(canonicalPrefix) + MAX_PATH;
329
if (len > MAX_PATH_LENGTH) {
330
WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
332
if (wcanonicalizeWithPrefix(canonicalPrefix,
333
pathWithCanonicalPrefix,
335
rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
339
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
341
} else if (wcanonicalizeWithPrefix(canonicalPrefix,
342
pathWithCanonicalPrefix,
343
canonicalPath, MAX_PATH_LENGTH) >= 0) {
344
rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
346
} END_UNICODE_STRING(env, pathWithCanonicalPrefix);
347
} END_UNICODE_STRING(env, canonicalPrefix);
348
if (rv == NULL && !(*env)->ExceptionCheck(env)) {
349
JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
381
static BOOL isReservedDeviceNameW(WCHAR* path) {
385
DWORD retLen = GetFullPathNameW(path,
389
if ((retLen == BUFSIZE - 1 || retLen == BUFSIZE - 2) &&
390
buf[0] == L'\\' && buf[1] == L'\\' &&
391
buf[2] == L'.' && buf[3] == L'\\') {
392
WCHAR* dname = _wcsupr(buf + 4);
393
if (wcscmp(dname, L"CON") == 0 ||
394
wcscmp(dname, L"PRN") == 0 ||
395
wcscmp(dname, L"AUX") == 0 ||
396
wcscmp(dname, L"NUL") == 0)
398
if ((wcsncmp(dname, L"COM", 3) == 0 ||
399
wcsncmp(dname, L"LPT", 3) == 0) &&
400
dname[3] - L'0' > 0 &&
401
dname[3] - L'0' <= 9)
407
JNIEXPORT jint JNICALL
408
Java_java_io_WinNTFileSystem_getBooleanAttributes0(JNIEnv *env, jobject this,
413
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
416
if (!isReservedDeviceNameW(pathbuf)) {
417
DWORD a = getFinalAttributes(pathbuf);
418
if (a != INVALID_FILE_ATTRIBUTES) {
419
rv = (java_io_FileSystem_BA_EXISTS
420
| ((a & FILE_ATTRIBUTE_DIRECTORY)
421
? java_io_FileSystem_BA_DIRECTORY
422
: java_io_FileSystem_BA_REGULAR)
423
| ((a & FILE_ATTRIBUTE_HIDDEN)
424
? java_io_FileSystem_BA_HIDDEN : 0));
433
JNICALL Java_java_io_WinNTFileSystem_checkAccess0(JNIEnv *env, jobject this,
434
jobject file, jint access)
437
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
440
attr = GetFileAttributesW(pathbuf);
441
attr = getFinalAttributesIfReparsePoint(pathbuf, attr);
443
if (attr == INVALID_FILE_ATTRIBUTES)
446
case java_io_FileSystem_ACCESS_READ:
447
case java_io_FileSystem_ACCESS_EXECUTE:
449
case java_io_FileSystem_ACCESS_WRITE:
451
if ((attr & FILE_ATTRIBUTE_DIRECTORY) ||
452
(attr & FILE_ATTRIBUTE_READONLY) == 0)
462
JNIEXPORT jboolean JNICALL
463
Java_java_io_WinNTFileSystem_setPermission0(JNIEnv *env, jobject this,
469
jboolean rv = JNI_FALSE;
472
if (access == java_io_FileSystem_ACCESS_READ ||
473
access == java_io_FileSystem_ACCESS_EXECUTE) {
476
pathbuf = fileToNTPath(env, file, ids.path);
479
a = GetFileAttributesW(pathbuf);
482
if ((a != INVALID_FILE_ATTRIBUTES) &&
483
((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
485
WCHAR *fp = getFinalPath(env, pathbuf);
487
a = INVALID_FILE_ATTRIBUTES;
491
a = GetFileAttributesW(pathbuf);
494
if ((a != INVALID_FILE_ATTRIBUTES) &&
495
((a & FILE_ATTRIBUTE_DIRECTORY) == 0))
498
a = a & ~FILE_ATTRIBUTE_READONLY;
500
a = a | FILE_ATTRIBUTE_READONLY;
501
if (SetFileAttributesW(pathbuf, a))
508
JNIEXPORT jlong JNICALL
509
Java_java_io_WinNTFileSystem_getLastModifiedTime0(JNIEnv *env, jobject this,
513
ULARGE_INTEGER modTime;
516
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
519
h = CreateFileW(pathbuf,
523
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
529
FILE_FLAG_BACKUP_SEMANTICS,
532
if (h != INVALID_HANDLE_VALUE) {
533
if (GetFileTime(h, NULL, NULL, &t)) {
534
modTime.LowPart = (DWORD) t.dwLowDateTime;
535
modTime.HighPart = (LONG) t.dwHighDateTime;
536
rv = modTime.QuadPart / 10000;
537
rv -= 11644473600000;
545
JNIEXPORT jlong JNICALL
546
Java_java_io_WinNTFileSystem_getLength0(JNIEnv *env, jobject this, jobject file)
549
WIN32_FILE_ATTRIBUTE_DATA wfad;
550
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
553
if (GetFileAttributesExW(pathbuf,
554
GetFileExInfoStandard,
556
if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
557
rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;
560
BY_HANDLE_FILE_INFORMATION finfo;
561
if (getFileInformation(pathbuf, &finfo)) {
562
rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) +
567
if (GetLastError() == ERROR_SHARING_VIOLATION) {
574
WIN32_FIND_DATAW fileData;
575
HANDLE h = FindFirstFileW(pathbuf, &fileData);
576
if (h != INVALID_HANDLE_VALUE) {
577
if ((fileData.dwFileAttributes &
578
FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
579
WCHAR backslash = L'\\';
580
WCHAR *pslash = wcsrchr(pathbuf, backslash);
581
if (pslash == NULL) {
586
WCHAR *fslash = wcsrchr(fileData.cFileName, backslash);
587
if (fslash == NULL) {
588
fslash = fileData.cFileName;
592
if (wcscmp(pslash, fslash) == 0) {
593
ULARGE_INTEGER length;
594
length.LowPart = fileData.nFileSizeLow;
595
length.HighPart = fileData.nFileSizeHigh;
596
if (length.QuadPart <= _I64_MAX) {
597
rv = (jlong)length.QuadPart;
611
JNIEXPORT jboolean JNICALL
612
Java_java_io_WinNTFileSystem_createFileExclusively0(JNIEnv *env, jclass cls,
616
WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
619
if (isReservedDeviceNameW(pathbuf)) {
625
GENERIC_READ | GENERIC_WRITE,
626
FILE_SHARE_READ | FILE_SHARE_WRITE,
629
FILE_ATTRIBUTE_NORMAL |
630
FILE_FLAG_OPEN_REPARSE_POINT,
633
if (h == INVALID_HANDLE_VALUE) {
634
DWORD error = GetLastError();
635
if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
638
DWORD a = GetFileAttributesW(pathbuf);
639
if (a == INVALID_FILE_ATTRIBUTES) {
641
JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
653
removeFileOrDirectory(const jchar *path)
658
SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
659
a = GetFileAttributesW(path);
660
if (a == INVALID_FILE_ATTRIBUTES) {
662
} else if (a & FILE_ATTRIBUTE_DIRECTORY) {
663
return !RemoveDirectoryW(path);
665
return !DeleteFileW(path);
669
JNIEXPORT jboolean JNICALL
670
Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file)
672
jboolean rv = JNI_FALSE;
673
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
674
if (pathbuf == NULL) {
677
if (removeFileOrDirectory(pathbuf) == 0) {
684
JNIEXPORT jobjectArray JNICALL
685
Java_java_io_WinNTFileSystem_list0(JNIEnv *env, jobject this, jobject file)
689
WIN32_FIND_DATAW find_data;
691
jobjectArray rv, old;
698
str_class = JNU_ClassString(env);
699
CHECK_NULL_RETURN(str_class, NULL);
701
pathbuf = fileToNTPath(env, file, ids.path);
704
search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);
705
if (search_path == 0) {
708
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
711
wcscpy(search_path, pathbuf);
713
fattr = GetFileAttributesW(search_path);
714
if (fattr == INVALID_FILE_ATTRIBUTES) {
717
} else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
723
len = (int)wcslen(search_path);
724
while (search_path[len-1] == L' ') {
727
search_path[len] = 0;
730
if ((search_path[0] == L'\\' && search_path[1] == L'\0') ||
731
(search_path[1] == L':'
732
&& (search_path[2] == L'\0'
733
|| (search_path[2] == L'\\' && search_path[3] == L'\0')))) {
735
wcscat(search_path, L"*");
737
wcscat(search_path, L"\\*");
741
handle = FindFirstFileW(search_path, &find_data);
743
if (handle == INVALID_HANDLE_VALUE) {
744
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
749
rv = (*env)->NewObjectArray(env, 0, str_class, NULL);
757
rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);
764
if (!wcscmp(find_data.cFileName, L".")
765
|| !wcscmp(find_data.cFileName, L".."))
767
name = (*env)->NewString(env, find_data.cFileName,
768
(jsize)wcslen(find_data.cFileName));
775
rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);
776
if (rv == NULL || JNU_CopyObjectArray(env, rv, old, len) < 0) {
780
(*env)->DeleteLocalRef(env, old);
782
(*env)->SetObjectArrayElement(env, rv, len++, name);
783
(*env)->DeleteLocalRef(env, name);
785
} while (FindNextFileW(handle, &find_data));
787
err = GetLastError();
789
if (err != ERROR_NO_MORE_FILES) {
796
rv = (*env)->NewObjectArray(env, len, str_class, NULL);
799
if (JNU_CopyObjectArray(env, rv, old, len) < 0)
806
JNIEXPORT jboolean JNICALL
807
Java_java_io_WinNTFileSystem_createDirectory0(JNIEnv *env, jobject this,
811
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
812
if (pathbuf == NULL) {
816
h = CreateDirectoryW(pathbuf, NULL);
827
JNIEXPORT jboolean JNICALL
828
Java_java_io_WinNTFileSystem_rename0(JNIEnv *env, jobject this, jobject from,
832
jboolean rv = JNI_FALSE;
833
WCHAR *frompath = fileToNTPath(env, from, ids.path);
834
WCHAR *topath = fileToNTPath(env, to, ids.path);
835
if (frompath != NULL && topath != NULL && _wrename(frompath, topath) == 0) {
844
JNIEXPORT jboolean JNICALL
845
Java_java_io_WinNTFileSystem_setLastModifiedTime0(JNIEnv *env, jobject this,
846
jobject file, jlong time)
848
jboolean rv = JNI_FALSE;
849
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
853
h = CreateFileW(pathbuf,
854
FILE_WRITE_ATTRIBUTES,
855
FILE_SHARE_READ | FILE_SHARE_WRITE,
858
FILE_FLAG_BACKUP_SEMANTICS,
860
if (h != INVALID_HANDLE_VALUE) {
861
ULARGE_INTEGER modTime;
863
modTime.QuadPart = (time + 11644473600000L) * 10000L;
864
t.dwLowDateTime = (DWORD)modTime.LowPart;
865
t.dwHighDateTime = (DWORD)modTime.HighPart;
866
if (SetFileTime(h, NULL, NULL, &t)) {
877
JNIEXPORT jboolean JNICALL
878
Java_java_io_WinNTFileSystem_setReadOnly0(JNIEnv *env, jobject this,
881
jboolean rv = JNI_FALSE;
883
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
886
a = GetFileAttributesW(pathbuf);
889
if ((a != INVALID_FILE_ATTRIBUTES) &&
890
((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
892
WCHAR *fp = getFinalPath(env, pathbuf);
894
a = INVALID_FILE_ATTRIBUTES;
898
a = GetFileAttributesW(pathbuf);
902
if ((a != INVALID_FILE_ATTRIBUTES) &&
903
((a & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
904
if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))
914
JNIEXPORT jobject JNICALL
915
Java_java_io_WinNTFileSystem_getDriveDirectory(JNIEnv *env, jobject this,
919
jchar *p = currentDir(drive);
921
if (p == NULL) return NULL;
922
if (iswalpha(*p) && (p[1] == L':')) p += 2;
923
ret = (*env)->NewString(env, p, (jsize)wcslen(p));
928
JNIEXPORT jint JNICALL
929
Java_java_io_WinNTFileSystem_listRoots0(JNIEnv *env, jclass ignored)
931
return GetLogicalDrives();
934
JNIEXPORT jlong JNICALL
935
Java_java_io_WinNTFileSystem_getSpace0(JNIEnv *env, jobject this,
936
jobject file, jint t)
938
WCHAR volname[MAX_PATH_LENGTH + 1];
940
WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
942
if (GetVolumePathNameW(pathbuf, volname, MAX_PATH_LENGTH)) {
943
ULARGE_INTEGER totalSpace, freeSpace, usableSpace;
944
if (GetDiskFreeSpaceExW(volname, &usableSpace, &totalSpace, &freeSpace)) {
946
case java_io_FileSystem_SPACE_TOTAL:
947
rv = long_to_jlong(totalSpace.QuadPart);
949
case java_io_FileSystem_SPACE_FREE:
950
rv = long_to_jlong(freeSpace.QuadPart);
952
case java_io_FileSystem_SPACE_USABLE:
953
rv = long_to_jlong(usableSpace.QuadPart);
967
JNIEXPORT jint JNICALL
968
Java_java_io_WinNTFileSystem_getNameMax0(JNIEnv *env, jobject this,
972
DWORD maxComponentLength;
974
if (pathname == NULL) {
975
res = GetVolumeInformationW(NULL,
984
WITH_UNICODE_STRING(env, pathname, path) {
985
res = GetVolumeInformationW(path,
993
} END_UNICODE_STRING(env, path);
997
JNU_ThrowIOExceptionWithLastError(env,
998
"Could not get maximum component length");
1001
return (jint)maxComponentLength;