jdk

Форк
0
/
WinNTFileSystem_md.c 
1002 строки · 32.1 Кб
1
/*
2
 * Copyright (c) 2001, 2023, 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
#include <assert.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <ctype.h>
30
#include <direct.h>
31
#include <windows.h>
32
#include <io.h>
33
#include <limits.h>
34
#include <wchar.h>
35
#include <Winioctl.h>
36

37
#include "jni.h"
38
#include "io_util.h"
39
#include "jlong.h"
40
#include "io_util_md.h"
41
#include "java_io_FileSystem.h"
42

43
#define MAX_PATH_LENGTH 1024
44

45
static struct {
46
    jfieldID path;
47
} ids;
48

49
/**
50
 * GetFinalPathNameByHandle is available on Windows Vista and newer
51
 */
52
typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
53
static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
54

55
JNIEXPORT void JNICALL
56
Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
57
{
58
    HMODULE handle;
59
    jclass fileClass;
60

61
    fileClass = (*env)->FindClass(env, "java/io/File");
62
    CHECK_NULL(fileClass);
63
    ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
64
    CHECK_NULL(ids.path);
65

66
    // GetFinalPathNameByHandle requires Windows Vista or newer
67
    if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
68
                            GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
69
                           (LPCWSTR)&CreateFileW, &handle) != 0)
70
    {
71
        GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
72
            GetProcAddress(handle, "GetFinalPathNameByHandleW");
73
    }
74
}
75

76
/* -- Path operations -- */
77

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);
80

81
/**
82
 * Retrieves the fully resolved (final) path for the given path or NULL
83
 * if the function fails.
84
 */
85
static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)
86
{
87
    HANDLE h;
88
    WCHAR *result;
89
    DWORD error;
90

91
    /* Need Windows Vista or newer to get the final path */
92
    if (GetFinalPathNameByHandle_func == NULL)
93
        return NULL;
94

95
    h = CreateFileW(path,
96
                    FILE_READ_ATTRIBUTES,
97
                    FILE_SHARE_DELETE |
98
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
99
                    NULL,
100
                    OPEN_EXISTING,
101
                    FILE_FLAG_BACKUP_SEMANTICS,
102
                    NULL);
103
    if (h == INVALID_HANDLE_VALUE)
104
        return NULL;
105

106
    /**
107
     * Allocate a buffer for the resolved path. For a long path we may need
108
     * to allocate a larger buffer.
109
     */
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) {
114
            /* retry with a buffer of the right size */
115
            WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR));
116
            if (newResult != NULL) {
117
                result = newResult;
118
                len = (*GetFinalPathNameByHandle_func)(h, result, len, 0);
119
            } else {
120
                len = 0;
121
                JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
122
            }
123
        }
124

125
        if (len > 0) {
126
            /**
127
             * Strip prefix (should be \\?\ or \\?\UNC)
128
             */
129
            if (result[0] == L'\\' && result[1] == L'\\' &&
130
                result[2] == L'?' && result[3] == L'\\')
131
            {
132
                int isUnc = (result[4] == L'U' &&
133
                             result[5] == L'N' &&
134
                             result[6] == L'C');
135
                int prefixLen = (isUnc) ? 7 : 4;
136
                int prefixToKeep = (isUnc) ? 1 : 0;
137
                // the amount to copy includes terminator
138
                int amountToCopy = len - prefixLen + 1;
139
                wmemmove(result + prefixToKeep, result + prefixLen, amountToCopy);
140
            }
141
        }
142

143
        /* unable to get final path */
144
        if (len == 0 && result != NULL) {
145
            free(result);
146
            result = NULL;
147
        }
148
    } else {
149
        JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
150
    }
151

152
    error = GetLastError();
153
    if (CloseHandle(h))
154
        SetLastError(error);
155
    return result;
156
}
157

158
/**
159
 * Retrieves file information for the specified file. If the file is
160
 * symbolic link then the information on fully resolved target is
161
 * returned.
162
 */
163
static BOOL getFileInformation(const WCHAR *path,
164
                               BY_HANDLE_FILE_INFORMATION *finfo)
