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