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