165
{
166
    BOOL result;
167
    DWORD error;
168
    HANDLE h = CreateFileW(path,
169
                           FILE_READ_ATTRIBUTES,
170
                           FILE_SHARE_DELETE |
171
                               FILE_SHARE_READ | FILE_SHARE_WRITE,
172
                           NULL,
173
                           OPEN_EXISTING,
174
                           FILE_FLAG_BACKUP_SEMANTICS,
175
                           NULL);
176
    if (h == INVALID_HANDLE_VALUE)
177
        return FALSE;
178
    result = GetFileInformationByHandle(h, finfo);
179
    error = GetLastError();
180
    if (CloseHandle(h))
181
        SetLastError(error);
182
    return result;
183
}
184

185
/**
186
 * path is likely to be a Unix domain socket.
187
 * Verify and if it is return its attributes
188
 */
189
static DWORD getFinalAttributesUnixSocket(const WCHAR *path)
190
{
191
    DWORD result;
192
    BY_HANDLE_FILE_INFORMATION finfo;
193
    REPARSE_GUID_DATA_BUFFER reparse;
194

195
    HANDLE h = CreateFileW(path,
196
                           FILE_READ_ATTRIBUTES,
197
                           FILE_SHARE_DELETE |
198
                               FILE_SHARE_READ | FILE_SHARE_WRITE,
199
                           NULL,
200
                           OPEN_EXISTING,
201
                           FILE_FLAG_BACKUP_SEMANTICS |
202
                               FILE_FLAG_OPEN_REPARSE_POINT,
203
                           NULL);
204

205
    if (h == INVALID_HANDLE_VALUE)
206
        return INVALID_FILE_ATTRIBUTES;
207

208

209
    if (!GetFileInformationByHandle(h, &finfo)) {
210
        DWORD error = GetLastError();
211
        if (CloseHandle(h)) {
212
            SetLastError(error);
213
        }
214
        return INVALID_FILE_ATTRIBUTES;
215
    }
216

217
    if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
218
        CloseHandle(h);
219
        return INVALID_FILE_ATTRIBUTES;
220
    }
221

222
    /* check the reparse tag */
223

224
    if (DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, &reparse,
225
                (DWORD)sizeof(reparse), &result, NULL) == 0) {
226
        CloseHandle(h);
227
        return INVALID_FILE_ATTRIBUTES;
228
    }
229

230
    if (reparse.ReparseTag != IO_REPARSE_TAG_AF_UNIX) {
231
        CloseHandle(h);
232
        return INVALID_FILE_ATTRIBUTES;
233
    }
234

235
    CloseHandle(h);
236
    return finfo.dwFileAttributes;
237
}
238

239
/**
240
 * If the given attributes are the attributes of a reparse point, then
241
 * read and return the attributes of the special cases.
242
 */
243
DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)
244
{
245
    if ((a != INVALID_FILE_ATTRIBUTES) &&
246
        ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
247
    {
248
        BY_HANDLE_FILE_INFORMATION finfo;
249
        BOOL res = getFileInformation(path, &finfo);
250
        a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
251
    }
252
    return a;
253
}
254

255
/**
256
 * Take special cases into account when retrieving the attributes
257
 * of path
258
 */
259
DWORD getFinalAttributes(WCHAR *path)
260
{
261
    DWORD attr = INVALID_FILE_ATTRIBUTES;
262

263
    WIN32_FILE_ATTRIBUTE_DATA wfad;
264
    WIN32_FIND_DATAW wfd;
265
    HANDLE h;
266

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);
272
            }
273
        }
274
    } else {
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);
279
            FindClose(h);
280
        }
281
    }
282
    return attr;
283
}
284

285
JNIEXPORT jstring JNICALL
286
Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
287
                                           jstring pathname)
288
{
289
    jstring rv = NULL;
290
    WCHAR canonicalPath[MAX_PATH_LENGTH];
291

292
    WITH_UNICODE_STRING(env, pathname, path) {
293
        /* we estimate the max length of memory needed as
294
           "currentDir. length + pathname.length"
295
         */
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));
300
            if (cp != NULL) {
301
                if (wcanonicalize(path, cp, len) >= 0) {
302
                    rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
303
                }
304
                free(cp);
305
            } else {
306
                JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
307
            }
308
        } else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
309
            rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
310
        }
311
    } END_UNICODE_STRING(env, path);
312
    if (rv == NULL && !(*env)->ExceptionCheck(env)) {
313
        JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
314
    }
315
    return rv;
316
}
317

318

319
JNIEXPORT jstring JNICALL
320
Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
321
                                                     jstring canonicalPrefixString,
322
                                                     jstring pathWithCanonicalPrefixString)
323
{
324
    jstring rv = NULL;
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));
331
                if (cp != NULL) {
332
                    if (wcanonicalizeWithPrefix(canonicalPrefix,
333
                                                pathWithCanonicalPrefix,
334
                                                cp, len) >= 0) {
335
                      rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
336
                    }
337
                    free(cp);
338
                } else {
339
                    JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
340
                }
341
            } else if (wcanonicalizeWithPrefix(canonicalPrefix,
342
                                               pathWithCanonicalPrefix,
343
                                               canonicalPath, MAX_PATH_LENGTH) >= 0) {
344
                rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
345
            }
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");
350
    }
351
    return rv;
352
}
353

354
/* -- Attribute accessors -- */
355

356
/* Check whether or not the file name in "path" is a Windows reserved
357
   device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
358
   returned result from GetFullPathName, which should be in thr form of
359
   "\\.\[ReservedDeviceName]" if the path represents a reserved device
360
   name.
361
   Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer
362
   important anyway) is a device name, so we don't check it here.
363
   GetFileAttributesEx will catch it later by returning 0 on NT/XP/
364
   200X.
365

366
   Note2: Theoretically the implementation could just lookup the table
367
   below linearly if the first 4 characters of the fullpath returned
368
   from GetFullPathName are "\\.\". The current implementation should
369
   achieve the same result. If Microsoft add more names into their
370
   reserved device name repository in the future, which probably will
371
   never happen, we will need to revisit the lookup implementation.
372

373
static WCHAR* ReservedDEviceNames[] = {
374
    L"CON", L"PRN", L"AUX", L"NUL",
375
    L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9",
376
    L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9",
377
    L"CLOCK$"
378
};
379
 */
380

381
static BOOL isReservedDeviceNameW(WCHAR* path) {
382
#define BUFSIZE 9
383
    WCHAR buf[BUFSIZE];
384
    WCHAR *lpf = NULL;
385
    DWORD retLen = GetFullPathNameW(path,
386
                                   BUFSIZE,
387
                                   buf,
388
                                   &lpf);
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)
397
            return TRUE;
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)
402
            return TRUE;
403
    }
404
    return FALSE;
405
}
406

407
JNIEXPORT jint JNICALL
408
Java_java_io_WinNTFileSystem_getBooleanAttributes0(JNIEnv *env, jobject this,
409
                                                   jobject file)
410
{
411
    jint rv = 0;
412

413
    WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
414
    if (pathbuf == NULL)
415
        return rv;
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));
425
        }
426
    }
427
    free(pathbuf);
428
    return rv;
429
}
430

431

432
JNIEXPORT jboolean
433
JNICALL Java_java_io_WinNTFileSystem_checkAccess0(JNIEnv *env, jobject this,
434
                                                  jobject file, jint access)
435
{
436
    DWORD attr;
437
    WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
438
    if (pathbuf == NULL)
439
        return JNI_FALSE;
440
    attr = GetFileAttributesW(pathbuf);
441
    attr = getFinalAttributesIfReparsePoint(pathbuf, attr);
442
    free(pathbuf);
443
    if (attr == INVALID_FILE_ATTRIBUTES)
444
        return JNI_FALSE;
445
    switch (access) {
446
    case java_io_FileSystem_ACCESS_READ:
447
    case java_io_FileSystem_ACCESS_EXECUTE:
448
        return JNI_TRUE;
449
    case java_io_FileSystem_ACCESS_WRITE:
450
        /* Read-only attribute ignored on directories */
451
        if ((attr & FILE_ATTRIBUTE_DIRECTORY) ||
452
            (attr & FILE_ATTRIBUTE_READONLY) == 0)
453
            return JNI_TRUE;
454
        else
455
            return JNI_FALSE;
456
    default:
457
        assert(0);
458
        return JNI_FALSE;
459
    }
460
}
461

462
JNIEXPORT jboolean JNICALL
463
Java_java_io_WinNTFileSystem_setPermission0(JNIEnv *env, jobject this,
464
                                            jobject file,
465
                                            jint access,
466
                                            jboolean enable,
467
                                            jboolean owneronly)
468
{
469
    jboolean rv = JNI_FALSE;
470
    WCHAR *pathbuf;
471
    DWORD a;
472
    if (access == java_io_FileSystem_ACCESS_READ ||
473
        access == java_io_FileSystem_ACCESS_EXECUTE) {
474
        return enable;
475
    }
476
    pathbuf = fileToNTPath(env, file, ids.path);
477
    if (pathbuf == NULL)
478
        return JNI_FALSE;
479
    a = GetFileAttributesW(pathbuf);
480

481
    /* if reparse point, get final target */
482
    if ((a != INVALID_FILE_ATTRIBUTES) &&
483
        ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
484
    {
485
        WCHAR *fp = getFinalPath(env, pathbuf);
486
        if (fp == NULL) {
487
            a = INVALID_FILE_ATTRIBUTES;
488
        } else {
489
            free(pathbuf);
490
            pathbuf = fp;
491
            a = GetFileAttributesW(pathbuf);
492
        }
493
    }
494
    if ((a != INVALID_FILE_ATTRIBUTES) &&
495
        ((a & FILE_ATTRIBUTE_DIRECTORY) == 0))
496
    {
497
        if (enable)
498
            a =  a & ~FILE_ATTRIBUTE_READONLY;
499
        else
500
            a =  a | FILE_ATTRIBUTE_READONLY;
501
        if (SetFileAttributesW(pathbuf, a))
502
            rv = JNI_TRUE;
503
    }
504
    free(pathbuf);
505
    return rv;
506
}
507

508
JNIEXPORT jlong JNICALL
509
Java_java_io_WinNTFileSystem_getLastModifiedTime0(JNIEnv *env, jobject this,
510
                                                  jobject file)
511
{
512
    jlong rv = 0;
513
    ULARGE_INTEGER modTime;
514
    FILETIME t;
515
    HANDLE h;
516
    WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
517
    if (pathbuf == NULL)
518
        return rv;
519
    h = CreateFileW(pathbuf,
520
                    /* Device query access */
521
                    0,
522
                    /* Share it */
523
                    FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
524
                    /* No security attributes */
525
                    NULL,
526
                    /* Open existing or fail */
527
                    OPEN_EXISTING,
528
                    /* Backup semantics for directories */
529
                    FILE_FLAG_BACKUP_SEMANTICS,
530
                    /* No template file */
531
                    NULL);
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;
538
        }
539
        CloseHandle(h);
540
    }
541
    free(pathbuf);
542
    return rv;
543
}
544

545
JNIEXPORT jlong JNICALL
546
Java_java_io_WinNTFileSystem_getLength0(JNIEnv *env, jobject this, jobject file)
547
{
548
    jlong rv = 0;
549
    WIN32_FILE_ATTRIBUTE_DATA wfad;
550
    WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
551
    if (pathbuf == NULL)
552
        return rv;
553
    if (GetFileAttributesExW(pathbuf,
554
                             GetFileExInfoStandard,
555
                             &wfad)) {
556
        if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
557
            rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;
558
        } else {
559
            /* file is a reparse point so read attributes of final target */
560
            BY_HANDLE_FILE_INFORMATION finfo;
561
            if (getFileInformation(pathbuf, &finfo)) {
562
                rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) +
563
                    finfo.nFileSizeLow;
564
            }
565
        }
566
    } else {
567
        if (GetLastError() == ERROR_SHARING_VIOLATION) {
568
            //
569
            // The error is a "share violation", which means the file/dir
570
            // must exist. Try FindFirstFile, we know this at least works
571
            // for pagefile.sys.
572
            //
573

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) {
582
                        pslash = pathbuf;
583
                    } else {
584
                        pslash++;
585
                    }
586
                    WCHAR *fslash = wcsrchr(fileData.cFileName, backslash);
587
                    if (fslash == NULL) {
588
                        fslash = fileData.cFileName;
589
                    } else {
590
                        fslash++;
591
                    }
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;
598
                        }
599
                    }
600
                }
601
                FindClose(h);
602
            }
603
        }
604
    }
605
    free(pathbuf);
606
    return rv;
607
}
608

609
/* -- File operations -- */
610

611
JNIEXPORT jboolean JNICALL
612
Java_java_io_WinNTFileSystem_createFileExclusively0(JNIEnv *env, jclass cls,
613
                                                    jstring path)
614
{
615
    HANDLE h = NULL;
616
    WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
617
    if (pathbuf == NULL)
618
        return JNI_FALSE;
619
    if (isReservedDeviceNameW(pathbuf)) {
620
        free(pathbuf);
621
        return JNI_FALSE;
622
    }
623
    h = CreateFileW(
624
        pathbuf,                              /* Wide char path name */
625
        GENERIC_READ | GENERIC_WRITE,         /* Read and write permission */
626
        FILE_SHARE_READ | FILE_SHARE_WRITE,   /* File sharing flags */
627
        NULL,                                 /* Security attributes */
628
        CREATE_NEW,                           /* creation disposition */
629
        FILE_ATTRIBUTE_NORMAL |
630
            FILE_FLAG_OPEN_REPARSE_POINT,     /* flags and attributes */
631
        NULL);
632

633
    if (h == INVALID_HANDLE_VALUE) {
634
        DWORD error = GetLastError();
635
        if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
636
            // return false rather than throwing an exception when there is
637
            // an existing file.
638
            DWORD a = GetFileAttributesW(pathbuf);
639
            if (a == INVALID_FILE_ATTRIBUTES) {
640
                SetLastError(error);
641
                JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
642
            }
643
        }
644
        free(pathbuf);
645
        return JNI_FALSE;
646
    }
647
    free(pathbuf);
648
    CloseHandle(h);
649
    return JNI_TRUE;
650
}
651

652
static int
653
removeFileOrDirectory(const jchar *path)
654
{
655
    /* Returns 0 on success */
656
    DWORD a;
657

658
    SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
659
    a = GetFileAttributesW(path);
660
    if (a == INVALID_FILE_ATTRIBUTES) {
661
        return 1;
662
    } else if (a & FILE_ATTRIBUTE_DIRECTORY) {
663
        return !RemoveDirectoryW(path);
664
    } else {
665
        return !DeleteFileW(path);
666
    }
667
}
668

669
JNIEXPORT jboolean JNICALL
670
Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file)
671
{
672
    jboolean rv = JNI_FALSE;
673
    WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
674
    if (pathbuf == NULL) {
675
        return JNI_FALSE;
676
    }
677
    if (removeFileOrDirectory(pathbuf) == 0) {
678
        rv = JNI_TRUE;
679
    }
680
    free(pathbuf);
681
    return rv;
682
}
683

684
JNIEXPORT jobjectArray JNICALL
685
Java_java_io_WinNTFileSystem_list0(JNIEnv *env, jobject this, jobject file)
686
{
687
    WCHAR *search_path;
688
    HANDLE handle;
689
    WIN32_FIND_DATAW find_data;
690
    int len, maxlen;
691
    jobjectArray rv, old;
692
    DWORD fattr;
693
    jstring name;
694
    jclass str_class;
695
    WCHAR *pathbuf;
696
    DWORD err;
697

698
    str_class = JNU_ClassString(env);
699
    CHECK_NULL_RETURN(str_class, NULL);
700

701
    pathbuf = fileToNTPath(env, file, ids.path);
702
    if (pathbuf == NULL)
703
        return NULL;
704
    search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);
705
    if (search_path == 0) {
706
        free (pathbuf);
707
        errno = ENOMEM;
708
        JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
709
        return NULL;
710
    }
711
    wcscpy(search_path, pathbuf);
712
    free(pathbuf);
713
    fattr = GetFileAttributesW(search_path);
714
    if (fattr == INVALID_FILE_ATTRIBUTES) {
715
        free(search_path);
716
        return NULL;
717
    } else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
718
        free(search_path);
719
        return NULL;
720
    }
721

722
    /* Remove trailing space chars from directory name */
723
    len = (int)wcslen(search_path);
724
    while (search_path[len-1] == L' ') {
725
        len--;
726
    }
727
    search_path[len] = 0;
728

729
    /* Append "*", or possibly "\\*", to path */
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')))) {
734
        /* No '\\' needed for cases like "\" or "Z:" or "Z:\" */
735
        wcscat(search_path, L"*");
736
    } else {
737
        wcscat(search_path, L"\\*");
738
    }
739

740
    /* Open handle to the first file */
741
    handle = FindFirstFileW(search_path, &find_data);
742
    free(search_path);
743
    if (handle == INVALID_HANDLE_VALUE) {
744
        if (GetLastError() != ERROR_FILE_NOT_FOUND) {
745
            // error
746
            return NULL;
747
        } else {
748
            // No files found - return an empty array
749
            rv = (*env)->NewObjectArray(env, 0, str_class, NULL);
750
            return rv;
751
        }
752
    }
753

754
    /* Allocate an initial String array */
755
    len = 0;
756
    maxlen = 16;
757
    rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);
758
    if (rv == NULL) { // Couldn't allocate an array
759
        FindClose(handle);
760
        return NULL;
761
    }
762
    /* Scan the directory */
763
    do {
764
        if (!wcscmp(find_data.cFileName, L".")
765
                                || !wcscmp(find_data.cFileName, L".."))
766
           continue;
767
        name = (*env)->NewString(env, find_data.cFileName,
768
                                 (jsize)wcslen(find_data.cFileName));
769
        if (name == NULL) {
770
            FindClose(handle);
771
            return NULL; // error
772
        }
773
        if (len == maxlen) {
774
            old = rv;
775
            rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);
776
            if (rv == NULL || JNU_CopyObjectArray(env, rv, old, len) < 0) {
777
                FindClose(handle);
778
                return NULL; // error
779
            }
780
            (*env)->DeleteLocalRef(env, old);
781
        }
782
        (*env)->SetObjectArrayElement(env, rv, len++, name);
783
        (*env)->DeleteLocalRef(env, name);
784

785
    } while (FindNextFileW(handle, &find_data));
786

787
    err = GetLastError();
788
    FindClose(handle);
789
    if (err != ERROR_NO_MORE_FILES) {
790
        return NULL; // error
791
    }
792

793
    if (len < maxlen) {
794
        /* Copy the final results into an appropriately-sized array */
795
        old = rv;
796
        rv = (*env)->NewObjectArray(env, len, str_class, NULL);
797
        if (rv == NULL)
798
            return NULL; /* error */
799
        if (JNU_CopyObjectArray(env, rv, old, len) < 0)
800
            return NULL; /* error */
801
    }
802
    return rv;
803
}
804

805

806
JNIEXPORT jboolean JNICALL
807
Java_java_io_WinNTFileSystem_createDirectory0(JNIEnv *env, jobject this,
808
                                              jobject file)
809
{
810
    BOOL h = FALSE;
811
    WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
812
    if (pathbuf == NULL) {
813
        /* Exception is pending */
814
        return JNI_FALSE;
815
    }
816
    h = CreateDirectoryW(pathbuf, NULL);
817
    free(pathbuf);
818

819
    if (h == 0) {
820
        return JNI_FALSE;
821
    }
822

823
    return JNI_TRUE;
824
}
825

826

827
JNIEXPORT jboolean JNICALL
828
Java_java_io_WinNTFileSystem_rename0(JNIEnv *env, jobject this, jobject from,
829
                                     jobject to)
830
{
831

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) {
836
        rv = JNI_TRUE;
837
    }
838
    free(frompath);
839
    free(topath);
840
    return rv;
841
}
842

843

844
JNIEXPORT jboolean JNICALL
845
Java_java_io_WinNTFileSystem_setLastModifiedTime0(JNIEnv *env, jobject this,
846
                                                  jobject file, jlong time)
847
{
848
    jboolean rv = JNI_FALSE;
849
    WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
850
    HANDLE h;
851
    if (pathbuf == NULL)
852
        return JNI_FALSE;
853
    h = CreateFileW(pathbuf,
854
                    FILE_WRITE_ATTRIBUTES,
855
                    FILE_SHARE_READ | FILE_SHARE_WRITE,
856
                    NULL,
857
                    OPEN_EXISTING,
858
                    FILE_FLAG_BACKUP_SEMANTICS,
859
                    0);
860
    if (h != INVALID_HANDLE_VALUE) {
861
        ULARGE_INTEGER modTime;
862
        FILETIME t;
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)) {
867
            rv = JNI_TRUE;
868
        }
869
        CloseHandle(h);
870
    }
871
    free(pathbuf);
872

873
    return rv;
874
}
875

876

877
JNIEXPORT jboolean JNICALL
878
Java_java_io_WinNTFileSystem_setReadOnly0(JNIEnv *env, jobject this,
879
                                          jobject file)
880
{
881
    jboolean rv = JNI_FALSE;
882
    DWORD a;
883
    WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
884
    if (pathbuf == NULL)
885
        return JNI_FALSE;
886
    a = GetFileAttributesW(pathbuf);
887

888
    /* if reparse point, get final target */
889
    if ((a != INVALID_FILE_ATTRIBUTES) &&
890
        ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
891
    {
892
        WCHAR *fp = getFinalPath(env, pathbuf);
893
        if (fp == NULL) {
894
            a = INVALID_FILE_ATTRIBUTES;
895
        } else {
896
            free(pathbuf);
897
            pathbuf = fp;
898
            a = GetFileAttributesW(pathbuf);
899
        }
900
    }
901

902
    if ((a != INVALID_FILE_ATTRIBUTES) &&
903
        ((a & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
904
        if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))
905
            rv = JNI_TRUE;
906
    }
907
    free(pathbuf);
908
    return rv;
909
}
910

911
/* -- Filesystem interface -- */
912

913

914
JNIEXPORT jobject JNICALL
915
Java_java_io_WinNTFileSystem_getDriveDirectory(JNIEnv *env, jobject this,
916
                                               jint drive)
917
{
918
    jstring ret = NULL;
919
    jchar *p = currentDir(drive);
920
    jchar *pf = p;
921
    if (p == NULL) return NULL;
922
    if (iswalpha(*p) && (p[1] == L':')) p += 2;
923
    ret = (*env)->NewString(env, p, (jsize)wcslen(p));
924
    free (pf);
925
    return ret;
926
}
927

928
JNIEXPORT jint JNICALL
929
Java_java_io_WinNTFileSystem_listRoots0(JNIEnv *env, jclass ignored)
930
{
931
    return GetLogicalDrives();
932
}
933

934
JNIEXPORT jlong JNICALL
935
Java_java_io_WinNTFileSystem_getSpace0(JNIEnv *env, jobject this,
936
                                       jobject file, jint t)
937
{
938
    WCHAR volname[MAX_PATH_LENGTH + 1];
939
    jlong rv = 0L;
940
    WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
941

942
    if (GetVolumePathNameW(pathbuf, volname, MAX_PATH_LENGTH)) {
943
        ULARGE_INTEGER totalSpace, freeSpace, usableSpace;
944
        if (GetDiskFreeSpaceExW(volname, &usableSpace, &totalSpace, &freeSpace)) {
945
            switch(t) {
946
            case java_io_FileSystem_SPACE_TOTAL:
947
                rv = long_to_jlong(totalSpace.QuadPart);
948
                break;
949
            case java_io_FileSystem_SPACE_FREE:
950
                rv = long_to_jlong(freeSpace.QuadPart);
951
                break;
952
            case java_io_FileSystem_SPACE_USABLE:
953
                rv = long_to_jlong(usableSpace.QuadPart);
954
                break;
955
            default:
956
                assert(0);
957
            }
958
        }
959
    }
960

961
    free(pathbuf);
962
    return rv;
963
}
964

965
// pathname is expected to be either null or to contain the root
966
// of the path terminated by a backslash
967
JNIEXPORT jint JNICALL
968
Java_java_io_WinNTFileSystem_getNameMax0(JNIEnv *env, jobject this,
969
                                         jstring pathname)
970
{
971
    BOOL res = 0;
972
    DWORD maxComponentLength;
973

974
    if (pathname == NULL) {
975
            res = GetVolumeInformationW(NULL,
976
                                        NULL,
977
                                        0,
978
                                        NULL,
979
                                        &maxComponentLength,
980
                                        NULL,
981
                                        NULL,
982
                                        0);
983
    } else {
984
        WITH_UNICODE_STRING(env, pathname, path) {
985
            res = GetVolumeInformationW(path,
986
                                        NULL,
987
                                        0,
988
                                        NULL,
989
                                        &maxComponentLength,
990
                                        NULL,
991
                                        NULL,
992
                                        0);
993
        } END_UNICODE_STRING(env, path);
994
    }
995

996
    if (res == 0) {
997
        JNU_ThrowIOExceptionWithLastError(env,
998
            "Could not get maximum component length");
999
    }
1000

1001
    return (jint)maxComponentLength;
1002
}
1003

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.